from typing import Any, Callable, Union from urllib.parse import urlparse from .. import background_tasks from ..client import Client from ..context import context from ..element import Element from ..elements.sub_pages import SubPages from .javascript import run_javascript class Navigate: """Navigation functions These functions allow you to navigate within the browser history and to external URLs. *Added in version 2.0.0* """ def __init__(self) -> None: self.history = History() def back(self) -> None: """ui.navigate.back Navigates back in the browser history. It is equivalent to clicking the back button in the browser. """ run_javascript('history.back()') def forward(self) -> None: """ui.navigate.forward Navigates forward in the browser history. It is equivalent to clicking the forward button in the browser. """ run_javascript('history.forward()') def reload(self) -> None: """ui.navigate.reload Reload the current page. It is equivalent to clicking the reload button in the browser. """ run_javascript('history.go(0)') def to(self, target: Union[Callable[..., Any], str, Element], new_tab: bool = False) -> None: """ui.navigate.to (formerly ui.open) Can be used to programmatically open a different page or URL. When using the `new_tab` parameter, the browser might block the new tab. This is a browser setting and cannot be changed by the application. You might want to use `ui.link` and its `new_tab` parameter instead. :param target: page function, NiceGUI element on the same page or string that is a an absolute URL or relative path from base URL :param new_tab: whether to open the target in a new tab (might be blocked by the browser) """ if isinstance(target, str): path = target elif isinstance(target, Element): path = f'#{target.html_id}' elif callable(target): path = Client.page_routes[target] else: raise TypeError(f'Invalid target type: {type(target)}') if not new_tab and isinstance(target, str): parsed = urlparse(path) if not parsed.scheme and not parsed.netloc and \ any(isinstance(el, SubPages) for el in context.client.elements.values()): async def navigate_sub_pages(client: Client) -> None: with client: await client.sub_pages_router._handle_navigate(path) # pylint: disable=protected-access background_tasks.create(navigate_sub_pages(context.client), name='navigate_sub_pages') return context.client.open(path, new_tab) class History: def push(self, url: str) -> None: """Push a URL to the browser navigation history. See JavaScript's `pushState `_ for more information. *Added in version 2.13.0* :param url: relative or absolute URL """ run_javascript(f'history.pushState({{}}, "", "{url}");') def replace(self, url: str) -> None: """Replace the current URL in the browser history. See JavaScript's `replaceState `_ for more information. *Added in version 2.13.0* :param url: relative or absolute URL """ run_javascript(f'history.replaceState({{}}, "", "{url}");') navigate = Navigate()