In Qt < 5.10 (and also sometimes on Windows), we get extra spaces or newlines
when moving to the end of the document. However, this only happens *sometimes*,
and manual testing confirms that with the current workaround, we actually lose
the last char in the selection.
I'm not sure what's happening there, but instead of making things worse with
the workaround, let's just be a bit less strict with the checking there and
accept both variants... This seems like some Chromium bug we can't do much
about.
Resolves#4199.
To avoid accidentally highlighting characters that were introduced by
html escaping the text before feeding it to setHtml, we can't just
escape the whole string before adding the highlighting. Instead, we need
to break the string up on the pattern, format and escape the individual
parts, then join them back together.
re.escape includes empty strings if there is a match at the start/end,
which ensures that matches always land on odd indices:
https://docs.python.org/3/library/re.html#re.split
> If there are capturing groups in the separator and it matches at the
> start of the string, the result will start with an empty string. The
> same holds for the end of the string
Resolves the example case in #4199, but not the larger problem. We don't
need to escape quotes as we don't put the string in an attribute value.
From the docs at
https://docs.python.org/3/library/html.html#html.escape:
> If the optional flag quote is true, the characters (") and (') are also
> translated; this helps for inclusion in an HTML attribute value
> delimited by quotes, as in <a href="...">.
Escaping quotes means we end up with a literal ' in the completion
view wherever there is a quote in the source text.
However, problem in #4199, where unexpected parts of the text are
highlighted, can also happen with '<', '>', and '&', which still must be
escaped.
When we click the download button in PDF.js, it downloads a blob://qute:...
URL. We can detect that and force a download rather than opening it in PDF.js
again.
Note that what actually happens depends on the Qt version and backend:
QtWebKit (any Qt version):
Downloads always work properly (regardless of Qt version).
QtWebEngine, Qt 5.7.1:
Downloads work.
QtWebEngine, Qt 5.9 - 5.11:
Downloads won't work as we need to tell PDF.js to not use blob: URLs:
https://bugreports.qt.io/browse/QTBUG-70420 - in theory, PDF.js could fall back
to downloading the existing qute:// URL, but it has a whitelist of schemes
which does not include qute://... Since it's not in that whitelist, it just
ends up doing nothing at all.
QtWebEngine, Qt 5.12:
Downloads should hopefully work properly again, as we can register the qute://
scheme with Chromium, which allows us to use blob:// URLs.
This reverts commit 9c731bde85627308fdde4730b0181a014096cb47.
We need to set some PDF.js options, so we can't just use the default viewer
with ?file=...
Previously calling `script.code()` would fail if the script didn't have
a `name`. This wasn't being hit in practice because the only place that
constructs GreasemonkeyScripts was checking for that condition and add
the filename there as a fallback.
This change make the `name` attribute more explicitly mandatory by
failing with a `ValueError` if it is not provided and make it still
possible to use the filename fallback in that case by adding a
`filename` keyward argument to `__init__()`.
Additionally where `script_meta` is used in `script.code()` a fallback
to and emptry string was added so it doesn't fail for raw javascript
files without greasemonkey metadata.
Otherwise, stuff goes haywire when trying to use the caret mode very fast (like
in a unit test), because new stuff runs before we've managed to update the selection.
Before Qt 5.11.2, for unique origins, we always got QUrl() and thus passed it
through.
With Qt 5.11.2, only missing origins (browser-initiated requests) get an empty
initiator, while unique origins get QUrl("null"):
https://codereview.qt-project.org/#/c/234849/https://bugreports.qt.io/browse/QTBUG-69372
In theory, those should be locked down (as an unique origin is e.g. a sandboxed
iframe) and never have access to any other content.
However, thanks to a Qt bug, XHR on qute:// pages has QUrl("null") as origin as
long as the URL scheme is not registered. We can only do the registering once
Qt 5.12 is out.
Since unique origins were effectively already allowed on Qt 5.11.0/.1, we pass
them through here as well until Qt 5.12.
See #4198
If the blacklist is only valid for the completion, the setting should also be
under completion.
This also un-renames history.gap_interval and renames
completion.web_history_max_items.
Fixes#3060
IOERR: The SQLITE_IOERR result code says that the operation could not finish
because the operating system reported an I/O error.
CANTOPEN: The SQLITE_CANTOPEN result code indicates that SQLite was unable to
open a file. The file in question might be a primary database file or on of
several temporary disk files.
This adds a new CompletionMetaInfo table which is a simple key/value store.
Thanks to Python/sqlite duck typing, we can use that to store values of any
type, even new ones in the future.
Currently, the only allowed key is force_rebuild, which forces a rebuild of the
CompletionHistory table. This will be needed for a future change.
`ListCategory` sorts its completion by default, we are already building
the categories in the right order so don't need that.
The test tests the case of where you have 11 tabs and if the model was
sorted the tabs with index 10 and 11 would be sorted before the one with
index 2.
The `random.sample` bit for the tab url and title is to also make sure
the model isn't being sorted on those columns, whithout haveng to write
and all ten lines.
We changed this a while ago in a2f62238f1
already, but Ctrl-V was kind of cumbersome as well, as it conflicted with
pasting.
Shift-Escape is closer to the default leave-mode binding (Escape), and also
unlikely to conflict as it's used for the task manager in Chrome.
- Update the docstring for repeat
- Remove the blank line after the docstring
- Update the docstring with scripts/dev/src2asciidoc.py
- Simplify the test
On Qt 5.7.1, window.print() caused a CommandError which wasn't handled as the
command was called from accept_navigation_request.
Instead, we now show the dialog in AbstractPrinting and use that directly.
Fixes#2603
The call to processEvents fixes an apparent race condition with some window
managers, e.g. i3. QT seems to be thinking, that the window is not marked as
urgent and toggles it twice, so synchronizing before issuing the alert makes QT
behave correctly.
This change should not change the behaviour on other systems only correct the
fault reported in #2603.
In ffc29ee043 (part of v1.0.0), a
qute://settings/set URL was added to change settings.
Contrary to what I apparently believed at the time, it *is* possible for
websites to access `qute://*` URLs (i.e., neither QtWebKit nor QtWebEngine
prohibit such requests, other than the usual cross-origin rules).
In other words, this means a website can e.g. have an `<img>` tag which loads a
`qute://settings/set` URL, which then sets `editor.command` to a bash script.
The result of that is arbitrary code execution.
Fixes#4060
See #2332
Add an additional argument to is_blocked for the current url, and enable
the host_blocking.enabled property to be set per domain.
This allows to bypass host blocking for specific domains
Moves the 5.8 check to `_WebEngineScripts.init()`.
Changes `_inject_userscripts` to allow for the two code paths. With
5.7.1 we need to specify the injection point and not clear all scripts
for each call, since we have to call it three times.
Change the 5.8+ hook to call a new method which passes all the scripts
into `_inject_userscripts` so that doesn't have to have a fallback
conditional inside it because thats an inversion of responsibility!
Pulling the remove scripts part into a seperate function and making it
the callers responsibilty to call that first would tidy it up a little
more but meh.
I was worried about just doing `_widget.page().urlChanged.connect()`
once at tab init, where before it was connected at page init, because I
was under the impression that the child page can be replaced at any
time, eg when navigating to a new origin. But under manual testing I
didn't see that at all. Maybe I was mistaken or maybe that only started
in a later Qt version.
Replace characters that Windows doesn't like from generated and
suggested filenames for downloads. Does not apply to filenames that a
user inters via the downloads location prompt.
Fixes#3922
QtWebEngine (via chromium) has the ability to run injected scripts in
isolated "worlds". What is isolated is just the javascript environment,
so variables and functions defined by the page and the script won't
clobber each other, or be able to interact (including variables saved to
the global `window` object). The DOM is still accessible from "isolated"
scripts.
This is NOT a security measure. You cannot put untrusted scripts in one
of these isolated worlds and expect it to not be able to do whatever
page js can do, it is just for namespacing convenience. See
https://stackoverflow.com/questions/9515704/insert-code-into-the-page-context-using-a-content-script
for some examples of how to inject scripts into the page scope using DOM
elements.
Now you can specify the world ID in a `@qute-js-world` directive like:
```
// ==UserScript==
// @name Do thing
// @match *://some.site/*
// @qute-js-world 1234
// ==/UserScript==
document.body.innerHTML = "<strong>overwritten</strong>"
```
The QtWebEngine docs say worldid is a `quint32` so you can put whatever
number (positive, whole, real) you want there. I have chosen to allow
the `qutebrowser.utils.usertypes` enum as aliases for IDs that are
predefined in
`qutebrowser.browser.webengine.webenginetab._JS_WORLD_MAP`. So you can
pass `main`, `application`, `user` or `jseval` in there too. `main` (0)
is the default one and is the only one in which JS disabled when
`content.javascript.enabled` is set to `false`. All others are still
enabled.
I'm not sure whether using any of those already-named worlds makes
sense, apart from `main`. We could stop people from using them I
suppose. Another option is to allow people to pass in `*` as a value to
have scripts put into their own little worlds, probably backed by a
counter in the GreaseMonkeyManager class.
Chrome docs: https://developer.chrome.com/extensions/content_scripts#execution-environment
Webengine docs: https://doc.qt.io/qt-5/qwebenginescript.html#details