| LEFT | RIGHT | 
|---|
| 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 | 
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 108       listItem.setAttribute("role", "section"); | 108       listItem.setAttribute("role", "section"); | 
| 109 | 109 | 
| 110       let label = listItem.querySelector(".display"); | 110       let label = listItem.querySelector(".display"); | 
| 111       if (item.recommended && label.hasAttribute("data-tooltip")) | 111       if (item.recommended && label.hasAttribute("data-tooltip")) | 
| 112       { | 112       { | 
| 113         let tooltipId = label.getAttribute("data-tooltip"); | 113         let tooltipId = label.getAttribute("data-tooltip"); | 
| 114         tooltipId = tooltipId.replace("%value%", item.recommended); | 114         tooltipId = tooltipId.replace("%value%", item.recommended); | 
| 115         label.setAttribute("data-tooltip", tooltipId); | 115         label.setAttribute("data-tooltip", tooltipId); | 
| 116       } | 116       } | 
| 117 | 117 | 
| 118       let controls = listItem.querySelectorAll(".control"); | 118       for (let control of listItem.querySelectorAll(".control")) | 
| 119       for (let k = 0; k < controls.length; k++) | 119       { | 
| 120       { | 120         if (control.hasAttribute("title")) | 
| 121         if (controls[k].hasAttribute("title")) |  | 
| 122         { | 121         { | 
| 123           let titleValue = getMessage(controls[k].getAttribute("title")); | 122           let titleValue = getMessage(control.getAttribute("title")); | 
| 124           controls[k].setAttribute("title", titleValue); | 123           control.setAttribute("title", titleValue); | 
| 125         } | 124         } | 
| 126       } | 125       } | 
| 127 | 126 | 
| 128       this._setEmpty(table, null); | 127       this._setEmpty(table, null); | 
| 129       if (table.hasChildNodes()) | 128       if (table.hasChildNodes()) | 
| 130       { | 129       { | 
| 131         table.insertBefore(listItem, | 130         table.insertBefore(listItem, | 
| 132             table.childNodes[this.items.indexOf(item)]); | 131             table.childNodes[this.items.indexOf(item)]); | 
| 133       } | 132       } | 
| 134       else | 133       else | 
| 135         table.appendChild(listItem); | 134         table.appendChild(listItem); | 
| 136       this.updateItem(item); | 135       this.updateItem(item); | 
| 137     } | 136     } | 
| 138     return length; | 137     return length; | 
| 139   }; | 138   }; | 
| 140 | 139 | 
| 141   Collection.prototype.removeItem = function(item) | 140   Collection.prototype.removeItem = function(item) | 
| 142   { | 141   { | 
| 143     let index = this.items.indexOf(item); | 142     let index = this.items.indexOf(item); | 
| 144     if (index == -1) | 143     if (index == -1) | 
| 145       return; | 144       return; | 
| 146 | 145 | 
| 147     this.items.splice(index, 1); | 146     this.items.splice(index, 1); | 
| 148     let getListElement = this._createElementQuery(item); | 147     let getListElement = this._createElementQuery(item); | 
| 149     for (let i = 0; i < this.details.length; i++) | 148     for (let detail of this.details) | 
| 150     { | 149     { | 
| 151       let table = E(this.details[i].id); | 150       let table = E(detail.id); | 
| 152       let element = getListElement(table); | 151       let element = getListElement(table); | 
| 153 | 152 | 
| 154       // Element gets removed so make sure to handle focus appropriately | 153       // Element gets removed so make sure to handle focus appropriately | 
| 155       let control = element.querySelector(".control"); | 154       let control = element.querySelector(".control"); | 
| 156       if (control && control == document.activeElement) | 155       if (control && control == document.activeElement) | 
| 157       { | 156       { | 
| 158         if (!focusNextElement(element.parentElement, control)) | 157         if (!focusNextElement(element.parentElement, control)) | 
| 159         { | 158         { | 
| 160           // Fall back to next focusable element within same tab or dialog | 159           // Fall back to next focusable element within same tab or dialog | 
| 161           let focusableElement = element.parentElement; | 160           let focusableElement = element.parentElement; | 
| 162           while (focusableElement) | 161           while (focusableElement) | 
| 163           { | 162           { | 
| 164             if (focusableElement.classList.contains("tab-content") || | 163             if (focusableElement.classList.contains("tab-content") || | 
| 165                 focusableElement.classList.contains("dialog-content")) | 164                 focusableElement.classList.contains("dialog-content")) | 
| 166               break; | 165               break; | 
| 167 | 166 | 
| 168             focusableElement = focusableElement.parentElement; | 167             focusableElement = focusableElement.parentElement; | 
| 169           } | 168           } | 
| 170           focusNextElement(focusableElement || document, control); | 169           focusNextElement(focusableElement || document, control); | 
| 171         } | 170         } | 
| 172       } | 171       } | 
| 173 | 172 | 
| 174       element.parentElement.removeChild(element); | 173       element.parentElement.removeChild(element); | 
| 175       if (this.items.length == 0) | 174       if (this.items.length == 0) | 
| 176         this._setEmpty(table, this.details[i].emptyText); | 175         this._setEmpty(table, detail.emptyText); | 
| 177     } | 176     } | 
| 178   }; | 177   }; | 
| 179 | 178 | 
| 180   Collection.prototype.updateItem = function(item) | 179   Collection.prototype.updateItem = function(item) | 
| 181   { | 180   { | 
| 182     let access = (item.url || item.text).replace(/'/g, "\\'"); | 181     let access = (item.url || item.text).replace(/'/g, "\\'"); | 
| 183     for (let i = 0; i < this.details.length; i++) | 182     for (let i = 0; i < this.details.length; i++) | 
| 184     { | 183     { | 
| 185       let table = E(this.details[i].id); | 184       let table = E(this.details[i].id); | 
| 186       let element = table.querySelector("[data-access='" + access + "']"); | 185       let element = table.querySelector("[data-access='" + access + "']"); | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 240 | 239 | 
| 241       let sourceElement = element.querySelector(".context-menu .source"); | 240       let sourceElement = element.querySelector(".context-menu .source"); | 
| 242       if (sourceElement) | 241       if (sourceElement) | 
| 243         sourceElement.setAttribute("href", item.url); | 242         sourceElement.setAttribute("href", item.url); | 
| 244     } | 243     } | 
| 245   }; | 244   }; | 
| 246 | 245 | 
| 247   Collection.prototype.clearAll = function() | 246   Collection.prototype.clearAll = function() | 
| 248   { | 247   { | 
| 249     this.items = []; | 248     this.items = []; | 
| 250     for (let i = 0; i < this.details.length; i++) | 249     for (let detail of this.details) | 
| 251     { | 250     { | 
| 252       let table = E(this.details[i].id); | 251       let table = E(detail.id); | 
| 253       let element = table.firstChild; | 252       let element = table.firstChild; | 
| 254       while (element) | 253       while (element) | 
| 255       { | 254       { | 
| 256         if (element.tagName == "LI" && !element.classList.contains("static")) | 255         if (element.tagName == "LI" && !element.classList.contains("static")) | 
| 257           table.removeChild(element); | 256           table.removeChild(element); | 
| 258         element = element.nextElementSibling; | 257         element = element.nextElementSibling; | 
| 259       } | 258       } | 
| 260 | 259 | 
| 261       this._setEmpty(table, this.details[i].emptyText); | 260       this._setEmpty(table, detail.emptyText); | 
| 262     } | 261     } | 
| 263   }; | 262   }; | 
| 264 | 263 | 
| 265   function focusNextElement(container, currentElement) | 264   function focusNextElement(container, currentElement) | 
| 266   { | 265   { | 
| 267     let focusables = container.querySelectorAll("a, button, input, .control"); | 266     let focusables = container.querySelectorAll("a, button, input, .control"); | 
| 268     focusables = Array.prototype.slice.call(focusables); | 267     focusables = Array.prototype.slice.call(focusables); | 
| 269     let index = focusables.indexOf(currentElement); | 268     let index = focusables.indexOf(currentElement); | 
| 270     index += (index == focusables.length - 1) ? -1 : 1; | 269     index += (index == focusables.length - 1) ? -1 : 1; | 
| 271 | 270 | 
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 386     } | 385     } | 
| 387     else | 386     else | 
| 388       collections.customFilters.addItem(filter); | 387       collections.customFilters.addItem(filter); | 
| 389 | 388 | 
| 390     filtersMap[filter.text] = filter; | 389     filtersMap[filter.text] = filter; | 
| 391   } | 390   } | 
| 392 | 391 | 
| 393   function loadRecommendations() | 392   function loadRecommendations() | 
| 394   { | 393   { | 
| 395     fetch("subscriptions.xml") | 394     fetch("subscriptions.xml") | 
| 396       .then(response => | 395       .then((response) => | 
| 397       { | 396       { | 
| 398         return response.text(); | 397         return response.text(); | 
| 399       }) | 398       }) | 
| 400       .then(text => | 399       .then((text) => | 
| 401       { | 400       { | 
| 402         let doc = new DOMParser().parseFromString(text, "application/xml"); | 401         let doc = new DOMParser().parseFromString(text, "application/xml"); | 
| 403         let elements = doc.documentElement.getElementsByTagName("subscription"); | 402         let elements = doc.documentElement.getElementsByTagName("subscription"); | 
| 404         for (let i = 0; i < elements.length; i++) | 403         for (let element of elements) | 
| 405         { | 404         { | 
| 406           let element = elements[i]; |  | 
| 407           let type = element.getAttribute("type"); | 405           let type = element.getAttribute("type"); | 
| 408           let subscription = { | 406           let subscription = { | 
| 409             disabled: true, | 407             disabled: true, | 
| 410             downloadStatus: null, | 408             downloadStatus: null, | 
| 411             homepage: null, | 409             homepage: null, | 
| 412             originalTitle: element.getAttribute("title"), | 410             originalTitle: element.getAttribute("title"), | 
| 413             recommended: type, | 411             recommended: type, | 
| 414             url: element.getAttribute("url") | 412             url: element.getAttribute("url") | 
| 415           }; | 413           }; | 
| 416 | 414 | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 443         return element.getAttribute("data-" + dataName); | 441         return element.getAttribute("data-" + dataName); | 
| 444       } | 442       } | 
| 445 | 443 | 
| 446       element = element.parentElement; | 444       element = element.parentElement; | 
| 447     } | 445     } | 
| 448     return null; | 446     return null; | 
| 449   } | 447   } | 
| 450 | 448 | 
| 451   function sendMessageHandleErrors(message, onSuccess) | 449   function sendMessageHandleErrors(message, onSuccess) | 
| 452   { | 450   { | 
| 453     ext.backgroundPage.sendMessage(message, errors => | 451     ext.backgroundPage.sendMessage(message, (errors) => | 
| 454     { | 452     { | 
| 455       if (errors.length > 0) | 453       if (errors.length > 0) | 
| 456         alert(errors.join("\n")); | 454         alert(errors.join("\n")); | 
| 457       else if (onSuccess) | 455       else if (onSuccess) | 
| 458         onSuccess(); | 456         onSuccess(); | 
| 459     }); | 457     }); | 
| 460   } | 458   } | 
| 461 | 459 | 
| 462   function openDocLink(id) | 460   function openDocLink(id) | 
| 463   { | 461   { | 
| 464     getDocLink(id, link => | 462     getDocLink(id, (link) => | 
| 465     { | 463     { | 
| 466       if (id == "share-general") | 464       if (id == "share-general") | 
| 467         openSharePopup(link); | 465         openSharePopup(link); | 
| 468       else | 466       else | 
| 469         location.href = link; | 467         location.href = link; | 
| 470     }); | 468     }); | 
| 471   } | 469   } | 
| 472 | 470 | 
| 473   function switchTab(id) | 471   function switchTab(id) | 
| 474   { | 472   { | 
| 475     location.hash = id; | 473     location.hash = id; | 
| 476   } | 474   } | 
| 477 | 475 | 
| 478   function onClick(e) | 476   function onClick(e) | 
| 479   { | 477   { | 
| 480     let context = document.querySelector(".show-context-menu"); | 478     let context = document.querySelector(".show-context-menu"); | 
| 481     if (context) | 479     if (context) | 
| 482       context.classList.remove("show-context-menu"); | 480       context.classList.remove("show-context-menu"); | 
| 483 | 481 | 
| 484     let element = e.target; | 482     let element = findParentData(e.target, "action", true); | 
| 485     while (element && !element.hasAttribute("data-action")) | 483     if (!element) | 
| 486       element = element.parentElement; | 484       return; | 
| 487 | 485 | 
| 488     element = findParentData(e.target, "action", true); |  | 
| 489     let actions = element.getAttribute("data-action").split(","); | 486     let actions = element.getAttribute("data-action").split(","); | 
| 490     for (let i = 0; i < actions.length; i++) | 487     for (let action of actions) | 
| 491     { | 488     { | 
| 492       switch (actions[i]) | 489       switch (action) | 
| 493       { | 490       { | 
| 494         case "add-domain-exception": | 491         case "add-domain-exception": | 
| 495           addWhitelistedDomain(); | 492           addWhitelistedDomain(); | 
| 496           break; | 493           break; | 
| 497         case "add-predefined-subscription": { | 494         case "add-predefined-subscription": { | 
| 498           let dialog = E("dialog-content-predefined"); | 495           let dialog = E("dialog-content-predefined"); | 
| 499           let title = dialog.querySelector("h3").textContent; | 496           let title = dialog.querySelector("h3").textContent; | 
| 500           let url = dialog.querySelector(".url").textContent; | 497           let url = dialog.querySelector(".url").textContent; | 
| 501           addEnableSubscription(url, title); | 498           addEnableSubscription(url, title); | 
| 502           closeDialog(); | 499           closeDialog(); | 
| 503           break; | 500           break; | 
| 504         } | 501         } | 
| 505         case "cancel-custom-filters": | 502         case "cancel-custom-filters": | 
| 506           E("custom-filters").classList.remove("mode-edit"); | 503           E("custom-filters").classList.remove("mode-edit"); | 
| 507           break; | 504           break; | 
| 508         case "cancel-domain-exception": | 505         case "cancel-domain-exception": | 
| 509           E("whitelisting-textbox").value = ""; | 506           E("whitelisting-textbox").value = ""; | 
| 510           document.querySelector("#whitelisting .controls").classList. | 507           document.querySelector("#whitelisting .controls").classList | 
| 511             remove("mode-edit"); | 508             .remove("mode-edit"); | 
| 512           break; | 509           break; | 
| 513         case "close-dialog": | 510         case "close-dialog": | 
| 514           closeDialog(); | 511           closeDialog(); | 
| 515           break; | 512           break; | 
| 516         case "edit-custom-filters": | 513         case "edit-custom-filters": | 
| 517           E("custom-filters").classList.add("mode-edit"); | 514           E("custom-filters").classList.add("mode-edit"); | 
| 518           editCustomFilters(); | 515           editCustomFilters(); | 
| 519           break; | 516           break; | 
| 520         case "edit-domain-exception": | 517         case "edit-domain-exception": | 
| 521           document.querySelector("#whitelisting .controls").classList. | 518           document.querySelector("#whitelisting .controls").classList | 
| 522             add("mode-edit"); | 519             .add("mode-edit"); | 
| 523           E("whitelisting-textbox").focus(); | 520           E("whitelisting-textbox").focus(); | 
| 524           break; | 521           break; | 
| 525         case "import-subscription": { | 522         case "import-subscription": { | 
| 526           let url = E("blockingList-textbox").value; | 523           let url = E("blockingList-textbox").value; | 
| 527           addEnableSubscription(url); | 524           addEnableSubscription(url); | 
| 528           closeDialog(); | 525           closeDialog(); | 
| 529           break; | 526           break; | 
| 530         } | 527         } | 
| 531         case "open-dialog": { | 528         case "open-dialog": { | 
| 532           let dialog = findParentData(element, "dialog", false); | 529           let dialog = findParentData(element, "dialog", false); | 
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 745         searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + | 742         searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + | 
| 746           this.value.toLowerCase() + "\"]) { display: none; }"; | 743           this.value.toLowerCase() + "\"]) { display: none; }"; | 
| 747       } | 744       } | 
| 748     } | 745     } | 
| 749 | 746 | 
| 750     // Initialize navigation sidebar | 747     // Initialize navigation sidebar | 
| 751     ext.backgroundPage.sendMessage({ | 748     ext.backgroundPage.sendMessage({ | 
| 752       type: "app.get", | 749       type: "app.get", | 
| 753       what: "addonVersion" | 750       what: "addonVersion" | 
| 754     }, | 751     }, | 
| 755     addonVersion => | 752     (addonVersion) => | 
| 756     { | 753     { | 
| 757       E("abp-version").textContent = addonVersion; | 754       E("abp-version").textContent = addonVersion; | 
| 758     }); | 755     }); | 
| 759     getDocLink("releases", link => | 756     getDocLink("releases", (link) => | 
| 760     { | 757     { | 
| 761       E("link-version").setAttribute("href", link); | 758       E("link-version").setAttribute("href", link); | 
| 762     }); | 759     }); | 
| 763 | 760 | 
| 764     updateShareLink(); | 761     updateShareLink(); | 
| 765     updateTooltips(); | 762     updateTooltips(); | 
| 766 | 763 | 
| 767     // Initialize interactive UI elements | 764     // Initialize interactive UI elements | 
| 768     document.body.addEventListener("click", onClick, false); | 765     document.body.addEventListener("click", onClick, false); | 
| 769     document.body.addEventListener("keyup", onKeyUp, false); | 766     document.body.addEventListener("keyup", onKeyUp, false); | 
| 770     let placeholderValue = getMessage("options_dialog_language_find"); | 767     let placeholderValue = getMessage("options_dialog_language_find"); | 
| 771     E("find-language").setAttribute("placeholder", placeholderValue); | 768     E("find-language").setAttribute("placeholder", placeholderValue); | 
| 772     E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); | 769     E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); | 
| 773     E("whitelisting-textbox").addEventListener("keypress", e => | 770     E("whitelisting-textbox").addEventListener("keypress", (e) => | 
| 774     { | 771     { | 
| 775       if (getKey(e) == "Enter") | 772       if (getKey(e) == "Enter") | 
| 776         addWhitelistedDomain(); | 773         addWhitelistedDomain(); | 
| 777     }, false); | 774     }, false); | 
| 778 | 775 | 
| 779     // Advanced tab | 776     // Advanced tab | 
| 780     let tweaks = document.querySelectorAll("#tweaks li[data-pref]"); | 777     let tweaks = document.querySelectorAll("#tweaks li[data-pref]"); | 
| 781     tweaks = Array.prototype.map.call(tweaks, checkbox => | 778     tweaks = Array.prototype.map.call(tweaks, (checkbox) => | 
| 782     { | 779     { | 
| 783       return checkbox.getAttribute("data-pref"); | 780       return checkbox.getAttribute("data-pref"); | 
| 784     }); | 781     }); | 
| 785     tweaks.forEach(key => | 782     for (let key of tweaks) | 
| 786     { | 783     { | 
| 787       getPref(key, value => | 784       getPref(key, (value) => | 
| 788       { | 785       { | 
| 789         onPrefMessage(key, value, true); | 786         onPrefMessage(key, value, true); | 
| 790       }); | 787       }); | 
| 791     }); | 788     } | 
| 792     ext.backgroundPage.sendMessage({ | 789     ext.backgroundPage.sendMessage({ | 
| 793       type: "app.get", | 790       type: "app.get", | 
| 794       what: "features" | 791       what: "features" | 
| 795     }, | 792     }, | 
| 796     features => | 793     (features) => | 
| 797     { | 794     { | 
| 798       hidePref("show_devtools_panel", !features.devToolsPanel); | 795       hidePref("show_devtools_panel", !features.devToolsPanel); | 
| 799     }); | 796     }); | 
| 800 | 797 | 
| 801     let filterTextbox = document.querySelector("#custom-filters-add input"); | 798     let filterTextbox = document.querySelector("#custom-filters-add input"); | 
| 802     placeholderValue = getMessage("options_customFilters_textbox_placeholder"); | 799     placeholderValue = getMessage("options_customFilters_textbox_placeholder"); | 
| 803     filterTextbox.setAttribute("placeholder", placeholderValue); | 800     filterTextbox.setAttribute("placeholder", placeholderValue); | 
| 804     function addCustomFilters() | 801     function addCustomFilters() | 
| 805     { | 802     { | 
| 806       let filterText = filterTextbox.value; | 803       let filterText = filterTextbox.value; | 
| 807       sendMessageHandleErrors({ | 804       sendMessageHandleErrors({ | 
| 808         type: "filters.add", | 805         type: "filters.add", | 
| 809         text: filterText | 806         text: filterText | 
| 810       }, | 807       }, | 
| 811       () => | 808       () => | 
| 812       { | 809       { | 
| 813         filterTextbox.value = ""; | 810         filterTextbox.value = ""; | 
| 814       }); | 811       }); | 
| 815     } | 812     } | 
| 816     E("custom-filters-add").addEventListener("submit", e => | 813     E("custom-filters-add").addEventListener("submit", (e) => | 
| 817     { | 814     { | 
| 818       e.preventDefault(); | 815       e.preventDefault(); | 
| 819       addCustomFilters(); | 816       addCustomFilters(); | 
| 820     }, false); | 817     }, false); | 
|  | 818 | 
|  | 819     // Help tab | 
|  | 820     getDocLink("faq", (link) => | 
|  | 821     { | 
|  | 822       E("link-faq").setAttribute("href", link); | 
|  | 823     }); | 
|  | 824     getDocLink("social_twitter", (link) => | 
|  | 825     { | 
|  | 826       E("link-twitter").setAttribute("href", link); | 
|  | 827     }); | 
|  | 828     getDocLink("social_facebook", (link) => | 
|  | 829     { | 
|  | 830       E("link-facebook").setAttribute("href", link); | 
|  | 831     }); | 
|  | 832     getDocLink("social_gplus", (link) => | 
|  | 833     { | 
|  | 834       E("link-gplus").setAttribute("href", link); | 
|  | 835     }); | 
|  | 836     getDocLink("social_renren", (link) => | 
|  | 837     { | 
|  | 838       E("link-renren").setAttribute("href", link); | 
|  | 839     }); | 
|  | 840     getDocLink("social_weibo", (link) => | 
|  | 841     { | 
|  | 842       E("link-weibo").setAttribute("href", link); | 
|  | 843     }); | 
|  | 844 | 
|  | 845     // Set forum link | 
|  | 846     ext.backgroundPage.sendMessage({ | 
|  | 847       type: "app.get", | 
|  | 848       what: "platform" | 
|  | 849     }, | 
|  | 850     (platform) => | 
|  | 851     { | 
|  | 852       ext.backgroundPage.sendMessage({ | 
|  | 853         type: "app.get", | 
|  | 854         what: "application" | 
|  | 855       }, | 
|  | 856       (application) => | 
|  | 857       { | 
|  | 858         if (platform == "chromium" && application != "opera") | 
|  | 859           application = "chrome"; | 
|  | 860 | 
|  | 861         getDocLink(application + "_support", (link) => | 
|  | 862         { | 
|  | 863           E("link-forum").setAttribute("href", link); | 
|  | 864         }); | 
|  | 865       }); | 
|  | 866     }); | 
| 821 | 867 | 
| 822     E("dialog").addEventListener("keydown", function(e) | 868     E("dialog").addEventListener("keydown", function(e) | 
| 823     { | 869     { | 
| 824       switch (getKey(e)) | 870       switch (getKey(e)) | 
| 825       { | 871       { | 
| 826         case "Escape": | 872         case "Escape": | 
| 827           closeDialog(); | 873           closeDialog(); | 
| 828           break; | 874           break; | 
| 829         case "Tab": | 875         case "Tab": | 
| 830           if (e.shiftKey) | 876           if (e.shiftKey) | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 879     filtersMap = Object.create(null); | 925     filtersMap = Object.create(null); | 
| 880 | 926 | 
| 881     // Empty collections and lists | 927     // Empty collections and lists | 
| 882     for (let property in collections) | 928     for (let property in collections) | 
| 883       collections[property].clearAll(); | 929       collections[property].clearAll(); | 
| 884 | 930 | 
| 885     ext.backgroundPage.sendMessage({ | 931     ext.backgroundPage.sendMessage({ | 
| 886       type: "subscriptions.get", | 932       type: "subscriptions.get", | 
| 887       special: true | 933       special: true | 
| 888     }, | 934     }, | 
| 889     subscriptions => | 935     (subscriptions) => | 
| 890     { | 936     { | 
| 891       // Load filters | 937       // Load filters | 
| 892       for (let i = 0; i < subscriptions.length; i++) | 938       for (let subscription of subscriptions) | 
| 893       { | 939       { | 
| 894         ext.backgroundPage.sendMessage({ | 940         ext.backgroundPage.sendMessage({ | 
| 895           type: "filters.get", | 941           type: "filters.get", | 
| 896           subscriptionUrl: subscriptions[i].url | 942           subscriptionUrl: subscription.url | 
| 897         }, | 943         }, | 
| 898         filters => | 944         (filters) => | 
| 899         { | 945         { | 
| 900           for (let filter of filters) | 946           for (let filter of filters) | 
| 901             updateFilter(filter); | 947             updateFilter(filter); | 
| 902         }); | 948         }); | 
| 903       } | 949       } | 
| 904     }); | 950     }); | 
| 905     loadRecommendations(); | 951     loadRecommendations(); | 
| 906     ext.backgroundPage.sendMessage({ | 952     ext.backgroundPage.sendMessage({ | 
| 907       type: "prefs.get", | 953       type: "prefs.get", | 
| 908       key: "subscriptions_exceptionsurl" | 954       key: "subscriptions_exceptionsurl" | 
| 909     }, | 955     }, | 
| 910     url => | 956     (url) => | 
| 911     { | 957     { | 
| 912       acceptableAdsUrl = url; | 958       acceptableAdsUrl = url; | 
| 913       addSubscription({ | 959       addSubscription({ | 
| 914         url: acceptableAdsUrl, | 960         url: acceptableAdsUrl, | 
| 915         disabled: true | 961         disabled: true | 
| 916       }); | 962       }); | 
| 917 | 963 | 
| 918       // Load user subscriptions | 964       // Load user subscriptions | 
| 919       ext.backgroundPage.sendMessage({ | 965       ext.backgroundPage.sendMessage({ | 
| 920         type: "subscriptions.get", | 966         type: "subscriptions.get", | 
| 921         downloadable: true | 967         downloadable: true | 
| 922       }, | 968       }, | 
| 923       subscriptions => | 969       (subscriptions) => | 
| 924       { | 970       { | 
| 925         for (let i = 0; i < subscriptions.length; i++) | 971         for (let subscription of subscriptions) | 
| 926           onSubscriptionMessage("added", subscriptions[i]); | 972           onSubscriptionMessage("added", subscription); | 
| 927       }); | 973       }); | 
| 928     }); | 974     }); | 
| 929   } | 975   } | 
| 930 | 976 | 
| 931   function addWhitelistedDomain() | 977   function addWhitelistedDomain() | 
| 932   { | 978   { | 
| 933     let domain = E("whitelisting-textbox"); | 979     let domain = E("whitelisting-textbox"); | 
| 934     if (domain.value) | 980     if (domain.value) | 
| 935     { | 981     { | 
| 936       sendMessageHandleErrors({ | 982       sendMessageHandleErrors({ | 
| 937         type: "filters.add", | 983         type: "filters.add", | 
| 938         text: "@@||" + domain.value.toLowerCase() + "^$document" | 984         text: "@@||" + domain.value.toLowerCase() + "^$document" | 
| 939       }); | 985       }); | 
| 940     } | 986     } | 
| 941 | 987 | 
| 942     domain.value = ""; | 988     domain.value = ""; | 
| 943     document.querySelector("#whitelisting .controls"). | 989     document.querySelector("#whitelisting .controls") | 
| 944       classList.remove("mode-edit"); | 990       .classList.remove("mode-edit"); | 
| 945   } | 991   } | 
| 946 | 992 | 
| 947   function editCustomFilters() | 993   function editCustomFilters() | 
| 948   { | 994   { | 
| 949     let customFilterItems = collections.customFilters.items; |  | 
| 950     let filterTexts = []; | 995     let filterTexts = []; | 
| 951     for (let i = 0; i < customFilterItems.length; i++) | 996     for (let customFilterItem of collections.customFilters.items) | 
| 952       filterTexts.push(customFilterItems[i].text); | 997       filterTexts.push(customFilterItem.text); | 
| 953     E("custom-filters-raw").value = filterTexts.join("\n"); | 998     E("custom-filters-raw").value = filterTexts.join("\n"); | 
| 954   } | 999   } | 
| 955 | 1000 | 
| 956   function addEnableSubscription(url, title, homepage) | 1001   function addEnableSubscription(url, title, homepage) | 
| 957   { | 1002   { | 
| 958     let messageType = null; | 1003     let messageType = null; | 
| 959     let knownSubscription = subscriptionsMap[url]; | 1004     let knownSubscription = subscriptionsMap[url]; | 
| 960     if (knownSubscription && knownSubscription.disabled == true) | 1005     if (knownSubscription && knownSubscription.disabled == true) | 
| 961       messageType = "subscriptions.toggle"; | 1006       messageType = "subscriptions.toggle"; | 
| 962     else | 1007     else | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1050   function hidePref(key, value) | 1095   function hidePref(key, value) | 
| 1051   { | 1096   { | 
| 1052     let element = document.querySelector("[data-pref='" + key + "']"); | 1097     let element = document.querySelector("[data-pref='" + key + "']"); | 
| 1053     if (element) | 1098     if (element) | 
| 1054       element.setAttribute("aria-hidden", value); | 1099       element.setAttribute("aria-hidden", value); | 
| 1055   } | 1100   } | 
| 1056 | 1101 | 
| 1057   function getPref(key, callback) | 1102   function getPref(key, callback) | 
| 1058   { | 1103   { | 
| 1059     let checkPref = getPref.checks[key] || getPref.checkNone; | 1104     let checkPref = getPref.checks[key] || getPref.checkNone; | 
| 1060     checkPref(isActive => | 1105     checkPref((isActive) => | 
| 1061     { | 1106     { | 
| 1062       if (!isActive) | 1107       if (!isActive) | 
| 1063       { | 1108       { | 
| 1064         hidePref(key, !isActive); | 1109         hidePref(key, !isActive); | 
| 1065         return; | 1110         return; | 
| 1066       } | 1111       } | 
| 1067 | 1112 | 
| 1068       ext.backgroundPage.sendMessage({ | 1113       ext.backgroundPage.sendMessage({ | 
| 1069         type: "prefs.get", | 1114         type: "prefs.get", | 
| 1070         key | 1115         key | 
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1118     function onResult(isBlocked) | 1163     function onResult(isBlocked) | 
| 1119     { | 1164     { | 
| 1120       isAnyBlocked |= isBlocked; | 1165       isAnyBlocked |= isBlocked; | 
| 1121       if (!--checksRemaining) | 1166       if (!--checksRemaining) | 
| 1122       { | 1167       { | 
| 1123         // Hide the share tab if a script on the share page would be blocked | 1168         // Hide the share tab if a script on the share page would be blocked | 
| 1124         E("tab-share").hidden = isAnyBlocked; | 1169         E("tab-share").hidden = isAnyBlocked; | 
| 1125       } | 1170       } | 
| 1126     } | 1171     } | 
| 1127 | 1172 | 
| 1128     for (let i = 0; i < shareResources.length; i++) | 1173     for (let sharedResource of shareResources) | 
| 1129       checkShareResource(shareResources[i], onResult); | 1174       checkShareResource(sharedResource, onResult); | 
| 1130   } | 1175   } | 
| 1131 | 1176 | 
| 1132   function getMessages(id) | 1177   function getMessages(id) | 
| 1133   { | 1178   { | 
| 1134     let messages = []; | 1179     let messages = []; | 
| 1135     for (let i = 1, message = ext.i18n.getMessage(id + "_" + i); message; i++) | 1180     for (let i = 1; true; i++) | 
|  | 1181     { | 
|  | 1182       let message = ext.i18n.getMessage(id + "_" + i); | 
|  | 1183       if (!message) | 
|  | 1184         break; | 
|  | 1185 | 
| 1136       messages.push(message); | 1186       messages.push(message); | 
|  | 1187     } | 
| 1137     return messages; | 1188     return messages; | 
| 1138   } | 1189   } | 
| 1139 | 1190 | 
| 1140   function updateTooltips() | 1191   function updateTooltips() | 
| 1141   { | 1192   { | 
| 1142     let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]"); | 1193     let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]"); | 
| 1143     for (let i = 0; i < anchors.length; i++) | 1194     for (let anchor of anchors) | 
| 1144     { | 1195     { | 
| 1145       let anchor = anchors[i]; |  | 
| 1146       let id = anchor.getAttribute("data-tooltip"); | 1196       let id = anchor.getAttribute("data-tooltip"); | 
| 1147 | 1197 | 
| 1148       let wrapper = document.createElement("div"); | 1198       let wrapper = document.createElement("div"); | 
| 1149       wrapper.className = "tooltip"; | 1199       wrapper.className = "tooltip"; | 
| 1150       anchor.parentNode.replaceChild(wrapper, anchor); | 1200       anchor.parentNode.replaceChild(wrapper, anchor); | 
| 1151       wrapper.appendChild(anchor); | 1201       wrapper.appendChild(anchor); | 
| 1152 | 1202 | 
| 1153       let topTexts = getMessages(id); | 1203       let topTexts = getMessages(id); | 
| 1154       let bottomTexts = getMessages(id + "_notes"); | 1204       let bottomTexts = getMessages(id + "_notes"); | 
| 1155 | 1205 | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 1171 | 1221 | 
| 1172       let imageSource = anchor.getAttribute("data-tooltip-image"); | 1222       let imageSource = anchor.getAttribute("data-tooltip-image"); | 
| 1173       if (imageSource) | 1223       if (imageSource) | 
| 1174       { | 1224       { | 
| 1175         let image = document.createElement("img"); | 1225         let image = document.createElement("img"); | 
| 1176         image.src = imageSource; | 1226         image.src = imageSource; | 
| 1177         image.alt = ""; | 1227         image.alt = ""; | 
| 1178         tooltip.appendChild(image); | 1228         tooltip.appendChild(image); | 
| 1179       } | 1229       } | 
| 1180 | 1230 | 
| 1181       for (let j = 0; j < topTexts.length; j++) | 1231       for (let topText of topTexts) | 
| 1182       { | 1232       { | 
| 1183         let paragraph = document.createElement("p"); | 1233         let paragraph = document.createElement("p"); | 
| 1184         paragraph.innerHTML = topTexts[j]; | 1234         paragraph.innerHTML = topText; | 
| 1185         tooltip.appendChild(paragraph); | 1235         tooltip.appendChild(paragraph); | 
| 1186       } | 1236       } | 
| 1187       if (bottomTexts.length > 0) | 1237       if (bottomTexts.length > 0) | 
| 1188       { | 1238       { | 
| 1189         let notes = document.createElement("div"); | 1239         let notes = document.createElement("div"); | 
| 1190         notes.className = "notes"; | 1240         notes.className = "notes"; | 
| 1191         for (let j = 0; j < bottomTexts.length; j++) | 1241         for (let bottomText of bottomTexts) | 
| 1192         { | 1242         { | 
| 1193           let paragraph = document.createElement("p"); | 1243           let paragraph = document.createElement("p"); | 
| 1194           paragraph.innerHTML = bottomTexts[j]; | 1244           paragraph.innerHTML = bottomText; | 
| 1195           notes.appendChild(paragraph); | 1245           notes.appendChild(paragraph); | 
| 1196         } | 1246         } | 
| 1197         tooltip.appendChild(notes); | 1247         tooltip.appendChild(notes); | 
| 1198       } | 1248       } | 
| 1199 | 1249 | 
| 1200       wrapper.appendChild(tooltip); | 1250       wrapper.appendChild(tooltip); | 
| 1201     } | 1251     } | 
| 1202   } | 1252   } | 
| 1203 | 1253 | 
| 1204   ext.onMessage.addListener(message => | 1254   ext.onMessage.addListener((message) => | 
| 1205   { | 1255   { | 
| 1206     switch (message.type) | 1256     switch (message.type) | 
| 1207     { | 1257     { | 
| 1208       case "app.respond": | 1258       case "app.respond": | 
| 1209         switch (message.action) | 1259         switch (message.action) | 
| 1210         { | 1260         { | 
| 1211           case "addSubscription": | 1261           case "addSubscription": | 
| 1212             let subscription = message.args[0]; | 1262             let subscription = message.args[0]; | 
| 1213             let dialog = E("dialog-content-predefined"); | 1263             let dialog = E("dialog-content-predefined"); | 
| 1214             dialog.querySelector("h3").textContent = subscription.title || ""; | 1264             dialog.querySelector("h3").textContent = subscription.title || ""; | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1247   }); | 1297   }); | 
| 1248   ext.backgroundPage.sendMessage({ | 1298   ext.backgroundPage.sendMessage({ | 
| 1249     type: "subscriptions.listen", | 1299     type: "subscriptions.listen", | 
| 1250     filter: ["added", "disabled", "homepage", "lastDownload", "removed", | 1300     filter: ["added", "disabled", "homepage", "lastDownload", "removed", | 
| 1251              "title", "downloadStatus", "downloading"] | 1301              "title", "downloadStatus", "downloading"] | 
| 1252   }); | 1302   }); | 
| 1253 | 1303 | 
| 1254   window.addEventListener("DOMContentLoaded", onDOMLoaded, false); | 1304   window.addEventListener("DOMContentLoaded", onDOMLoaded, false); | 
| 1255   window.addEventListener("hashchange", onHashChange, false); | 1305   window.addEventListener("hashchange", onHashChange, false); | 
| 1256 } | 1306 } | 
| LEFT | RIGHT | 
|---|