fix: make navigation no-focus by default
- Change nav open and open-wait to avoid activating newly created tabs unless --focus is explicitly requested. - Send background=true for default opens so older or remote extensions also avoid stealing focus even if they ignore the new focus flag. - Remove the redundant --bg flag from navigation and search CLI commands now that no-focus/background behavior is the default. - Thread focus support through the sync SDK, async SDK, tab helpers, and workflow decorators. - Update README and demo usage to document the new default and --focus opt-in. - Bump package and extension metadata to 0.12.3. - Add regression coverage for CLI help, wire payloads, and extension behavior.
This commit is contained in:
@@ -84,6 +84,7 @@ class AsyncDecoratorsNS(WorkflowDecoratorsMixin):
|
||||
wait: bool = False,
|
||||
timeout: float = 30.0,
|
||||
background: bool = False,
|
||||
focus: bool = False,
|
||||
window: str | None = None,
|
||||
group: str | None = None,
|
||||
close: bool = False,
|
||||
@@ -95,6 +96,7 @@ class AsyncDecoratorsNS(WorkflowDecoratorsMixin):
|
||||
wait=wait,
|
||||
timeout=timeout,
|
||||
background=background,
|
||||
focus=focus,
|
||||
window=window,
|
||||
group=group,
|
||||
)
|
||||
|
||||
@@ -10,13 +10,13 @@ def nav_group():
|
||||
|
||||
@nav_group.command("open")
|
||||
@click.argument("url")
|
||||
@click.option("--bg", is_flag=True, help="Open in background (no focus)")
|
||||
@click.option("--focus", is_flag=True, help="Bring the opened tab/window to the front")
|
||||
@click.option("--window", "window_name", default=None, help="Open in named window")
|
||||
@click.option("--group", "group_name", default=None, help="Open directly into a tab group (name or ID)")
|
||||
@handle_errors
|
||||
def cmd_open(url, bg, window_name, group_name):
|
||||
"""Open URL in a new tab."""
|
||||
client_from_ctx().nav.open(url, background=bg, window=window_name, group=group_name)
|
||||
def cmd_open(url, focus, window_name, group_name):
|
||||
"""Open URL in a new tab without stealing focus by default."""
|
||||
client_from_ctx().nav.open(url, focus=focus, window=window_name, group=group_name)
|
||||
suffix = ""
|
||||
if group_name:
|
||||
suffix = f" in group '{group_name}'"
|
||||
@@ -70,13 +70,13 @@ def cmd_focus(pattern):
|
||||
@nav_group.command("open-wait")
|
||||
@click.argument("url")
|
||||
@click.option("--timeout", type=float, default=30.0, show_default=True, help="Max seconds to wait for load")
|
||||
@click.option("--bg", is_flag=True, help="Open in background (no focus)")
|
||||
@click.option("--focus", is_flag=True, help="Bring the opened tab/window to the front")
|
||||
@click.option("--window", "window_name", default=None, help="Open in named window")
|
||||
@click.option("--group", "group_name", default=None, help="Open in tab group")
|
||||
@handle_errors
|
||||
def cmd_open_wait(url, timeout, bg, window_name, group_name):
|
||||
def cmd_open_wait(url, timeout, focus, window_name, group_name):
|
||||
"""Open URL in a new tab and wait until fully loaded."""
|
||||
tab = client_from_ctx().nav.open_wait(url, timeout=timeout, background=bg, window=window_name, group=group_name)
|
||||
tab = client_from_ctx().nav.open_wait(url, timeout=timeout, focus=focus, window=window_name, group=group_name)
|
||||
console.print(f"[green]Loaded:[/green] {url}" + (f" — {tab.title}" if tab.title else ""))
|
||||
|
||||
@nav_group.command("wait")
|
||||
|
||||
@@ -63,13 +63,12 @@ def search_group():
|
||||
def _build_command(engine_key: str, help_text: str) -> click.Command:
|
||||
@click.command(engine_key, help=help_text)
|
||||
@click.argument("query", nargs=-1, required=True)
|
||||
@click.option("--bg", is_flag=True, help="Open in background (no focus)")
|
||||
@click.option("--window", "window", default=None, help="Open in named window")
|
||||
@click.option("--group", "group", default=None, help="Open in tab group (name or ID)")
|
||||
@handle_errors
|
||||
def _cmd(query, bg, window, group):
|
||||
def _cmd(query, window, group):
|
||||
terms = " ".join(query)
|
||||
client_from_ctx().nav.search(engine_key, terms, background=bg, window=window, group=group)
|
||||
client_from_ctx().nav.search(engine_key, terms, window=window, group=group)
|
||||
suffix = f" in group '{group}'" if group else (f" in window '{window}'" if window else "")
|
||||
display = _DISPLAY_NAMES.get(engine_key, engine_key.capitalize())
|
||||
console.print(f"[green]Searching[/green] [cyan]{display}[/cyan]: {terms}{suffix}")
|
||||
|
||||
@@ -4,8 +4,8 @@ from __future__ import annotations
|
||||
from browser_cli.models import Tab
|
||||
from browser_cli.sdk.base import Namespace, sdk_command
|
||||
|
||||
def _open_args(self, url, *, background=False, window=None, group=None):
|
||||
return {"url": url, "background": background, "window": window, "group": group}
|
||||
def _open_args(self, url, *, background=False, focus=False, window=None, group=None):
|
||||
return {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group}
|
||||
|
||||
def _tab_args(self, tab_id=None):
|
||||
return {"tabId": tab_id}
|
||||
@@ -14,8 +14,16 @@ class NavigationNS(Namespace):
|
||||
"""Open URLs, navigate history, and focus tabs."""
|
||||
|
||||
@sdk_command("navigate.open", _open_args)
|
||||
def open(self, url: str, *, background: bool = False, window: str | None = None, group: str | None = None) -> None:
|
||||
"""Open *url* in a new tab."""
|
||||
def open(
|
||||
self,
|
||||
url: str,
|
||||
*,
|
||||
background: bool = False,
|
||||
focus: bool = False,
|
||||
window: str | None = None,
|
||||
group: str | None = None,
|
||||
) -> None:
|
||||
"""Open *url* in a new tab without stealing OS focus by default."""
|
||||
|
||||
def open_wait(
|
||||
self,
|
||||
@@ -23,6 +31,7 @@ class NavigationNS(Namespace):
|
||||
*,
|
||||
timeout: float = 30.0,
|
||||
background: bool = False,
|
||||
focus: bool = False,
|
||||
window: str | None = None,
|
||||
group: str | None = None,
|
||||
) -> Tab:
|
||||
@@ -30,7 +39,7 @@ class NavigationNS(Namespace):
|
||||
return self.require_tab(
|
||||
self.command("navigate.open_wait", {
|
||||
"url": url, "timeout": int(timeout * 1000),
|
||||
"background": background, "window": window, "group": group,
|
||||
"background": background or not focus, "focus": focus, "window": window, "group": group,
|
||||
}),
|
||||
"navigate.open_wait returned unexpected data",
|
||||
)
|
||||
@@ -61,7 +70,7 @@ class NavigationNS(Namespace):
|
||||
|
||||
def search(
|
||||
self, engine: str, query: str, *,
|
||||
background: bool = False, window: str | None = None, group: str | None = None,
|
||||
background: bool = False, focus: bool = False, window: str | None = None, group: str | None = None,
|
||||
) -> None:
|
||||
"""Open a search query in the given engine (e.g. 'google', 'youtube', 'ddg')."""
|
||||
from urllib.parse import quote_plus
|
||||
@@ -70,4 +79,4 @@ class NavigationNS(Namespace):
|
||||
if template is None:
|
||||
raise ValueError(f"Unknown search engine '{engine}'. Available: {', '.join(ENGINES)}")
|
||||
url = template.format(query=quote_plus(query))
|
||||
self.command("navigate.open", {"url": url, "background": background, "window": window, "group": group})
|
||||
self.command("navigate.open", {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group})
|
||||
|
||||
@@ -24,17 +24,19 @@ class TabsNS(Namespace):
|
||||
wait: bool = False,
|
||||
timeout: float = 30.0,
|
||||
background: bool = False,
|
||||
focus: bool = False,
|
||||
window: str | None = None,
|
||||
group: str | None = None,
|
||||
) -> Tab:
|
||||
"""Open *url* in a new tab and return a bound :class:`Tab`.
|
||||
|
||||
Set ``wait=True`` to block until the page reaches ``readyState=complete``.
|
||||
Pass ``focus=True`` to explicitly bring the created tab/window forward.
|
||||
"""
|
||||
if wait:
|
||||
return self._c.nav.open_wait(url, timeout=timeout, background=background, window=window, group=group)
|
||||
return self._c.nav.open_wait(url, timeout=timeout, background=background, focus=focus, window=window, group=group)
|
||||
return self.require_tab(
|
||||
self.command("navigate.open", {"url": url, "background": background, "window": window, "group": group}),
|
||||
self.command("navigate.open", {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group}),
|
||||
"navigate.open returned unexpected data",
|
||||
)
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ class WorkflowDecoratorsMixin:
|
||||
wait: bool = False,
|
||||
timeout: float = 30.0,
|
||||
background: bool = False,
|
||||
focus: bool = False,
|
||||
window: str | None = None,
|
||||
group: str | None = None,
|
||||
close: bool = False,
|
||||
@@ -97,6 +98,7 @@ class WorkflowDecoratorsMixin:
|
||||
wait=wait,
|
||||
timeout=timeout,
|
||||
background=background,
|
||||
focus=focus,
|
||||
window=window,
|
||||
group=group,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user