Browse files

Merge branch 'issue-1377'

Conflicts:
	content/config.js

Fixes: #1377
  • Loading branch information...
2 parents 262d5e8 + 23241da commit 6d9e0ca28dc4b733c24799f6be7eaf2119bd8b88 @arantius arantius committed Jul 22, 2011
View
15 CREDITS
@@ -1,15 +1,24 @@
Greasemonkey is Open Source, released under the terms of the MIT license;
see the LICENSE.mit file.
+Greasemonkey contains code derived from AdBlock ( http://adblock.mozdev.org/ ),
+reused under the terms of the MPL license; see LICENSE.mpl.
+
Greasemonkey contains code derived from FireBug ( http://getfirebug.com/ ),
reused under the terms of the BSD license; see LICENSE.bsd.
Greasemonkey contains code derived from SlipperyMonkey, originally by
Dave Townsend, reused under the terms of the MIT license.
( http://www.oxymoronical.com/blog/2010/07/How-to-extend-the-new-Add-ons-Manager )
+Greasemonkey contains code derived from Scriptish
+( https://github.com/scriptish/scriptish ), reused under the terms of the MIT
+license.
+
Greasemonkey also contains code derived from Mozilla projects, including
-Firefox ( http://mozilla.org/ ). This code is reused under the MPL license;
-see the LICENSE.mpl file. All such code is located in the content/third-party/
-directory, and all such files contain the appropriate licensing disclaimers
+Firefox ( http://mozilla.org/ ), reused under the MPL license; see the
+LICENSE.mpl file.
+
+All MPL code is located in the content/third-party/ and modules/third-party/
+directories, and all such files contain the appropriate licensing disclaimers
and notifications.
View
1 components/greasemonkey.js
@@ -209,7 +209,6 @@ function startup() {
loader.loadSubScript("chrome://greasemonkey/content/scriptrequire.js");
loader.loadSubScript("chrome://greasemonkey/content/scriptresource.js");
loader.loadSubScript("chrome://greasemonkey/content/scripticon.js");
- loader.loadSubScript("chrome://greasemonkey/content/convert2RegExp.js");
loader.loadSubScript("chrome://greasemonkey/content/miscapis.js");
loader.loadSubScript("chrome://greasemonkey/content/xmlhttprequester.js");
loader.loadSubScript("chrome://greasemonkey/content/scriptdownloader.js");
View
20 content/config.js
@@ -1,3 +1,5 @@
+Components.utils.import("resource://greasemonkey/third-party/MatchPattern.js");
+
function Config() {
this._saveTimer = null;
this._scripts = null;
@@ -8,6 +10,8 @@ function Config() {
this._observers = [];
}
+Config.prototype.GM_GUID = "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}";
+
Config.prototype.initialize = function() {
this._updateVersion();
this._load();
@@ -174,6 +178,14 @@ Config.prototype.parse = function(source, uri, updateScript) {
case "exclude":
script._excludes.push(value);
break;
+ case "match":
+ try {
+ var match = new MatchPattern(value);
+ script._matches.push(match);
+ } catch (e) {
+ GM_logError("Ignoring @match pattern " + value + " because:\n" + e);
+ }
+ break;
case "icon":
script._rawMeta += header + '\0' + value + '\0';
try {
@@ -255,7 +267,9 @@ Config.prototype.parse = function(source, uri, updateScript) {
if ("document-start" != script._runAt && "document-end" != script._runAt) {
script._runAt = "document-end";
}
- if (script._includes.length == 0) script._includes.push("*");
+ if (script._includes.length == 0 && script._matches.length == 0) {
+ script._includes.push("*");
+ }
return script;
};
@@ -413,12 +427,12 @@ Config.prototype._updateVersion = function() {
// Firefox <= 3.6.*
var extMan = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
- var item = extMan.getItemForID(GM_GUID);
+ var item = extMan.getItemForID(this.GM_GUID);
GM_prefRoot.setValue("version", item.version);
} else {
// Firefox 3.7+
Components.utils.import("resource://gre/modules/AddonManager.jsm");
- AddonManager.getAddonByID(GM_GUID, function(addon) {
+ AddonManager.getAddonByID(this.GM_GUID, function(addon) {
GM_prefRoot.setValue("version", addon.version);
});
}
View
8 content/install.js
@@ -1,15 +1,17 @@
var GMInstall = {
init: function() {
- var ioservice = Components.classes["@mozilla.org/network/io-service;1"]
- .getService(Components.interfaces.nsIIOService);
-
this.htmlNs_ = "http://www.w3.org/1999/xhtml";
this.scriptDownloader_ = window.arguments[0];
this.script_ = this.scriptDownloader_.script;
this.setupIncludes("includes", "includes-desc", this.script_.includes);
this.setupIncludes("excludes", "excludes-desc", this.script_.excludes);
+ var matches = [];
+ for (var i = 0, match = null; match = this.script_.matches[i]; i++) {
+ matches.push(match.pattern);
+ }
+ this.setupIncludes("matches", "matches-desc", matches);
this.dialog_ = document.documentElement;
this.extraButton_ = this.dialog_.getButton("extra1");
View
8 content/install.xul
@@ -52,6 +52,14 @@
<description id="includes-desc"
style="font-style:italic" />
</vbox>
+ <vbox id="matches"
+ style="margin-bottom:1em; display:none"
+ >
+ <label
+ value="&install.matches;" />
+ <description id="matches-desc"
+ style="font-style:italic" />
+ </vbox>
<vbox id="excludes"
style="display:none"
>
View
41 content/script.js
@@ -1,3 +1,6 @@
+Components.utils.import("resource://greasemonkey/third-party/convert2RegExp.js");
+Components.utils.import("resource://greasemonkey/third-party/MatchPattern.js");
+
function Script(configNode) {
this._observers = [];
@@ -19,6 +22,7 @@ function Script(configNode) {
this.needsUninstall = false;
this._includes = [];
this._excludes = [];
+ this._matches = [];
this._requires = [];
this._resources = [];
this._unwrap = false;
@@ -31,20 +35,23 @@ function Script(configNode) {
}
Script.prototype.matchesURL = function(url) {
- function test(glob) {
+ function testClude(glob) {
// Do not run in about:blank unless _specifically_ requested. See #1298
if (-1 !== url.indexOf('about:blank')
&& -1 == glob.indexOf('about:blank')
) {
return false;
}
- return convert2RegExp(glob).test(url);
+ return GM_convert2RegExp(glob).test(url);
+ }
+ function testMatch(matchPattern) {
+ return matchPattern.doMatch(url);
}
return GM_isGreasemonkeyable(url)
- && this._includes.some(test)
- && !this._excludes.some(test);
+ && (this._includes.some(testClude) || this._matches.some(testMatch))
+ && !this._excludes.some(testClude);
};
Script.prototype._changed = function(event, data) {
@@ -96,6 +103,9 @@ function Script_getIncludes() { return this._includes.concat(); });
Script.prototype.__defineGetter__('excludes',
function Script_getExcludes() { return this._excludes.concat(); });
+Script.prototype.__defineGetter__('matches',
+function Script_getMatches() { return this._matches.concat(); });
+
Script.prototype.addInclude = function(url) {
this._includes.push(url);
this._changed("edit-include-add", url);
@@ -220,6 +230,9 @@ Script.prototype._loadFromConfigNode = function(node) {
case "Exclude":
this._excludes.push(childNode.textContent);
break;
+ case "Match":
+ this._matches.push(new MatchPattern(childNode.textContent));
+ break;
case "Require":
var scriptRequire = new ScriptRequire(this);
scriptRequire._filename = childNode.getAttribute("filename");
@@ -250,18 +263,21 @@ Script.prototype._loadFromConfigNode = function(node) {
Script.prototype.toConfigNode = function(doc) {
var scriptNode = doc.createElement("Script");
- for (var j = 0; j < this._includes.length; j++) {
- var includeNode = doc.createElement("Include");
- includeNode.appendChild(doc.createTextNode(this._includes[j]));
+ function addNode(name, content) {
+ var node = doc.createElement(name);
+ node.appendChild(doc.createTextNode(content));
scriptNode.appendChild(doc.createTextNode("\n\t\t"));
- scriptNode.appendChild(includeNode);
+ scriptNode.appendChild(node);
}
+ for (var j = 0; j < this._includes.length; j++) {
+ addNode('Include', this._includes[j]);
+ }
for (var j = 0; j < this._excludes.length; j++) {
- var excludeNode = doc.createElement("Exclude");
- excludeNode.appendChild(doc.createTextNode(this._excludes[j]));
- scriptNode.appendChild(doc.createTextNode("\n\t\t"));
- scriptNode.appendChild(excludeNode);
+ addNode('Exclude', this._excludes[j]);
+ }
+ for (var j = 0; j < this._matches.length; j++) {
+ addNode('Match', this._matches[j].pattern);
}
for (var j = 0; j < this._requires.length; j++) {
@@ -394,6 +410,7 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin, chromeWin) {
// Copy new values.
this._includes = newScript._includes;
this._excludes = newScript._excludes;
+ this._matches = newScript._matches;
this._description = newScript._description;
this._runAt = newScript._runAt;
this._unwrap = newScript._unwrap;
View
55 content/utils.js
@@ -1,5 +1,7 @@
-const GM_GUID = "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}";
+// Load module-ized methods here for legacy access.
+Components.utils.import("resource://greasemonkey/utils.js");
+// Define legacy methods.
var GM_consoleService = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
@@ -55,6 +57,7 @@ function GM_logError(e, opt_warn, fileName, lineNumber) {
var flags = opt_warn ? 1 : 0;
+ if ("string" == typeof e) e = new Error(e);
// third parameter "sourceLine" is supposed to be the line, of the source,
// on which the error happened. we don't know it. (directly...)
consoleError.init(e.message, fileName, null, lineNumber,
@@ -69,9 +72,6 @@ function GM_log(message, force) {
}
}
-// TODO: this stuff was copied wholesale and not refactored at all. Lots of
-// the UI and Config rely on it. Needs rethinking.
-
function GM_openInEditor(script) {
var editor = GM_getEditor();
if (!editor) {
@@ -332,24 +332,6 @@ function GM_setEnabled(enabled) {
GM_prefRoot.setValue("enabled", enabled);
}
-function GM_uriFromUrl(url, base) {
- var ioService = Components.classes["@mozilla.org/network/io-service;1"]
- .getService(Components.interfaces.nsIIOService);
- var baseUri = null;
- if (typeof base === "string") {
- baseUri = GM_uriFromUrl(base);
- } else if (base) {
- baseUri = base;
- }
-
- try {
- return ioService.newURI(url, null, baseUri);
- } catch (e) {
- return null;
- }
-}
-GM_uriFromUrl = GM_memoize(GM_uriFromUrl);
-
// UTF-8 encodes input, SHA-1 hashes it and returns the 40-char hex version.
function GM_sha1(unicode) {
var unicodeConverter = Components
@@ -401,35 +383,6 @@ function GM_scriptMatchesUrlAndRuns(script, url, when) {
&& script.matchesURL(url);
}
-// Decorate a function with a memoization wrapper, with a limited-size cache
-// to reduce peak memory utilization. Simple usage:
-//
-// function foo(arg1, arg2) { /* complex operation */ }
-// foo = GM_memoize(foo);
-//
-// The memoized function may have any number of arguments, but they must be
-// be serializable, and uniquely. It's safest to use this only on functions
-// that accept primitives.
-function GM_memoize(func, limit) {
- limit = limit || 3000;
- var cache = {__proto__: null};
- var keylist = [];
-
- return function(a) {
- var args = Array.prototype.slice.call(arguments);
- var key = uneval(args);
- if (key in cache) return cache[key];
-
- var result = func.apply(null, args);
-
- cache[key] = result;
-
- if (keylist.push(key) > limit) delete cache[keylist.shift()];
-
- return result;
- }
-}
-
function GM_newUserScript() {
window.openDialog(
"chrome://greasemonkey/content/newscript.xul", null,
View
1 locale/en-US/greasemonkey.dtd
@@ -12,6 +12,7 @@
<!ENTITY statusbar.enabled.accesskey "E">
<!ENTITY install.title "Greasemonkey Installation">
<!ENTITY install.runson "runs on:">
+<!ENTITY install.matches "matches:">
<!ENTITY install.butnoton "does not run on:">
<!ENTITY install.warning1 "Malicious scripts can violate your privacy and act on your behalf without your knowledge.">
<!ENTITY install.warning2 "You should only install scripts from sources that you trust.">
View
4 locale/en-US/greasemonkey.properties
@@ -1 +1,5 @@
extensions.{e4a8a97b-f2ed-450b-b12d-ee082ba24781}.description=A User Script Manager for Firefox
+error.matchPattern.parse=@match: Could not parse the pattern.
+error.matchPattern.scheme=@match: Invalid scheme specified.
+error.matchPattern.host=@match: Invalid host specified.
+error.matchPattern.path=@match: Invalid path specified.
View
124 modules/third-party/MatchPattern.js
@@ -0,0 +1,124 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Page Modifications code.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * David Dahl <ddahl@mozilla.com>
+ * Drew Willcoxon <adw@mozilla.com>
+ * Erik Vold <erikvvold@gmail.com>
+ * Nils Maier <maierman@web.de>
+ * Anthony Lieuallen <arantius@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ['MatchPattern'];
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.import("resource://greasemonkey/third-party/convert2RegExp.js");
+Components.utils.import("resource://greasemonkey/utils.js");
+
+var validSchemes = ['http', 'https', 'ftp', 'file'];
+var REG_HOST = /^(?:\*\.)?[^*\/]+$|^\*$|^$/;
+var getString = (function() {
+ var stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
+ .getService(Components.interfaces.nsIStringBundleService);
+ return stringBundleService.createBundle(
+ 'chrome://greasemonkey/locale/greasemonkey.properties')
+ .GetStringFromName;
+})();
+
+// For the format of "pattern", see:
+// http://code.google.com/chrome/extensions/match_patterns.html
+function MatchPattern(pattern) {
+ this._pattern = pattern;
+
+ // Special case "<all_urls>".
+ if (pattern == "<all_urls>") {
+ this._all = true;
+ this._scheme = "all_urls";
+ return;
+ }
+
+ // Special case wild scheme.
+ if (pattern[0] == "*") {
+ this._wildScheme = true;
+ // Forge http, to satisfy the URI parser, and get a host.
+ pattern = "http" + pattern.slice(1);
+ }
+
+ var uri = GM_uriFromUrl(pattern);
+ if (!uri) {
+ throw new Error(getString("error.matchPattern.parse"));
+ }
+
+ var scheme = this._wildScheme ? "all" : uri.scheme;
+ if (scheme != "all" && validSchemes.indexOf(scheme) == -1) {
+ throw new Error(getString("error.matchPattern.scheme"));
+ }
+
+ var host = uri.host;
+ if (!REG_HOST.test(host)) {
+ throw new Error(getString("error.matchPattern.host"));
+ }
+
+ var path = uri.path;
+ if (path[0] !== "/") {
+ throw new Error(getString("error.matchPattern.path"));
+ }
+
+ this._scheme = scheme;
+ if (host) {
+ this._hostExpr = GM_convert2RegExp(host.replace(/^\*\./, "*"));
+ } else {
+ // If omitted, then it means "", an alias for localhost.
+ this._hostExpr = /^$/;
+ }
+ this._pathExpr = GM_convert2RegExp(path, false, true);
+}
+
+MatchPattern.prototype.__defineGetter__('pattern',
+function MatchPattern_getPattern() { return '' + this._pattern; });
+
+MatchPattern.prototype.doMatch = function(uriSpec) {
+ var matchURI = GM_uriFromUrl(uriSpec);
+
+ if (validSchemes.indexOf(matchURI.scheme) == -1) {
+ return false;
+ }
+
+ if (this._all) {
+ return true;
+ }
+ if (!this._wildScheme && this._scheme != matchURI.scheme) {
+ return false;
+ }
+ return this._hostExpr.test(matchURI.host)
+ && this._pathExpr.test(matchURI.path);
+};
View
37 content/convert2RegExp.js → modules/third-party/convert2RegExp.js
@@ -1,6 +1,37 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is AdBlock for Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Henrik Aasted Sorensen.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Henrik Aasted Sorensen <henrik@aasted.org>
+ * Stefan Kinitz <mcmurmel.blah@gmx.de>
+ * Rue <quill@ethereal.net>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var EXPORTED_SYMBOLS = ['GM_convert2RegExp'];
+
+Components.utils.import("resource://greasemonkey/utils.js");
+
+
// Converts a pattern in this programs simple notation to a regular expression.
-// thanks AdBlock! http://www.mozdev.org/source/browse/adblock/adblock/
-function convert2RegExp( pattern ) {
+function GM_convert2RegExp( pattern ) {
var s = new String(pattern);
var res = new String("^");
@@ -47,4 +78,4 @@ function convert2RegExp( pattern ) {
}
return new RegExp(res + "$", "i");
}
-convert2RegExp = GM_memoize(convert2RegExp);
+GM_convert2RegExp = GM_memoize(GM_convert2RegExp);
View
54 modules/utils.js
@@ -0,0 +1,54 @@
+var EXPORTED_SYMBOLS = [
+ 'GM_memoize',
+ 'GM_uriFromUrl',
+ ];
+
+
+// Decorate a function with a memoization wrapper, with a limited-size cache
+// to reduce peak memory utilization. Simple usage:
+//
+// function foo(arg1, arg2) { /* complex operation */ }
+// foo = GM_memoize(foo);
+//
+// The memoized function may have any number of arguments, but they must be
+// be serializable, and uniquely. It's safest to use this only on functions
+// that accept primitives.
+function GM_memoize(func, limit) {
+ limit = limit || 3000;
+ var cache = {__proto__: null};
+ var keylist = [];
+
+ return function(a) {
+ var args = Array.prototype.slice.call(arguments);
+ var key = uneval(args);
+ if (key in cache) return cache[key];
+
+ var result = func.apply(null, args);
+
+ cache[key] = result;
+
+ if (keylist.push(key) > limit) delete cache[keylist.shift()];
+
+ return result;
+ }
+}
+
+
+function GM_uriFromUrl(url, base) {
+ var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+ var baseUri = null;
+
+ if (typeof base === "string") {
+ baseUri = GM_uriFromUrl(base);
+ } else if (base) {
+ baseUri = base;
+ }
+
+ try {
+ return ioService.newURI(url, null, baseUri);
+ } catch (e) {
+ return null;
+ }
+}
+GM_uriFromUrl = GM_memoize(GM_uriFromUrl);

0 comments on commit 6d9e0ca

Please sign in to comment.