| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2016 Eyeo GmbH | 3  * Copyright (C) 2006-2016 Eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
| 18 "use strict"; | 18 "use strict"; | 
| 19 | 19 | 
| 20 (function() | 20 (function() | 
| 21 { | 21 { | 
| 22   var subscriptionsMap = Object.create(null); | 22   var subscriptionsMap = Object.create(null); | 
| 23   var recommendationsMap = Object.create(null); | 23   var recommendationsMap = Object.create(null); | 
| 24   var filtersMap = Object.create(null); | 24   var filtersMap = Object.create(null); | 
| 25   var collections = Object.create(null); | 25   var collections = Object.create(null); | 
| 26   var maxLabelId = 0; | 26   var maxLabelId = 0; | 
|  | 27   var getMessage = ext.i18n.getMessage; | 
|  | 28   var filterErrors = | 
|  | 29   { | 
|  | 30     "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL", | 
|  | 31     "synchronize_connection_error": "options_filterList_lastDownload_connectionE
      rror", | 
|  | 32     "synchronize_invalid_data": "options_filterList_lastDownload_invalidData", | 
|  | 33     "synchronize_checksum_mismatch": "options_filterList_lastDownload_checksumMi
      smatch" | 
|  | 34   }; | 
| 27 | 35 | 
| 28   function Collection(details) | 36   function Collection(details) | 
| 29   { | 37   { | 
| 30     this.details = details; | 38     this.details = details; | 
| 31     this.items = []; | 39     this.items = []; | 
| 32   } | 40   } | 
| 33 | 41 | 
| 34   Collection.prototype._setEmpty = function(table, text) | 42   Collection.prototype._setEmpty = function(table, text) | 
| 35   { | 43   { | 
| 36     var placeholder = table.querySelector(".empty-placeholder"); | 44     var placeholder = table.querySelector(".empty-placeholder"); | 
| 37     if (text && !placeholder) | 45     if (text && !placeholder) | 
| 38     { | 46     { | 
| 39       placeholder = document.createElement("li"); | 47       placeholder = document.createElement("li"); | 
| 40       placeholder.className = "empty-placeholder"; | 48       placeholder.className = "empty-placeholder"; | 
| 41       placeholder.textContent = ext.i18n.getMessage(text); | 49       placeholder.textContent = getMessage(text); | 
| 42       table.appendChild(placeholder); | 50       table.appendChild(placeholder); | 
| 43     } | 51     } | 
| 44     else if (placeholder) | 52     else if (placeholder) | 
| 45       table.removeChild(placeholder); | 53       table.removeChild(placeholder); | 
| 46   } | 54   } | 
| 47 | 55 | 
|  | 56   Collection.prototype._createElementQuery = function(item) | 
|  | 57   { | 
|  | 58     var access = (item.url || item.text).replace(/'/g, "\\'"); | 
|  | 59     return function(container) | 
|  | 60     { | 
|  | 61       return container.querySelector("[data-access='" + access + "']"); | 
|  | 62     }; | 
|  | 63   }; | 
|  | 64 | 
| 48   Collection.prototype.addItems = function() | 65   Collection.prototype.addItems = function() | 
| 49   { | 66   { | 
| 50     var length = Array.prototype.push.apply(this.items, arguments); | 67     var length = Array.prototype.push.apply(this.items, arguments); | 
| 51     if (length == 0) | 68     if (length == 0) | 
| 52       return; | 69       return; | 
| 53 | 70 | 
| 54     this.items.sort(function(a, b) | 71     this.items.sort(function(a, b) | 
| 55     { | 72     { | 
| 56       var aValue = (a.title || a.text || a.url).toLowerCase(); | 73       var aValue = (a.title || a.text || a.url).toLowerCase(); | 
| 57       var bValue = (b.title || b.text || b.url).toLowerCase(); | 74       var bValue = (b.title || b.text || b.url).toLowerCase(); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 75         if (control) | 92         if (control) | 
| 76         { | 93         { | 
| 77           // We use aria-labelledby to avoid triggering the control when | 94           // We use aria-labelledby to avoid triggering the control when | 
| 78           // interacting with the label | 95           // interacting with the label | 
| 79           control.setAttribute("aria-labelledby", labelId); | 96           control.setAttribute("aria-labelledby", labelId); | 
| 80           control.addEventListener("click", this.details[j].onClick, false); | 97           control.addEventListener("click", this.details[j].onClick, false); | 
| 81         } | 98         } | 
| 82 | 99 | 
| 83         this._setEmpty(table, null); | 100         this._setEmpty(table, null); | 
| 84         if (table.hasChildNodes()) | 101         if (table.hasChildNodes()) | 
| 85           table.insertBefore(listItem, table.childNodes[this.items.indexOf(item)
      ]); | 102         { | 
|  | 103           table.insertBefore(listItem, | 
|  | 104               table.childNodes[this.items.indexOf(item)]); | 
|  | 105         } | 
| 86         else | 106         else | 
| 87           table.appendChild(listItem); | 107           table.appendChild(listItem); | 
| 88         this.updateItem(item); | 108         this.updateItem(item); | 
| 89       } | 109       } | 
| 90     } | 110     } | 
| 91     return length; | 111     return length; | 
| 92   }; | 112   }; | 
| 93 | 113 | 
| 94   Collection.prototype.removeItem = function(item) | 114   Collection.prototype.removeItem = function(item) | 
| 95   { | 115   { | 
| 96     var index = this.items.indexOf(item); | 116     var index = this.items.indexOf(item); | 
| 97     if (index == -1) | 117     if (index == -1) | 
| 98       return; | 118       return; | 
| 99 | 119 | 
| 100     this.items.splice(index, 1); | 120     this.items.splice(index, 1); | 
|  | 121     var getListElement = this._createElementQuery(item); | 
| 101     for (var i = 0; i < this.details.length; i++) | 122     for (var i = 0; i < this.details.length; i++) | 
| 102     { | 123     { | 
| 103       var table = E(this.details[i].id); | 124       var table = E(this.details[i].id); | 
| 104       var element = table.childNodes[index]; | 125       var element = getListElement(table); | 
| 105 | 126 | 
| 106       // Element gets removed so make sure to handle focus appropriately | 127       // Element gets removed so make sure to handle focus appropriately | 
| 107       var control = element.querySelector(".control"); | 128       var control = element.querySelector(".control"); | 
| 108       if (control && control == document.activeElement) | 129       if (control && control == document.activeElement) | 
| 109       { | 130       { | 
| 110         if (!focusNextElement(element.parentElement, control)) | 131         if (!focusNextElement(element.parentElement, control)) | 
| 111         { | 132         { | 
| 112           // Fall back to next focusable element within same tab or dialog | 133           // Fall back to next focusable element within same tab or dialog | 
| 113           var focusableElement = element.parentElement; | 134           var focusableElement = element.parentElement; | 
| 114           while (focusableElement) | 135           while (focusableElement) | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 132   Collection.prototype.updateItem = function(item) | 153   Collection.prototype.updateItem = function(item) | 
| 133   { | 154   { | 
| 134     var access = (item.url || item.text).replace(/'/g, "\\'"); | 155     var access = (item.url || item.text).replace(/'/g, "\\'"); | 
| 135     for (var i = 0; i < this.details.length; i++) | 156     for (var i = 0; i < this.details.length; i++) | 
| 136     { | 157     { | 
| 137       var table = E(this.details[i].id); | 158       var table = E(this.details[i].id); | 
| 138       var element = table.querySelector("[data-access='" + access + "']"); | 159       var element = table.querySelector("[data-access='" + access + "']"); | 
| 139       if (!element) | 160       if (!element) | 
| 140         continue; | 161         continue; | 
| 141 | 162 | 
| 142       var text = item.title || item.url || item.text; | 163       var title = item.title || item.url || item.text; | 
| 143       element.querySelector(".display").textContent = text; | 164       element.querySelector(".display").textContent = title; | 
| 144       if (text) | 165       if (title) | 
| 145         element.setAttribute("data-search", text.toLowerCase()); | 166         element.setAttribute("data-search", title.toLowerCase()); | 
| 146       var control = element.querySelector(".control[role='checkbox']"); | 167       var control = element.querySelector(".control[role='checkbox']"); | 
| 147       if (control) | 168       if (control) | 
| 148         control.setAttribute("aria-checked", item.disabled == false); | 169         control.setAttribute("aria-checked", item.disabled == false); | 
|  | 170 | 
|  | 171       var downloadStatus = item.downloadStatus; | 
|  | 172       var dateElement = element.querySelector(".date"); | 
|  | 173       var timeElement = element.querySelector(".time"); | 
|  | 174       if(dateElement && timeElement) | 
|  | 175       { | 
|  | 176         var message = element.querySelector(".message"); | 
|  | 177         ext.backgroundPage.sendMessage( | 
|  | 178         { | 
|  | 179           type: "subscriptions.isDownloading", | 
|  | 180           url: item.url | 
|  | 181         }, | 
|  | 182         function(isDownloading) | 
|  | 183         { | 
|  | 184           if (isDownloading) | 
|  | 185           { | 
|  | 186             var text = getMessage("options_filterList_lastDownload_inProgress"); | 
|  | 187             message.textContent = text; | 
|  | 188             element.classList.add("show-message"); | 
|  | 189           } | 
|  | 190           else if (downloadStatus && downloadStatus != "synchronize_ok") | 
|  | 191           { | 
|  | 192             if (downloadStatus in filterErrors) | 
|  | 193               message.textContent = getMessage(filterErrors[downloadStatus]); | 
|  | 194             else | 
|  | 195               message.textContent = item.downloadStatus; | 
|  | 196             element.classList.add("show-message"); | 
|  | 197           } | 
|  | 198           else if (item.lastDownload > 0) | 
|  | 199           { | 
|  | 200             var dateTime = i18n_formatDateTime(item.lastDownload * 1000); | 
|  | 201             dateElement.textContent = dateTime[0]; | 
|  | 202             timeElement.textContent = dateTime[1]; | 
|  | 203             element.classList.remove("show-message"); | 
|  | 204           } | 
|  | 205         }); | 
|  | 206       } | 
|  | 207       var websiteElement = element.querySelector(".context-menu .website"); | 
|  | 208       var sourceElement = element.querySelector(".context-menu .source"); | 
|  | 209       if (websiteElement && item.homepage) | 
|  | 210         websiteElement.setAttribute("href", item.homepage); | 
|  | 211       if (sourceElement) | 
|  | 212         sourceElement.setAttribute("href", item.url); | 
| 149     } | 213     } | 
| 150   }; | 214   }; | 
| 151 | 215 | 
| 152   Collection.prototype.clearAll = function() | 216   Collection.prototype.clearAll = function() | 
| 153   { | 217   { | 
| 154     this.items = []; | 218     this.items = []; | 
| 155     for (var i = 0; i < this.details.length; i++) | 219     for (var i = 0; i < this.details.length; i++) | 
| 156     { | 220     { | 
| 157       var table = E(this.details[i].id); | 221       var table = E(this.details[i].id); | 
| 158       var template = table.querySelector("template"); | 222       var element = table.firstChild; | 
| 159       table.innerHTML = ""; | 223       while (element) | 
| 160       table.appendChild(template); | 224       { | 
|  | 225         if (element.tagName == "LI" && !element.classList.contains("static")) | 
|  | 226           table.removeChild(element); | 
|  | 227         element = element.nextElementSibling; | 
|  | 228       } | 
|  | 229 | 
| 161       this._setEmpty(table, this.details[i].emptyText); | 230       this._setEmpty(table, this.details[i].emptyText); | 
| 162     } | 231     } | 
| 163   }; | 232   }; | 
| 164 | 233 | 
| 165   function focusNextElement(container, currentElement) | 234   function focusNextElement(container, currentElement) | 
| 166   { | 235   { | 
| 167     var focusables = container.querySelectorAll("a, button, input, .control"); | 236     var focusables = container.querySelectorAll("a, button, input, .control"); | 
| 168     focusables = Array.prototype.slice.call(focusables); | 237     focusables = Array.prototype.slice.call(focusables); | 
| 169     var index = focusables.indexOf(currentElement); | 238     var index = focusables.indexOf(currentElement); | 
| 170     index += (index == focusables.length - 1) ? -1 : 1; | 239     index += (index == focusables.length - 1) ? -1 : 1; | 
| 171 | 240 | 
| 172     var nextElement = focusables[index]; | 241     var nextElement = focusables[index]; | 
| 173     if (!nextElement) | 242     if (!nextElement) | 
| 174       return false; | 243       return false; | 
| 175 | 244 | 
| 176     nextElement.focus(); | 245     nextElement.focus(); | 
| 177     return true; | 246     return true; | 
| 178   } | 247   } | 
| 179 | 248 | 
| 180   function onToggleSubscriptionClick(e) | 249   function toggleRemoveSubscription(e) | 
| 181   { | 250   { | 
| 182     e.preventDefault(); | 251     e.preventDefault(); | 
| 183     var checkbox = e.target; | 252     var subscriptionUrl = findParentData(e.target, "access", false); | 
| 184     var subscriptionUrl = checkbox.parentElement.getAttribute("data-access"); | 253     if (e.target.getAttribute("aria-checked") == "true") | 
| 185     if (checkbox.getAttribute("aria-checked") == "true") |  | 
| 186     { | 254     { | 
| 187       ext.backgroundPage.sendMessage({ | 255       ext.backgroundPage.sendMessage({ | 
| 188         type: "subscriptions.remove", | 256         type: "subscriptions.remove", | 
| 189         url: subscriptionUrl | 257         url: subscriptionUrl | 
| 190       }); | 258       }); | 
| 191     } | 259     } | 
| 192     else | 260     else | 
| 193       addEnableSubscription(subscriptionUrl); | 261       addEnableSubscription(subscriptionUrl); | 
| 194   } | 262   } | 
| 195 | 263 | 
|  | 264   function toggleDisableSubscription(e) | 
|  | 265   { | 
|  | 266     e.preventDefault(); | 
|  | 267     var subscriptionUrl = findParentData(e.target, "access", false); | 
|  | 268     ext.backgroundPage.sendMessage( | 
|  | 269     { | 
|  | 270       type: "subscriptions.toggle", | 
|  | 271       keepInstalled: true, | 
|  | 272       url: subscriptionUrl | 
|  | 273     }); | 
|  | 274   } | 
|  | 275 | 
| 196   function onAddLanguageSubscriptionClick(e) | 276   function onAddLanguageSubscriptionClick(e) | 
| 197   { | 277   { | 
| 198     e.preventDefault(); | 278     e.preventDefault(); | 
| 199     var url = this.parentNode.getAttribute("data-access"); | 279     var url = findParentData(this, "access", false); | 
| 200     addEnableSubscription(url); | 280     addEnableSubscription(url); | 
| 201   } | 281   } | 
| 202 | 282 | 
| 203   function onRemoveFilterClick() | 283   function onRemoveFilterClick() | 
| 204   { | 284   { | 
| 205     var filter = this.parentNode.getAttribute("data-access"); | 285     var filter = findParentData(this, "access", false); | 
| 206     ext.backgroundPage.sendMessage( | 286     ext.backgroundPage.sendMessage( | 
| 207     { | 287     { | 
| 208       type: "filters.remove", | 288       type: "filters.remove", | 
| 209       text: filter | 289       text: filter | 
| 210     }); | 290     }); | 
| 211   } | 291   } | 
| 212 | 292 | 
| 213   collections.popular = new Collection( | 293   collections.popular = new Collection( | 
| 214   [ | 294   [ | 
| 215     { | 295     { | 
| 216       id: "recommend-list-table", | 296       id: "recommend-list-table", | 
| 217       onClick: onToggleSubscriptionClick | 297       onClick: toggleRemoveSubscription | 
| 218     } | 298     } | 
| 219   ]); | 299   ]); | 
| 220   collections.langs = new Collection( | 300   collections.langs = new Collection( | 
| 221   [ | 301   [ | 
| 222     { | 302     { | 
| 223       id: "blocking-languages-table", | 303       id: "blocking-languages-table", | 
| 224       emptyText: "options_dialog_language_added_empty", | 304       emptyText: "options_dialog_language_added_empty", | 
| 225       onClick: onToggleSubscriptionClick | 305       onClick: toggleRemoveSubscription | 
| 226     }, | 306     }, | 
| 227     { | 307     { | 
| 228       id: "blocking-languages-dialog-table", | 308       id: "blocking-languages-dialog-table", | 
| 229       emptyText: "options_dialog_language_added_empty" | 309       emptyText: "options_dialog_language_added_empty" | 
| 230     } | 310     } | 
| 231   ]); | 311   ]); | 
| 232   collections.allLangs = new Collection( | 312   collections.allLangs = new Collection( | 
| 233   [ | 313   [ | 
| 234     { | 314     { | 
| 235       id: "all-lang-table", | 315       id: "all-lang-table", | 
| 236       emptyText: "options_dialog_language_other_empty", | 316       emptyText: "options_dialog_language_other_empty", | 
| 237       onClick: onAddLanguageSubscriptionClick | 317       onClick: onAddLanguageSubscriptionClick | 
| 238     } | 318     } | 
| 239   ]); | 319   ]); | 
| 240   collections.acceptableAds = new Collection( | 320   collections.acceptableAds = new Collection( | 
| 241   [ | 321   [ | 
| 242     { | 322     { | 
| 243       id: "acceptableads-table", | 323       id: "acceptableads-table", | 
| 244       onClick: onToggleSubscriptionClick | 324       onClick: toggleRemoveSubscription | 
| 245     } | 325     } | 
| 246   ]); | 326   ]); | 
| 247   collections.custom = new Collection( | 327   collections.custom = new Collection( | 
| 248   [ | 328   [ | 
| 249     { | 329     { | 
| 250       id: "custom-list-table", | 330       id: "custom-list-table", | 
| 251       onClick: onToggleSubscriptionClick | 331       onClick: toggleRemoveSubscription | 
| 252     } | 332     } | 
| 253   ]); | 333   ]); | 
| 254   collections.whitelist = new Collection( | 334   collections.whitelist = new Collection( | 
| 255   [ | 335   [ | 
| 256     { | 336     { | 
| 257       id: "whitelisting-table", | 337       id: "whitelisting-table", | 
| 258       emptyText: "options_whitelisted_empty", | 338       emptyText: "options_whitelisted_empty", | 
| 259       onClick: onRemoveFilterClick | 339       onClick: onRemoveFilterClick | 
| 260     } | 340     } | 
| 261   ]); | 341   ]); | 
| 262   collections.customFilters = new Collection( | 342   collections.customFilters = new Collection( | 
| 263   [ | 343   [ | 
| 264     { | 344     { | 
| 265       id: "custom-filters-table", | 345       id: "custom-filters-table", | 
| 266       emptyText: "options_customFilters_empty" | 346       emptyText: "options_customFilters_empty" | 
| 267     } | 347     } | 
| 268   ]); | 348   ]); | 
|  | 349   collections.filterLists = new Collection( | 
|  | 350   [ | 
|  | 351     { | 
|  | 352       id: "all-filter-lists-table", | 
|  | 353       onClick: toggleDisableSubscription | 
|  | 354     } | 
|  | 355   ]); | 
| 269 | 356 | 
| 270   function updateSubscription(subscription) | 357   function observeSubscription(subscription) | 
| 271   { | 358   { | 
| 272     var subscriptionUrl = subscription.url; | 359     function onObjectChanged(change) | 
| 273     var knownSubscription = subscriptionsMap[subscriptionUrl]; |  | 
| 274     if (knownSubscription) |  | 
| 275       knownSubscription.disabled = subscription.disabled; |  | 
| 276     else |  | 
| 277     { | 360     { | 
| 278       getAcceptableAdsURL(function(acceptableAdsUrl) | 361       for (var i = 0; i < change.length; i++) | 
| 279       { | 362       { | 
| 280         function onObjectChanged() | 363         if (change[i].name == "disabled") | 
| 281         { | 364         { | 
| 282           for (var i in collections) | 365           var recommendation = recommendationsMap[subscription.url]; | 
| 283             collections[i].updateItem(subscription); |  | 
| 284 |  | 
| 285           var recommendation = recommendationsMap[subscriptionUrl]; |  | 
| 286           if (recommendation && recommendation.type == "ads") | 366           if (recommendation && recommendation.type == "ads") | 
| 287           { | 367           { | 
| 288             if (subscription.disabled == false) | 368             if (subscription.disabled == false) | 
| 289             { | 369             { | 
| 290               collections.allLangs.removeItem(subscription); | 370               collections.allLangs.removeItem(subscription); | 
| 291               collections.langs.addItems(subscription); | 371               collections.langs.addItems(subscription); | 
| 292             } | 372             } | 
| 293             else | 373             else | 
| 294             { | 374             { | 
| 295               collections.allLangs.addItems(subscription); | 375               collections.allLangs.addItems(subscription); | 
| 296               collections.langs.removeItem(subscription); | 376               collections.langs.removeItem(subscription); | 
| 297             } | 377             } | 
| 298           } | 378           } | 
| 299         } | 379         } | 
|  | 380         for (var i in collections) | 
|  | 381           collections[i].updateItem(subscription); | 
|  | 382       } | 
|  | 383     } | 
| 300 | 384 | 
| 301         if (!Object.observe) | 385     if (!Object.observe) | 
|  | 386     { | 
|  | 387       ["disabled", "lastDownload"].forEach(function(property) | 
|  | 388       { | 
|  | 389         subscription["$" + property] = subscription[property]; | 
|  | 390         Object.defineProperty(subscription, property, | 
| 302         { | 391         { | 
| 303           // Currently only "disabled" property of subscription used for observa
      tion | 392           get: function() | 
| 304           // but with Advanced tab implementation we should also add more proper
      ties. |  | 
| 305           ["disabled"].forEach(function(property) |  | 
| 306           { | 393           { | 
| 307             subscription["$" + property] = subscription[property]; | 394             return this["$" + property]; | 
| 308             Object.defineProperty(subscription, property, | 395           }, | 
|  | 396           set: function(newValue) | 
|  | 397           { | 
|  | 398             var oldValue = this["$" + property]; | 
|  | 399             if (oldValue != newValue) | 
| 309             { | 400             { | 
| 310               get: function() | 401               this["$" + property] = newValue; | 
| 311               { | 402               var change = Object.create(null); | 
| 312                 return this["$" + property]; | 403               change.name = property; | 
| 313               }, | 404               onObjectChanged([change]); | 
| 314               set: function(value) | 405             } | 
| 315               { | 406           } | 
| 316                 this["$" + property] = value; | 407         }); | 
| 317                 onObjectChanged(); | 408       }); | 
| 318               } | 409     } | 
| 319             }); | 410     else | 
| 320           }); | 411     { | 
| 321         } | 412       Object.observe(subscription, onObjectChanged); | 
| 322         else | 413     } | 
| 323         { | 414   } | 
| 324           Object.observe(subscription, onObjectChanged); |  | 
| 325         } |  | 
| 326 | 415 | 
|  | 416   function updateSubscription(subscription) | 
|  | 417   { | 
|  | 418     var subscriptionUrl = subscription.url; | 
|  | 419     var knownSubscription = subscriptionsMap[subscriptionUrl]; | 
|  | 420     if (knownSubscription) | 
|  | 421     { | 
|  | 422       for (var property in subscription) | 
|  | 423         if (property != "title") | 
|  | 424           knownSubscription[property] = subscription[property]; | 
|  | 425     } | 
|  | 426     else | 
|  | 427     { | 
|  | 428       observeSubscription(subscription); | 
|  | 429       getAcceptableAdsURL(function(acceptableAdsUrl) | 
|  | 430       { | 
| 327         var collection = null; | 431         var collection = null; | 
| 328         if (subscriptionUrl in recommendationsMap) | 432         if (subscriptionUrl in recommendationsMap) | 
| 329         { | 433         { | 
| 330           var recommendation = recommendationsMap[subscriptionUrl]; | 434           var recommendation = recommendationsMap[subscriptionUrl]; | 
| 331           if (recommendation.type != "ads") | 435           if (recommendation.type != "ads") | 
| 332             collection = collections.popular; | 436             collection = collections.popular; | 
| 333           else if (subscription.disabled == false) | 437           else if (subscription.disabled == false) | 
| 334             collection = collections.langs; | 438             collection = collections.langs; | 
| 335           else | 439           else | 
| 336             collection = collections.allLangs; | 440             collection = collections.allLangs; | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 374         var elements = doc.documentElement.getElementsByTagName("subscription"); | 478         var elements = doc.documentElement.getElementsByTagName("subscription"); | 
| 375         for (var i = 0; i < elements.length; i++) | 479         for (var i = 0; i < elements.length; i++) | 
| 376         { | 480         { | 
| 377           var element = elements[i]; | 481           var element = elements[i]; | 
| 378           var subscription = Object.create(null); | 482           var subscription = Object.create(null); | 
| 379           subscription.title = element.getAttribute("title"); | 483           subscription.title = element.getAttribute("title"); | 
| 380           subscription.url = element.getAttribute("url"); | 484           subscription.url = element.getAttribute("url"); | 
| 381           subscription.disabled = null; | 485           subscription.disabled = null; | 
| 382           subscription.downloadStatus = null; | 486           subscription.downloadStatus = null; | 
| 383           subscription.homepage = null; | 487           subscription.homepage = null; | 
| 384           subscription.lastSuccess = null; |  | 
| 385           var recommendation = Object.create(null); | 488           var recommendation = Object.create(null); | 
| 386           recommendation.type = element.getAttribute("type"); | 489           recommendation.type = element.getAttribute("type"); | 
| 387           var prefix = element.getAttribute("prefixes"); | 490           var prefix = element.getAttribute("prefixes"); | 
| 388           if (prefix) | 491           if (prefix) | 
| 389           { | 492           { | 
| 390             prefix = prefix.replace(/\W/g, "_"); | 493             prefix = prefix.replace(/\W/g, "_"); | 
| 391             subscription.title = ext.i18n.getMessage("options_language_" + prefi
      x); | 494             subscription.title = getMessage("options_language_" + prefix); | 
| 392           } | 495           } | 
| 393           else | 496           else | 
| 394           { | 497           { | 
| 395             var type = recommendation.type.replace(/\W/g, "_"); | 498             var type = recommendation.type.replace(/\W/g, "_"); | 
| 396             subscription.title = ext.i18n.getMessage("common_feature_" + type + 
      "_title"); | 499             subscription.title = getMessage("common_feature_" + type + "_title")
      ; | 
| 397           } | 500           } | 
| 398 | 501 | 
| 399           recommendationsMap[subscription.url] = recommendation; | 502           recommendationsMap[subscription.url] = recommendation; | 
| 400           updateSubscription(subscription); | 503           updateSubscription(subscription); | 
| 401         } | 504         } | 
| 402       }); | 505       }); | 
| 403   } | 506   } | 
| 404 | 507 | 
|  | 508   function findParentData(element, dataName, returnElement) | 
|  | 509   { | 
|  | 510     while (element) | 
|  | 511     { | 
|  | 512       if (element.hasAttribute("data-" + dataName)) | 
|  | 513         return returnElement ? element : element.getAttribute("data-" + dataName
      ); | 
|  | 514 | 
|  | 515       element = element.parentElement; | 
|  | 516     } | 
|  | 517     return null; | 
|  | 518   } | 
|  | 519 | 
| 405   function onClick(e) | 520   function onClick(e) | 
| 406   { | 521   { | 
|  | 522     var context = document.querySelector(".show-context-menu"); | 
|  | 523     if (context) | 
|  | 524       context.classList.remove("show-context-menu"); | 
|  | 525 | 
| 407     var element = e.target; | 526     var element = e.target; | 
| 408     while (true) | 527     while (true) | 
| 409     { | 528     { | 
| 410       if (!element) | 529       if (!element) | 
| 411         return; | 530         return; | 
| 412 | 531 | 
| 413       if (element.hasAttribute("data-action")) | 532       if (element.hasAttribute("data-action")) | 
| 414         break; | 533         break; | 
| 415 | 534 | 
| 416       element = element.parentElement; | 535       element = element.parentElement; | 
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 462           { | 581           { | 
| 463             type: "filters.importRaw", | 582             type: "filters.importRaw", | 
| 464             text: E("custom-filters-raw").value | 583             text: E("custom-filters-raw").value | 
| 465           }); | 584           }); | 
| 466           E("custom-filters").classList.remove("mode-edit"); | 585           E("custom-filters").classList.remove("mode-edit"); | 
| 467           break; | 586           break; | 
| 468         case "switch-tab": | 587         case "switch-tab": | 
| 469           document.body.setAttribute("data-tab", | 588           document.body.setAttribute("data-tab", | 
| 470             element.getAttribute("data-tab")); | 589             element.getAttribute("data-tab")); | 
| 471           break; | 590           break; | 
|  | 591         case "update-all-subscriptions": | 
|  | 592           ext.backgroundPage.sendMessage( | 
|  | 593           { | 
|  | 594             type: "subscriptions.update" | 
|  | 595           }); | 
|  | 596           break; | 
|  | 597         case "open-context-menu": | 
|  | 598           var listItem = findParentData(element, "access", true); | 
|  | 599           if (listItem != context) | 
|  | 600             listItem.classList.add("show-context-menu"); | 
|  | 601           break; | 
|  | 602         case "update-subscription": | 
|  | 603           ext.backgroundPage.sendMessage( | 
|  | 604           { | 
|  | 605             type: "subscriptions.update", | 
|  | 606             url: findParentData(element, "access", false) | 
|  | 607           }); | 
|  | 608           break; | 
|  | 609         case "remove-subscription": | 
|  | 610           ext.backgroundPage.sendMessage( | 
|  | 611           { | 
|  | 612             type: "subscriptions.remove", | 
|  | 613             url: findParentData(element, "access", false) | 
|  | 614           }); | 
|  | 615           break; | 
| 472       } | 616       } | 
| 473     } | 617     } | 
| 474   } | 618   } | 
| 475 | 619 | 
| 476   function onDOMLoaded() | 620   function onDOMLoaded() | 
| 477   { | 621   { | 
| 478     var recommendationTemplate = document.querySelector("#recommend-list-table t
      emplate"); |  | 
| 479     var popularText = ext.i18n.getMessage("options_popular"); |  | 
| 480     recommendationTemplate.content.querySelector(".popular").textContent = popul
      arText; |  | 
| 481     var languagesTemplate = document.querySelector("#all-lang-table template"); |  | 
| 482     var buttonText = ext.i18n.getMessage("options_button_add"); |  | 
| 483     languagesTemplate.content.querySelector(".button-add span").textContent = bu
      ttonText; |  | 
| 484 |  | 
| 485     populateLists(); | 622     populateLists(); | 
| 486 |  | 
| 487     function onFindLanguageKeyUp() | 623     function onFindLanguageKeyUp() | 
| 488     { | 624     { | 
| 489       var searchStyle = E("search-style"); | 625       var searchStyle = E("search-style"); | 
| 490       if (!this.value) | 626       if (!this.value) | 
| 491         searchStyle.innerHTML = ""; | 627         searchStyle.innerHTML = ""; | 
| 492       else | 628       else | 
| 493         searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this
      .value.toLowerCase() + "\"]) { display: none; }"; | 629         searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this
      .value.toLowerCase() + "\"]) { display: none; }"; | 
| 494     } | 630     } | 
| 495 | 631 | 
| 496     function getKey(e) | 632     function getKey(e) | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 523 | 659 | 
| 524     getDocLink("contribute", function(link) | 660     getDocLink("contribute", function(link) | 
| 525     { | 661     { | 
| 526       document.querySelector("#tab-contribute a").setAttribute("href", link); | 662       document.querySelector("#tab-contribute a").setAttribute("href", link); | 
| 527     }); | 663     }); | 
| 528 | 664 | 
| 529     updateShareLink(); | 665     updateShareLink(); | 
| 530 | 666 | 
| 531     // Initialize interactive UI elements | 667     // Initialize interactive UI elements | 
| 532     document.body.addEventListener("click", onClick, false); | 668     document.body.addEventListener("click", onClick, false); | 
| 533     var placeholderValue  = ext.i18n.getMessage("options_dialog_language_find"); | 669     var placeholderValue  = getMessage("options_dialog_language_find"); | 
| 534     E("find-language").setAttribute("placeholder", placeholderValue); | 670     E("find-language").setAttribute("placeholder", placeholderValue); | 
| 535     E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); | 671     E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); | 
| 536     E("whitelisting-textbox").addEventListener("keypress", function(e) | 672     E("whitelisting-textbox").addEventListener("keypress", function(e) | 
| 537     { | 673     { | 
| 538       if (getKey(e) == "Enter") | 674       if (getKey(e) == "Enter") | 
| 539         addWhitelistedDomain(); | 675         addWhitelistedDomain(); | 
| 540     }, false); | 676     }, false); | 
| 541 | 677 | 
| 542     // Advanced tab | 678     // Advanced tab | 
| 543     var filterTextbox = document.querySelector("#custom-filters-add input"); | 679     var filterTextbox = document.querySelector("#custom-filters-add input"); | 
| 544     placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeh
      older"); | 680     placeholderValue = getMessage("options_customFilters_textbox_placeholder"); | 
| 545     filterTextbox.setAttribute("placeholder", placeholderValue); | 681     filterTextbox.setAttribute("placeholder", placeholderValue); | 
| 546     function addCustomFilters() | 682     function addCustomFilters() | 
| 547     { | 683     { | 
| 548       var filterText = filterTextbox.value; | 684       var filterText = filterTextbox.value; | 
| 549       ext.backgroundPage.sendMessage( | 685       ext.backgroundPage.sendMessage( | 
| 550       { | 686       { | 
| 551         type: "filters.add", | 687         type: "filters.add", | 
| 552         text: filterText | 688         text: filterText | 
| 553       }); | 689       }); | 
| 554       filterTextbox.value = ""; | 690       filterTextbox.value = ""; | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 642             updateFilter(filters[i]); | 778             updateFilter(filters[i]); | 
| 643         }); | 779         }); | 
| 644       } | 780       } | 
| 645     }); | 781     }); | 
| 646     loadRecommendations(); | 782     loadRecommendations(); | 
| 647     getAcceptableAdsURL(function(acceptableAdsUrl) | 783     getAcceptableAdsURL(function(acceptableAdsUrl) | 
| 648     { | 784     { | 
| 649       var subscription = Object.create(null); | 785       var subscription = Object.create(null); | 
| 650       subscription.url = acceptableAdsUrl; | 786       subscription.url = acceptableAdsUrl; | 
| 651       subscription.disabled = true; | 787       subscription.disabled = true; | 
| 652       subscription.title = ext.i18n.getMessage("options_acceptableAds_descriptio
      n"); | 788       subscription.title = getMessage("options_acceptableAds_description"); | 
| 653       updateSubscription(subscription); | 789       updateSubscription(subscription); | 
| 654 | 790 | 
| 655       // Load user subscriptions | 791       // Load user subscriptions | 
| 656       ext.backgroundPage.sendMessage( | 792       ext.backgroundPage.sendMessage( | 
| 657       { | 793       { | 
| 658         type: "subscriptions.get", | 794         type: "subscriptions.get", | 
| 659         downloadable: true | 795         downloadable: true | 
| 660       }, | 796       }, | 
| 661       function(subscriptions) | 797       function(subscriptions) | 
| 662       { | 798       { | 
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 748         updateShareLink(); | 884         updateShareLink(); | 
| 749         break; | 885         break; | 
| 750     } | 886     } | 
| 751   } | 887   } | 
| 752 | 888 | 
| 753   function onSubscriptionMessage(action, subscription) | 889   function onSubscriptionMessage(action, subscription) | 
| 754   { | 890   { | 
| 755     switch (action) | 891     switch (action) | 
| 756     { | 892     { | 
| 757       case "added": | 893       case "added": | 
|  | 894         updateSubscription(subscription); | 
|  | 895         updateShareLink(); | 
|  | 896 | 
|  | 897         var knownSubscription = subscriptionsMap[subscription.url]; | 
|  | 898         if (knownSubscription) | 
|  | 899           collections.filterLists.addItems(knownSubscription); | 
|  | 900         else | 
|  | 901           collections.filterLists.addItems(subscription); | 
|  | 902         break; | 
| 758       case "disabled": | 903       case "disabled": | 
| 759         updateSubscription(subscription); | 904         updateSubscription(subscription); | 
| 760         updateShareLink(); | 905         updateShareLink(); | 
| 761         break; | 906         break; | 
|  | 907       case "lastDownload": | 
|  | 908         updateSubscription(subscription); | 
|  | 909         break; | 
| 762       case "homepage": | 910       case "homepage": | 
| 763         // TODO: NYI | 911         // TODO: NYI | 
| 764         break; | 912         break; | 
| 765       case "removed": | 913       case "removed": | 
|  | 914         var knownSubscription = subscriptionsMap[subscription.url]; | 
| 766         getAcceptableAdsURL(function(acceptableAdsUrl) | 915         getAcceptableAdsURL(function(acceptableAdsUrl) | 
| 767         { | 916         { | 
| 768           if (subscription.url == acceptableAdsUrl) | 917           if (subscription.url == acceptableAdsUrl) | 
| 769           { | 918           { | 
| 770             subscription.disabled = true; | 919             subscription.disabled = true; | 
| 771             updateSubscription(subscription); | 920             updateSubscription(subscription); | 
| 772           } | 921           } | 
| 773           else | 922           else | 
| 774           { | 923           { | 
| 775             var knownSubscription = subscriptionsMap[subscription.url]; |  | 
| 776             if (subscription.url in recommendationsMap) | 924             if (subscription.url in recommendationsMap) | 
| 777               knownSubscription.disabled = true; | 925               knownSubscription.disabled = true; | 
| 778             else | 926             else | 
| 779             { | 927             { | 
| 780               collections.custom.removeItem(knownSubscription); | 928               collections.custom.removeItem(knownSubscription); | 
| 781               delete subscriptionsMap[subscription.url]; | 929               delete subscriptionsMap[subscription.url]; | 
| 782             } | 930             } | 
| 783           } | 931           } | 
| 784           updateShareLink(); | 932           updateShareLink(); | 
|  | 933           collections.filterLists.removeItem(knownSubscription); | 
| 785         }); | 934         }); | 
| 786         break; | 935         break; | 
| 787       case "title": | 936       case "title": | 
| 788         // TODO: NYI | 937         // TODO: NYI | 
| 789         break; | 938         break; | 
| 790     } | 939     } | 
| 791   } | 940   } | 
| 792 | 941 | 
| 793   function onShareLinkClick(e) | 942   function onShareLinkClick(e) | 
| 794   { | 943   { | 
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 864     filter: ["addSubscription", "error"] | 1013     filter: ["addSubscription", "error"] | 
| 865   }); | 1014   }); | 
| 866   ext.backgroundPage.sendMessage( | 1015   ext.backgroundPage.sendMessage( | 
| 867   { | 1016   { | 
| 868     type: "filters.listen", | 1017     type: "filters.listen", | 
| 869     filter: ["added", "loaded", "removed"] | 1018     filter: ["added", "loaded", "removed"] | 
| 870   }); | 1019   }); | 
| 871   ext.backgroundPage.sendMessage( | 1020   ext.backgroundPage.sendMessage( | 
| 872   { | 1021   { | 
| 873     type: "subscriptions.listen", | 1022     type: "subscriptions.listen", | 
| 874     filter: ["added", "disabled", "homepage", "removed", "title"] | 1023     filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title"
      ] | 
| 875   }); | 1024   }); | 
| 876 | 1025 | 
| 877   window.addEventListener("DOMContentLoaded", onDOMLoaded, false); | 1026   window.addEventListener("DOMContentLoaded", onDOMLoaded, false); | 
| 878 })(); | 1027 })(); | 
| OLD | NEW | 
|---|