Sat, 10 Feb 2018 19:53:07 +0100
Implemented support for GreaseMonkey 4.0 for the web browser NG.
--- a/WebBrowser/GreaseMonkey/GreaseMonkeyJavaScript.py Sat Feb 10 17:24:42 2018 +0100 +++ b/WebBrowser/GreaseMonkey/GreaseMonkeyJavaScript.py Sat Feb 10 19:53:07 2018 +0100 @@ -10,119 +10,110 @@ from __future__ import unicode_literals bootstrap_js = """ -if(typeof GM_xmlhttpRequest === "undefined") { - GM_xmlhttpRequest = function(/* object */ details) { - details.method = details.method.toUpperCase() || "GET"; +var GM = { + info: { + script: { + description: "", + excludes: [], + includes: [], + matches: [], + name: "", + namespace: "", + resources: {}, + 'run-at': "document-end", + version: "" + }, + scriptMetaStr: "", + scriptHandler: "eric Browser GreaseMonkey", + version: "4.0" + } +}; +window.GM = GM; - if(!details.url) { - throw("GM_xmlhttpRequest requires an URL."); - } +function GM_info() { + return GM.info; +} + +function GM_xmlhttpRequest(/* object */ details) { + details.method = details.method.toUpperCase() || "GET"; + + if (!details.url) { + throw("GM_xmlhttpRequest requires an URL."); + } - // build XMLHttpRequest object - var oXhr = new XMLHttpRequest; - // run it - if(oXhr) { - if("onreadystatechange" in details) - oXhr.onreadystatechange = function() { - details.onreadystatechange(oXhr) - }; - if("onload" in details) - oXhr.onload = function() { details.onload(oXhr) }; - if("onerror" in details) - oXhr.onerror = function() { details.onerror(oXhr) }; + // build XMLHttpRequest object + var oXhr = new XMLHttpRequest; + // run it + if("onreadystatechange" in details) + oXhr.onreadystatechange = function() { + details.onreadystatechange(oXhr) }; + if("onload" in details) + oXhr.onload = function() { details.onload(oXhr) }; + if("onerror" in details) + oXhr.onerror = function() { details.onerror(oXhr) }; + + oXhr.open(details.method, details.url, true); + + if("headers" in details) + for(var header in details.headers) + oXhr.setRequestHeader(header, details.headers[header]); - oXhr.open(details.method, details.url, true); - - if("headers" in details) - for(var header in details.headers) - oXhr.setRequestHeader(header, details.headers[header]); + if("data" in details) + oXhr.send(details.data); + else + oXhr.send(); +} - if("data" in details) - oXhr.send(details.data); - else - oXhr.send(); - } else - throw ("This Browser is not supported, please upgrade.") +function GM_addStyle(/* string */ styles) { + var head = document.getElementsByTagName("head")[0]; + if (head === undefined) { + document.onreadystatechange = function() { + if (document.readyState == "interactive") { + var oStyle = document.createElement("style"); + oStyle.setAttribute("type", "text/css"); + oStyle.appendChild(document.createTextNode(styles)); + document.getElementsByTagName("head")[0].appendChild(oStyle); + } + } + } + else { + var oStyle = document.createElement("style"); + oStyle.setAttribute("type", "text/css"); + oStyle.appendChild(document.createTextNode(styles)); + head.appendChild(oStyle); } } -if(typeof GM_addStyle === "undefined") { - function GM_addStyle(/* String */ styles) { - var head = document.getElementsByTagName("head")[0]; - if (head === undefined) { - document.onreadystatechange = function() { - if (document.readyState == "interactive") { - var oStyle = document.createElement("style"); - oStyle.setAttribute("type", "text\/css"); - oStyle.appendChild(document.createTextNode(styles)); - document.getElementsByTagName("head")[0].appendChild(oStyle); - } - } - } - else { - var oStyle = document.createElement("style"); - oStyle.setAttribute("type", "text\/css"); - oStyle.appendChild(document.createTextNode(styles)); - head.appendChild(oStyle); - } - } +function GM_log(log) { + if(console) + console.log(log); } -if(typeof GM_log === "undefined") { - function GM_log(log) { - if(console) - console.log(log); - } +function GM_openInTab(url) { + return window.open(url); } -if(typeof GM_openInTab === "undefined") { - function GM_openInTab(url) { - window.open(url) - } +function GM_setClipboard(text) { + external.extra.greasemonkey.setClipboard(text); } -// Define unsafe window -var unsafeWindow = window; -window.wrappedJSObject = unsafeWindow; +// GM_registerMenuCommand not supported +function GM_registerMenuCommand(caption, commandFunc, accessKey) { } -// GM_registerMenuCommand not supported -if(typeof GM_registerMenuCommand === "undefined") { - function GM_registerMenuCommand(caption, commandFunc, accessKey) { } -} - -// GM Resource not supported -if(typeof GM_getResourceText === "undefined") { - function GM_getResourceText(resourceName) { - throw ("eric6 Web Browser: GM Resource is not supported!"); - } -} +// GM_getResourceUrl not supported +function GM_getResourceUrl(resourceName) { } -if(typeof GM_getResourceURL === "undefined") { - function GM_getResourceURL(resourceName) { - throw ("eric6 Web Browser: GM Resource is not supported!"); - } -} - -// GM Settings not supported -if(typeof GM_getValue === "undefined") { - function GM_getValue(name, defaultValue) { - return defaultValue; - } -} +// GreaseMonkey 4.0 support +GM.openInTab = GM_openInTab; +GM.setClipboard = GM_setClipboard; +GM.xmlhttpRequest = GM_xmlhttpRequest; -if(typeof GM_setValue === "undefined") { - function GM_setValue(name, value) { } -} - -if(typeof GM_deleteValue === "undefined") { - function GM_deleteValue(name) { } -} - -if(typeof GM_listValues === "undefined") { - function GM_listValues() { - return new Array(""); - } -} +// GM_getResourceUrl not supported +GM.getResourceUrl = function(resourceName) { + return new Promise((resolve, reject) => { + reject(); + }); +}; """ @@ -152,4 +143,90 @@ function GM_setValue(aKey, aVal) {{ localStorage.setItem("{0}" + aKey, aVal); }} + +// GreaseMonkey 4.0 support +var asyncCall = (func) => {{ + if (window._eric_external) {{ + func(); + }} else {{ + document.addEventListener("_eric_external_created", func); + }} +}}; + +var decode = (val) => {{ + val = String(val); + if (!val.length) {{ + return val; + }} + var v = val.substr(1); + if (val[0] == "b") {{ + return Boolean(v == "true" ? true : false); + }} else if (val[0] == "i") {{ + return Number(v); + }} else if (val[0] == "s") {{ + return v; + }} else {{ + return undefined; + }} +}}; + +var encode = (val) => {{ + if (typeof val == "boolean") {{ + return "b" + (val ? "true" : "false"); + }} else if (typeof val == "number") {{ + return "i" + String(val); + }} else if (typeof val == "string") {{ + return "s" + val; + }} else {{ + return ""; + }} +}}; + +GM.deleteValue = function(name) {{ + return new Promise((resolve, reject) => {{ + asyncCall(() => {{ + external.extra.greasemonkey.deleteValue("{0}", name, (res) => {{ + if (res) {{ + resolve(); + }} else {{ + reject(); + }} + }}); + }}); + }}); +}}; + +GM.getValue = function(name, value) {{ + return new Promise((resolve) => {{ + asyncCall(() => {{ + external.extra.greasemonkey.getValue("{0}", name, encode(value), + (res) => {{ + resolve(decode(res)); + }}); + }}); + }}); +}}; + +GM.setValue = function(name, value) {{ + return new Promise((resolve, reject) => {{ + asyncCall(() => {{ + external.extra.greasemonkey.setValue("{0}", name, encode(value), + (res) => {{ + if (res) {{ + resolve(); + }} else {{ + reject(); + }} + }}); + }}); + }}); +}}; + +GM.listValues = function() {{ + return new Promise((resolve) => {{ + asyncCall(() => {{ + external.extra.greasemonkey.listValues("{0}", resolve); + }}); + }}); +}}; """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/GreaseMonkey/GreaseMonkeyJsObject.py Sat Feb 10 19:53:07 2018 +0100 @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2018 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the Python side for GreaseMonkey scripts. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, QObject, QSettings +from PyQt5.QtGui import QGuiApplication + + +class GreaseMonkeyJsObject(QObject): + """ + Class implementing the Python side for GreaseMonkey scripts. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object + @type QObject + """ + super(GreaseMonkeyJsObject, self).__init__(parent) + + self.__settings = None + + def setSettingsFile(self, name): + """ + Public method to set the settings file for the GreaseMonkey parameters. + + @param name name of the settings file + @type str + """ + if self.__settings is not None: + self.__settings.sync() + self.__settings = None + + self.__settings = QSettings(name, QSettings.IniFormat) + + @pyqtSlot(str, str, str) + def getValue(self, nspace, name, dValue): + """ + Public slot to get the value for the named variable for the identified + script. + + @param nspace unique script id + @type str + @param name name of the variable + @type str + @param dValue default value + @type str + @return value for the named variable + @rtype str + """ + vName = "GreaseMonkey-{0}/{1}".format(nspace, name) + sValue = self.__settings.value(vName, dValue) + if not sValue: + return dValue + + return sValue + + @pyqtSlot(str, str, str) + def setValue(self, nspace, name, value): + """ + Public slot to set the value for the named variable for the identified + script. + + @param nspace unique script id + @type str + @param name name of the variable + @type str + @param value value to be set + @type str + @return flag indicating success + @rtype bool + """ + vName = "GreaseMonkey-{0}/{1}".format(nspace, name) + self.__settings.setValue(vName, value) + self.__settings.sync() + return True + + @pyqtSlot(str, str) + def deleteValue(self, nspace, name): + """ + Public slot to set delete the named variable for the identified script. + + @param nspace unique script id + @type str + @param name name of the variable + @type str + @return flag indicating success + @rtype bool + """ + vName = "GreaseMonkey-{0}/{1}".format(nspace, name) + self.__settings.remove(vName) + self.__settings.sync() + return True + + @pyqtSlot(str) + def listValues(self, nspace): + """ + Public slot to list the stored variables for the identified script. + + @param nspace unique script id + @type str + @return list of stored variables + @rtype list of str + """ + nspaceName = "GreaseMonkey-{0}".format(nspace) + self.__settings.beginGroup(nspaceName) + keys = self.__settings.allKeys() + self.__settings.endGroup() + + return keys + + @pyqtSlot(str) + def setClipboard(self, text): + """ + Public slot to set some clipboard text. + + @param text text to be copied to the clipboard + @type str + """ + QGuiApplication.clipboard().setText(text)
--- a/WebBrowser/GreaseMonkey/GreaseMonkeyManager.py Sat Feb 10 17:24:42 2018 +0100 +++ b/WebBrowser/GreaseMonkey/GreaseMonkeyManager.py Sat Feb 10 19:53:07 2018 +0100 @@ -21,6 +21,9 @@ import Preferences from WebBrowser.WebBrowserWindow import WebBrowserWindow +from WebBrowser.JavaScript.ExternalJsObject import ExternalJsObject + +from .GreaseMonkeyJsObject import GreaseMonkeyJsObject class GreaseMonkeyManager(QObject): @@ -43,6 +46,8 @@ self.__scripts = [] self.__downloaders = [] + self.__jsObject = GreaseMonkeyJsObject(self) + QTimer.singleShot(0, self.__load) def showConfigurationDialog(self, parent=None): @@ -322,6 +327,11 @@ else: collection = WebBrowserWindow.webProfile().scripts() collection.insert(script.webScript()) + + self.__jsObject.setSettingsFile(os.path.join( + Utilities.getConfigDir(), "web_browser", + "greasemonkey_values.ini")) + ExternalJsObject.registerExtraObject("GreaseMonkey", self.__jsObject) def __scriptChanged(self, script): """
--- a/eric6.e4p Sat Feb 10 17:24:42 2018 +0100 +++ b/eric6.e4p Sat Feb 10 19:53:07 2018 +0100 @@ -1472,6 +1472,7 @@ <Source>WebBrowser/GreaseMonkey/GreaseMonkeyConfiguration/__init__.py</Source> <Source>WebBrowser/GreaseMonkey/GreaseMonkeyDownloader.py</Source> <Source>WebBrowser/GreaseMonkey/GreaseMonkeyJavaScript.py</Source> + <Source>WebBrowser/GreaseMonkey/GreaseMonkeyJsObject.py</Source> <Source>WebBrowser/GreaseMonkey/GreaseMonkeyManager.py</Source> <Source>WebBrowser/GreaseMonkey/GreaseMonkeyScript.py</Source> <Source>WebBrowser/GreaseMonkey/__init__.py</Source> @@ -2199,14 +2200,14 @@ </Resources> <Others> <Other>.hgignore</Other> + <Other>APIs/Python/zope-2.10.7.api</Other> + <Other>APIs/Python/zope-2.11.2.api</Other> + <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/Python3/PyQt4.bas</Other> <Other>APIs/Python3/PyQt5.bas</Other> <Other>APIs/Python3/QScintilla2.bas</Other> <Other>APIs/Python3/eric6.api</Other> <Other>APIs/Python3/eric6.bas</Other> - <Other>APIs/Python/zope-2.10.7.api</Other> - <Other>APIs/Python/zope-2.11.2.api</Other> - <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/QSS/qss.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>