mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-28 11:27:32 +09:00
641 lines
21 KiB
Python
641 lines
21 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, keys, Wait
|
|
|
|
from firefox_puppeteer.ui.base import UIBaseLib
|
|
|
|
|
|
class NavBar(UIBaseLib):
|
|
"""Provides access to the DOM elements contained in the
|
|
navigation bar as well as the location bar."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(NavBar, self).__init__(*args, **kwargs)
|
|
|
|
self._locationbar = None
|
|
|
|
@property
|
|
def back_button(self):
|
|
"""Provides access to the DOM element back button in the navbar.
|
|
|
|
:returns: Reference to the back button.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'back-button')
|
|
|
|
@property
|
|
def forward_button(self):
|
|
"""Provides access to the DOM element forward button in the navbar.
|
|
|
|
:returns: Reference to the forward button.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'forward-button')
|
|
|
|
@property
|
|
def home_button(self):
|
|
"""Provides access to the DOM element home button in the navbar.
|
|
|
|
:returns: Reference to the home button element
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'home-button')
|
|
|
|
@property
|
|
def locationbar(self):
|
|
"""Provides access to the DOM elements contained in the
|
|
locationbar.
|
|
|
|
See the :class:`LocationBar` reference.
|
|
"""
|
|
if not self._locationbar:
|
|
urlbar = self.marionette.find_element(By.ID, 'urlbar')
|
|
self._locationbar = LocationBar(self.marionette, self.window, urlbar)
|
|
|
|
return self._locationbar
|
|
|
|
@property
|
|
def menu_button(self):
|
|
"""Provides access to the DOM element menu button in the navbar.
|
|
|
|
:returns: Reference to the menu button element.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'PanelUI-menu-button')
|
|
|
|
@property
|
|
def toolbar(self):
|
|
"""The DOM element which represents the navigation toolbar.
|
|
|
|
:returns: Reference to the navigation toolbar.
|
|
"""
|
|
return self.element
|
|
|
|
|
|
class LocationBar(UIBaseLib):
|
|
"""Provides access to and methods for the DOM elements contained in the
|
|
locationbar (the text area of the ui that typically displays the current url)."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(LocationBar, self).__init__(*args, **kwargs)
|
|
|
|
self._autocomplete_results = None
|
|
self._identity_popup = None
|
|
|
|
@property
|
|
def autocomplete_results(self):
|
|
"""Provides access to and methods for the location bar
|
|
autocomplete results.
|
|
|
|
See the :class:`AutocompleteResults` reference."""
|
|
if not self._autocomplete_results:
|
|
popup = self.marionette.find_element(By.ID, 'PopupAutoCompleteRichResult')
|
|
self._autocomplete_results = AutocompleteResults(self.marionette,
|
|
self.window, popup)
|
|
|
|
return self._autocomplete_results
|
|
|
|
def clear(self):
|
|
"""Clears the contents of the url bar (via the DELETE shortcut)."""
|
|
self.focus('shortcut')
|
|
self.urlbar.send_keys(keys.Keys.DELETE)
|
|
Wait(self.marionette).until(
|
|
lambda _: self.value == '',
|
|
message='Contents of location bar could not be cleared.')
|
|
|
|
def close_context_menu(self):
|
|
"""Closes the Location Bar context menu by a key event."""
|
|
# TODO: This method should be implemented via the menu API.
|
|
self.contextmenu.send_keys(keys.Keys.ESCAPE)
|
|
|
|
@property
|
|
def connection_icon(self):
|
|
""" Provides access to the urlbar connection icon.
|
|
|
|
:returns: Reference to the connection icon element.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'connection-icon')
|
|
|
|
@property
|
|
def contextmenu(self):
|
|
"""Provides access to the urlbar context menu.
|
|
|
|
:returns: Reference to the urlbar context menu.
|
|
"""
|
|
# TODO: This method should be implemented via the menu API.
|
|
parent = self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'textbox-input-box'})
|
|
return parent.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input-box-contextmenu'})
|
|
|
|
@property
|
|
def focused(self):
|
|
"""Checks the focus state of the location bar.
|
|
|
|
:returns: `True` if focused, otherwise `False`
|
|
"""
|
|
return self.urlbar.get_attribute('focused') == 'true'
|
|
|
|
@property
|
|
def identity_icon(self):
|
|
""" Provides access to the urlbar identity icon.
|
|
|
|
:returns: Reference to the identity icon element.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'identity-icon')
|
|
|
|
def focus(self, event='click'):
|
|
"""Focus the location bar according to the provided event.
|
|
|
|
:param eventt: The event to synthesize in order to focus the urlbar
|
|
(one of `click` or `shortcut`).
|
|
"""
|
|
if event == 'click':
|
|
self.urlbar.click()
|
|
elif event == 'shortcut':
|
|
cmd_key = self.window.localize_entity('openCmd.commandkey')
|
|
self.window.send_shortcut(cmd_key, accel=True)
|
|
else:
|
|
raise ValueError("An unknown event type was passed: %s" % event)
|
|
|
|
Wait(self.marionette).until(
|
|
lambda _: self.focused,
|
|
message='Location bar has not be focused.')
|
|
|
|
def get_contextmenu_entry(self, action):
|
|
"""Retrieves the urlbar context menu entry corresponding
|
|
to the given action.
|
|
|
|
:param action: The action corresponding to the retrieved value.
|
|
:returns: Reference to the urlbar contextmenu entry.
|
|
"""
|
|
# TODO: This method should be implemented via the menu API.
|
|
entries = self.contextmenu.find_elements(By.CSS_SELECTOR, 'menuitem')
|
|
filter_on = 'cmd_%s' % action
|
|
found = [e for e in entries if e.get_attribute('cmd') == filter_on]
|
|
return found[0] if len(found) else None
|
|
|
|
@property
|
|
def history_drop_marker(self):
|
|
"""Provides access to the history drop marker.
|
|
|
|
:returns: Reference to the history drop marker.
|
|
"""
|
|
return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'historydropmarker'})
|
|
|
|
@property
|
|
def identity_box(self):
|
|
"""The DOM element which represents the identity box.
|
|
|
|
:returns: Reference to the identity box.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'identity-box')
|
|
|
|
@property
|
|
def identity_country_label(self):
|
|
"""The DOM element which represents the identity icon country label.
|
|
|
|
:returns: Reference to the identity icon country label.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'identity-icon-country-label')
|
|
|
|
@property
|
|
def identity_organization_label(self):
|
|
"""The DOM element which represents the identity icon label.
|
|
|
|
:returns: Reference to the identity icon label.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'identity-icon-label')
|
|
|
|
@property
|
|
def identity_popup(self):
|
|
"""Provides utility members for accessing and manipulating the
|
|
identity popup.
|
|
|
|
See the :class:`IdentityPopup` reference.
|
|
"""
|
|
if not self._identity_popup:
|
|
popup = self.marionette.find_element(By.ID, 'identity-popup')
|
|
self._identity_popup = IdentityPopup(self.marionette,
|
|
self.window, popup)
|
|
|
|
return self._identity_popup
|
|
|
|
def load_url(self, url):
|
|
"""Load the specified url in the location bar by synthesized
|
|
keystrokes.
|
|
|
|
:param url: The url to load.
|
|
"""
|
|
self.clear()
|
|
self.focus('shortcut')
|
|
self.urlbar.send_keys(url + keys.Keys.ENTER)
|
|
|
|
@property
|
|
def notification_popup(self):
|
|
"""Provides access to the DOM element notification popup.
|
|
|
|
:returns: Reference to the notification popup.
|
|
"""
|
|
return self.marionette.find_element(By.ID, "notification-popup")
|
|
|
|
def open_identity_popup(self):
|
|
"""Open the identity popup."""
|
|
self.identity_box.click()
|
|
Wait(self.marionette).until(
|
|
lambda _: self.identity_popup.is_open,
|
|
message='Identity popup has not been opened.')
|
|
|
|
@property
|
|
def reload_button(self):
|
|
"""Provides access to the DOM element reload button.
|
|
|
|
:returns: Reference to the reload button.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'urlbar-reload-button')
|
|
|
|
def reload_url(self, trigger='button', force=False):
|
|
"""Reload the currently open page.
|
|
|
|
:param trigger: The event type to use to cause the reload (one of
|
|
`shortcut`, `shortcut2`, or `button`).
|
|
:param force: Whether to cause a forced reload.
|
|
"""
|
|
# TODO: The force parameter is ignored for the moment. Use
|
|
# mouse event modifiers or actions when they're ready.
|
|
# Bug 1097705 tracks this feature in marionette.
|
|
if trigger == 'button':
|
|
self.reload_button.click()
|
|
elif trigger == 'shortcut':
|
|
cmd_key = self.window.localize_entity('reloadCmd.commandkey')
|
|
self.window.send_shortcut(cmd_key)
|
|
elif trigger == 'shortcut2':
|
|
self.window.send_shortcut(keys.Keys.F5)
|
|
|
|
@property
|
|
def stop_button(self):
|
|
"""Provides access to the DOM element stop button.
|
|
|
|
:returns: Reference to the stop button.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'urlbar-stop-button')
|
|
|
|
@property
|
|
def urlbar(self):
|
|
"""Provides access to the DOM element urlbar.
|
|
|
|
:returns: Reference to the url bar.
|
|
"""
|
|
return self.marionette.find_element(By.ID, 'urlbar')
|
|
|
|
@property
|
|
def urlbar_input(self):
|
|
"""Provides access to the urlbar input element.
|
|
|
|
:returns: Reference to the urlbar input.
|
|
"""
|
|
return self.urlbar.find_element(By.ANON_ATTRIBUTE, {'anonid': 'input'})
|
|
|
|
@property
|
|
def value(self):
|
|
"""Provides access to the currently displayed value of the urlbar.
|
|
|
|
:returns: The urlbar value.
|
|
"""
|
|
return self.urlbar.get_property('value')
|
|
|
|
|
|
class AutocompleteResults(UIBaseLib):
|
|
"""Wraps DOM elements and methods for interacting with autocomplete results."""
|
|
|
|
def close(self, force=False):
|
|
"""Closes the urlbar autocomplete popup.
|
|
|
|
:param force: If true, the popup is closed by its own hide function,
|
|
otherwise a key event is sent to close the popup.
|
|
"""
|
|
if not self.is_open:
|
|
return
|
|
|
|
if force:
|
|
self.marionette.execute_script("""
|
|
arguments[0].hidePopup();
|
|
""", script_args=[self.element])
|
|
else:
|
|
self.element.send_keys(keys.Keys.ESCAPE)
|
|
|
|
Wait(self.marionette).until(
|
|
lambda _: not self.is_open,
|
|
message='Autocomplete popup has not been closed.')
|
|
|
|
def get_matching_text(self, result, match_type):
|
|
"""Returns an array of strings of the matching text within an autocomplete
|
|
result in the urlbar.
|
|
|
|
:param result: The result to inspect for matches.
|
|
:param match_type: The type of match to search for (one of `title` or `url`).
|
|
"""
|
|
|
|
if match_type not in ('title', 'url'):
|
|
raise ValueError('match_type provided must be one of'
|
|
'"title" or "url", not %s' % match_type)
|
|
|
|
# Search for nodes of the given type with emphasized text
|
|
emphasized_nodes = result.find_elements(
|
|
By.ANON_ATTRIBUTE,
|
|
{'class': 'ac-emphasize-text ac-emphasize-text-%s' % match_type}
|
|
)
|
|
|
|
return [node.get_property('textContent') for node in emphasized_nodes]
|
|
|
|
@property
|
|
def visible_results(self):
|
|
"""Supplies the list of visible autocomplete result nodes.
|
|
|
|
:returns: The list of visible results.
|
|
"""
|
|
match_count = self.element.get_property('_matchCount')
|
|
|
|
return self.marionette.execute_script("""
|
|
let rv = [];
|
|
let node = arguments[0];
|
|
let count = arguments[1];
|
|
|
|
for (let i = 0; i < count; ++i) {
|
|
rv.push(node.getItemAtIndex(i));
|
|
}
|
|
|
|
return rv;
|
|
""", script_args=[self.results, match_count])
|
|
|
|
@property
|
|
def is_open(self):
|
|
"""Returns whether this popup is currently open.
|
|
|
|
:returns: True when the popup is open, otherwise false.
|
|
"""
|
|
return self.element.get_property('state') == 'open'
|
|
|
|
@property
|
|
def is_complete(self):
|
|
"""Returns when this popup is open and autocomplete results are complete.
|
|
|
|
:returns: True, when autocomplete results have been populated.
|
|
"""
|
|
return self.marionette.execute_script("""
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
|
|
let win = Services.focus.activeWindow;
|
|
if (win) {
|
|
return win.gURLBar.controller.searchStatus >=
|
|
Components.interfaces.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
|
|
}
|
|
|
|
return null;
|
|
""")
|
|
|
|
@property
|
|
def results(self):
|
|
"""
|
|
:returns: The autocomplete result container node.
|
|
"""
|
|
return self.element.find_element(By.ANON_ATTRIBUTE,
|
|
{'anonid': 'richlistbox'})
|
|
|
|
@property
|
|
def selected_index(self):
|
|
"""Provides the index of the selected item in the autocomplete list.
|
|
|
|
:returns: The index.
|
|
"""
|
|
return self.results.get_property('selectedIndex')
|
|
|
|
|
|
class IdentityPopup(UIBaseLib):
|
|
"""Wraps DOM elements and methods for interacting with the identity popup."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(IdentityPopup, self).__init__(*args, **kwargs)
|
|
|
|
self._view = None
|
|
|
|
@property
|
|
def is_open(self):
|
|
"""Returns whether this popup is currently open.
|
|
|
|
:returns: True when the popup is open, otherwise false.
|
|
"""
|
|
return self.element.get_property('state') == 'open'
|
|
|
|
def close(self, force=False):
|
|
"""Closes the identity popup by hitting the escape key.
|
|
|
|
:param force: Optional, If `True` force close the popup.
|
|
Defaults to `False`
|
|
"""
|
|
if not self.is_open:
|
|
return
|
|
|
|
if force:
|
|
self.marionette.execute_script("""
|
|
arguments[0].hidePopup();
|
|
""", script_args=[self.element])
|
|
else:
|
|
self.element.send_keys(keys.Keys.ESCAPE)
|
|
|
|
Wait(self.marionette).until(
|
|
lambda _: not self.is_open,
|
|
message='Identity popup has not been closed.')
|
|
|
|
@property
|
|
def view(self):
|
|
"""Provides utility members for accessing and manipulating the
|
|
identity popup's multi view.
|
|
|
|
See the :class:`IdentityPopupMultiView` reference.
|
|
"""
|
|
if not self._view:
|
|
view = self.marionette.find_element(By.ID, 'identity-popup-multiView')
|
|
self._view = IdentityPopupMultiView(self.marionette, self.window, view)
|
|
|
|
return self._view
|
|
|
|
|
|
class IdentityPopupMultiView(UIBaseLib):
|
|
|
|
def _create_view_for_id(self, view_id):
|
|
"""Creates an instance of :class:`IdentityPopupView` for the specified view id.
|
|
|
|
:param view_id: The ID of the view to create an instance of.
|
|
|
|
:returns: :class:`IdentityPopupView` instance
|
|
"""
|
|
mapping = {'identity-popup-mainView': IdentityPopupMainView,
|
|
'identity-popup-securityView': IdentityPopupSecurityView,
|
|
}
|
|
|
|
view = self.marionette.find_element(By.ID, view_id)
|
|
return mapping.get(view_id, IdentityPopupView)(self.marionette, self.window, view)
|
|
|
|
@property
|
|
def main(self):
|
|
"""The DOM element which represents the main view.
|
|
|
|
:returns: Reference to the main view.
|
|
"""
|
|
return self._create_view_for_id('identity-popup-mainView')
|
|
|
|
@property
|
|
def security(self):
|
|
"""The DOM element which represents the security view.
|
|
|
|
:returns: Reference to the security view.
|
|
"""
|
|
return self._create_view_for_id('identity-popup-securityView')
|
|
|
|
|
|
class IdentityPopupView(UIBaseLib):
|
|
|
|
@property
|
|
def selected(self):
|
|
"""Checks if the view is selected.
|
|
|
|
:return: `True` if the view is selected.
|
|
"""
|
|
return self.element.get_attribute('current') == 'true'
|
|
|
|
|
|
class IdentityPopupMainView(IdentityPopupView):
|
|
|
|
@property
|
|
def selected(self):
|
|
"""Checks if the view is selected.
|
|
|
|
:return: `True` if the view is selected.
|
|
"""
|
|
return self.marionette.execute_script("""
|
|
return arguments[0].panelMultiView.getAttribute('viewtype') == 'main';
|
|
""", script_args=[self.element])
|
|
|
|
@property
|
|
def expander(self):
|
|
"""The DOM element which represents the expander button for the security content.
|
|
|
|
:returns: Reference to the identity popup expander button.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-expander')
|
|
|
|
@property
|
|
def host(self):
|
|
"""The DOM element which represents the identity-popup content host.
|
|
|
|
:returns: Reference to the identity-popup content host.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
|
|
|
|
@property
|
|
def insecure_connection_label(self):
|
|
"""The DOM element which represents the identity popup insecure connection label.
|
|
|
|
:returns: Reference to the identity-popup insecure connection label.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
|
|
|
|
@property
|
|
def internal_connection_label(self):
|
|
"""The DOM element which represents the identity popup internal connection label.
|
|
|
|
:returns: Reference to the identity-popup internal connection label.
|
|
"""
|
|
return self.element.find_element(By.CSS_SELECTOR, 'description[when-connection=chrome]')
|
|
|
|
@property
|
|
def permissions(self):
|
|
"""The DOM element which represents the identity-popup permissions content.
|
|
|
|
:returns: Reference to the identity-popup permissions.
|
|
"""
|
|
return self.element.find_element(By.ID, 'identity-popup-permissions-content')
|
|
|
|
@property
|
|
def secure_connection_label(self):
|
|
"""The DOM element which represents the identity popup secure connection label.
|
|
|
|
:returns: Reference to the identity-popup secure connection label.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
|
|
|
|
|
|
class IdentityPopupSecurityView(IdentityPopupView):
|
|
|
|
@property
|
|
def disable_mixed_content_blocking_button(self):
|
|
"""The DOM element which represents the disable mixed content blocking button.
|
|
|
|
:returns: Reference to the disable mixed content blocking button.
|
|
"""
|
|
return self.element.find_element(By.CSS_SELECTOR,
|
|
'button[when-mixedcontent=active-blocked]')
|
|
|
|
@property
|
|
def enable_mixed_content_blocking_button(self):
|
|
"""The DOM element which represents the enable mixed content blocking button.
|
|
|
|
:returns: Reference to the enable mixed content blocking button.
|
|
"""
|
|
return self.element.find_element(By.CSS_SELECTOR,
|
|
'button[when-mixedcontent=active-loaded]')
|
|
|
|
@property
|
|
def host(self):
|
|
"""The DOM element which represents the identity-popup content host.
|
|
|
|
:returns: Reference to the identity-popup content host.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-headline host')
|
|
|
|
@property
|
|
def insecure_connection_label(self):
|
|
"""The DOM element which represents the identity popup insecure connection label.
|
|
|
|
:returns: Reference to the identity-popup insecure connection label.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-not-secure')
|
|
|
|
@property
|
|
def more_info_button(self):
|
|
"""The DOM element which represents the identity-popup more info button.
|
|
|
|
:returns: Reference to the identity-popup more info button.
|
|
"""
|
|
label = self.window.localize_entity('identity.moreInfoLinkText2')
|
|
|
|
return self.element.find_element(By.CSS_SELECTOR, u'button[label="{}"]'.format(label))
|
|
|
|
@property
|
|
def owner(self):
|
|
"""The DOM element which represents the identity-popup content owner.
|
|
|
|
:returns: Reference to the identity-popup content owner.
|
|
"""
|
|
return self.element.find_element(By.ID, 'identity-popup-content-owner')
|
|
|
|
@property
|
|
def owner_location(self):
|
|
"""The DOM element which represents the identity-popup content supplemental.
|
|
|
|
:returns: Reference to the identity-popup content supplemental.
|
|
"""
|
|
return self.element.find_element(By.ID, 'identity-popup-content-supplemental')
|
|
|
|
@property
|
|
def secure_connection_label(self):
|
|
"""The DOM element which represents the identity popup secure connection label.
|
|
|
|
:returns: Reference to the identity-popup secure connection label.
|
|
"""
|
|
return self.element.find_element(By.CLASS_NAME, 'identity-popup-connection-secure')
|
|
|
|
@property
|
|
def verifier(self):
|
|
"""The DOM element which represents the identity-popup content verifier.
|
|
|
|
:returns: Reference to the identity-popup content verifier.
|
|
"""
|
|
return self.element.find_element(By.ID, 'identity-popup-content-verifier')
|