1 Components.utils.import("resource://gre/modules/AddonManager.jsm");
2 Components.utils.import("resource://gre/modules/Services.jsm");
3 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
5 const Cc = Components.classes;
6 const Ci = Components.interfaces;
8 const NS_XHTML = "http://www.w3.org/1999/xhtml";
10 var gDBStarted = false;
13 XPCOMUtils.defineLazyGetter(this, "ScriptDB", function() {
15 var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
16 getService(Ci.mozIJSSubScriptLoader);
18 loader.loadSubScript(gRootURI.spec + "includes/scriptdb.js", scope);
20 return scope.ScriptDatabase;
23 LOGE("Exception loading database", e);
28 dump("SLMNKY: " + aStr + "\n");
31 function LOGE(aStr, aException) {
32 dump("SLMNKY: " + aStr + ": " + aException + "\n");
33 if ("stack" in aException)
34 dump(aException.stack);
37 function getManagerStyles() {
38 return "#category-scripts > .category-icon,\
39 .addon[type=user-script] .icon,\
40 #detail-view[type=user-script] #detail-icon {\
41 list-style-image: url(" + gRootURI.spec + "images/script.png)\
45 function ExtendedStringBundle(aBase) {
46 this.basebundle = aBase;
50 ExtendedStringBundle.prototype = {
54 GetStringFromName: function(aName) {
55 if (aName in this.strings)
56 return this.strings[aName];
57 return this.basebundle.GetStringFromName(aName);
60 formatStringFromName: function(aName, aArgs, aLength) {
61 return this.basebundle.formatStringFromName(aName, aArgs, aLength);
65 var WindowObserver = {
66 addToAddonsManager: function(aWindow) {
67 var window = aWindow.wrappedJSObject;
70 var bundle = new ExtendedStringBundle(window.gStrings.ext);
71 bundle.strings["header-user-script"] = "User Scripts";
72 window.gStrings.ext = bundle;
74 var plugins = window.document.getElementById("category-plugins");
75 var scripts = window.document.createElement("richlistitem");
76 scripts.setAttribute("id", "category-scripts");
77 scripts.setAttribute("value", "addons://list/user-script");
78 scripts.setAttribute("class", "category");
79 scripts.setAttribute("name", "User Scripts");
80 plugins.parentNode.insertBefore(scripts, plugins);
82 var styles = window.document.createElementNS(NS_XHTML, "style");
83 styles.setAttribute("id", "script-styles");
84 styles.setAttribute("type", "text/css");
85 styles.appendChild(window.document.createTextNode(getManagerStyles()));
86 window.document.documentElement.appendChild(styles);
89 LOGE("Exception in injectIntoAddonsManager", e);
93 findAllAddonsManagers: function() {
95 var windows = Services.wm.getEnumerator("navigator:browser");
96 while (windows.hasMoreElements()) {
97 var window = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
98 window.gBrowser.browsers.forEach(function(aBrowser) {
99 if (aBrowser.currentURI.spec == "about:addons")
100 managers.push(aBrowser.contentWindow);
106 addToAddonsManagers: function() {
107 var managers = this.findAllAddonsManagers();
108 managers.forEach(function(aWindow) {
109 this.addToAddonsManager(aWindow);
113 removeFromAddonsManagers: function() {
114 var managers = this.findAllAddonsManagers();
115 managers.forEach(function(aWindow) {
116 var window = aWindow.wrappedJSObject;
117 var scripts = window.document.getElementById("category-scripts");
118 scripts.parentNode.removeChild(scripts);
119 var styles = window.document.getElementById("script-styles");
120 styles.parentNode.removeChild(styles);
121 window.gStrings.ext = window.gStrings.ext.basebundle;
125 installPrompt: function(aWindow) {
126 var window = aWindow.wrappedJSObject;
128 window.addEventListener("load", function() {
129 if (!Services.prompt.confirm(window, "Install Script?", "Do you want to install this user script?"))
132 ScriptDB.installScript(window.document.body.textContent,
133 aWindow.document.documentURIObject);
137 injectScripts: function(aWindow, aScripts) {
138 var safeWin = new XPCNativeWrapper(aWindow.wrappedJSObject);
140 aScripts.forEach(function(aScript) {
141 LOG("Injecting " + aScript.name);
142 var sandbox = new Components.utils.Sandbox(safeWin);
143 sandbox.window = safeWin;
144 sandbox.document = sandbox.window.document;
145 sandbox.unsafeWindow = aWindow.wrappedJSObject;
146 sandbox.__proto__ = safeWin;
148 var code = "(function(){" + aScript.script + "})()";
151 Components.utils.evalInSandbox(code, sandbox, "1.8");
154 LOGE("Exception in injected script", e);
159 observe: function(aSubject, aTopic, aData) {
161 var window = aSubject;
162 var uri = window.document.documentURIObject;
164 case "content-document-global-created":
165 LOG("Content window loaded: " + uri.spec);
166 var scripts = ScriptDB.getScriptsForURI(uri);
167 if (scripts.length > 0) {
168 window.addEventListener("DOMContentLoaded", function() {
169 WindowObserver.injectScripts(window, scripts);
172 if (uri.spec.substring(uri.spec.length - 8) == ".user.js" &&
173 !ScriptDB.hasScript(uri))
174 this.installPrompt(window);
176 case "chrome-document-global-created":
177 LOG("Chrome window loaded: " + uri.spec);
178 if (uri.spec == "about:addons") {
179 window.addEventListener("load", function() {
180 WindowObserver.addToAddonsManager(window);
187 LOGE("Exception in observe", e);
192 var AddonProvider = {
193 getAddonByID: function(aId, aCallback) {
194 aCallback(ScriptDB.getScript(aId));
197 getAddonsByTypes: function(aTypes, aCallback) {
198 if (aTypes && aTypes.indexOf("user-script") < 0)
201 aCallback(ScriptDB.getAllScripts());
205 function startup(aParams) {
209 gRootURI = Services.io.newFileURI(aParams.installPath);
210 Services.obs.addObserver(WindowObserver, "content-document-global-created", false);
211 Services.obs.addObserver(WindowObserver, "chrome-document-global-created", false);
212 AddonManagerPrivate.registerProvider(AddonProvider);
214 WindowObserver.addToAddonsManagers();
217 LOGE("Exception during startup", e);
221 function shutdown() {
225 WindowObserver.removeFromAddonsManagers();
227 AddonManagerPrivate.unregisterProvider(AddonProvider);
228 Services.obs.removeObserver(WindowObserver, "content-document-global-created");
229 Services.obs.removeObserver(WindowObserver, "chrome-document-global-created");
235 LOGE("Exception during shutdown", e);