[Pkg-mozext-commits] [adblock-plus] 14/87: Issue 2375 - Implement Filter list section in new options page advanced tab

David Prévot taffit at moszumanska.debian.org
Sat Apr 30 17:59:03 UTC 2016


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

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

commit d73d640fd8271096e967f00faab88fa3e11d5cf6
Author: Manvel Saroyan <manvel at adblockplus.org>
Date:   Fri Feb 5 12:31:41 2016 +0100

    Issue 2375 - Implement Filter list section in new options page advanced tab
---
 README.md                 |   2 +
 background.js             |  41 +++++-
 i18n.js                   |  46 +++++--
 locale/en-US/options.json |  90 ++++++++----
 messageResponder.js       |  28 +++-
 options.html              |  81 +++++++----
 options.js                | 289 +++++++++++++++++++++++++++++----------
 skin/options-sprite.png   | Bin 2855 -> 4988 bytes
 skin/options.css          | 340 ++++++++++++++++++++++++++++++++++++----------
 9 files changed, 710 insertions(+), 207 deletions(-)

diff --git a/README.md b/README.md
index 3bd7aa5..1ebbc51 100644
--- a/README.md
+++ b/README.md
@@ -78,3 +78,5 @@ The behavior of this page is affected by a number of URL parameters:
   errors when adding new filters on the options page
 * `blockedURLs`: a comma-separated list of URLs that should be considered
   blocked (necessary to test the check for blocked scripts in sharing buttons).
+* `downloadStatus`: Sets downloadStatus parameter for filter lists, can be used
+  to trigger various filter list download errors
diff --git a/background.js b/background.js
index 3bb096f..acf4a51 100644
--- a/background.js
+++ b/background.js
@@ -36,7 +36,8 @@
     seenDataCorruption: false,
     filterlistsReinitialized: false,
     addSubscription: false,
-    filterError: false
+    filterError: false,
+    downloadStatus: "synchronize_ok"
   };
   updateFromURL(params);
 
@@ -71,7 +72,9 @@
       this.url = url;
       this.title = "Subscription " + url;
       this.disabled = false;
-      this.lastDownload = 1234;
+      this._lastDownload = 1234;
+      this.homepage = "https://easylist.adblockplus.org/";
+      this.downloadStatus = params.downloadStatus;
     },
 
     SpecialSubscription: function(url)
