Greasemonkey: Add run-at document-idle.

Supposed to be after all the assets have finished loading and in page js
has run. Not that we can garuntee that last bit. If a script misbehaves
because a precondition isn't yet met I suggest adding a defer method to
the script that adds a timer until the precondition is met.

Also changed the map/filter calls to use list comprehensions to keep
pylint happy. Even if it does look uglier.
This commit is contained in:
Jimmy 2017-06-07 15:45:12 +12:00
parent 13728387d7
commit 25f626a436
2 changed files with 19 additions and 11 deletions

View File

@ -238,6 +238,7 @@ class GreasemonkeyManager(QObject):
"""Re-Read greasemonkey scripts from disk."""
self._run_start = []
self._run_end = []
self._run_idle = []
scripts_dir = os.path.abspath(_scripts_dir())
log.greasemonkey.debug("Reading scripts from: {}".format(scripts_dir))
@ -254,6 +255,8 @@ class GreasemonkeyManager(QObject):
self._run_start.append(script)
elif script.run_at == 'document-end':
self._run_end.append(script)
elif script.run_at == 'document-idle':
self._run_idle.append(script)
else:
log.greasemonkey.warning("Script {} has invalid run-at "
"defined, defaulting to "
@ -269,15 +272,18 @@ class GreasemonkeyManager(QObject):
"""Fetch scripts that are registered to run for url.
returns a tuple of lists of scripts meant to run at (document-start,
document-end)
document-end, document-idle)
"""
match = functools.partial(fnmatch.fnmatch, url)
tester = (lambda script:
any(map(match, script.includes())) and not
any(map(match, script.excludes())))
return (list(filter(tester, self._run_start)),
list(filter(tester, self._run_end)))
any([match(pat) for pat in script.includes]) and
not any([match(pat) for pat in script.excludes]))
return (
[script for script in self._run_start if tester(script)],
[script for script in self._run_end if tester(script)],
[script for script in self._run_idle if tester(script)]
)
def all_scripts(self):
"""Return all scripts found in the configured script directory."""
return self._run_start + self._run_end
return self._run_start + self._run_end + self._run_idle

View File

@ -90,6 +90,8 @@ class BrowserPage(QWebPage):
functools.partial(self.inject_userjs, load='start'))
self.mainFrame().initialLayoutCompleted.connect(
functools.partial(self.inject_userjs, load='end'))
self.mainFrame().loadFinished.connect(
functools.partial(self.inject_userjs, load='idle'))
def javaScriptPrompt(self, frame, js_msg, default):
"""Override javaScriptPrompt to use qutebrowser prompts."""
@ -292,20 +294,20 @@ class BrowserPage(QWebPage):
"""Inject user javascripts into the page.
param: The page load stage to inject the corresponding scripts
for. Support values are "start" and "end",
for. Support values are "start", "end" and "idle",
corresponding to the allowed values of the `@run-at`
directive in the greasemonkey metadata spec.
"""
greasemonkey = objreg.get('greasemonkey')
url = self.currentFrame().url()
start_scripts, end_scripts = greasemonkey.scripts_for(url.toDisplayString())
log.greasemonkey.debug('scripts: {}'.format(start_scripts if start else end_scripts))
toload = []
start_scripts, end_scripts, idle_scripts = \
greasemonkey.scripts_for(url.toDisplayString())
if load == "start":
toload = start_scripts
elif load == "end":
toload = end_scripts
elif load == "idle":
toload = idle_scripts
for script in toload:
log.webview.debug('Running GM script: {}'.format(script.name))