mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 03:47:31 +09:00
260 lines
10 KiB
Python
260 lines
10 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
from marionette_driver import By, Wait
|
|
from marionette_driver.errors import NoSuchElementException
|
|
|
|
from firefox_puppeteer.ui.about_window.window import AboutWindow
|
|
from firefox_puppeteer.ui.browser.notifications import (
|
|
AddOnInstallBlockedNotification,
|
|
AddOnInstallConfirmationNotification,
|
|
AddOnInstallCompleteNotification,
|
|
AddOnInstallFailedNotification,
|
|
AddOnProgressNotification,
|
|
BaseNotification)
|
|
from firefox_puppeteer.ui.browser.tabbar import TabBar
|
|
from firefox_puppeteer.ui.browser.toolbars import NavBar
|
|
from firefox_puppeteer.ui.pageinfo.window import PageInfoWindow
|
|
from firefox_puppeteer.ui.windows import BaseWindow, Windows
|
|
|
|
|
|
class BrowserWindow(BaseWindow):
|
|
"""Representation of a browser window."""
|
|
|
|
window_type = 'navigator:browser'
|
|
|
|
dtds = [
|
|
'chrome://branding/locale/brand.dtd',
|
|
'chrome://browser/locale/aboutPrivateBrowsing.dtd',
|
|
'chrome://browser/locale/browser.dtd',
|
|
'chrome://browser/locale/netError.dtd',
|
|
]
|
|
|
|
properties = [
|
|
'chrome://branding/locale/brand.properties',
|
|
'chrome://branding/locale/browserconfig.properties',
|
|
'chrome://browser/locale/browser.properties',
|
|
'chrome://browser/locale/preferences/preferences.properties',
|
|
'chrome://global/locale/browser.properties',
|
|
]
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(BrowserWindow, self).__init__(*args, **kwargs)
|
|
|
|
self._navbar = None
|
|
self._tabbar = None
|
|
|
|
@property
|
|
def default_homepage(self):
|
|
"""The default homepage as used by the current locale.
|
|
|
|
:returns: The default homepage for the current locale.
|
|
"""
|
|
return self.marionette.get_pref('browser.startup.homepage',
|
|
value_type='nsIPrefLocalizedString')
|
|
|
|
@property
|
|
def is_private(self):
|
|
"""Returns True if this is a Private Browsing window."""
|
|
self.switch_to()
|
|
|
|
with self.marionette.using_context('chrome'):
|
|
return self.marionette.execute_script("""
|
|
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
|
|
let chromeWindow = arguments[0].ownerDocument.defaultView;
|
|
return PrivateBrowsingUtils.isWindowPrivate(chromeWindow);
|
|
""", script_args=[self.window_element])
|
|
|
|
@property
|
|
def navbar(self):
|
|
"""Provides access to the navigation bar. This is the toolbar containing
|
|
the back, forward and home buttons. It also contains the location bar.
|
|
|
|
See the :class:`~ui.browser.toolbars.NavBar` reference.
|
|
"""
|
|
self.switch_to()
|
|
|
|
if not self._navbar:
|
|
navbar = self.window_element.find_element(By.ID, 'nav-bar')
|
|
self._navbar = NavBar(self.marionette, self, navbar)
|
|
|
|
return self._navbar
|
|
|
|
@property
|
|
def notification(self):
|
|
"""Provides access to the currently displayed notification."""
|
|
|
|
notifications_map = {
|
|
'addon-install-blocked-notification': AddOnInstallBlockedNotification,
|
|
'addon-install-confirmation-notification': AddOnInstallConfirmationNotification,
|
|
'addon-install-complete-notification': AddOnInstallCompleteNotification,
|
|
'addon-install-failed-notification': AddOnInstallFailedNotification,
|
|
'addon-progress-notification': AddOnProgressNotification,
|
|
}
|
|
|
|
try:
|
|
notification = self.window_element.find_element(
|
|
By.CSS_SELECTOR, '#notification-popup popupnotification')
|
|
|
|
notification_id = notification.get_attribute('id')
|
|
return notifications_map.get(notification_id, BaseNotification)(
|
|
self.marionette, self, notification)
|
|
|
|
except NoSuchElementException:
|
|
return None # no notification is displayed
|
|
|
|
def wait_for_notification(self, notification_class=BaseNotification,
|
|
timeout=5):
|
|
"""Waits for the specified notification to be displayed.
|
|
|
|
:param notification_class: Optional, the notification class to wait for.
|
|
If `None` is specified it will wait for any notification to be closed.
|
|
Defaults to `BaseNotification`.
|
|
:param timeout: Optional, how long to wait for the expected notification.
|
|
Defaults to 5 seconds.
|
|
"""
|
|
wait = Wait(self.marionette, timeout=timeout)
|
|
|
|
if notification_class:
|
|
if notification_class is BaseNotification:
|
|
message = 'No notification was shown.'
|
|
else:
|
|
message = '{0} was not shown.'.format(notification_class.__name__)
|
|
wait.until(
|
|
lambda _: isinstance(self.notification, notification_class),
|
|
message=message)
|
|
else:
|
|
message = 'Unexpected notification shown.'
|
|
wait.until(
|
|
lambda _: self.notification is None,
|
|
message='Unexpected notification shown.')
|
|
|
|
@property
|
|
def tabbar(self):
|
|
"""Provides access to the tab bar.
|
|
|
|
See the :class:`~ui.browser.tabbar.TabBar` reference.
|
|
"""
|
|
self.switch_to()
|
|
|
|
if not self._tabbar:
|
|
tabbrowser = self.window_element.find_element(By.ID, 'tabbrowser-tabs')
|
|
self._tabbar = TabBar(self.marionette, self, tabbrowser)
|
|
|
|
return self._tabbar
|
|
|
|
def close(self, trigger='menu', force=False):
|
|
"""Closes the current browser window by using the specified trigger.
|
|
|
|
:param trigger: Optional, method to close the current browser window. This can
|
|
be a string with one of `menu` or `shortcut`, or a callback which gets triggered
|
|
with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
|
|
|
|
:param force: Optional, forces the closing of the window by using the Gecko API.
|
|
Defaults to `False`.
|
|
"""
|
|
def callback(win):
|
|
# Prepare action which triggers the opening of the browser window
|
|
if callable(trigger):
|
|
trigger(win)
|
|
elif trigger == 'menu':
|
|
self.menubar.select_by_id('file-menu', 'menu_closeWindow')
|
|
elif trigger == 'shortcut':
|
|
win.send_shortcut(win.localize_entity('closeCmd.key'),
|
|
accel=True, shift=True)
|
|
else:
|
|
raise ValueError('Unknown closing method: "%s"' % trigger)
|
|
|
|
BaseWindow.close(self, callback, force)
|
|
|
|
def get_final_url(self, url):
|
|
"""Loads the page at `url` and returns the resulting url.
|
|
|
|
This function enables testing redirects.
|
|
|
|
:param url: The url to test.
|
|
:returns: The resulting loaded url.
|
|
"""
|
|
with self.marionette.using_context('content'):
|
|
self.marionette.navigate(url)
|
|
return self.marionette.get_url()
|
|
|
|
def open_browser(self, trigger='menu', is_private=False):
|
|
"""Opens a new browser window by using the specified trigger.
|
|
|
|
:param trigger: Optional, method in how to open the new browser window. This can
|
|
be a string with one of `menu` or `shortcut`, or a callback which gets triggered
|
|
with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
|
|
|
|
:param is_private: Optional, if True the new window will be a private browsing one.
|
|
|
|
:returns: :class:`BrowserWindow` instance for the new browser window.
|
|
"""
|
|
def callback(win):
|
|
# Prepare action which triggers the opening of the browser window
|
|
if callable(trigger):
|
|
trigger(win)
|
|
elif trigger == 'menu':
|
|
menu_id = 'menu_newPrivateWindow' if is_private else 'menu_newNavigator'
|
|
self.menubar.select_by_id('file-menu', menu_id)
|
|
elif trigger == 'shortcut':
|
|
cmd_key = 'privateBrowsingCmd.commandkey' if is_private else 'newNavigatorCmd.key'
|
|
win.send_shortcut(win.localize_entity(cmd_key),
|
|
accel=True, shift=is_private)
|
|
else:
|
|
raise ValueError('Unknown opening method: "%s"' % trigger)
|
|
|
|
return BaseWindow.open_window(self, callback, BrowserWindow)
|
|
|
|
def open_about_window(self, trigger='menu'):
|
|
"""Opens the about window by using the specified trigger.
|
|
|
|
:param trigger: Optional, method in how to open the new browser window. This can
|
|
either the string `menu` or a callback which gets triggered
|
|
with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
|
|
|
|
:returns: :class:`AboutWindow` instance of the opened window.
|
|
"""
|
|
def callback(win):
|
|
# Prepare action which triggers the opening of the browser window
|
|
if callable(trigger):
|
|
trigger(win)
|
|
elif trigger == 'menu':
|
|
self.menubar.select_by_id('helpMenu', 'aboutName')
|
|
else:
|
|
raise ValueError('Unknown opening method: "%s"' % trigger)
|
|
|
|
return BaseWindow.open_window(self, callback, AboutWindow)
|
|
|
|
def open_page_info_window(self, trigger='menu'):
|
|
"""Opens the page info window by using the specified trigger.
|
|
|
|
:param trigger: Optional, method in how to open the new browser window. This can
|
|
be a string with one of `menu` or `shortcut`, or a callback which gets triggered
|
|
with the current :class:`BrowserWindow` as parameter. Defaults to `menu`.
|
|
|
|
:returns: :class:`PageInfoWindow` instance of the opened window.
|
|
"""
|
|
def callback(win):
|
|
# Prepare action which triggers the opening of the browser window
|
|
if callable(trigger):
|
|
trigger(win)
|
|
elif trigger == 'menu':
|
|
self.menubar.select_by_id('tools-menu', 'menu_pageInfo')
|
|
elif trigger == 'shortcut':
|
|
if win.marionette.session_capabilities['platformName'] == 'windows_nt':
|
|
raise ValueError('Page info shortcut not available on Windows.')
|
|
win.send_shortcut(win.localize_entity('pageInfoCmd.commandkey'),
|
|
accel=True)
|
|
elif trigger == 'context_menu':
|
|
# TODO: Add once we can do right clicks
|
|
pass
|
|
else:
|
|
raise ValueError('Unknown opening method: "%s"' % trigger)
|
|
|
|
return BaseWindow.open_window(self, callback, PageInfoWindow)
|
|
|
|
|
|
Windows.register_window(BrowserWindow.window_type, BrowserWindow)
|