@@ -83,6 +86,9 @@
   };
   modules.subscriptionClasses.Subscription.fromURL = function(url)
   {
+    if (url in knownSubscriptions)
+      return knownSubscriptions[url];
+
     if (/^https?:\/\//.test(url))
       return new modules.subscriptionClasses.Subscription(url);
     else
@@ -90,6 +96,19 @@
   };
   modules.subscriptionClasses.DownloadableSubscription = modules.subscriptionClasses.Subscription;
 
+  modules.subscriptionClasses.Subscription.prototype =
+  {
+    get lastDownload()
+    {
+      return this._lastDownload;
+    },
+    set lastDownload(value)
+    {
+      this._lastDownload = value;
+      modules.filterNotifier.FilterNotifier.triggerListeners("subscription.lastDownload", this);
+    }
+  };
+
   modules.filterStorage = {
     FilterStorage: {
       get subscriptions()
@@ -184,7 +203,23 @@
   };
 
   modules.synchronizer = {
-    Synchronizer: {}
+    Synchronizer: {
+      _downloading: false,
+      execute: function(subscription, manual) 
+      {
+        subscription.lastDownload = 0;
+        modules.synchronizer.Synchronizer._downloading = true;
+        setTimeout(function()
+        {
+          modules.synchronizer.Synchronizer._downloading = false;
+          subscription.lastDownload = Date.now() / 1000;
+        }, 500);
+      },
+      isExecuting: function(url)
+      {
+        return modules.synchronizer.Synchronizer._downloading;
+      }
+    }
   };
 
   modules.matcher = {
diff --git a/i18n.js b/i18n.js
index f5232a4..6db0881 100644
--- a/i18n.js
+++ b/i18n.js
@@ -65,21 +65,30 @@ ext.i18n.setElementText = function(element, stringName, arguments)
 // Loads i18n strings
 function loadI18nStrings()
 {
-  var nodes = document.querySelectorAll("[class^='i18n_']");
-  for(var i = 0; i < nodes.length; i++)
+  function addI18nStringsToElements(containerElement)
   {
-    var node = nodes[i];
-    var arguments = JSON.parse("[" + node.textContent + "]");
-    if (arguments.length == 0)
-      arguments = null;
+    var elements = containerElement.querySelectorAll("[class^='i18n_']");
+    for(var i = 0; i < elements.length; i++)
+    {
+      var node = elements[i];
+      var arguments = JSON.parse("[" + node.textContent + "]");
+      if (arguments.length == 0)
+        arguments = null;
 
-    var className = node.className;
-    if (className instanceof SVGAnimatedString)
-      className = className.animVal;
-    var stringName = className.split(/\s/)[0].substring(5);
+      var className = node.className;
+      if (className instanceof SVGAnimatedString)
+        className = className.animVal;
+      var stringName = className.split(/\s/)[0].substring(5);
 
-    ext.i18n.setElementText(node, stringName, arguments);
+      ext.i18n.setElementText(node, stringName, arguments);
+    }
   }
+  addI18nStringsToElements(document);
+  // Content of Template is not rendered on runtime so we need to add
+  // translation strings for each Template documentFragment content individually 
+  var templates = document.querySelectorAll("template");
+  for (var i = 0; i < templates.length; i++)
+    addI18nStringsToElements(templates[i].content);
 }
 
 // Provides a more readable string of the current date and time
@@ -95,5 +104,20 @@ function i18n_timeDateStrings(when)
     return [timeString, d.toLocaleDateString()];
 }
 
+// Formats date string to ["YYYY-MM-DD", "mm:ss"] format
+function i18n_formatDateTime(when)
+{
+  var date = new Date(when);
+  var dateParts = [date.getFullYear(), date.getMonth() + 1, date.getDate(),
+                  date.getHours(), date.getMinutes()];
+
+  var dateParts = dateParts.map(function(datePart)
+  {
+    return datePart < 10 ? "0" + datePart : datePart;
+  });
+
+  return [dateParts.splice(0, 3).join("-"), dateParts.join(":")];
+}
+
 // Fill in the strings as soon as possible
 window.addEventListener("DOMContentLoaded", loadI18nStrings, true);
diff --git a/locale/en-US/options.json b/locale/en-US/options.json
index 3abf9e6..df15b80 100644
--- a/locale/en-US/options.json
+++ b/locale/en-US/options.json
@@ -76,8 +76,8 @@
     "message": "popular"
   },
   "options_furtherBlocking_add": {
-    "description": "Button name for adding other blocking list in General tab",
-    "message": "add other blocking list"
+    "description": "Button name for adding other filter list in General tab",
+    "message": "add other filter list"
   },
   "options_exceptions_title": {
     "description": "Exceptions section name in General tab",
@@ -136,16 +136,16 @@
     "message": "cancel"
   },
   "options_tweaks_title": {
-    "description": "Tweaks section name in Advanced tab",
+    "description": "Section title in Advanced tab",
     "message": "Tweaks"
   },
   "options_tweaks_blockElement": {
     "description": "Show block Element option in Advanced tab",
     "message": "Show <a>Block Element</a> right-click menu item"
   },
-  "options_blockingList_title": {
-    "description": "Blocking list section title in Advanced tab",
-    "message": "Blocking list"
+  "options_filterList_title": {
+    "description": "Section title in Advanced tab",
+    "message": "Filter lists"
   },
   "options_tab_overview": {
     "description": "Tab name in Advanced tab",
@@ -153,32 +153,72 @@
   },
   "options_tab_ownList": {
     "description": "Tab name in Advanced tab",
-    "message": "Edit or create own blocking list"
+    "message": "Edit or create own filter list"
   },
-  "options_tableCol_name": {
+  "options_column_name": {
     "description": "Name of column of subscription list table in Advanced tab",
     "message": "Name"
   },
-  "options_tableCol_description": {
+  "options_column_date": {
     "description": "Name of column of subscription list table in Advanced tab",
-    "message": "Description"
+    "message": "Last update"
   },
-  "options_tableCol_date": {
-    "description": "Name of column of subscription list table in Advanced tab",
-    "message": "Date"
-  },
-  "options_blockingList_add": {
+  "options_filterList_add": {
     "description": "Import button in Advanced tab",
-    "message": "add/import other blocking list"
+    "message": "add/import other filter list"
   },
-  "options_blockingList_update": {
+  "options_filterList_update": {
     "description": "Update button in Advanced tab",
-    "message": "Update all blocking lists"
+    "message": "update all filter lists"
   },
   "options_customFilters_empty": {
     "description": "Text shown when list of custom filters is empty",
     "message": "There are no custom filters."
   },
+  "options_filterList_lastDownload_invalidURL": {
+    "description": "Error message in advanced tab",
+    "message": "Failed, not a valid address"
+  },
+  "options_filterList_lastDownload_connectionError": {
+    "description": "Error message in advanced tab",
+    "message": "Failed, download failure"
+  },
+  "options_filterList_lastDownload_invalidData": {
+    "description": "Error message in advanced tab",
+    "message": "Failed, not a valid filter list"
+  },
+  "options_filterList_lastDownload_checksumMismatch": {
+    "description": "Error message in advanced tab",
+    "message": "Failed, checksum mismatch"
+  },
+  "options_filterList_lastDownload_inProgress": {
+    "description": "Progress message in advanced tab",
+    "message": "Downloading…"
+  },
+  "options_filterList_updateNow": {
+    "description": "Context menu item in advanced tab, appears after click on subscription",
+    "message": "update now"
+  },
+  "options_filterList_website": {
+    "description": "Context menu item in advanced tab, appears after click on subscription",
+    "message": "website"
+  },
+  "options_filterList_source": {
+    "description": "Context menu item in advanced tab, appears after click on subscription",
+    "message": "source"
+  },
+  "options_filterList_delete": {
+    "description": "Context menu item in advanced tab, appears after click on subscription",
+    "message": "delete"
+  },
+  "options_filterList_own_list": {
+    "description": "Name of custom subscription entry in filter list section in Advanced tab",
+    "message": "Own filter list"
+  },
+  "options_filterList_edit_own_list": {
+    "description": "Entry in filter list section in Advanced tab",
+    "message": "edit your filter list"
+  },
   "options_customFilters_title": {
     "description": "Custom filters option name in Advanced tab",
     "message": "Blocking rules"
@@ -205,7 +245,7 @@
   },
   "options_faq_description": {
     "description": "FAQ section description in Help tab",
-    "message": "You only need to refresh your blocking list in \"Advanced\" very often, but there are also other known problems."
+    "message": "You only need to refresh your filter list in \"Advanced\" very often, but there are also other known problems."
   },
   "options_forum_title": {
     "description": "Forum section name in Help tab",
@@ -229,15 +269,15 @@
   },
   "options_dialog_predefined_confirm": {
     "description": "Confirming to add a predefined subscription when asked in a dialog",
-    "message": "Yes, use this blocking list"
+    "message": "Yes, use this filter list"
   },
   "options_dialog_predefined_title": {
     "description": "Dialog title for adding a predefined subscription",
-    "message": "Do you really want to use this blocking list?"
+    "message": "Do you really want to use this filter list?"
   },
   "options_dialog_custom_title": {
     "description": "Title of custom subscription modal dialog",
-    "message": "Add other blocking list"
+    "message": "Add other filter list"
   },
   "options_close": {
     "description": "Close modal button",
@@ -249,11 +289,11 @@
   },
   "options_dialog_custom_import": {
     "description": "Button in add custom subscription modal dialog",
-    "message": "import blocking list with this URL"
+    "message": "import filter list with this URL"
   },
   "options_dialog_edit_own_list": {
-    "description": "Edit own blocking list section name in custom subscription modal dialog",
-    "message": "edit own blocking list"
+    "description": "Edit own filter list section name in custom subscription modal dialog",
+    "message": "edit own filter list"
   },
   "options_dialog_create_own_list": {
     "description": "Button in custom subscription modal dialog",
diff --git a/messageResponder.js b/messageResponder.js
index 90f2c9a..0708fcd 100644
--- a/messageResponder.js
+++ b/messageResponder.js
@@ -47,7 +47,7 @@
   }
 
   var convertSubscription = convertObject.bind(null, ["disabled",
-    "downloadStatus", "homepage", "lastSuccess", "title", "url"]);
+    "downloadStatus", "homepage", "lastDownload", "title", "url"]);
   var convertFilter = convertObject.bind(null, ["text"]);
 
   var changeListeners = null;
@@ -333,8 +333,17 @@
         break;
       case "subscriptions.toggle":
         var subscription = Subscription.fromURL(message.url);
-        if (subscription.url in FilterStorage.knownSubscriptions && !subscription.disabled)
-          FilterStorage.removeSubscription(subscription);
+        if (subscription.url in FilterStorage.knownSubscriptions)
+        {
+          if (subscription.disabled || message.keepInstalled)
+          {
+            subscription.disabled = !subscription.disabled;
+            FilterNotifier.triggerListeners("subscription.disabled",
+                                            subscription);
+          }
+          else
+            FilterStorage.removeSubscription(subscription);
+        }
         else
         {
           subscription.disabled = false;
@@ -345,6 +354,19 @@
             Synchronizer.execute(subscription);
         }
         break;
+      case "subscriptions.update":
+        var subscriptions = message.url ? [Subscription.fromURL(message.url)] : 
+                            FilterStorage.subscriptions;
+        for (var i = 0; i < subscriptions.length; i++)
+        {
+          var subscription = subscriptions[i];
+          if (subscription instanceof DownloadableSubscription)
+            Synchronizer.execute(subscription, true);
+        }
+        break;
+      case "subscriptions.isDownloading":
+        callback(Synchronizer.isExecuting(message.url));
+        break;
     }
   });
 })(this);
