[Pkg-mozext-commits] [adblock-plus] 18/52: Implemented fake background page and proper message responder there

David Prévot taffit at moszumanska.debian.org
Thu Jan 22 21:43:45 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository adblock-plus.

commit 87a7c25f4fd3b187818229b552a2260c599ade42
Author: Wladimir Palant <trev at adblockplus.org>
Date:   Fri Dec 19 18:44:23 2014 +0100

    Implemented fake background page and proper message responder there
    
    --HG--
    extra : rebase_source : 494b7c6396a8407c1f04ed56d483401cc41fb3b7
    extra : amend_source : da2ea4e0a3b286300bd7d825065ce135b22ca2ed
    extra : histedit_source : 0d9e01408727890bce9d2a0b4146e30caa537d59%2C7bc4cdd24122f3d436c03418b213b402f23c2cbc
---
 README.md           |  10 ++-
 background.html     |  29 +++++++++
 background.js       | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ext/background.js   |  78 ++++++++++++++++++++++++
 ext/common.js       |  60 +++++++++++++++++-
 ext/content.js      | 148 +++++++++++---------------------------------
 firstRun.js         |   5 +-
 messageResponder.js | 160 ++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 542 insertions(+), 120 deletions(-)

diff --git a/README.md b/README.md
index 18716d4..c31d070 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,14 @@ as they will do in the final product.
 Directory structure
 -------------------
 
-* Top-level files: HTML pages and scripts meant to be imported into the
-  respective products.
+* Top-level files:
+  * `firstRun.html` and `firstRun.js`: First-run page, see below
+  * `i18n.js`: Localization functions, should be included by all pages.
+  * `utils.js`: Utility functions, to be removed soon.
+  * `messageResponder.js`: Script to be used on the background page to respond
+    to messages sent by UI code.
+  * `background.html`, `background.js`: Test implementation of the background
+    page, should *not be imported*.
 * `locale` directory: Localized strings, with one directory per locale. The
   Firefox format for locale identifiers is used (xx-YY where xx is the language
   code and YY the optional region code). The localization strings themselves are
