diff --git a/CHANGELOG b/CHANGELOG index 5c8534d0b..8e850b927 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Version 1.5.0 * added support for Proxy Auto-Config (PAC) * added option to open another private window from private window * added delete action in edit context menu on page + * GreaseMonkey: added support for GM_Settings * fixed: size of preferences dialog on low-res screens Version 1.4.1 diff --git a/src/plugins/GreaseMonkey/GreaseMonkey.pro b/src/plugins/GreaseMonkey/GreaseMonkey.pro index 983ebf05c..d8e87cf2b 100644 --- a/src/plugins/GreaseMonkey/GreaseMonkey.pro +++ b/src/plugins/GreaseMonkey/GreaseMonkey.pro @@ -14,7 +14,8 @@ SOURCES += gm_plugin.cpp \ settings/gm_settings.cpp \ settings/gm_settingslistdelegate.cpp \ settings/gm_settingsscriptinfo.cpp \ - settings/gm_settingslistwidget.cpp + settings/gm_settingslistwidget.cpp \ + gm_jsobject.cpp HEADERS += gm_plugin.h \ gm_manager.h \ @@ -26,7 +27,8 @@ HEADERS += gm_plugin.h \ settings/gm_settings.h \ settings/gm_settingslistdelegate.h \ settings/gm_settingsscriptinfo.h \ - settings/gm_settingslistwidget.h + settings/gm_settingslistwidget.h \ + gm_jsobject.h FORMS += \ gm_addscriptdialog.ui \ diff --git a/src/plugins/GreaseMonkey/data/bootstrap.js b/src/plugins/GreaseMonkey/data/bootstrap.js index 1d6e85d8f..a49a5f683 100644 --- a/src/plugins/GreaseMonkey/data/bootstrap.js +++ b/src/plugins/GreaseMonkey/data/bootstrap.js @@ -67,6 +67,31 @@ if(typeof GM_openInTab === "undefined") { } } +// GM Settings Impl +if(typeof GM_getValueImpl === "undefined") { + function GM_getValueImpl(namespace, name, value) { + return window._qz_greasemonkey.getValue(namespace, name, value); + } +} + +if(typeof GM_setValueImpl === "undefined") { + function GM_setValueImpl(namespace, name, value) { + window._qz_greasemonkey.setValue(namespace, name, value); + } +} + +if(typeof GM_deleteValueImpl === "undefined") { + function GM_deleteValueImpl(namespace, name) { + window._qz_greasemonkey.deleteValue(namespace, name); + } +} + +if(typeof GM_listValuesImpl === "undefined") { + function GM_listValuesImpl(namespace) { + return window._qz_greasemonkey.listValues(namespace); + } +} + // Define unsafe window var unsafeWindow = window; window.wrappedJSObject = unsafeWindow; @@ -88,24 +113,3 @@ if(typeof GM_getResourceURL === "undefined") { throw ("QupZilla: GM Resource is not supported!"); } } - -// GM Settings not supported -if(typeof GM_getValue === "undefined") { - function GM_getValue(name, defaultValue) { - return defaultValue; - } -} - -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(""); - } -} diff --git a/src/plugins/GreaseMonkey/data/bootstrap.min.js b/src/plugins/GreaseMonkey/data/bootstrap.min.js index 71bfbbcf0..faa697c01 100644 --- a/src/plugins/GreaseMonkey/data/bootstrap.min.js +++ b/src/plugins/GreaseMonkey/data/bootstrap.min.js @@ -1 +1 @@ -if(typeof GM_xmlhttpRequest==="undefined")GM_xmlhttpRequest=function(details){details.method=details.method.toUpperCase()||"GET";if(!details.url)throw"GM_xmlhttpRequest requires an URL.";var oXhr=new XMLHttpRequest;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)};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()}else throw"This Browser is not supported, please upgrade.";};if(typeof GM_addStyle==="undefined"){function GM_addStyle(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_log==="undefined"){function GM_log(log){if(console)console.log(log)}}if(typeof GM_openInTab==="undefined"){function GM_openInTab(url){window.open(url)}}var unsafeWindow=window;window.wrappedJSObject=unsafeWindow;if(typeof GM_registerMenuCommand==="undefined"){function GM_registerMenuCommand(caption,commandFunc,accessKey){}}if(typeof GM_getResourceText==="undefined"){function GM_getResourceText(resourceName){throw"QupZilla: GM Resource is not supported!";}}if(typeof GM_getResourceURL==="undefined"){function GM_getResourceURL(resourceName){throw"QupZilla: GM Resource is not supported!";}}if(typeof GM_getValue==="undefined"){function GM_getValue(name,defaultValue){return defaultValue}}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("")}}; +if(typeof GM_xmlhttpRequest==="undefined")GM_xmlhttpRequest=function(details){details.method=details.method.toUpperCase()||"GET";if(!details.url)throw"GM_xmlhttpRequest requires an URL.";var oXhr=new XMLHttpRequest;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)};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()}else throw"This Browser is not supported, please upgrade.";}; if(typeof GM_addStyle==="undefined"){function GM_addStyle(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_log==="undefined"){function GM_log(log){if(console)console.log(log)}}if(typeof GM_openInTab==="undefined"){function GM_openInTab(url){window.open(url)}}if(typeof GM_getValueImpl==="undefined"){function GM_getValueImpl(namespace,name,value){return window._qz_greasemonkey.getValue(namespace,name,value)}}if(typeof GM_setValueImpl==="undefined"){function GM_setValueImpl(namespace,name,value){window._qz_greasemonkey.setValue(namespace,name,value)}} if(typeof GM_deleteValueImpl==="undefined"){function GM_deleteValueImpl(namespace,name){window._qz_greasemonkey.deleteValue(namespace,name)}}if(typeof GM_listValuesImpl==="undefined"){function GM_listValuesImpl(namespace){return window._qz_greasemonkey.listValues(namespace)}}var unsafeWindow=window;window.wrappedJSObject=unsafeWindow;if(typeof GM_registerMenuCommand==="undefined"){function GM_registerMenuCommand(caption,commandFunc,accessKey){}} if(typeof GM_getResourceText==="undefined"){function GM_getResourceText(resourceName){throw"QupZilla: GM Resource is not supported!";}}if(typeof GM_getResourceURL==="undefined"){function GM_getResourceURL(resourceName){throw"QupZilla: GM Resource is not supported!";}}; diff --git a/src/plugins/GreaseMonkey/gm_jsobject.cpp b/src/plugins/GreaseMonkey/gm_jsobject.cpp new file mode 100644 index 000000000..500fa5dac --- /dev/null +++ b/src/plugins/GreaseMonkey/gm_jsobject.cpp @@ -0,0 +1,122 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "gm_jsobject.h" + +GM_JSObject::GM_JSObject(QObject* parent) + : QObject(parent) + , m_settings(0) +{ +} + +void GM_JSObject::setSettingsFile(const QString &name) +{ + if (m_settings) { + m_settings->sync(); + delete m_settings; + } + + m_settings = new QSettings(name, QSettings::IniFormat); +} + +QVariant GM_JSObject::getValue(const QString &nspace, const QString &name, const QVariant &dValue) +{ + QString valueName = QString("GreaseMonkey-%1/%2").arg(nspace, name); + QString savedValue = m_settings->value(valueName, dValue).toString(); + + if (savedValue.isEmpty()) { + return dValue; + } + + QString actualValue = savedValue.mid(1).trimmed(); + if (actualValue.isEmpty()) { + return dValue; + } + + switch (savedValue.at(0).toAscii()) { + case 'b': + return QVariant(actualValue == QLatin1String("true")); + + case 'i': { + bool ok; + int val = actualValue.toInt(&ok); + return ok ? QVariant(val) : dValue; + } + + case 's': + return actualValue; + + default: + break; + } + + return dValue; +} + +void GM_JSObject::setValue(const QString &nspace, const QString &name, const QVariant &value) +{ + QString savedValue; + + switch (value.type()) { + case QVariant::Bool: + savedValue = value.toBool() ? "btrue" : "bfalse"; + break; + + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Double: + savedValue = "i" + QString::number(value.toInt()); + break; + + case QVariant::String: + savedValue = "s" + value.toString(); + break; + + default: + break; + } + + QString valueName = QString("GreaseMonkey-%1/%2").arg(nspace, name); + m_settings->setValue(valueName, savedValue); +} + +void GM_JSObject::deleteValue(const QString &nspace, const QString &name) +{ + QString valueName = QString("GreaseMonkey-%1/%2").arg(nspace, name); + m_settings->remove(valueName); +} + +QStringList GM_JSObject::listValues(const QString &nspace) +{ + QString nspaceName = QString("GreaseMonkey-%1").arg(nspace); + + m_settings->beginGroup(nspaceName); + QStringList keys = m_settings->allKeys(); + m_settings->endGroup(); + + return keys; +} + +GM_JSObject::~GM_JSObject() +{ + if (m_settings) { + m_settings->sync(); + delete m_settings; + } +} diff --git a/src/plugins/GreaseMonkey/gm_jsobject.h b/src/plugins/GreaseMonkey/gm_jsobject.h new file mode 100644 index 000000000..f9323799d --- /dev/null +++ b/src/plugins/GreaseMonkey/gm_jsobject.h @@ -0,0 +1,45 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef GM_JSOBJECT_H +#define GM_JSOBJECT_H + +#include +#include +#include +#include + +class GM_JSObject : public QObject +{ + Q_OBJECT +public: + explicit GM_JSObject(QObject* parent = 0); + ~GM_JSObject(); + + void setSettingsFile(const QString &name); + +public slots: + QVariant getValue(const QString &nspace, const QString &name, const QVariant &dValue); + void setValue(const QString &nspace, const QString &name, const QVariant &value); + void deleteValue(const QString &nspace, const QString &name); + QStringList listValues(const QString &nspace); + +private: + QSettings* m_settings; +}; + +#endif // GM_JSOBJECT_H diff --git a/src/plugins/GreaseMonkey/gm_manager.cpp b/src/plugins/GreaseMonkey/gm_manager.cpp index 0d8b4ec44..007b3f25d 100644 --- a/src/plugins/GreaseMonkey/gm_manager.cpp +++ b/src/plugins/GreaseMonkey/gm_manager.cpp @@ -18,6 +18,7 @@ #include "gm_manager.h" #include "gm_script.h" #include "gm_downloader.h" +#include "gm_jsobject.h" #include "settings/gm_settings.h" #include "webpage.h" @@ -34,6 +35,7 @@ GM_Manager::GM_Manager(const QString &sPath, QObject* parent) : QObject(parent) , m_settingsPath(sPath) + , m_jsObject(new GM_JSObject(this)) { QTimer::singleShot(0, this, SLOT(load())); } @@ -197,6 +199,8 @@ void GM_Manager::pageLoadStart() return; } + frame->addToJavaScriptWindowObject("_qz_greasemonkey", m_jsObject); + foreach (GM_Script* script, m_startScripts) { if (script->match(urlString)) { frame->evaluateJavaScript(m_bootstrap + script->script()); @@ -206,7 +210,7 @@ void GM_Manager::pageLoadStart() foreach (GM_Script* script, m_endScripts) { if (script->match(urlString)) { const QString &jscript = QString("window.addEventListener(\"DOMContentLoaded\"," - "function(e) { %1 }, false);").arg(m_bootstrap + script->script()); + "function(e) { \n%1\n }, false);").arg(m_bootstrap + script->script()); frame->evaluateJavaScript(jscript); } } @@ -249,6 +253,7 @@ void GM_Manager::load() } m_bootstrap = QzTools::readAllFileContents(":gm/data/bootstrap.min.js"); + m_jsObject->setSettingsFile(m_settingsPath + "extensions.ini"); } bool GM_Manager::canRunOnScheme(const QString &scheme) diff --git a/src/plugins/GreaseMonkey/gm_manager.h b/src/plugins/GreaseMonkey/gm_manager.h index e018e073a..ae82793a7 100644 --- a/src/plugins/GreaseMonkey/gm_manager.h +++ b/src/plugins/GreaseMonkey/gm_manager.h @@ -26,6 +26,7 @@ class QUrl; class QNetworkRequest; class GM_Script; +class GM_JSObject; class GM_Settings; class GM_Manager : public QObject @@ -71,6 +72,7 @@ private: QPointer m_settings; QStringList m_disabledScripts; + GM_JSObject* m_jsObject; QList m_endScripts; QList m_startScripts; }; diff --git a/src/plugins/GreaseMonkey/gm_plugin.cpp b/src/plugins/GreaseMonkey/gm_plugin.cpp index 25e60bb62..b06ab2ec2 100644 --- a/src/plugins/GreaseMonkey/gm_plugin.cpp +++ b/src/plugins/GreaseMonkey/gm_plugin.cpp @@ -38,7 +38,7 @@ PluginSpec GM_Plugin::pluginSpec() spec.name = "GreaseMonkey"; spec.info = "Userscripts for QupZilla"; spec.description = "Provides support for userscripts (www.userscripts.org)"; - spec.version = "0.2.5"; + spec.version = "0.3.0"; spec.author = "David Rosca "; spec.icon = QPixmap(":gm/data/icon.png"); spec.hasSettings = true; diff --git a/src/plugins/GreaseMonkey/gm_script.cpp b/src/plugins/GreaseMonkey/gm_script.cpp index 8a5552998..00c7ef8e0 100644 --- a/src/plugins/GreaseMonkey/gm_script.cpp +++ b/src/plugins/GreaseMonkey/gm_script.cpp @@ -17,13 +17,13 @@ * ============================================================ */ #include "gm_script.h" #include "gm_manager.h" +#include "qzregexp.h" #include -#include "qzregexp.h" #include #include #include -#include +#include #include GM_Script::GM_Script(GM_Manager* manager, const QString &filePath) @@ -255,8 +255,16 @@ void GM_Script::parseScript() int index = fileData.indexOf(QLatin1String("// ==/UserScript==")) + 18; QString script = fileData.mid(index).trimmed(); + QString jscript("(function(){" + "function GM_getValue(name,val){return GM_getValueImpl('%1',name,val);}" + "function GM_setValue(name,val){return GM_setValueImpl('%1',name,val);}" + "function GM_deleteValue(name){return GM_deleteValueImpl('%1',name);}" + "function GM_listValues(){return GM_listValuesImpl('%1');}" + "\n%2\n})();"); + QString nspace = QCryptographicHash::hash(fullName().toUtf8(), QCryptographicHash::Md4).toHex(); + script.prepend(m_manager->requireScripts(requireList)); - script = QString("(function(){%1})();").arg(script); + script = jscript.arg(nspace, script); m_script = script; m_valid = !script.isEmpty();