diff --git a/options.html b/options.html
index a5e8695..9aca46c 100644
--- a/options.html
+++ b/options.html
@@ -43,7 +43,7 @@
               <a class="i18n_options_tab_general"></a>
               <span class="icon"></span>
             </li>
-            <li id="tab-advanced" data-action="switch-tab" data-tab="advanced">
+            <li id="tab-advanced" data-action="switch-tab" data-tab="advanced-allFilterLists">
               <a class="i18n_options_tab_advanced"></a>
               <span class="icon"></span>
             </li>
@@ -124,7 +124,7 @@
                     <template>
                       <button role="checkbox" class="control"></button>
                       <span class="display"></span>
-                      <span class="popular"></span>
+                      <span class="i18n_options_popular popular"></span>
                     </template>
                   </ul>
                   <ul id="custom-list-table" class="table list">
@@ -213,8 +213,11 @@
         <!-- Advanced tab content -->
         <div id="content-advanced" class="tab-content">
           <div>
-            <h1><span class="i18n_options_tweaks_title"></span><a class="i18n_options_readMore tooltip" href="#"></a></h1>
-            <ul class="table" style="width: auto;">
+            <h1>
+              <span class="i18n_options_tweaks_title"></span>
+              <a class="i18n_options_readMore tooltip"></a>
+            </h1>
+            <ul class="table">
               <li>
                 <button role="checkbox" id="easylist"></button>
                 <span id="block-element-explanation" class="i18n_options_tweaks_blockElement"></span>
@@ -222,31 +225,63 @@
             </ul>
           </div>
           <div>
-            <h1><span class="i18n_options_blockingList_title"></span><a class="i18n_options_readMore tooltip" href="#" target="_blank"></a></h1>
-            <ul id="blocking-list-tabs" class="tabs horizontal">
-              <li class="i18n_options_tab_overview active" data-show="blocking-list-overview"></li><li class="i18n_options_tab_ownList" data-show="custom-filters"></li>
+            <h1>
+              <span class="i18n_options_filterList_title"></span>
+              <a class="i18n_options_readMore tooltip"></a>
+            </h1>
+            <ul class="tabs horizontal">
+              <li class="i18n_options_tab_overview active" data-action="switch-tab" data-tab="advanced-allFilterLists"></li>
+              <li class="i18n_options_tab_ownList" data-action="switch-tab" data-tab="advanced-customFilters"></li>
             </ul>