diff --git a/background.html b/background.html
new file mode 100644
index 0000000..1f2d2d1
--- /dev/null
+++ b/background.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!--
+  - This file is part of Adblock Plus <http://adblockplus.org/>,
+  - Copyright (C) 2006-2014 Eyeo GmbH
+  -
+  - Adblock Plus is free software: you can redistribute it and/or modify
+  - it under the terms of the GNU General Public License version 3 as
+  - published by the Free Software Foundation.
+  -
+  - Adblock Plus 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 Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script type="text/javascript" src="ext/common.js"></script>
+    <script type="text/javascript" src="ext/background.js"></script>
+    <script type="text/javascript" src="background.js"></script>
+    <script type="text/javascript" src="messageResponder.js"></script>
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/background.js b/background.js
new file mode 100644
index 0000000..93f4896
--- /dev/null
+++ b/background.js
@@ -0,0 +1,172 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function(global)
+{
+  function updateFromURL(data)
+  {
+    if (window.location.search)
+    {
+      var params = window.location.search.substr(1).split("&");
+      for (var i = 0; i < params.length; i++)
+      {
+        var parts = params[i].split("=", 2);
+        if (parts.length == 2 && parts[0] in data)
+          data[parts[0]] = decodeURIComponent(parts[1]);
+      }
+    }
+  }
+
+  var subscriptions =[
+    "https://easylist-downloads.adblockplus.org/easylistgermany+easylist.txt",
+    "https://easylist-downloads.adblockplus.org/exceptionrules.txt",
+    "https://easylist-downloads.adblockplus.org/fanboy-social.txt"
+  ];
+
+  global.Utils = {
+    getDocLink: function(link)
+    {
+      return "https://adblockplus.org/redirect?link=" + encodeURIComponent(link);
+    }
+  };
+
+  global.Subscription = function(url)
+  {
+    this.url = url;
+    this.title = "Subscription " + url;
+    this.disabled = false;
+    this.lastDownload = 1234;
+  };
+
+  global.Subscription.fromURL = function(url)
+  {
+    return new global.Subscription(url);
+  };
+
+  global.DownloadableSubscription = global.Subscription;
+  global.SpecialSubscription = function() {};
+
+  global.FilterStorage = {
+    get subscriptions()
+    {
+      return subscriptions.map(global.Subscription.fromURL);
+    },
+
+    get knownSubscriptions()
+    {
+      var result = {};
+      for (var i = 0; i < subscriptions.length; i++)
+        result[subscriptions[i]] = global.Subscription.fromURL(subscriptions[i]);
+      return result;
+    },
+
+    addSubscription: function(subscription)
+    {
+      var index = subscriptions.indexOf(subscription.url);
+      if (index < 0)
+      {
+        subscriptions.push(subscription.url);
+        global.FilterNotifier.triggerListeners("subscription.added", subscription);
+      }
+    },
+
+    removeSubscription: function(subscription)
+    {
+      var index = subscriptions.indexOf(subscription.url);
+      if (index >= 0)
+      {
+        subscriptions.splice(index, 1);
+        global.FilterNotifier.triggerListeners("subscription.removed", subscription);
+      }
+    }
+  };
+
+  global.BlockingFilter = function() {};
+
+  global.defaultMatcher = {
+    matchesAny: function(url, requestType, docDomain, thirdParty)
+    {
+      var params = {blockedURLs: ""};
+      updateFromURL(params);
+      var blocked = params.blockedURLs.split(",");
+      if (blocked.indexOf(url) >= 0)
+        return new global.BlockingFilter();
+      else
+        return null;
+    }
+  };
+
+  var notifierListeners = [];
+  global.FilterNotifier = {
+    addListener: function(listener)
+    {
+      if (notifierListeners.indexOf(listener) < 0)
+        notifierListeners.push(listener);
+    },
+
+    removeListener: function(listener)
+    {
+      var index = notifierListeners.indexOf(listener);
+      if (index >= 0)
+        notifierListeners.splice(index, 1);
+    },
+
+    triggerListeners: function()
+    {
+      var args = Array.prototype.slice.apply(arguments);
+      var listeners = notifierListeners.slice();
+      for (var i = 0; i < listeners.length; i++)
+        listeners[i].apply(null, args);
+    }
+  };
+
+  global.require = function(module)
+  {
+    if (module == "info")
+    {
+      var result = {
+        platform: "gecko",
+        platformVersion: "34.0",
+        application: "firefox",
+        applicationVersion: "34.0"
+      };
+      updateFromURL(result);
+      return result;
+    }
+    else
+      return undefined;
+  }
+
+  global.openOptions = function()
+  {
+    window.open("http://example.com/options.html", "_blank");
+  };
+
+  global.Services = {
+    vc: {
+      compare: function(v1, v2)
+      {
+        return parseFloat(v1) - parseFloat(v2);
+      }
+    }
+  };
+
+  var issues = {seenDataCorruption: false, filterlistsReinitialized: false};
+  updateFromURL(issues);
+  global.seenDataCorruption = issues.seenDataCorruption;
+  global.filterlistsReinitialized = issues.filterlistsReinitialized;
+})(this);
diff --git a/ext/background.js b/ext/background.js
new file mode 100644
index 0000000..f0a7361
--- /dev/null
+++ b/ext/background.js
@@ -0,0 +1,78 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function(global)
+{
+  if (!global.ext)
+    global.ext = {};
+
+  window.addEventListener("load", function()
+  {
+    parent.postMessage({
+      type: "backgroundPageLoaded"
+    }, "*");
+  }, false)
+
+  function PageMap()
+  {
+    this._keys = [];
+    this._values = [];
+  }
+  PageMap.prototype = {
+    keys: function()
+    {
+      return this._keys.map(function(source)
+      {
+        return new global.ext.Page(source);
+      });
+    },
+
+    get: function(page)
+    {
+      return this._values[this._keys.indexOf(page._source)];
+    },
+
+    set: function(page, value)
+    {
+      var index = this._keys.indexOf(page._source);
+      if (index < 0)
+      {
+        index = this._keys.push(page._source) - 1;
+
+        var callback = function()
+        {
+          page._source.removeEventListener("unload", callback, false);
+          this.delete(page);
+        }.bind(this);
+        page._source.addEventListener("unload", callback, false);
+      }
+      this._values[index] = value;
+    },
+
+    delete: function(page)
+    {
+      var index = this._keys.indexOf(page._source);
+      if (index >= 0)
+      {
+        this._keys.splice(index, 1);
+        this._values.splice(index, 1);
+      }
+    }
+  };
+
+  global.ext.PageMap = PageMap;
+})(this);
diff --git a/ext/common.js b/ext/common.js
index 434b476..1104062 100644
--- a/ext/common.js
+++ b/ext/common.js
@@ -17,6 +17,63 @@
 
 (function(global)
 {
+  if (!global.ext)
+    global.ext = {};
+
+  function Page(source)
+  {
+    this._source = source;
+  }
+  Page.prototype =
+  {
+    sendMessage: function(message)
+    {
+      this._source.postMessage({
+        type: "message",
+        messageId: -1,
+        payload: message
+      }, "*");
+    }
+  };
+
+  global.ext.Page = Page;
+
+  /* Message passing */
+
+  global.ext.onMessage =
+  {
+    addListener: function(listener)
+    {
+      listener._extWrapper = function(event)
+      {
+        if (event.data.type != "message")
+          return;
+
+        var message = event.data.payload;
+        var messageId = event.data.messageId;
+        var sender = {
+          page: new Page(event.source)
+        };
+        var callback = function(message)
+        {
+          event.source.postMessage({
+            type: "response",
+            messageId: messageId,
+            payload: message
+          }, "*");
+        };
+        listener(message, sender, callback);
+      };
+      window.addEventListener("message", listener._extWrapper, false);
+    },
+
+    removeListener: function(listener)
+    {
+      if ("_extWrapper" in listener)
+        window.removeEventListener("message", listener._extWrapper, false);
+    }
+  };
+
   /* I18n */
 
   var getLocaleCandidates = function(selectedLocale)
@@ -110,9 +167,6 @@
     }
   };
 
