bootstrap.js
author Dave Townsend <dtownsend@oxymoronical.com>
Fri Jul 09 12:41:11 2010 -0700 (7 weeks ago)
changeset 0 f8b0b8c6f940
permissions -rw-r--r--
Initial import of demo extension
     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");

     4 

     5 const Cc = Components.classes;

     6 const Ci = Components.interfaces;

     7 

     8 const NS_XHTML = "http://www.w3.org/1999/xhtml";

     9 

    10 var gDBStarted = false;

    11 var gRootURI = null;

    12 

    13 XPCOMUtils.defineLazyGetter(this, "ScriptDB", function() {

    14   try {

    15     var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].

    16                  getService(Ci.mozIJSSubScriptLoader);

    17     var scope = {};

    18     loader.loadSubScript(gRootURI.spec + "includes/scriptdb.js", scope);

    19     gDBStarted = true;

    20     return scope.ScriptDatabase;

    21   }

    22   catch (e) {

    23     LOGE("Exception loading database", e);

    24   }

    25 });

    26 

    27 function LOG(aStr) {

    28   dump("SLMNKY: " + aStr + "\n");

    29 }

    30 

    31 function LOGE(aStr, aException) {

    32   dump("SLMNKY: " + aStr + ": " + aException + "\n");

    33   if ("stack" in aException)

    34     dump(aException.stack);

    35 }

    36 

    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)\

    42           }";

    43 }

    44 

    45 function ExtendedStringBundle(aBase) {

    46   this.basebundle = aBase;

    47   this.strings = {};

    48 }

    49 

    50 ExtendedStringBundle.prototype = {

    51   strings: null,

    52   basebundle: null,

    53 

    54   GetStringFromName: function(aName) {

    55     if (aName in this.strings)

    56       return this.strings[aName];

    57     return this.basebundle.GetStringFromName(aName);

    58   },

    59 

    60   formatStringFromName: function(aName, aArgs, aLength) {

    61     return this.basebundle.formatStringFromName(aName, aArgs, aLength);

    62   }

    63 };

    64 

    65 var WindowObserver = {

    66   addToAddonsManager: function(aWindow) {

    67     var window = aWindow.wrappedJSObject;

    68 

    69     try {

    70       var bundle = new ExtendedStringBundle(window.gStrings.ext);

    71       bundle.strings["header-user-script"] = "User Scripts";

    72       window.gStrings.ext = bundle;

    73 

    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);

    81 

    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);

    87     }

    88     catch (e) {

    89       LOGE("Exception in injectIntoAddonsManager", e);

    90     }

    91   },

    92 

    93   findAllAddonsManagers: function() {

    94     var managers = [];

    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);

   101       });

   102     }

   103     return managers;

   104   },

   105 

   106   addToAddonsManagers: function() {

   107     var managers = this.findAllAddonsManagers();

   108     managers.forEach(function(aWindow) {

   109       this.addToAddonsManager(aWindow);

   110     }, this);

   111   },

   112 

   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;

   122     });

   123   },

   124 

   125   installPrompt: function(aWindow) {

   126     var window = aWindow.wrappedJSObject;

   127 

   128     window.addEventListener("load", function() {

   129       if (!Services.prompt.confirm(window, "Install Script?", "Do you want to install this user script?"))

   130         return;

   131 

   132       ScriptDB.installScript(window.document.body.textContent,

   133                              aWindow.document.documentURIObject);

   134     }, false);

   135   },

   136 

   137   injectScripts: function(aWindow, aScripts) {

   138     var safeWin = new XPCNativeWrapper(aWindow.wrappedJSObject);

   139 

   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;

   147 

   148       var code = "(function(){" + aScript.script + "})()";

   149 

   150       try {

   151         Components.utils.evalInSandbox(code, sandbox, "1.8");

   152       }

   153       catch(e) {

   154         LOGE("Exception in injected script", e);

   155       }

   156     });

   157   },

   158 

   159   observe: function(aSubject, aTopic, aData) {

   160     try {

   161       var window = aSubject;

   162       var uri = window.document.documentURIObject;

   163       switch (aTopic) {

   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);

   170           }, false);

   171         }

   172         if (uri.spec.substring(uri.spec.length - 8) == ".user.js" &&

   173             !ScriptDB.hasScript(uri))

   174           this.installPrompt(window);

   175         break;

   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);

   181           }, false);

   182         }

   183         break;

   184       }

   185     }

   186     catch (e) {

   187       LOGE("Exception in observe", e);

   188     }

   189   }

   190 };

   191 

   192 var AddonProvider = {

   193   getAddonByID: function(aId, aCallback) {

   194     aCallback(ScriptDB.getScript(aId));

   195   },

   196 

   197   getAddonsByTypes: function(aTypes, aCallback) {

   198     if (aTypes && aTypes.indexOf("user-script") < 0)

   199       aCallback([]);

   200     else

   201       aCallback(ScriptDB.getAllScripts());

   202   }

   203 };

   204 

   205 function startup(aParams) {

   206   LOG("startup");

   207 

   208   try {

   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);

   213 

   214     WindowObserver.addToAddonsManagers();

   215   }

   216   catch (e) {

   217     LOGE("Exception during startup", e);

   218   }

   219 }

   220 

   221 function shutdown() {

   222   LOG("shutdown");

   223 

   224   try {

   225     WindowObserver.removeFromAddonsManagers();

   226 

   227     AddonManagerPrivate.unregisterProvider(AddonProvider);

   228     Services.obs.removeObserver(WindowObserver, "content-document-global-created");

   229     Services.obs.removeObserver(WindowObserver, "chrome-document-global-created");

   230 

   231     if (gDBStarted)

   232       ScriptDB.shutdown();

   233   }

   234   catch (e) {

   235     LOGE("Exception during shutdown", e);

   236   }

   237 }