-            <div id="blocking-list">
-              <div id="blocking-list-overview">
-                <ul class="table cols" style="width: auto;">
-                  <li class="col-name"><span class="i18n_options_tableCol_name"></span><span class="i18n_options_tableCol_description"></span><span class="i18n_options_tableCol_date"></span></li>
-                  <li><input type="checkbox" id="easylist"/><span>Easylist</span><span>Adblocking english sites</span><span>15 March 14 - 10:31</span></li>
-                  <li><input type="checkbox" id="easylist+de"/><span>Easylist Germany + Easylist</span><span>Adblocking english + german sites</span><span>15 March 14 - 10:31</span></li>
-                  <li><input type="checkbox" id="annoyance-fb"/><span>Facebook annoyance blocker</span><span>Blocks Facebook annoyances</span><span>15 March 14 - 10:31</span></li>
-                  <li><input type="checkbox" id="annoyance-youtube"/><span>Facebook annoyance blocker</span><span>Blocks Facebook annoyances</span><span>15 March 14 - 10:31</span></li>
-                  <li><input type="checkbox" id="own-list"/><span>Own blocking list</span><span>Your own blocking list</span><span><a href="#">edit your blocking list</a></span></li>
+            <div id="filter-lists">
+              <div id="all-filter-lists">
+                <div class="table-header">
+                  <h3 class="i18n_options_column_name"></h3>
+                  <h3 class="i18n_options_column_date"></h3>
+                </div>
+                <ul class="table cols" id="all-filter-lists-table">
+                  <template>
+                    <button role="checkbox" class="control"></button>
+                    <div>
+                      <span data-action="open-context-menu" class="display"></span>
+                      <div data-action="open-context-menu" class="arrow">
+                        <div class="context-menu">
+                          <div class="content">
+                            <a class="i18n_options_filterList_updateNow update-subscription" data-action="update-subscription"></a>
+                            <a class="i18n_options_filterList_website website" target="_blank"></a>
+                            <a class="i18n_options_filterList_source source" target="_blank"></a>
+                            <a class="i18n_options_filterList_delete delete" data-action="remove-subscription"></a>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <span class="date"></span>
+                    <span class="time"></span>
+                    <span class="message"></span>
+                  </template>
+                  <li class="static">
+                    <button role="checkbox" class="control" aria-checked="true" disabled="true"></button>
+                    <div>
+                      <span class="i18n_options_filterList_own_list"></span>
+                    </div>
+                    <span data-action="switch-tab,edit-custom-filters" data-tab="advanced-customFilters">
+                      <a class="i18n_options_filterList_edit_own_list"></a>
+                    </span>
+                  </li>
                 </ul>
                 <div class="controls">
-                  <button>
-                    <span class="icon icon-add"></span><span class="i18n_options_blockingList_add"></span>
+                  <button data-action="open-dialog" data-dialog="custom">
+                    <span class="icon icon-add"></span>
+                    <span class="i18n_options_filterList_add"></span>
                   </button>
-                  <button>
-                    <span class="icon icon-update"></span><span class="i18n_options_blockingList_update"></span>
+                  <button data-action="update-all-subscriptions">
+                    <span class="icon icon-update"></span>
+                    <span class="i18n_options_filterList_update"></span>
                   </button>
                 </div>
               </div>
               <div id="custom-filters">
-                <h2 id="custom-filters-header" class="i18n_options_customFilters_title"></h2>
+                <h3 id="custom-filters-header" class="i18n_options_customFilters_title"></h3>
                 <div id="custom-filters-wrapper">
                   <div id="custom-filters-list-wrapper">
                     <ul id="custom-filters-table" class="table list">
@@ -334,7 +369,7 @@
             <ul id="all-lang-table" class="table list">
               <template>
                 <button class="button-add control">
-                  +<span></span>
+                  +<span class="i18n_options_button_add"></span>
                 </button>
                 <span class="display"></span>
               </template>
@@ -352,7 +387,7 @@
           </div>
           <div class="dialog-content-block">
             <h3 class="i18n_options_dialog_edit_own_list"></h3>
-            <button class="i18n_options_dialog_create_own_list" data-action="close-dialog,switch-tab,edit-custom-filters" data-tab="advanced"></button>
+            <button class="i18n_options_dialog_create_own_list" data-action="close-dialog,switch-tab,edit-custom-filters" data-tab="advanced-customFilters"></button>
           </div>
         </div>
         <!-- Add predefined subscription -->
diff --git a/options.js b/options.js
index 300c724..53000f3 100644
--- a/options.js
+++ b/options.js
@@ -24,6 +24,14 @@
   var filtersMap = Object.create(null);
   var collections = Object.create(null);
   var maxLabelId = 0;
+  var getMessage = ext.i18n.getMessage;
+  var filterErrors =
+  {
+    "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL",
+    "synchronize_connection_error": "options_filterList_lastDownload_connectionError",
+    "synchronize_invalid_data": "options_filterList_lastDownload_invalidData",
+    "synchronize_checksum_mismatch": "options_filterList_lastDownload_checksumMismatch"
+  };
 
   function Collection(details)
   {
@@ -38,13 +46,22 @@
     {
       placeholder = document.createElement("li");
       placeholder.className = "empty-placeholder";
-      placeholder.textContent = ext.i18n.getMessage(text);
+      placeholder.textContent = getMessage(text);
       table.appendChild(placeholder);
     }
     else if (placeholder)
       table.removeChild(placeholder);
   }
 