-  if (!global.ext)
-    global.ext = {};
-
   global.ext.i18n = {
     getMessage: function(msgId, substitutions)
     {
diff --git a/ext/content.js b/ext/content.js
index a62f0c5..ad8d0f0 100644
--- a/ext/content.js
+++ b/ext/content.js
@@ -20,135 +20,55 @@
   if (!global.ext)
     global.ext = {};
 
-  function updateFromURL(data)
+  var backgroundFrame = document.createElement("iframe");
+  backgroundFrame.setAttribute("src", "background.html" + window.location.search);
+  backgroundFrame.style.display = "none";
+  window.addEventListener("DOMContentLoaded", function()
   {
-    if (window.location.search)
+    document.body.appendChild(backgroundFrame);
+  }, false);
+
+  var messageQueue = [];
+  var maxMessageId = -1;
+  var loadHandler = function(event)
+  {
+    if (event.data.type == "backgroundPageLoaded")
     {
-      var params = window.location.search.substr(1).split("&");
-      for (var i = 0; i < params.length; i++)
-      {
-        var parts = params[i].split("=", 2);
-        if (parts.length == 2 && parts[0] in data)
-          data[parts[0]] = decodeURIComponent(parts[1]);
-      }
+      var queue = messageQueue;
+      messageQueue = null;
+      if (queue)
+        for (var i = 0; i < queue.length; i++)
+          backgroundFrame.contentWindow.postMessage(queue[i], "*");
+      window.removeEventListener("message", loadHandler, false);
     }
   }
-
-  var subscriptions =[
-    "https://easylist-downloads.adblockplus.org/easylistgermany+easylist.txt",
-    "https://easylist-downloads.adblockplus.org/exceptionrules.txt",
-    "https://easylist-downloads.adblockplus.org/fanboy-social.txt"
-  ];
-
-  var listenerFilter = null;
+  window.addEventListener("message", loadHandler, false);
 
   global.ext.backgroundPage = {
     sendMessage: function(message, responseCallback)
     {
-      var respond = function(response)
-      {
-        setTimeout(responseCallback.bind(responseCallback, response), 0);
+      var rawMessage = {
+        type: "message",
+        messageId: ++maxMessageId,
+        payload: message
       };
+      if (messageQueue)
+        messageQueue.push(rawMessage);
+      else
+        backgroundFrame.contentWindow.postMessage(rawMessage, "*");
 
-      var dispatchListenerNotification = function(action)
+      if (responseCallback)
       {
-        var match = /^subscription\.(.*)/.exec(action);
-        if (match && listenerFilter && listenerFilter.indexOf(match[1]) >= 0)
+        var callbackWrapper = function(event)
         {
-          global.ext.onMessage._dispatch({
-            type: "subscriptions.listen",
-            action: match[1],
-            args: Array.prototype.slice.call(arguments, 1)
-          });
-        }
-      };
-
-      switch (message.type)
-      {
-        case "app.get":
-          if (message.what == "issues")
+          if (event.data.type == "response" && event.data.messageId == rawMessage.messageId)
           {
-            var response = {seenDataCorruption: false, filterlistsReinitialized: false};
-            updateFromURL(response);
-
-            var info = {platform: "gecko", platformVersion: "34.0", application: "firefox", applicationVersion: "34.0"};
-            updateFromURL(info);
-            response.legacySafariVersion = (info.platform == "safari" && (
-              parseInt(info.platformVersion, 10) < 6 ||  // beforeload breaks websites in Safari 5
-              info.platformVersion == "6.1" ||           // extensions are broken in 6.1 and 7.0
-              info.platformVersion == "7.0"));
-
-            respond(response);
+            window.removeEventListener("message", callbackWrapper, false);
+            responseCallback(event.data.payload);
           }
-          else if (message.what == "doclink")
-            respond("https://adblockplus.org/redirect?link=" + encodeURIComponent(message.link));
-          else
-            respond(null);
-          break;
-        case "app.open":
-          if (message.what == "options")
-            window.open("http://example.com/options.html", "_blank");
-          break;
-        case "subscriptions.get":
-          respond(subscriptions);
-          break;
-        case "filters.blocked":
-          var params = {blockedURLs: ""};
-          updateFromURL(params);
-          var blocked = params.blockedURLs.split(",");
-          respond(blocked.indexOf(message.url) >= 0);
-          break;
-        case "subscriptions.toggle":
-          var index = subscriptions.indexOf(message.url);
-          if (index >= 0)
-          {
-            subscriptions.splice(index, 1);
-            dispatchListenerNotification("subscription.removed", message.url);
-          }
-          else
-          {
-            subscriptions.push(message.url);
-            dispatchListenerNotification("subscription.added", message.url);
-          }
-          break;
-        case "subscriptions.listen":
-          listenerFilter = message.filter;
-          break;
-      }
-    }
-  };
-
-  var EventTarget = function(cancelable)
-  {
-    this._listeners = [];
-    this._cancelable = cancelable;
-  };
-  EventTarget.prototype = {
-    addListener: function(listener)
-    {
-      if (this._listeners.indexOf(listener) == -1)
-        this._listeners.push(listener);
-    },
-    removeListener: function(listener)
-    {
-      var idx = this._listeners.indexOf(listener);
-      if (idx != -1)
-        this._listeners.splice(idx, 1);
-    },
-    _dispatch: function()
-    {
-      var result = null;
-
-      for (var i = 0; i < this._listeners.length; i++)
-      {
-        result = this._listeners[i].apply(null, arguments);
-
-        if (this._cancelable && result === false)
-          break;
+        };
+        window.addEventListener("message", callbackWrapper, false);
       }
-
-      return result;
     }
   };
-  global.ext.onMessage = new EventTarget();
 })(this);
