Merge remote-tracking branch 'upstream/master' into jay/max-tab

This commit is contained in:
Jay Kamat 2018-09-27 19:03:15 -07:00
commit 14e55eae49
No known key found for this signature in database
GPG Key ID: 5D2E399600F4F7B5
34 changed files with 136 additions and 77 deletions

View File

@ -54,7 +54,7 @@ no-docstring-rgx=(^_|^main$)
[FORMAT] [FORMAT]
max-line-length=79 max-line-length=79
ignore-long-lines=(<?https?://|^# Copyright 201\d) ignore-long-lines=(<?https?://|^# Copyright 201\d|link:)
expected-line-ending-format=LF expected-line-ending-format=LF
[VARIABLES] [VARIABLES]

View File

@ -32,6 +32,8 @@ Added
QtWebEngine. QtWebEngine.
* Opening a PDF file now doesn't start a second request anymore. * Opening a PDF file now doesn't start a second request anymore.
* Opening PDFs on https:// sites now works properly. * Opening PDFs on https:// sites now works properly.
* New `--pdfjs` flag for `prompt-open-download`, so PDFs can be opened in
PDF.js with `<Ctrl-P>` in the download prompt.
- New `qt.process_model` setting which can be used to change Chromium's process - New `qt.process_model` setting which can be used to change Chromium's process
model. model.
- New `qt.low_end_device_mode` setting which turns on Chromium's low-end device - New `qt.low_end_device_mode` setting which turns on Chromium's low-end device
@ -68,6 +70,9 @@ Changed
patterns instead of globs. patterns instead of globs.
- In passthrough mode, Ctrl + Mousewheel now also gets passed through to the - In passthrough mode, Ctrl + Mousewheel now also gets passed through to the
page instead of zooming. page instead of zooming.
- Editing text in an external editor now simulates a JS "input" event, which
improves compatibility with websites reacting via JS to input.
- The `qute://settings` page is now properly sorted on Python 3.5.
Fixed Fixed
~~~~~ ~~~~~

View File

@ -88,7 +88,7 @@ git format-patch origin/master <1>
Running qutebrowser Running qutebrowser
------------------- -------------------
After link:install.html#tox[installing qutebrowser via tox], you can run After link:install{outfilesuffix}#tox[installing qutebrowser via tox], you can run
`.venv/bin/qutebrowser --debug --temp-basedir` to test your changes with debug `.venv/bin/qutebrowser --debug --temp-basedir` to test your changes with debug
logging enabled and without affecting existing running instances. logging enabled and without affecting existing running instances.

View File

@ -315,5 +315,5 @@ My issue is not listed.::
https://github.com/qutebrowser/qutebrowser/issues[the issue tracker] or https://github.com/qutebrowser/qutebrowser/issues[the issue tracker] or
using the `:report` command. using the `:report` command.
If you are reporting a segfault, make sure you read the If you are reporting a segfault, make sure you read the
link:doc/stacktrace.html[guide] on how to report them with all needed link:stacktrace{outfilesuffix}[guide] on how to report them with all needed
information. information.

View File

@ -758,11 +758,11 @@ This tries to automatically click on typical _Previous Page_ or _Next Page_ link
- `up`: Go up a level in the current URL. - `up`: Go up a level in the current URL.
- `increment`: Increment the last number in the URL. - `increment`: Increment the last number in the URL.
Uses the Uses the
link:settings.html#url.incdec_segments[url.incdec_segments] link:settings{outsuffix}#url.incdec_segments[url.incdec_segments]
config option. config option.
- `decrement`: Decrement the last number in the URL. - `decrement`: Decrement the last number in the URL.
Uses the Uses the
link:settings.html#url.incdec_segments[url.incdec_segments] link:settings{outsuffix}#url.incdec_segments[url.incdec_segments]
config option. config option.
@ -1666,7 +1666,7 @@ Shift the focus of the prompt file completion menu to another item.
[[prompt-open-download]] [[prompt-open-download]]
=== prompt-open-download === prompt-open-download
Syntax: +:prompt-open-download ['cmdline']+ Syntax: +:prompt-open-download [*--pdfjs*] ['cmdline']+
Immediately open a download. Immediately open a download.
@ -1678,6 +1678,9 @@ If no specific command is given, this will use the system's default application
cmdline. cmdline.
==== optional arguments
* +*-p*+, +*--pdfjs*+: Open the download via PDF.js.
==== note ==== note
* This command does not split arguments after the last argument and handles quotes literally. * This command does not split arguments after the last argument and handles quotes literally.

View File

@ -44,7 +44,7 @@ If you want to customize many settings, you can open the link:qute://settings[]
page by running `:set` without any arguments, where all settings are listed and page by running `:set` without any arguments, where all settings are listed and
customizable. customizable.
Using the link:commands.html#set[`:set`] command and command completion, you Using the link:commands{outfilesuffix}#set[`:set`] command and command completion, you
can quickly set settings interactively, for example `:set tabs.position left`. can quickly set settings interactively, for example `:set tabs.position left`.
Some settings are also customizable for a given Some settings are also customizable for a given
@ -53,8 +53,8 @@ https://developer.chrome.com/apps/match_patterns[URL pattern] by doing e.g.
To get more help about a setting, use e.g. `:help tabs.position`. To get more help about a setting, use e.g. `:help tabs.position`.
To bind and unbind keys, you can use the link:commands.html#bind[`:bind`] and To bind and unbind keys, you can use the link:commands{outfilesuffix}#bind[`:bind`] and
link:commands.html#unbind[`:unbind`] commands: link:commands{outfilesuffix}#unbind[`:unbind`] commands:
- Binding the key chain `,v` to the `:spawn mpv {url}` command: - Binding the key chain `,v` to the `:spawn mpv {url}` command:
`:bind ,v spawn mpv {url}` `:bind ,v spawn mpv {url}`
@ -67,9 +67,9 @@ See the help pages linked above (or `:help :bind`, `:help :unbind`) for more
information. information.
Other useful commands for config manipulation are Other useful commands for config manipulation are
link:commands.html#config-unset[`:config-unset`] to reset a value to its default, link:commands{outfilesuffix}#config-unset[`:config-unset`] to reset a value to its default,
link:commands.html#config-clear[`:config-clear`] to reset the entire configuration, link:commands{outfilesuffix}#config-clear[`:config-clear`] to reset the entire configuration,
and link:commands.html#config-cycle[`:config-cycle`] to cycle a setting between and link:commands{outfilesuffix}#config-cycle[`:config-cycle`] to cycle a setting between
different values. different values.
[[configpy]] [[configpy]]
@ -111,7 +111,7 @@ Note that qutebrowser does some Python magic so it's able to warn you about
mistyped config settings. As an example, if you do `c.tabs.possition = "left"`, mistyped config settings. As an example, if you do `c.tabs.possition = "left"`,
you'll get an error when starting. you'll get an error when starting.
See the link:settings.html[settings help page] for all available settings. The See the link:settings{outfilesuffix}[settings help page] for all available settings. The
accepted values depend on the type of the option. Commonly used are: accepted values depend on the type of the option. Commonly used are:
- Strings: `c.tabs.position = "left"` - Strings: `c.tabs.position = "left"`
@ -187,7 +187,7 @@ preferred to use the `config.bind` command. Doing so ensures the commands are
valid and normalizes different expressions which map to the same key. valid and normalizes different expressions which map to the same key.
For details on how to specify keys and the available modes, see the For details on how to specify keys and the available modes, see the
link:settings.html#bindings.commands[documentation] for the `bindings.commands` link:settings{outfilesuffix}#bindings.commands[documentation] for the `bindings.commands`
setting. setting.
To bind a key: To bind a key:

View File

@ -6,14 +6,14 @@ Documentation
The following help pages are currently available: The following help pages are currently available:
* link:../quickstart.html[Quick start guide] * link:../quickstart{outfilesuffix}[Quick start guide]
* link:../faq.html[Frequently asked questions] * link:../faq{outfilesuffix}[Frequently asked questions]
* link:../changelog.html[Change Log] * link:../changelog{outfilesuffix}[Change Log]
* link:commands.html[Documentation of commands] * link:commands{outfilesuffix}[Documentation of commands]
* link:configuring.html[Configuring qutebrowser] * link:configuring{outfilesuffix}[Configuring qutebrowser]
* link:settings.html[Documentation of settings] * link:settings{outfilesuffix}[Documentation of settings]
* link:../userscripts.html[How to write userscripts] * link:../userscripts{outfilesuffix}[How to write userscripts]
* link:../contributing.html[Contributing to qutebrowser] * link:../contributing{outfilesuffix}[Contributing to qutebrowser]
Getting help Getting help
------------ ------------

View File

@ -660,6 +660,7 @@ Default:
* +pass:[&lt;Ctrl-F&gt;]+: +pass:[rl-forward-char]+ * +pass:[&lt;Ctrl-F&gt;]+: +pass:[rl-forward-char]+
* +pass:[&lt;Ctrl-H&gt;]+: +pass:[rl-backward-delete-char]+ * +pass:[&lt;Ctrl-H&gt;]+: +pass:[rl-backward-delete-char]+
* +pass:[&lt;Ctrl-K&gt;]+: +pass:[rl-kill-line]+ * +pass:[&lt;Ctrl-K&gt;]+: +pass:[rl-kill-line]+
* +pass:[&lt;Ctrl-P&gt;]+: +pass:[prompt-open-download --pdfjs]+
* +pass:[&lt;Ctrl-U&gt;]+: +pass:[rl-unix-line-discard]+ * +pass:[&lt;Ctrl-U&gt;]+: +pass:[rl-unix-line-discard]+
* +pass:[&lt;Ctrl-W&gt;]+: +pass:[rl-unix-word-rubout]+ * +pass:[&lt;Ctrl-W&gt;]+: +pass:[rl-unix-word-rubout]+
* +pass:[&lt;Ctrl-X&gt;]+: +pass:[prompt-open-download]+ * +pass:[&lt;Ctrl-X&gt;]+: +pass:[prompt-open-download]+

View File

@ -31,7 +31,7 @@ pytest-cov==2.6.0
pytest-faulthandler==1.5.0 pytest-faulthandler==1.5.0
pytest-instafail==0.4.0 pytest-instafail==0.4.0
pytest-mock==1.10.0 pytest-mock==1.10.0
pytest-qt==3.1.0 pytest-qt==3.2.0
pytest-repeat==0.7.0 pytest-repeat==0.7.0
pytest-rerunfailures==4.1 pytest-rerunfailures==4.1
pytest-travis-fold==1.3.0 pytest-travis-fold==1.3.0

View File

@ -612,11 +612,11 @@ class CommandDispatcher:
- `up`: Go up a level in the current URL. - `up`: Go up a level in the current URL.
- `increment`: Increment the last number in the URL. - `increment`: Increment the last number in the URL.
Uses the Uses the
link:settings.html#url.incdec_segments[url.incdec_segments] link:settings{outsuffix}#url.incdec_segments[url.incdec_segments]
config option. config option.
- `decrement`: Decrement the last number in the URL. - `decrement`: Decrement the last number in the URL.
Uses the Uses the
link:settings.html#url.incdec_segments[url.incdec_segments] link:settings{outsuffix}#url.incdec_segments[url.incdec_segments]
config option. config option.
tab: Open in a new tab. tab: Open in a new tab.
@ -1659,6 +1659,8 @@ class CommandDispatcher:
""" """
try: try:
elem.set_value(text) elem.set_value(text)
# Kick off js handlers to trick them into thinking there was input.
elem.dispatch_event("input", bubbles=True)
except webelem.OrphanedError: except webelem.OrphanedError:
message.error('Edited element vanished') message.error('Edited element vanished')
ed.backup() ed.backup()

View File

@ -99,10 +99,10 @@ def _generate_pdfjs_script(filename):
} }
const viewer = window.PDFView || window.PDFViewerApplication; const viewer = window.PDFView || window.PDFViewerApplication;
viewer.open("{{ url }}"); viewer.open({{ url }});
}); });
""").render( """).render(
url=javascript.string_escape(url.toString(QUrl.FullyEncoded)), url=javascript.to_js(url.toString(QUrl.FullyEncoded)),
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70420 # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70420
disable_create_object_url=( disable_create_object_url=(
not qtutils.version_check('5.12') and not qtutils.version_check('5.12') and

View File

@ -139,6 +139,18 @@ class AbstractWebElement(collections.abc.MutableMapping):
"""Set the element value.""" """Set the element value."""
raise NotImplementedError raise NotImplementedError
def dispatch_event(self, event, bubbles=False,
cancelable=False, composed=False):
"""Dispatch an event to the element.
Args:
bubbles: Whether this event should bubble.
cancelable: Whether this event can be cancelled.
composed: Whether the event will trigger listeners outside of a
shadow root.
"""
raise NotImplementedError
def insert_text(self, text): def insert_text(self, text):
"""Insert the given text into the element.""" """Insert the given text into the element."""
raise NotImplementedError raise NotImplementedError

View File

@ -135,6 +135,10 @@ class WebEngineElement(webelem.AbstractWebElement):
def set_value(self, value): def set_value(self, value):
self._js_call('set_value', value) self._js_call('set_value', value)
def dispatch_event(self, event, bubbles=False,
cancelable=False, composed=False):
self._js_call('dispatch_event', event, bubbles, cancelable, composed)
def caret_position(self): def caret_position(self):
"""Get the text caret position for the current element. """Get the text caret position for the current element.

View File

@ -125,8 +125,20 @@ class WebKitElement(webelem.AbstractWebElement):
self._elem.setPlainText(value) self._elem.setPlainText(value)
else: else:
log.webelem.debug("Filling {!r} via javascript.".format(self)) log.webelem.debug("Filling {!r} via javascript.".format(self))
value = javascript.string_escape(value) value = javascript.to_js(value)
self._elem.evaluateJavaScript("this.value='{}'".format(value)) self._elem.evaluateJavaScript("this.value={}".format(value))
def dispatch_event(self, event, bubbles=False,
cancelable=False, composed=False):
self._check_vanished()
log.webelem.debug("Firing event on {!r} via javascript.".format(self))
self._elem.evaluateJavaScript(
"this.dispatchEvent(new Event({}, "
"{{'bubbles': {}, 'cancelable': {}, 'composed': {}}}))"
.format(javascript.to_js(event),
javascript.to_js(bubbles),
javascript.to_js(cancelable),
javascript.to_js(composed)))
def caret_position(self): def caret_position(self):
"""Get the text caret position for the current element.""" """Get the text caret position for the current element."""
@ -142,11 +154,11 @@ class WebKitElement(webelem.AbstractWebElement):
raise webelem.Error("Element is not editable!") raise webelem.Error("Element is not editable!")
log.webelem.debug("Inserting text into element {!r}".format(self)) log.webelem.debug("Inserting text into element {!r}".format(self))
self._elem.evaluateJavaScript(""" self._elem.evaluateJavaScript("""
var text = "{}"; var text = {};
var event = document.createEvent("TextEvent"); var event = document.createEvent("TextEvent");
event.initTextEvent("textInput", true, true, null, text); event.initTextEvent("textInput", true, true, null, text);
this.dispatchEvent(event); this.dispatchEvent(event);
""".format(javascript.string_escape(text))) """.format(javascript.to_js(text)))
def _parent(self): def _parent(self):
"""Get the parent element of this element.""" """Get the parent element of this element."""

View File

@ -2627,6 +2627,7 @@ bindings.default:
prompt: prompt:
<Return>: prompt-accept <Return>: prompt-accept
<Ctrl-X>: prompt-open-download <Ctrl-X>: prompt-open-download
<Ctrl-P>: prompt-open-download --pdfjs
<Shift-Tab>: prompt-item-focus prev <Shift-Tab>: prompt-item-focus prev
<Up>: prompt-item-focus prev <Up>: prompt-item-focus prev
<Tab>: prompt-item-focus next <Tab>: prompt-item-focus next

View File

@ -34,7 +34,7 @@ input { width: 98%; }
<th>Setting</th> <th>Setting</th>
<th>Value</th> <th>Value</th>
</tr> </tr>
{% for option in configdata.DATA.values() if not option.no_autoconfig %} {% for option in configdata.DATA.values()|sort(attribute='name') if not option.no_autoconfig %}
<tr> <tr>
<!-- FIXME: convert to string properly --> <!-- FIXME: convert to string properly -->
<td class="setting">{{ option.name }} (Current: {{ confget(option.name) | string |truncate(100) }}) <td class="setting">{{ option.name }} (Current: {{ confget(option.name) | string |truncate(100) }})

View File

@ -59,3 +59,4 @@ rules:
multiline-ternary: ["error", "always-multiline"] multiline-ternary: ["error", "always-multiline"]
max-lines-per-function: "off" max-lines-per-function: "off"
require-unicode-regexp: "off" require-unicode-regexp: "off"
max-params: "off"

View File

@ -1,5 +1,5 @@
/* eslint-disable max-len, max-statements, complexity, /* eslint-disable max-len, max-statements, complexity,
max-params, default-case, valid-jsdoc */ default-case, valid-jsdoc */
// Copyright 2014 The Chromium Authors. All rights reserved. // Copyright 2014 The Chromium Authors. All rights reserved.
// //

View File

@ -362,6 +362,15 @@ window._qutebrowser.webelem = (function() {
document.execCommand("insertText", false, text); document.execCommand("insertText", false, text);
}; };
funcs.dispatch_event = (id, event, bubbles = false,
cancelable = false, composed = false) => {
const elem = elements[id];
elem.dispatchEvent(
new Event(event, {"bubbles": bubbles,
"cancelable": cancelable,
"composed": composed}));
};
funcs.set_attribute = (id, name, value) => { funcs.set_attribute = (id, name, value) => {
elements[id].setAttribute(name, value); elements[id].setAttribute(name, value);
}; };

View File

@ -391,7 +391,7 @@ class PromptContainer(QWidget):
@cmdutils.register(instance='prompt-container', scope='window', @cmdutils.register(instance='prompt-container', scope='window',
modes=[usertypes.KeyMode.prompt], maxsplit=0) modes=[usertypes.KeyMode.prompt], maxsplit=0)
def prompt_open_download(self, cmdline: str = None): def prompt_open_download(self, cmdline: str = None, pdfjs=False):
"""Immediately open a download. """Immediately open a download.
If no specific command is given, this will use the system's default If no specific command is given, this will use the system's default
@ -402,9 +402,10 @@ class PromptContainer(QWidget):
is expanded to the temporary file name. If no `{}` is is expanded to the temporary file name. If no `{}` is
present, the filename is automatically appended to the present, the filename is automatically appended to the
cmdline. cmdline.
pdfjs: Open the download via PDF.js.
""" """
try: try:
self._prompt.download_open(cmdline) self._prompt.download_open(cmdline, pdfjs=pdfjs)
except UnsupportedOperationError: except UnsupportedOperationError:
pass pass
@ -537,8 +538,10 @@ class _BasePrompt(QWidget):
def accept(self, value=None): def accept(self, value=None):
raise NotImplementedError raise NotImplementedError
def download_open(self, _cmdline): def download_open(self, cmdline, pdfjs):
"""Open the download directly if this is a download prompt.""" """Open the download directly if this is a download prompt."""
utils.unused(cmdline)
utils.unused(pdfjs)
raise UnsupportedOperationError raise UnsupportedOperationError
def item_focus(self, _which): def item_focus(self, _which):
@ -757,8 +760,13 @@ class DownloadFilenamePrompt(FilenamePrompt):
self.question.answer = downloads.FileDownloadTarget(answer) self.question.answer = downloads.FileDownloadTarget(answer)
return done return done
def download_open(self, cmdline): def download_open(self, cmdline, pdfjs):
self.question.answer = downloads.OpenFileDownloadTarget(cmdline) if pdfjs:
target = downloads.PDFJSDownloadTarget()
else:
target = downloads.OpenFileDownloadTarget(cmdline)
self.question.answer = target
self.question.done() self.question.done()
message.global_bridge.prompt_done.emit(self.KEY_MODE) message.global_bridge.prompt_done.emit(self.KEY_MODE)
@ -767,6 +775,7 @@ class DownloadFilenamePrompt(FilenamePrompt):
('prompt-accept', 'Accept'), ('prompt-accept', 'Accept'),
('leave-mode', 'Abort'), ('leave-mode', 'Abort'),
('prompt-open-download', "Open download"), ('prompt-open-download', "Open download"),
('prompt-open-download --pdfjs', "Open download via PDF.js"),
('prompt-yank', "Yank URL"), ('prompt-yank', "Yank URL"),
] ]
return cmds return cmds

View File

@ -385,13 +385,14 @@ class TabBar(QTabBar):
if option.startswith('colors.tabs.'): if option.startswith('colors.tabs.'):
self.update() self.update()
# Clear _minimum_tab_size_hint_helper cache when appropriate # Clear tab size caches when appropriate
if option in ["tabs.indicator.padding", if option in ["tabs.indicator.padding",
"tabs.padding", "tabs.padding",
"tabs.indicator.width", "tabs.indicator.width",
"tabs.min_width", "tabs.min_width",
"tabs.pinned.shrink"]: "tabs.pinned.shrink"]:
self._minimum_tab_size_hint_helper.cache_clear() self._minimum_tab_size_hint_helper.cache_clear()
self._minimum_tab_height.cache_clear()
def _on_show_switching_delay_changed(self): def _on_show_switching_delay_changed(self):
"""Set timer interval when tabs.show_switching_delay got changed.""" """Set timer interval when tabs.show_switching_delay got changed."""
@ -468,6 +469,7 @@ class TabBar(QTabBar):
self._set_icon_size() self._set_icon_size()
# clear tab size cache # clear tab size cache
self._minimum_tab_size_hint_helper.cache_clear() self._minimum_tab_size_hint_helper.cache_clear()
self._minimum_tab_height.cache_clear()
def _set_icon_size(self): def _set_icon_size(self):
"""Set the tab bar favicon size.""" """Set the tab bar favicon size."""
@ -555,8 +557,7 @@ class TabBar(QTabBar):
# Only add padding if indicator exists # Only add padding if indicator exists
if indicator_width != 0: if indicator_width != 0:
padding_h += indicator_padding.left + indicator_padding.right padding_h += indicator_padding.left + indicator_padding.right
padding_v = padding.top + padding.bottom height = self._minimum_tab_height()
height = self.fontMetrics().height() + padding_v
width = (text_width + icon_width + width = (text_width + icon_width +
padding_h + indicator_width) padding_h + indicator_width)
min_width = config.val.tabs.min_width min_width = config.val.tabs.min_width
@ -565,6 +566,11 @@ class TabBar(QTabBar):
width = max(min_width, width) width = max(min_width, width)
return QSize(width, height) return QSize(width, height)
@functools.lru_cache(maxsize=1)
def _minimum_tab_height(self):
padding = config.cache['tabs.padding']
return self.fontMetrics().height() + padding.top + padding.bottom
def _tab_pinned(self, index: int) -> bool: def _tab_pinned(self, index: int) -> bool:
"""Return True if tab is pinned.""" """Return True if tab is pinned."""
if not 0 <= index < self.count(): if not 0 <= index < self.count():
@ -589,8 +595,7 @@ class TabBar(QTabBar):
# want to ensure it's valid in this special case. # want to ensure it's valid in this special case.
return QSize() return QSize()
minimum_size = self.minimumTabSizeHint(index) height = self._minimum_tab_height()
height = minimum_size.height()
if self.vertical: if self.vertical:
confwidth = str(config.cache['tabs.width']) confwidth = str(config.cache['tabs.width'])
if confwidth.endswith('%'): if confwidth.endswith('%'):
@ -600,7 +605,7 @@ class TabBar(QTabBar):
width = main_window.width() * perc / 100 width = main_window.width() * perc / 100
else: else:
width = int(confwidth) width = int(confwidth)
size = QSize(max(minimum_size.width(), width), height) size = QSize(width, height)
else: else:
if config.cache['tabs.pinned.shrink'] and self._tab_pinned(index): if config.cache['tabs.pinned.shrink'] and self._tab_pinned(index):
# Give pinned tabs the minimum size they need to display their # Give pinned tabs the minimum size they need to display their
@ -614,8 +619,9 @@ class TabBar(QTabBar):
if max_width > 0: if max_width > 0:
width = min(max_width, width) width = min(max_width, width)
# If we don't have enough space, we return the minimum size # If for some reason (tests, bugs) self.width() gives 0, use a
width = max(width, minimum_size.width()) # sane min of 10 px
width = max(width, 10)
size = QSize(width, height) size = QSize(width, height)
qtutils.ensure_valid(size) qtutils.ensure_valid(size)
return size return size

View File

@ -49,7 +49,7 @@ def string_escape(text):
return text return text
def _convert_js_arg(arg): def to_js(arg):
"""Convert the given argument so it's the equivalent in JS.""" """Convert the given argument so it's the equivalent in JS."""
if arg is None: if arg is None:
return 'undefined' return 'undefined'
@ -60,7 +60,7 @@ def _convert_js_arg(arg):
elif isinstance(arg, (int, float)): elif isinstance(arg, (int, float)):
return str(arg) return str(arg)
elif isinstance(arg, list): elif isinstance(arg, list):
return '[{}]'.format(', '.join(_convert_js_arg(e) for e in arg)) return '[{}]'.format(', '.join(to_js(e) for e in arg))
else: else:
raise TypeError("Don't know how to handle {!r} of type {}!".format( raise TypeError("Don't know how to handle {!r} of type {}!".format(
arg, type(arg).__name__)) arg, type(arg).__name__))
@ -68,7 +68,7 @@ def _convert_js_arg(arg):
def assemble(module, function, *args): def assemble(module, function, *args):
"""Assemble a javascript file and a function call.""" """Assemble a javascript file and a function call."""
js_args = ', '.join(_convert_js_arg(arg) for arg in args) js_args = ', '.join(to_js(arg) for arg in args)
if module == 'window': if module == 'window':
parts = ['window', function] parts = ['window', function]
else: else:

View File

@ -315,8 +315,8 @@ def _chromium_version():
Quick reference: Quick reference:
Qt 5.7: Chromium 49 Qt 5.7: Chromium 49
49.0.2623.111 (2016-03-02) 49.0.2623.111 (2016-03-31)
5.7.1: Security fixes up to 54.0.2840.87 (2016-10-19) 5.7.1: Security fixes up to 54.0.2840.87 (2016-11-01)
Qt 5.8: Chromium 53 Qt 5.8: Chromium 53
53.0.2785.148 (2016-08-31) 53.0.2785.148 (2016-08-31)
@ -324,20 +324,21 @@ def _chromium_version():
Qt 5.9: Chromium 56 Qt 5.9: Chromium 56
(LTS) 56.0.2924.122 (2017-01-25) (LTS) 56.0.2924.122 (2017-01-25)
5.9.6: Security fixes up to 66.0.3359.170 (2018-04-17) 5.9.6: Security fixes up to 66.0.3359.170 (2018-05-10)
Qt 5.10: Chromium 61 Qt 5.10: Chromium 61
61.0.3163.140 (2017-09-05) 61.0.3163.140 (2017-09-05)
5.10.1: Security fixes up to 64.0.3282.140 (2018-01-24) 5.10.1: Security fixes up to 64.0.3282.140 (2018-02-01)
Qt 5.11: Chromium 65 Qt 5.11: Chromium 65
65.0.3325.151 (.1: .230) (2018-03-06) 65.0.3325.151 (.1: .230) (2018-03-06)
5.11.1: Security fixes up to 67.0.3396.87 (2018-05-29) 5.11.2: Security fixes up to 68.0.3440.75 (2018-07-24)
Qt 5.12: Chromium 69 Qt 5.12: Chromium 69
current 5.12 branch: 69.0.3497.70 (2018-09-11) current 5.12 branch: 69.0.3497.70 (2018-09-11)
Also see https://www.chromium.org/developers/calendar Also see https://www.chromium.org/developers/calendar
and https://chromereleases.googleblog.com/
""" """
if QWebEngineProfile is None: if QWebEngineProfile is None:
# This should never happen # This should never happen

View File

@ -42,7 +42,6 @@ from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtNetwork import QNetworkCookieJar from PyQt5.QtNetwork import QNetworkCookieJar
import helpers.stubs as stubsmod import helpers.stubs as stubsmod
import helpers.utils
from qutebrowser.config import (config, configdata, configtypes, configexc, from qutebrowser.config import (config, configdata, configtypes, configexc,
configfiles, configcache) configfiles, configcache)
from qutebrowser.utils import objreg, standarddir, utils, usertypes from qutebrowser.utils import objreg, standarddir, utils, usertypes

View File

@ -27,8 +27,6 @@ import contextlib
import pytest import pytest
from PyQt5.QtCore import QObject, pyqtSignal
from qutebrowser.utils import qtutils from qutebrowser.utils import qtutils

View File

@ -25,7 +25,6 @@ import pytest
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.utils import usertypes from qutebrowser.utils import usertypes
from helpers import utils
@pytest.fixture @pytest.fixture
@ -298,7 +297,7 @@ class TestSearch:
with qtbot.wait_callback() as callback: with qtbot.wait_callback() as callback:
web_tab.search.search('fiv', result_cb=callback) web_tab.search.search('fiv', result_cb=callback)
assert callback.args == [True] callback.assert_called_with(True)
mode_manager.enter(usertypes.KeyMode.caret) mode_manager.enter(usertypes.KeyMode.caret)
caret.move_to_end_of_line() caret.move_to_end_of_line()
@ -312,11 +311,11 @@ class TestSearch:
with qtbot.wait_callback() as callback: with qtbot.wait_callback() as callback:
web_tab.search.search('w', result_cb=callback) web_tab.search.search('w', result_cb=callback)
assert callback.args == [True] callback.assert_called_with(True)
with qtbot.wait_callback() as callback: with qtbot.wait_callback() as callback:
web_tab.search.next_result(result_cb=callback) web_tab.search.next_result(result_cb=callback)
assert callback.args == [True] callback.assert_called_with(True)
mode_manager.enter(usertypes.KeyMode.caret) mode_manager.enter(usertypes.KeyMode.caret)

View File

@ -45,8 +45,8 @@ def test_generate_pdfjs_page(available, snippet, monkeypatch):
# Note that we got double protection, once because we use QUrl.FullyEncoded and # Note that we got double protection, once because we use QUrl.FullyEncoded and
# because we use qutebrowser.utils.javascript.string_escape. Characters # because we use qutebrowser.utils.javascript.to_js. Characters like " are
# like " are already replaced by QUrl. # already replaced by QUrl.
@pytest.mark.parametrize('filename, expected', [ @pytest.mark.parametrize('filename, expected', [
('foo.bar', "foo.bar"), ('foo.bar', "foo.bar"),
('foo"bar', "foo%22bar"), ('foo"bar', "foo%22bar"),

View File

@ -409,8 +409,8 @@ class TestWebKitElement:
assert elem.value() == 'js' assert elem.value() == 'js'
@pytest.mark.parametrize('editable, value, uses_js, arg', [ @pytest.mark.parametrize('editable, value, uses_js, arg', [
('false', 'foo', True, "this.value='foo'"), ('false', 'foo', True, 'this.value="foo"'),
('false', "foo'bar", True, r"this.value='foo\'bar'"), ('false', "foo'bar", True, r'this.value="foo\'bar"'),
('true', 'foo', False, 'foo'), ('true', 'foo', False, 'foo'),
]) ])
def test_set_value(self, editable, value, uses_js, arg): def test_set_value(self, editable, value, uses_js, arg):

View File

@ -27,7 +27,6 @@ import jinja2
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
import helpers.utils
from qutebrowser.utils import utils from qutebrowser.utils import utils
@ -112,7 +111,7 @@ class JSTester:
""" """
with self.qtbot.wait_callback() as callback: with self.qtbot.wait_callback() as callback:
self.tab.run_js_async(source, callback, world=world) self.tab.run_js_async(source, callback, world=world)
assert callback.args == [expected] callback.assert_called_with(expected)
@pytest.fixture @pytest.fixture

View File

@ -21,8 +21,6 @@
import pytest import pytest
import helpers.utils
QWebSettings = pytest.importorskip("PyQt5.QtWebKit").QWebSettings QWebSettings = pytest.importorskip("PyQt5.QtWebKit").QWebSettings
QWebPage = pytest.importorskip("PyQt5.QtWebKitWidgets").QWebPage QWebPage = pytest.importorskip("PyQt5.QtWebKitWidgets").QWebPage
@ -58,7 +56,7 @@ class CaretTester:
with self._qtbot.wait_callback() as callback: with self._qtbot.wait_callback() as callback:
self.js.tab.caret.selection(lambda text: callback(text.rstrip())) self.js.tab.caret.selection(lambda text: callback(text.rstrip()))
assert callback.args == ['MARKER'] callback.assert_called_with('MARKER')
def check_scrolled(self): def check_scrolled(self):
"""Check if the page is scrolled down.""" """Check if the page is scrolled down."""

View File

@ -62,9 +62,9 @@ class StylesheetTester:
"""Check whether the css in ELEMENT is set to VALUE.""" """Check whether the css in ELEMENT is set to VALUE."""
self.js.run("console.log({document});" self.js.run("console.log({document});"
"window.getComputedStyle({document}, null)" "window.getComputedStyle({document}, null)"
".getPropertyValue('{prop}');".format( ".getPropertyValue({prop});".format(
document=document_element, document=document_element,
prop=javascript.string_escape(css_style)), prop=javascript.to_js(css_style)),
value) value)
def check_eq(self, one, two, true=True): def check_eq(self, one, two, true=True):

View File

@ -240,7 +240,7 @@ class TestWindowIsolation:
with qtbot.wait_callback() as callback: with qtbot.wait_callback() as callback:
page.runJavaScript(setup.test_script, callback) page.runJavaScript(setup.test_script, callback)
assert callback.args == [setup.expected] callback.assert_called_with(setup.expected)
# The JSCore in 602.1 doesn't fully support Proxy. # The JSCore in 602.1 doesn't fully support Proxy.
@pytest.mark.qtwebkit6021_skip @pytest.mark.qtwebkit6021_skip

View File

@ -78,4 +78,4 @@ def test_simple_js_webengine(qtbot, webengineview, qapp,
with qtbot.wait_callback() as callback: with qtbot.wait_callback() as callback:
page.runJavaScript('1 + 1', world, callback) page.runJavaScript('1 + 1', world, callback)
assert callback.args == [expected] callback.assert_called_with(expected)

View File

@ -86,12 +86,12 @@ class TestStringEscape:
(True, 'true'), (True, 'true'),
([23, True, 'x'], '[23, true, "x"]'), ([23, True, 'x'], '[23, true, "x"]'),
]) ])
def test_convert_js_arg(arg, expected): def test_to_js(arg, expected):
if expected is TypeError: if expected is TypeError:
with pytest.raises(TypeError): with pytest.raises(TypeError):
javascript._convert_js_arg(arg) javascript.to_js(arg)
else: else:
assert javascript._convert_js_arg(arg) == expected assert javascript.to_js(arg) == expected
@pytest.mark.parametrize('base, expected_base', [ @pytest.mark.parametrize('base, expected_base', [