+  Collection.prototype._createElementQuery = function(item)
+  {
+    var access = (item.url || item.text).replace(/'/g, "\\'");
+    return function(container)
+    {
+      return container.querySelector("[data-access='" + access + "']");
+    };
+  };
+
   Collection.prototype.addItems = function() 
   {
     var length = Array.prototype.push.apply(this.items, arguments);
@@ -82,7 +99,10 @@
 
         this._setEmpty(table, null);
         if (table.hasChildNodes())
-          table.insertBefore(listItem, table.childNodes[this.items.indexOf(item)]);
+        {
+          table.insertBefore(listItem, 
+              table.childNodes[this.items.indexOf(item)]);
+        }
         else
           table.appendChild(listItem);
         this.updateItem(item);
@@ -98,10 +118,11 @@
       return;
 
     this.items.splice(index, 1);
+    var getListElement = this._createElementQuery(item);
     for (var i = 0; i < this.details.length; i++)
     {
       var table = E(this.details[i].id);
-      var element = table.childNodes[index];
+      var element = getListElement(table);
 
       // Element gets removed so make sure to handle focus appropriately
       var control = element.querySelector(".control");
@@ -139,13 +160,56 @@
       if (!element)
         continue;
 
-      var text = item.title || item.url || item.text;
-      element.querySelector(".display").textContent = text;
-      if (text)
-        element.setAttribute("data-search", text.toLowerCase());
+      var title = item.title || item.url || item.text;
+      element.querySelector(".display").textContent = title;
+      if (title)
+        element.setAttribute("data-search", title.toLowerCase());
       var control = element.querySelector(".control[role='checkbox']");
       if (control)
         control.setAttribute("aria-checked", item.disabled == false);
+
+      var downloadStatus = item.downloadStatus;
+      var dateElement = element.querySelector(".date");
+      var timeElement = element.querySelector(".time");
+      if(dateElement && timeElement)
+      {
+        var message = element.querySelector(".message");
+        ext.backgroundPage.sendMessage(
+        {
+          type: "subscriptions.isDownloading",
+          url: item.url
+        },
+        function(isDownloading)
+        {
+          if (isDownloading)
+          {
+            var text = getMessage("options_filterList_lastDownload_inProgress");
+            message.textContent = text;
+            element.classList.add("show-message");
+          }
+          else if (downloadStatus && downloadStatus != "synchronize_ok")
+          {
+            if (downloadStatus in filterErrors)
+              message.textContent = getMessage(filterErrors[downloadStatus]);
+            else
+              message.textContent = item.downloadStatus;
+            element.classList.add("show-message");
+          }
+          else if (item.lastDownload > 0)
+          {
+            var dateTime = i18n_formatDateTime(item.lastDownload * 1000);
+            dateElement.textContent = dateTime[0];
+            timeElement.textContent = dateTime[1];
+            element.classList.remove("show-message");
+          }
+        });
+      }
+      var websiteElement = element.querySelector(".context-menu .website");
+      var sourceElement = element.querySelector(".context-menu .source");
+      if (websiteElement && item.homepage)
+        websiteElement.setAttribute("href", item.homepage);
+      if (sourceElement)
+        sourceElement.setAttribute("href", item.url);
     }
   };
 
@@ -155,9 +219,14 @@
     for (var i = 0; i < this.details.length; i++)
     {
       var table = E(this.details[i].id);
-      var template = table.querySelector("template");
-      table.innerHTML = "";
-      table.appendChild(template);
+      var element = table.firstChild;
+      while (element)
+      {
+        if (element.tagName == "LI" && !element.classList.contains("static"))
+          table.removeChild(element);
+        element = element.nextElementSibling;
+      }
+
       this._setEmpty(table, this.details[i].emptyText);
     }
   };
@@ -177,12 +246,11 @@
     return true;
   }
 