diff --git a/firstRun.js b/firstRun.js
index 1819805..fc40eda 100644
--- a/firstRun.js
+++ b/firstRun.js
@@ -256,10 +256,13 @@
       ignoreDisabled: true
     }, function(subscriptions)
     {
+      var known = Object.create(null);
+      for (var i = 0; i < subscriptions.length; i++)
+        known[subscriptions[i].url] = true;
       for (var i = 0; i < featureSubscriptions.length; i++)
       {
         var featureSubscription = featureSubscriptions[i];
-        updateToggleButton(featureSubscription.feature, subscriptions.indexOf(featureSubscription.url) >= 0);
+        updateToggleButton(featureSubscription.feature, featureSubscription.url in known);
       }
     });
   }
diff --git a/messageResponder.js b/messageResponder.js
new file mode 100644
index 0000000..9a4b310
--- /dev/null
+++ b/messageResponder.js
@@ -0,0 +1,160 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus 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 Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function(global)
+{
+  var subscriptionKeys = ["disabled", "homepage", "lastSuccess", "title", "url", "downloadStatus"];
+  function convertSubscription(subscription)
+  {
+    var result = {};
+    for (var i = 0; i < subscriptionKeys.length; i++)
+      result[subscriptionKeys[i]] = subscription[subscriptionKeys[i]]
+    return result;
+  }
+
+  var changeListeners = null;
+  var messageTypes = {
+    "app": "app.listen",
+    "filter": "filters.listen",
+    "subscription": "subscriptions.listen"
+  };
+
+  function onFilterChange(action)
+  {
+    var parts = action.split(".", 2);
+    var type;
+    if (parts.length == 1)
+    {
+      type = "app";
+      action = parts[0];
+    }
+    else
+    {
+      type = parts[0];
+      action = parts[1];
+    }
+
+    if (!messageTypes.hasOwnProperty(type))
+      return;
+
+    var args = Array.prototype.slice.call(arguments, 1).map(function(arg)
+    {
+      if (arg instanceof Subscription)
+        return convertSubscription(arg);
+      else
+        return arg;
+    });
+
+    var pages = changeListeners.keys();
+    for (var i = 0; i < pages.length; i++)
+    {
+      var filters = changeListeners.get(pages[i]);
+      if (filters[type] && filters[type].indexOf(action) >= 0)
+      {
+        pages[i].sendMessage({
+          type: messageTypes[type],
+          action: action,
+          args: args
+        });
+      }
+    }
+  };
+
+  ext.onMessage.addListener(function(message, sender, callback)
+  {
+    switch (message.type)
+    {
+      case "app.get":
+        if (message.what == "issues")
+        {
+          var info = require("info");
+          callback({
+            seenDataCorruption: "seenDataCorruption" in global ? global.seenDataCorruption : false,
+            filterlistsReinitialized: "filterlistsReinitialized" in global ? global.filterlistsReinitialized : false,
+            legacySafariVersion: (info.platform == "safari" && (
+                Services.vc.compare(info.platformVersion, "6.0") < 0 ||   // beforeload breaks websites in Safari 5
+                Services.vc.compare(info.platformVersion, "6.1") == 0 ||  // extensions are broken in 6.1 and 7.0
+                Services.vc.compare(info.platformVersion, "7.0") == 0))
+          });
+        }
+        else if (message.what == "doclink")
+          callback(Utils.getDocLink(message.link));
+        else
+          callback(null);
+        break;
+      case "app.open":
+        if (message.what == "options")
+        {
+          if (typeof UI != "undefined")
+            UI.openFiltersDialog();
+          else
+            global.openOptions();
+        }
+        break;
+      case "subscriptions.get":
+        var subscriptions = FilterStorage.subscriptions.filter(function(s)
+        {
+          if (message.ignoreDisabled && s.disabled)
+            return false;
+          if (s instanceof DownloadableSubscription && message.downloadable)
+            return true;
+          if (s instanceof SpecialSubscription && message.special)
+            return true;
+          return false;
+        });
+        callback(subscriptions.map(convertSubscription));
+        break;
+      case "filters.blocked":
+        var filter = defaultMatcher.matchesAny(message.url, message.requestType, message.docDomain, message.thirdParty);
+        callback(filter instanceof BlockingFilter);
+        break;
+      case "subscriptions.toggle":
+        var subscription = Subscription.fromURL(message.url);
+        if (subscription.url in FilterStorage.knownSubscriptions && !subscription.disabled)
+          FilterStorage.removeSubscription(subscription);
+        else
+        {
+          subscription.disabled = false;
+          subscription.title = message.title;
+          subscription.homepage = message.homepage;
+          FilterStorage.addSubscription(subscription);
+          if (!subscription.lastDownload)
+            Synchronizer.execute(subscription);
+        }
+        break;
+      case "subscriptions.listen":
+        if (!changeListeners)
+        {
+          changeListeners = new global.ext.PageMap();
+          FilterNotifier.addListener(onFilterChange);
+        }
+
+        var filters = changeListeners.get(sender.page);
+        if (!filters)
+        {
+          filters = Object.create(null);
+          changeListeners.set(sender.page, filters);
+        }
+
+        if (message.filter)
+          filters.subscription = message.filter;
+        else
+          delete filters.subscription;
+        break;
+    }
+  });
+})(this);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git



More information about the Pkg-mozext-commits mailing list