SHARE
TWEET

WrapMsBrowserExtensionPageAndBackground.js

a guest Jan 15th, 2015 4,031 Never
  1. (function (nativeMsBrowser) {
  2.     var nativeJSON = window.JSON;
  3.  
  4.     Object.defineProperty(window, "msBrowser", {
  5.         get: delayInitMsBrowser,
  6.         configurable: true,
  7.         enumerable: true
  8.     });
  9.  
  10.     function delayInitMsBrowser() {
  11.         var wrapMsBrowser = Object.defineProperties({}, {
  12.             "runtime": {
  13.                 get: delayInitRuntime,
  14.                 configurable: true,
  15.                 enumerable: true
  16.             },
  17.             "storage": {
  18.                 get: delayInitStorage,
  19.                 configurable: true,
  20.                 enumerable: true
  21.             },
  22.             "tabs": {
  23.                 get: delayInitTabs,
  24.                 configurable: true,
  25.                 enumerable: true
  26.             },
  27.             "browserAction": {
  28.                 get: delayInitBrowserAction,
  29.                 configurable: true,
  30.                 enumerable: true
  31.             }
  32.         });
  33.  
  34.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  35.         Object.defineProperty(window, "msBrowser", {
  36.             value: wrapMsBrowser,
  37.             configurable: true,
  38.             enumerable: true
  39.         });
  40.         return wrapMsBrowser;
  41.     }
  42.  
  43.     function delayInitRuntime() {
  44.         var wrapRuntime = Object.defineProperties({}, {
  45.             "getURL": {
  46.                 value: nativeMsBrowser.runtime.getURL.bind(nativeMsBrowser.runtime),
  47.                 configurable: true,
  48.                 enumerable: true
  49.             },
  50.             "sendMessage": {
  51.                 value: sendMessageIndirect.bind(nativeMsBrowser.runtime),
  52.                 configurable: true,
  53.                 enumerable: true
  54.             },
  55.             "onMessage": {
  56.                 get: delayInitOnMessage,
  57.                 configurable: true,
  58.                 enumerable: true
  59.             },
  60.             "onMessageExternal": {
  61.                 get: delayInitOnMessageExternal,
  62.                 configurable: true,
  63.                 enumerable: true
  64.             }
  65.         });
  66.  
  67.         function onMessageAddListenerIndirect(callback) {
  68.             this.addListener(onMessageCallbackIndirect(callback));
  69.         }
  70.  
  71.         function onMessageCallbackIndirect(callback) {
  72.             return function () {
  73.                 var result = {};
  74.                 function sendResponse(response) {
  75.                     result.response = nativeJSON.stringify(response);
  76.                 }
  77.                 var msg = nativeJSON.parse(arguments[0].msg);
  78.                 result.async = callback(msg, arguments[0].sender, sendResponse.bind(window)) ? true : false;
  79.                 return result;
  80.                 // Need to handle sending the response async - http://osgvsowi/674353
  81.             }
  82.         }
  83.  
  84.         function responseCallbackIndirect(responseCallback) {
  85.             return function () {
  86.                 var jsonResponse = arguments[0];
  87.                 var response; // This is initialized to undefined.
  88.                 if (jsonResponse !== 'undefined') {
  89.                     // JSON.stringify(undefined) === undefined is packed for courier messaging as 'undefined' but JSON.parse('undefined') throws javascript error.
  90.                     // A response of "undefined" (type string) is packed for courier messaging as '"undefined"', hence will not conflict with a response of undefined (type undefined).
  91.                     response = nativeJSON.parse(jsonResponse);
  92.                 }
  93.                 responseCallback(response);
  94.             }
  95.         }
  96.  
  97.         function delayInitOnMessage() {
  98.             var wrapOnMessage = Object.defineProperties({}, {
  99.                 "addListener": {
  100.                     value: onMessageAddListenerIndirect.bind(nativeMsBrowser.runtime.onMessage),
  101.                     configurable: true,
  102.                     enumerable: true
  103.                 }
  104.             });
  105.  
  106.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  107.             Object.defineProperty(window.msBrowser.runtime, "onMessage", {
  108.                 value: wrapOnMessage,
  109.                 configurable: true,
  110.                 enumerable: true
  111.             });
  112.             return wrapOnMessage;
  113.         }
  114.  
  115.         function delayInitOnMessageExternal() {
  116.             var wrapOnMessageExternal = Object.defineProperties({}, {
  117.                 "addListener": {
  118.                     value: onMessageAddListenerIndirect.bind(nativeMsBrowser.runtime.onMessageExternal),
  119.                     configurable: true,
  120.                     enumerable: true
  121.                 }
  122.             });
  123.  
  124.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  125.             Object.defineProperty(window.msBrowser.runtime, "onMessageExternal", {
  126.                 value: wrapOnMessageExternal,
  127.                 configurable: true,
  128.                 enumerable: true
  129.             });
  130.             return wrapOnMessageExternal;
  131.         }
  132.  
  133.         function sendMessageIndirect(/* optional string extensionId, any message, optional object options, optional function responseCallback */) {
  134.  
  135.             if (arguments.length < 1) {
  136.                 return null;
  137.             }
  138.  
  139.             // The presence of multiple optional arguments in the order given here is resolved per the logic in chromium source code for alignSendMessageArguments.
  140.             // Javascript allows a function to be called with extra parameters at end that are discarded.
  141.             // Chrome parsed the arguments from the end so the behavior with extra args will not match "regular javascript expectation".
  142.  
  143.             var index = arguments.length - 1;
  144.  
  145.             var responseCallback = null;
  146.             if (typeof arguments[index] === "function") {
  147.                 responseCallback = responseCallbackIndirect(arguments[index]);
  148.                 --index;
  149.             }
  150.  
  151.             var options = null;
  152.             if (index >= 2) {
  153.                 // More than two arguments remain so options param must  present.
  154.                 options = arguments[index];
  155.                 --index;
  156.             }
  157.             else if (index === 2) {
  158.                 // This is ambiguous state actually, e.g. developer may be passing a string for the request and options object and expecting default extension id.
  159.                 // But chrome will treat it as having a non-default-extension id and use the options object for the request.
  160.                 // The logic: assume that the first param is the optional extension id if it is present and is a string, hence no options argument in this case.
  161.                 if (!(arguments[0] === null || typeof arguments[0] === "string")) {
  162.                     options = arguments[index];
  163.                     --index;
  164.                 }
  165.             }
  166.  
  167.             var message = arguments[index]; // Must be present.
  168.             --index;
  169.  
  170.             var extensionId = null;
  171.             if (index >= 0) {
  172.                 extensionId = arguments[index];
  173.                 --index;
  174.             }
  175.  
  176.             if (index !== -1) {
  177.                 // Requires exact number of arguments, no extra arguments allowed.
  178.                 return null;
  179.             }
  180.             else {
  181.                 // Always stringify on sendMessage side and always parse on the callback side.
  182.                 // Otherwise, callback cannot distinuish between a message sending an object and another message sending its string equivalent.
  183.                 return nativeMsBrowser.runtime.sendMessage(extensionId, nativeJSON.stringify(message), options, responseCallback);
  184.             }
  185.         };
  186.  
  187.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  188.         Object.defineProperty(window.msBrowser, "runtime", {
  189.             value: wrapRuntime,
  190.             configurable: true,
  191.             enumerable: true
  192.         });
  193.         return wrapRuntime;
  194.     }
  195.  
  196.     function delayInitStorage() {
  197.         var wrapStorage = Object.defineProperties({}, {
  198.             "local": {
  199.                 get: delayInitLocal,
  200.                 configurable: true,
  201.                 enumerable: true
  202.             },
  203.             "onChanged": {
  204.                 get: delayInitOnChanged,
  205.                 configurable: true,
  206.                 enumerable: true
  207.             }
  208.         });
  209.         function delayInitOnChanged() {
  210.             var wrapOnChanged = Object.defineProperties({}, {
  211.                 "addListener": {
  212.                     value: nativeMsBrowser.storage.onChanged.addListener.bind(nativeMsBrowser.storage.onChanged),
  213.                     configurable: true,
  214.                     enumerable: true
  215.                 }
  216.             });
  217.  
  218.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  219.             Object.defineProperty(window.msBrowser.storage, "onChanged", {
  220.                 value: wrapOnChanged,
  221.                 configurable: true,
  222.                 enumerable: true
  223.             });
  224.             return wrapOnChanged;
  225.         }
  226.         function delayInitLocal() {
  227.             var wrapLocal = Object.defineProperties({}, {
  228.                 "get": {
  229.                     value: nativeMsBrowser.storage.local.get.bind(nativeMsBrowser.storage.local),
  230.                     configurable: true,
  231.                     enumerable: true
  232.                 },
  233.                 "getBytesInUse": {
  234.                     value: nativeMsBrowser.storage.local.getBytesInUse.bind(nativeMsBrowser.storage.local),
  235.                     configurable: true,
  236.                     enumerable: true
  237.                 },
  238.                 "set": {
  239.                     value: nativeMsBrowser.storage.local.set.bind(nativeMsBrowser.storage.local),
  240.                     configurable: true,
  241.                     enumerable: true
  242.                 },
  243.                 "remove": {
  244.                     value: nativeMsBrowser.storage.local.remove.bind(nativeMsBrowser.storage.local),
  245.                     configurable: true,
  246.                     enumerable: true
  247.                 },
  248.                 "clear": {
  249.                     value: nativeMsBrowser.storage.local.clear.bind(nativeMsBrowser.storage.local),
  250.                     configurable: true,
  251.                     enumerable: true
  252.                 }
  253.             });
  254.  
  255.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  256.             Object.defineProperty(window.msBrowser.storage, "local", {
  257.                 value: wrapLocal,
  258.                 configurable: true,
  259.                 enumerable: true
  260.             });
  261.             return wrapLocal;
  262.         }
  263.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  264.         Object.defineProperty(window.msBrowser, "storage", {
  265.             value: wrapStorage,
  266.             configurable: true,
  267.             enumerable: true
  268.         });
  269.         return wrapStorage;
  270.     }
  271.  
  272.     function delayInitTabs() {
  273.         var wrapTabs = Object.defineProperties({}, {
  274.             "create": {
  275.                 value: nativeMsBrowser.tabs.create.bind(nativeMsBrowser.tabs),
  276.                 configurable: true,
  277.                 enumerable: true
  278.             },
  279.             "query": {
  280.                 value: nativeMsBrowser.tabs.query.bind(nativeMsBrowser.tabs),
  281.                 configurable: true,
  282.                 enumerable: true
  283.             }
  284.         });
  285.  
  286.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  287.         Object.defineProperty(window.msBrowser, "tabs", {
  288.             value: wrapTabs,
  289.             configurable: true,
  290.             enumerable: true
  291.         });
  292.         return wrapTabs;
  293.     }
  294.  
  295.     function delayInitBrowserAction()
  296.     {
  297.         var wrapBrowserAction = Object.defineProperties({}, {
  298.             "onClicked": {
  299.                 get: delayInitOnClicked,
  300.                 configurable: true,
  301.                 enumerable: true
  302.             }
  303.         });
  304.  
  305.         function delayInitOnClicked() {
  306.             var wrapOnClicked = Object.defineProperties({}, {
  307.                 "addListener": {
  308.                     value: nativeMsBrowser.browserAction.onClicked.addListener.bind(nativeMsBrowser.browserAction.onClicked),
  309.                     configurable: true,
  310.                     enumerable: true
  311.                 }
  312.             });
  313.  
  314.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  315.             Object.defineProperty(window.msBrowser.browserAction, "onClicked", {
  316.                 value: wrapOnClicked,
  317.                 configurable: true,
  318.                 enumerable: true
  319.             });
  320.  
  321.             return wrapOnClicked;
  322.         }
  323.  
  324.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  325.         Object.defineProperty(window.msBrowser, "browserAction", {
  326.             value: wrapBrowserAction,
  327.             configurable: true,
  328.             enumerable: true
  329.         });
  330.  
  331.         return wrapBrowserAction;
  332.     }
  333.  
  334. })(window.msBrowser);
  335.  
  336. // !!! End of File: be careful if you have to change the following line.
  337. // There is a null character at end of this line, enabling this resource to be used as a null terminated string:
RAW Paste Data
Top