-  function onToggleSubscriptionClick(e)
+  function toggleRemoveSubscription(e)
   {
     e.preventDefault();
-    var checkbox = e.target;
-    var subscriptionUrl = checkbox.parentElement.getAttribute("data-access");
-    if (checkbox.getAttribute("aria-checked") == "true")
+    var subscriptionUrl = findParentData(e.target, "access", false);
+    if (e.target.getAttribute("aria-checked") == "true")
     {
       ext.backgroundPage.sendMessage({
         type: "subscriptions.remove",
@@ -193,16 +261,28 @@
       addEnableSubscription(subscriptionUrl);
   }
 
+  function toggleDisableSubscription(e)
+  {
+    e.preventDefault();
+    var subscriptionUrl = findParentData(e.target, "access", false);
+    ext.backgroundPage.sendMessage(
+    {
+      type: "subscriptions.toggle",
+      keepInstalled: true,
+      url: subscriptionUrl
+    });
+  }
+
   function onAddLanguageSubscriptionClick(e)
   {
     e.preventDefault();
-    var url = this.parentNode.getAttribute("data-access");
+    var url = findParentData(this, "access", false);
     addEnableSubscription(url);
   }
 
   function onRemoveFilterClick()
   {
-    var filter = this.parentNode.getAttribute("data-access");
+    var filter = findParentData(this, "access", false);
     ext.backgroundPage.sendMessage(
     {
       type: "filters.remove",
@@ -214,7 +294,7 @@
   [
     {
       id: "recommend-list-table",
-      onClick: onToggleSubscriptionClick
+      onClick: toggleRemoveSubscription
     }
   ]);
   collections.langs = new Collection(
@@ -222,7 +302,7 @@
     {
       id: "blocking-languages-table",
       emptyText: "options_dialog_language_added_empty",
-      onClick: onToggleSubscriptionClick
+      onClick: toggleRemoveSubscription
     },
     {
       id: "blocking-languages-dialog-table",
@@ -241,14 +321,14 @@
   [
     {
       id: "acceptableads-table",
-      onClick: onToggleSubscriptionClick
+      onClick: toggleRemoveSubscription
     }
   ]);
   collections.custom = new Collection(
   [
     {
       id: "custom-list-table",
-      onClick: onToggleSubscriptionClick
+      onClick: toggleRemoveSubscription
     }
   ]);
   collections.whitelist = new Collection(
@@ -266,23 +346,23 @@
       emptyText: "options_customFilters_empty"
     }
   ]);
+  collections.filterLists = new Collection(
+  [
+    {
+      id: "all-filter-lists-table",
+      onClick: toggleDisableSubscription
+    }
+  ]);
 
-  function updateSubscription(subscription)
+  function observeSubscription(subscription)
   {
-    var subscriptionUrl = subscription.url;
-    var knownSubscription = subscriptionsMap[subscriptionUrl];
-    if (knownSubscription)
-      knownSubscription.disabled = subscription.disabled;
-    else
+    function onObjectChanged(change)
     {
-      getAcceptableAdsURL(function(acceptableAdsUrl)
+      for (var i = 0; i < change.length; i++)
       {
-        function onObjectChanged()
+        if (change[i].name == "disabled")
         {
-          for (var i in collections)
-            collections[i].updateItem(subscription);
-
-          var recommendation = recommendationsMap[subscriptionUrl];
+          var recommendation = recommendationsMap[subscription.url];
           if (recommendation && recommendation.type == "ads")
           {
             if (subscription.disabled == false)
@@ -297,33 +377,57 @@
             }
           }
         }
+        for (var i in collections)
+          collections[i].updateItem(subscription);
+      }
+    }
 
-        if (!Object.observe)
+    if (!Object.observe)
+    {
+      ["disabled", "lastDownload"].forEach(function(property)
+      {
+        subscription["$" + property] = subscription[property];
+        Object.defineProperty(subscription, property,
         {
-          // Currently only "disabled" property of subscription used for observation
-          // but with Advanced tab implementation we should also add more properties.
-          ["disabled"].forEach(function(property)
+          get: function()
           {
-            subscription["$" + property] = subscription[property];
-            Object.defineProperty(subscription, property,
+            return this["$" + property];
+          },
+          set: function(newValue)
+          {
+            var oldValue = this["$" + property];
+            if (oldValue != newValue)
             {
-              get: function()
-              {
-                return this["$" + property];
-              },
-              set: function(value)
-              {
-                this["$" + property] = value;
-                onObjectChanged();
-              }
-            });
-          });
-        }
-        else
-        {
-          Object.observe(subscription, onObjectChanged);
-        }
+              this["$" + property] = newValue;
+              var change = Object.create(null);
+              change.name = property;
+              onObjectChanged([change]);
+            }
+          }
+        });
+      });
+    }
+    else
+    {
+      Object.observe(subscription, onObjectChanged);
+    }
+  }
 
+  function updateSubscription(subscription)
+  {
+    var subscriptionUrl = subscription.url;
+    var knownSubscription = subscriptionsMap[subscriptionUrl];
+    if (knownSubscription)
+    {
+      for (var property in subscription)
+        if (property != "title")
+          knownSubscription[property] = subscription[property];
+    }
+    else
+    {
+      observeSubscription(subscription);
+      getAcceptableAdsURL(function(acceptableAdsUrl)
+      {
         var collection = null;
         if (subscriptionUrl in recommendationsMap)
         {
@@ -381,19 +485,18 @@
           subscription.disabled = null;
           subscription.downloadStatus = null;
           subscription.homepage = null;
-          subscription.lastSuccess = null;
           var recommendation = Object.create(null);
           recommendation.type = element.getAttribute("type");
           var prefix = element.getAttribute("prefixes");
           if (prefix)
           {
             prefix = prefix.replace(/\W/g, "_");
-            subscription.title = ext.i18n.getMessage("options_language_" + prefix);
+            subscription.title = getMessage("options_language_" + prefix);
           }
           else
           {
             var type = recommendation.type.replace(/\W/g, "_");
-            subscription.title = ext.i18n.getMessage("common_feature_" + type + "_title");
+            subscription.title = getMessage("common_feature_" + type + "_title");
           }
 
           recommendationsMap[subscription.url] = recommendation;
@@ -402,8 +505,24 @@
       });
   }
 
+  function findParentData(element, dataName, returnElement)
+  {
+    while (element)
+    {
+      if (element.hasAttribute("data-" + dataName))
+        return returnElement ? element : element.getAttribute("data-" + dataName);
+
+      element = element.parentElement;
+    }
+    return null;
+  }
+
   function onClick(e)
   {
+    var context = document.querySelector(".show-context-menu");
+    if (context)
+      context.classList.remove("show-context-menu");
+
     var element = e.target;
     while (true)
     {
@@ -469,21 +588,38 @@
           document.body.setAttribute("data-tab",
             element.getAttribute("data-tab"));
           break;
+        case "update-all-subscriptions":
+          ext.backgroundPage.sendMessage(
+          {
+            type: "subscriptions.update"
+          });
+          break;
+        case "open-context-menu":
+          var listItem = findParentData(element, "access", true);
+          if (listItem != context)
+            listItem.classList.add("show-context-menu");
+          break;
+        case "update-subscription":
+          ext.backgroundPage.sendMessage(
+          {
+            type: "subscriptions.update",
+            url: findParentData(element, "access", false)
+          });
+          break;
+        case "remove-subscription":
+          ext.backgroundPage.sendMessage(
+          {
+            type: "subscriptions.remove",
+            url: findParentData(element, "access", false)
+          });
+          break;
       }
     }
   }
 
   function onDOMLoaded()
   {
-    var recommendationTemplate = document.querySelector("#recommend-list-table template");
-    var popularText = ext.i18n.getMessage("options_popular");
-    recommendationTemplate.content.querySelector(".popular").textContent = popularText;
-    var languagesTemplate = document.querySelector("#all-lang-table template");
-    var buttonText = ext.i18n.getMessage("options_button_add");
-    languagesTemplate.content.querySelector(".button-add span").textContent = buttonText;
-
     populateLists();
-
     function onFindLanguageKeyUp()
     {
       var searchStyle = E("search-style");
@@ -530,7 +666,7 @@
 
     // Initialize interactive UI elements
     document.body.addEventListener("click", onClick, false);
-    var placeholderValue  = ext.i18n.getMessage("options_dialog_language_find");
+    var placeholderValue  = getMessage("options_dialog_language_find");
     E("find-language").setAttribute("placeholder", placeholderValue);
     E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
     E("whitelisting-textbox").addEventListener("keypress", function(e)
@@ -541,7 +677,7 @@
 
     // Advanced tab
     var filterTextbox = document.querySelector("#custom-filters-add input");
-    placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeholder");
+    placeholderValue = getMessage("options_customFilters_textbox_placeholder");
     filterTextbox.setAttribute("placeholder", placeholderValue);
     function addCustomFilters()
     {
@@ -649,7 +785,7 @@
       var subscription = Object.create(null);
       subscription.url = acceptableAdsUrl;
       subscription.disabled = true;
-      subscription.title = ext.i18n.getMessage("options_acceptableAds_description");
+      subscription.title = getMessage("options_acceptableAds_description");
       updateSubscription(subscription);
 
       // Load user subscriptions
@@ -755,14 +891,27 @@
     switch (action)
     {
       case "added":
+        updateSubscription(subscription);
+        updateShareLink();
+
+        var knownSubscription = subscriptionsMap[subscription.url];
+        if (knownSubscription)
+          collections.filterLists.addItems(knownSubscription);
+        else
+          collections.filterLists.addItems(subscription);
+        break;
       case "disabled":
         updateSubscription(subscription);
         updateShareLink();
         break;
+      case "lastDownload":
+        updateSubscription(subscription);
+        break;
       case "homepage":
         // TODO: NYI
         break;
       case "removed":
+        var knownSubscription = subscriptionsMap[subscription.url];
         getAcceptableAdsURL(function(acceptableAdsUrl)
         {
           if (subscription.url == acceptableAdsUrl)
@@ -772,7 +921,6 @@
           }
           else
           {
-            var knownSubscription = subscriptionsMap[subscription.url];
             if (subscription.url in recommendationsMap)
               knownSubscription.disabled = true;
             else
@@ -782,6 +930,7 @@
             }
           }
           updateShareLink();
+          collections.filterLists.removeItem(knownSubscription);
         });
         break;
       case "title":
@@ -871,7 +1020,7 @@
   ext.backgroundPage.sendMessage(
   {
     type: "subscriptions.listen",
-    filter: ["added", "disabled", "homepage", "removed", "title"]
+    filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title"]
   });
 
   window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
diff --git a/skin/options-sprite.png b/skin/options-sprite.png
index 535e418..3d6ef68 100755
Binary files a/skin/options-sprite.png and b/skin/options-sprite.png differ
diff --git a/skin/options.css b/skin/options.css
index a667cf0..273c481 100644
--- a/skin/options.css
+++ b/skin/options.css
@@ -202,9 +202,9 @@ button[role="checkbox"][aria-checked="true"]
   padding: 14px 20px;
 }
 
-body[data-tab="general"] #tab-general,
-body[data-tab="advanced"] #tab-advanced,
-body[data-tab="help"] #tab-help
+body[data-tab|="general"] #tab-general,
+body[data-tab|="advanced"] #tab-advanced,
+body[data-tab|="help"] #tab-help
 {
   background-color: #FFFFFF;
   border-radius: 3px 0px 0px 3px;
@@ -222,9 +222,9 @@ body[data-tab="help"] #tab-help
   -webkit-padding-start: 21px;
 }
 
-html[dir="rtl"] body[data-tab="general"] #tab-general,
-html[dir="rtl"] body[data-tab="advanced"] #tab-advanced,
-html[dir="rtl"] body[data-tab="help"] #tab-help
+html[dir="rtl"] body[data-tab|="general"] #tab-general,
+html[dir="rtl"] body[data-tab|="advanced"] #tab-advanced,
+html[dir="rtl"] body[data-tab|="help"] #tab-help
 {
   border-radius: 0px 3px 3px 0px;
 }
@@ -329,9 +329,9 @@ html[dir="rtl"] body[data-tab="help"] #tab-help
   display: none;
 }
 
-body[data-tab="general"] #content-general,
-body[data-tab="advanced"] #content-advanced,
-body[data-tab="help"] #content-help
+body[data-tab|="general"] #content-general,
+body[data-tab|="advanced"] #content-advanced,
+body[data-tab|="help"] #content-help
 {
   display: block;
 }
@@ -368,8 +368,8 @@ div.button
   white-space: nowrap;
 }
 
-.table.list li:nth-child(odd),
-.table.cols li:nth-child(even),
+.table.list li:nth-of-type(odd),
+.table.cols li:nth-of-type(odd),
 .table li.empty-placeholder
 {
   background-color: #F5F5F5;
@@ -380,55 +380,16 @@ div.button
   vertical-align: top;
 }
 
-.table.cols span
-{
-  display: inline-block;
-  width: 30%;
-}
-
-.table.cols .col-name
+.table.cols
 {
   border-bottom: 1px solid #CDCDCD;
+  border-top: 1px solid #CDCDCD;
 }
 
-.table.cols .col-name span
-{
-  display: inline-block;
-  width: 30%;
-}
-
-.table.cols .col-name span:first-child
-{
-  -webkit-padding-start: 38px;
-  -moz-padding-start: 38px;
-}
-
-.table input[type="checkbox"]
-{
-  margin-top: 0px;
-  -moz-margin-end: 20px;
-  -webkit-margin-end: 20px;
-  padding: 0px 0px 0px 0px;
-  visibility: hidden;
-}
-
-.table input[type="checkbox"]::before
-{
-  content: "";
-  background-position: -51px 0px;
-  height: 18px;
-  width: 18px;
-  visibility: visible;
-}
-
-.table input[type="checkbox"]:checked::before
+button[disabled="true"]
 {
-  content: "";
-  background-position: -68px 0px;
-  height: 18px;
-  padding: 0px;
-  width: 18px;
-  visibility: visible;
+  border-radius: 2px;
+  background-color: #ccc;
 }
 
 .table button.delete
@@ -455,32 +416,31 @@ div.button
 
 .tabs.horizontal
 {
+  display: flex;
   margin-bottom: 0px;
   padding: 0px;
 }
 
 .tabs.horizontal li
 {
-  border-bottom: 1px solid #A1A1A1;
   display: inline-block;
+  border-bottom: 1px solid #A1A1A1;
+  padding: 10px 46px;
   color: #3A7BA6;
-  padding: 10px 0px 11px 0px;
   text-align: center;
-  width: 50%;
-}
-
-.tabs.horizontal li.active
-{
-  border-bottom: 2px solid #1E8728;
-  color: black;
-  font-weight: 600;
-  padding-bottom: 10px;
 }
 
-.icon, .table button[role="checkbox"], .table button.delete,
-#content-help a::before, #dialog-close::before,
+.icon,
+button[role="checkbox"],
+.table button.delete,
+#content-help a::before,
+#dialog-close::before,
 #custom-filters-add button::after,
-#dialog-body button::before
+#dialog-body button::before,
+.date::before,
+.time::before,
+#all-filter-lists .arrow,
+.context-menu .content a::before
 {
   background-image: url(options-sprite.png);
   display: inline-block;
@@ -624,7 +584,7 @@ div.button
 
 .icon-enter
 {
-  background-position: -18px -85px;
+  background-position: -18px -32px;
   cursor: pointer;
   height: 10px;
   position: absolute;
@@ -646,6 +606,138 @@ div.button
   Advanced tab content
 */
 
+#filter-lists > div
+{
+  display: none;
+}
+
+body[data-tab="advanced-allFilterLists"] #all-filter-lists,
+body[data-tab="advanced-customFilters"] #custom-filters
+{
+  display: block;
+}
+
+body[data-tab="advanced-allFilterLists"] #content-advanced [data-tab="advanced-allFilterLists"],
+body[data-tab="advanced-customFilters"] #content-advanced [data-tab="advanced-customFilters"]
+{
+  border-bottom: 2px solid #1E8728;
+  padding-bottom: 10px;
+  color: black;
+  font-weight: 600;
+}
+
+#all-filter-lists .table
+{
+  display: inline-block;
+}
+
+#all-filter-lists .table li
+{
+  padding-left: 16px;
+  padding-right: 16px;
+}
+
+#all-filter-lists .table li > div
+{
+  display: flex;
+  width: 330px;
+}
+
+.table-header
+{
+  display: flex;
+}
+    
+#filter-lists h3
+{
+  display: inline-block;
+  margin-bottom: 7px;
+  font-size: 14px;
+}
+
+.table-header h3:first-child
+{
+  width: 330px;
+  -webkit-padding-start: 54px;
+  -moz-padding-start: 54px;
+}
+
+#all-filter-lists .table li span.display
+{
+  cursor: pointer;
+}
+
+#all-filter-lists .table .head span:first-child
+{
+  -webkit-padding-start: 38px;
+  -moz-padding-start: 38px;
+}
+
+#all-filter-lists .controls
+{
+  padding-top: 0px;
+  border-top: none;
+}
+
+#all-filter-lists .controls button
+{
+  margin-top: 14px;
+}
+
+#all-filter-lists .arrow
+{
+  position: relative;
+  margin: auto 6px;
+  border-style: none;
+  padding: 0px;
+  width: 6px;
+  height: 4px;
+  background-position: -1px -54px;
+  cursor: pointer;
+}
+
+#all-filter-lists .table li:last-of-type a
+{
+  color: #3A7BA6;
+  text-decoration: none;
+  cursor: pointer;
+}
+
+#all-filter-lists .table li:last-of-type > span:last-child
+{
+  -webkit-margin-start: auto;
+  -moz-margin-start: auto;
+}
+
+#all-filter-lists li.show-message .date,
+#all-filter-lists li.show-message .time,
+#all-filter-lists li:not(.show-message) .message
+{
+  display: none;
+}
+
+.date::before
+{
+  content: "";
+  -webkit-margin-end: 6px;
+  -moz-margin-end: 6px;
+  height: 12px;
+  width: 12px;
+  background-position: -7px -49px;
+}
+
+.time::before
+{
+  content: "";
+  -webkit-margin-end: 6px;
+  -moz-margin-end: 6px;
+  -webkit-margin-start: 12px;
+  -moz-margin-start: 12px;
+  height: 12px;
+  width: 12px;
+  background-position: -20px -49px;
+}
+
 #custom-filters-header
 {
   padding: 0px 20px;
@@ -768,7 +860,7 @@ div.button
 #custom-filters-add button::after
 {
   content: "";
-  background-position: -28px -85px;
+  background-position: -28px -32px;
   cursor: pointer;
   height: 10px;
   -webkit-margin-start: 6px;
@@ -793,6 +885,20 @@ div.button
   text-decoration: none;
 }
 
+.context-menu
+{
+  display: inline-block;
+  position: relative;
+  border-bottom: none;
+}
+
+.context-menu a
+{
+  vertical-align: middle;
+  white-space: nowrap;
+  color: #FFF;
+}
+
 #content-advanced .tooltip
 {
   -moz-margin-start: 8px;
@@ -846,7 +952,8 @@ div[role="tooltip"]:hover
   transition-delay: 0ms;
 }
 
-div[role="tooltip"]::before
+div[role="tooltip"]::before,
+div.context-menu::before
 {
   background-image: url(options-sprite.png);
   background-position: -8px -42px;
@@ -858,6 +965,95 @@ div[role="tooltip"]::before
   left: 30px;
 }
 
+div.context-menu
+{
+  position: absolute;
+  top: 16px;
+  z-index: 1;
+  visibility: hidden;
+}
+
+div.context-menu::before
+{
+  left: -4px;
+}
+
+html[dir="rtl"] div.context-menu::before
+{
+  left: inherit;
+  right: -4px;
+}
+
+div.context-menu .content
+{
+  position: relative;
+  left: calc(-50% + 2px);
+  border-radius: 3px;
+  padding: 4px 10px;
+  background-color: rgba(45, 45, 45, 0.95);
+  cursor: default;
+}
+
+html[dir="rtl"] div.context-menu .content
+{
+  left: inherit;
+  right: -50%;
+}
+
+li.show-context-menu div.context-menu
+{
+  visibility: visible;
+}
+
+div.context-menu > div a::before
+{
+  content: "";
+  -moz-margin-end: 8px;
+  -webkit-margin-end: 8px;
+}
+
+div.context-menu > div a
+{
+  display: block;
+  padding: 7px 4px;
+  border-bottom: 1px solid #CDCDCD;
+  text-decoration: none;
+  cursor: pointer;
+  vertical-align: middle;
+}
+
+div.context-menu > div a::before
+{
+  vertical-align: middle;
+  height: 16px;
+  width: 16px;
+}
+
+div.context-menu > div a:last-child
+{
+  border: none;
+}
+
+.context-menu .update-subscription::before
+{
+  background-position: -38px -31px;
+}
+
+.context-menu .website::before
+{
+  background-position: -33px -47px;
+}
+
+.context-menu .source::before
+{
+  background-position: -53px -34px;
+}
+
+.context-menu .delete::before
+{
+  background-position: -71px -34px;
+}
+
 html[dir="ltr"] div[role="tooltip"].flip-vertical::before,
 html[dir="rtl"] div[role="tooltip"]:not(.flip-vertical)::before
 {

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