OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2015 Eyeo GmbH |
| 4 * |
| 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 |
| 7 * published by the Free Software Foundation. |
| 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 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/>. |
| 16 */ |
| 17 |
| 18 "use strict"; |
| 19 |
| 20 (function() |
| 21 { |
| 22 var acceptableAdsUrl = null; |
| 23 |
| 24 var optionObj = |
| 25 { |
| 26 collections: |
| 27 { |
| 28 push: function() |
| 29 { |
| 30 var length = Array.prototype.push.apply(this, arguments); |
| 31 this.sort(function(a, b) |
| 32 { |
| 33 var aValue = (a.title || a.url || a.text).toLowerCase(); |
| 34 var bValue = (b.title || b.url || a.text).toLowerCase(); |
| 35 if (aValue < bValue) |
| 36 return -1; |
| 37 if (aValue > bValue) |
| 38 return 1; |
| 39 return 0; |
| 40 }); |
| 41 for (var i=0; i < arguments.length; i++) |
| 42 { |
| 43 for (var j=0; j < this.table.length; j++) |
| 44 { |
| 45 var object = arguments[i]; |
| 46 var text = object.title || object.text; |
| 47 var access = object.url || object.text; |
| 48 var index = this.indexOf(object); |
| 49 var table = E(this.table[j].id); |
| 50 var template = this.table[j].template; |
| 51 var listener = this.table[j].listener; |
| 52 |
| 53 var list = document.createElement("li"); |
| 54 list.innerHTML = template; |
| 55 list.dataset.access = access; |
| 56 list.getElementsByClassName("display")[0].textContent = text; |
| 57 if (object.isAdsType) |
| 58 list.dataset.value = text.toLowerCase(); |
| 59 |
| 60 var control = list.getElementsByClassName("control")[0]; |
| 61 if (control) |
| 62 { |
| 63 control.addEventListener("click", listener, false); |
| 64 control.checked = !object.disabled; |
| 65 } |
| 66 if (table.hasChildNodes) |
| 67 table.insertBefore(list, table.childNodes[index]); |
| 68 else |
| 69 table.appendChild(list); |
| 70 } |
| 71 } |
| 72 return length; |
| 73 }, |
| 74 remove: function(obj) |
| 75 { |
| 76 var index = this.indexOf(obj); |
| 77 this.splice(index, 1); |
| 78 var access = obj.url || obj.text; |
| 79 for (var i=0; i < this.table.length; i++) |
| 80 { |
| 81 var table = E(this.table[i].id); |
| 82 var element = table.querySelector("[data-access='"+access+"']"); |
| 83 element.parentElement.removeChild(element); |
| 84 } |
| 85 } |
| 86 }, |
| 87 subscriptions: { |
| 88 getArray: function(subscription) |
| 89 { |
| 90 var collArray = null; |
| 91 if (subscription.isPopular) |
| 92 collArray = collections.popular; |
| 93 else if (subscription.isAdsType && subscription.disabled) |
| 94 collArray = collections.allLangs; |
| 95 else if (subscription.isAdsType && !subscription.disabled) |
| 96 collArray = collections.langs; |
| 97 else if (subscription.url == acceptableAdsUrl) |
| 98 collArray = collections.acceptableAds; |
| 99 else |
| 100 collArray = collections.custom; |
| 101 return collArray; |
| 102 }, |
| 103 update: function(subscription) |
| 104 { |
| 105 var optionSubscription = this[subscription.url]; |
| 106 if (optionSubscription) |
| 107 optionSubscription.disabled = subscription.disabled; |
| 108 else |
| 109 { |
| 110 var collArray = this.getArray(subscription); |
| 111 optionObj.observe(subscription, ["disabled"]); |
| 112 collArray.push = collections.push; |
| 113 collArray.push(subscription); |
| 114 this[subscription.url] = subscription; |
| 115 } |
| 116 }, |
| 117 remove: function(subscription) |
| 118 { |
| 119 var optionSubscription = this[subscription.url]; |
| 120 |
| 121 if (optionSubscription.isAdsType) |
| 122 { |
| 123 collections.langs.remove(optionSubscription); |
| 124 collections.allLangs.push(optionSubscription); |
| 125 } |
| 126 else if(optionSubscription.isPopular) |
| 127 { |
| 128 optionSubscription.disabled = true; |
| 129 } |
| 130 else |
| 131 { |
| 132 collections.custom.remove(optionSubscription); |
| 133 } |
| 134 }, |
| 135 chboxListener: function(e) |
| 136 { |
| 137 e.preventDefault(); |
| 138 var target = e.target; |
| 139 var isChecked = target.checked; |
| 140 var url = e.target.parentNode.dataset.access; |
| 141 if (!isChecked) |
| 142 SendMessage.removeSubscription(url); |
| 143 else |
| 144 SendMessage.addSubscription(url); |
| 145 }, |
| 146 acceptableAdsListener: function(e) |
| 147 { |
| 148 e.preventDefault(); |
| 149 var target = e.target; |
| 150 var isChecked = target.checked; |
| 151 var url = e.target.parentNode.dataset.access; |
| 152 |
| 153 if (isChecked) |
| 154 SendMessage.addSubscription(url); |
| 155 else |
| 156 SendMessage.removeSubscription(url); |
| 157 }, |
| 158 addBtnListener: function(e) |
| 159 { |
| 160 e.preventDefault(); |
| 161 var url = this.parentNode.dataset.access; |
| 162 SendMessage.addSubscription(url); |
| 163 } |
| 164 }, |
| 165 filters: |
| 166 { |
| 167 update: function(filter) |
| 168 { |
| 169 var optionFilter = this[filter.text]; |
| 170 var match = filter.text.match(/^@@\|\|([^\/:]+)\^\$document$/); |
| 171 if (match && !optionFilter) |
| 172 { |
| 173 filter.title = match[1]; |
| 174 collections.whitelist.push(filter); |
| 175 this[filter.text] = filter; |
| 176 } |
| 177 else |
| 178 { |
| 179 // TODO: add `filters[i].text` to list of custom filters |
| 180 } |
| 181 }, |
| 182 remove: function(filter) |
| 183 { |
| 184 collections.whitelist.remove(filter); |
| 185 }, |
| 186 deleteBtnClick: function() |
| 187 { |
| 188 var filter = this.parentNode.dataset.access; |
| 189 SendMessage.removeFilter(filter); |
| 190 } |
| 191 }, |
| 192 observe: function(obj, props) |
| 193 { |
| 194 props.forEach(function(property) |
| 195 { |
| 196 obj["__"+property] = obj[property]; |
| 197 Object.defineProperty(obj, property, |
| 198 { |
| 199 get: function() |
| 200 { |
| 201 return this["__"+property]; |
| 202 }, |
| 203 set: function(value) |
| 204 { |
| 205 this["__"+property] = value; |
| 206 var access = obj.url || obj.text; |
| 207 var elements = document.querySelectorAll("[data-access='" + access +
"']"); |
| 208 for (var i=0; i < elements.length; i++) |
| 209 { |
| 210 var elem = elements[i]; |
| 211 var control = elem.getElementsByClassName("control")[0]; |
| 212 if (control.tagName == "INPUT") |
| 213 control.checked = !obj.disabled; |
| 214 if (obj.isAdsType) |
| 215 { |
| 216 collections.allLangs.remove(obj); |
| 217 collections.langs.push(obj); |
| 218 } |
| 219 } |
| 220 } |
| 221 }); |
| 222 }); |
| 223 } |
| 224 }; |
| 225 |
| 226 function createCollArray(tables) |
| 227 { |
| 228 var array = []; |
| 229 array.push = optionObj.collections.push; |
| 230 array.remove = optionObj.collections.remove; |
| 231 array.table = tables; |
| 232 return array; |
| 233 } |
| 234 |
| 235 var collections = optionObj.collections; |
| 236 collections.popular = createCollArray([ |
| 237 { |
| 238 id: "recommend-list-table", |
| 239 template: "<input type='checkbox' class='control' /><span class='display'>
</span><span class='popular'>popular</span>", |
| 240 listener: optionObj.subscriptions.chboxListener |
| 241 } |
| 242 ]); |
| 243 collections.langs = createCollArray([ |
| 244 { |
| 245 id: "blocking-languages-table", |
| 246 template: "<input type='checkbox' class='control' /><span class='display'>
</span>", |
| 247 listener: optionObj.subscriptions.chboxListener |
| 248 }, |
| 249 { |
| 250 id: "blocking-languages-modal-table", |
| 251 template: "<span class='display'></span>" |
| 252 } |
| 253 ]); |
| 254 collections.allLangs = createCollArray([ |
| 255 { |
| 256 id: "all-lang-table", |
| 257 template: "<button class='button-add control'><span>+add</span></button><s
pan class='display'></span>", |
| 258 listener: optionObj.subscriptions.addBtnListener |
| 259 } |
| 260 ]); |
| 261 collections.acceptableAds = createCollArray([ |
| 262 { |
| 263 id: "acceptableads-table", |
| 264 template: "<input type='checkbox' class='control' /><span class='display'>
</span>", |
| 265 listener: optionObj.subscriptions.acceptableAdsListener |
| 266 } |
| 267 ]); |
| 268 collections.custom = createCollArray([ |
| 269 { |
| 270 id: "custom-list-table", |
| 271 template: "<input type='checkbox' class='control' /><span class='display'>
</span>", |
| 272 listener: optionObj.subscriptions.chboxListener |
| 273 } |
| 274 ]); |
| 275 collections.whitelist = createCollArray([ |
| 276 { |
| 277 id: "whitelisting-table", |
| 278 template: "<button class='delete control'></button><span class='display'><
/span>", |
| 279 listener: optionObj.filters.deleteBtnClick |
| 280 } |
| 281 ]); |
| 282 |
| 283 var Recommendations = |
| 284 { |
| 285 load: function() |
| 286 { |
| 287 var request = new XMLHttpRequest(); |
| 288 request.open("GET", "subscriptions.xml", false); |
| 289 request.onload = function() |
| 290 { |
| 291 var list = document.getElementById("subscriptionSelector"); |
| 292 var docElem = request.responseXML.documentElement; |
| 293 var elements = docElem.getElementsByTagName("subscription"); |
| 294 for (var i = 0; i < elements.length; i++) |
| 295 { |
| 296 var element = elements[i]; |
| 297 var subscription = Object.create(null); |
| 298 subscription.title = element.getAttribute("title"); |
| 299 subscription.url = element.getAttribute("url"); |
| 300 subscription.disabled = true; |
| 301 var prefix = element.getAttribute("prefixes"); |
| 302 if (prefix) |
| 303 { |
| 304 subscription.isAdsType = true; |
| 305 var prefix = element.getAttribute("prefixes").replace(/,/g, '_'); |
| 306 subscription.title = ext.i18n.getMessage("options_language_" + prefi
x); |
| 307 } |
| 308 else |
| 309 subscription.title = element.getAttribute("specialization"); |
| 310 |
| 311 if (element.getAttribute("popular")) |
| 312 subscription.isPopular = true; |
| 313 optionObj.subscriptions.update(subscription); |
| 314 } |
| 315 }.bind(this); |
| 316 request.send(); |
| 317 } |
| 318 }; |
| 319 |
| 320 function onDOMLoaded() |
| 321 { |
| 322 updateShareLink(); |
| 323 populateLists(); |
| 324 |
| 325 var tabList = document.querySelectorAll("#main-navigation-tabs li"); |
| 326 for (var i = 0; i < tabList.length; ++i) |
| 327 { |
| 328 tabList[i].addEventListener("click", function(ev) |
| 329 { |
| 330 document.body.dataset.tab = this.id.substr(4); |
| 331 }, false); |
| 332 } |
| 333 |
| 334 var searchLanguage = function() |
| 335 { |
| 336 var searchStyle = document.getElementById('search_style'); |
| 337 var searchVal = this.value; |
| 338 if (!searchVal) |
| 339 searchStyle.innerHTML = ""; |
| 340 else |
| 341 searchStyle.innerHTML = "#all-lang-table li:not([data-value*=\"" + this.
value.toLowerCase() + "\"]) { display: none; }"; |
| 342 }; |
| 343 |
| 344 // Update version number in navigation sidebar |
| 345 ext.backgroundPage.sendMessage({ |
| 346 method: "app.get", |
| 347 what: "addonVersion" |
| 348 }, function(addonVersion) |
| 349 { |
| 350 E("abp-version").textContent = addonVersion; |
| 351 }); |
| 352 |
| 353 var whitelistDomainBtnClick = function() |
| 354 { |
| 355 var domain = E("whitelisting-textbox").value; |
| 356 if (domain) |
| 357 SendMessage.addWhitelistedDomain(domain); |
| 358 E("whitelisting-textbox").value = ""; |
| 359 }; |
| 360 |
| 361 var placeholderValue = ext.i18n.getMessage("options_modal_language_find"); |
| 362 E("find-language").setAttribute("placeholder", placeholderValue); |
| 363 setLinks("block-element-explanation", "#"); |
| 364 |
| 365 E("add-blocking-list").addEventListener("click", function() |
| 366 { |
| 367 openModal("customlist"); |
| 368 }, false); |
| 369 E("add-website-language").addEventListener("click", function() |
| 370 { |
| 371 openModal("language"); |
| 372 }, false); |
| 373 E("modal-close").addEventListener("click", function() |
| 374 { |
| 375 delete document.body.dataset.modal; |
| 376 }, false); |
| 377 E("edit-ownBlockingList-btn").addEventListener("click", editOwnRulsBtnClick,
false); |
| 378 E("find-language").addEventListener("keyup", searchLanguage, false); |
| 379 E("whitelisting-add-icon").addEventListener("click", whitelistDomainBtnClick
, false); |
| 380 E("whitelisting-add-btn").addEventListener("click", whitelistDomainBtnClick,
false); |
| 381 E("whitelisting-enter-icon").addEventListener("click", whitelistDomainBtnCli
ck, false); |
| 382 E("whitelisting-textbox").addEventListener("keypress", function(e) |
| 383 { |
| 384 if (e.keyCode == 13) |
| 385 whitelistDomainBtnClick(); |
| 386 }, false); |
| 387 E("whitelisting-cancel-btn").addEventListener("click", function() |
| 388 { |
| 389 E("whitelisting-textbox").value = ""; |
| 390 }, false); |
| 391 E("import-blockingList-btn").addEventListener("click", function() |
| 392 { |
| 393 var url = E("blockingList-textbox").value; |
| 394 SendMessage.addSubscription(url); |
| 395 delete document.body.dataset.modal; |
| 396 }, false); |
| 397 } |
| 398 |
| 399 function openModal(name) |
| 400 { |
| 401 document.body.dataset.modal = name; |
| 402 var title = "options_modal_" + name + "_title"; |
| 403 E("modal-title").textContent = ext.i18n.getMessage(title); |
| 404 } |
| 405 |
| 406 function populateLists() |
| 407 { |
| 408 ext.backgroundPage.sendMessage( |
| 409 { |
| 410 type: "subscriptions.get", |
| 411 special: true |
| 412 }, function(subscriptions) |
| 413 { |
| 414 // Load filters |
| 415 for (var i = 0; i < subscriptions.length; i++) |
| 416 { |
| 417 ext.backgroundPage.sendMessage( |
| 418 { |
| 419 type: "filters.get", |
| 420 subscriptionUrl: subscriptions[i].url |
| 421 }, function(filters) |
| 422 { |
| 423 for (var i = 0; i < filters.length; i++) |
| 424 optionObj.filters.update(filters[i]); |
| 425 }); |
| 426 } |
| 427 }); |
| 428 Recommendations.load(); |
| 429 SendMessage.getAcceptableAdsURL(function(url) |
| 430 { |
| 431 acceptableAdsUrl = url; |
| 432 var subscription = Object.create(null); |
| 433 subscription.url = acceptableAdsUrl; |
| 434 subscription.disabled = true; |
| 435 subscription.title = ext.i18n.getMessage("options_acceptableAds_descriptio
n"); |
| 436 optionObj.subscriptions.update(subscription); |
| 437 |
| 438 // Load user subscriptions |
| 439 ext.backgroundPage.sendMessage( |
| 440 { |
| 441 type: "subscriptions.get", |
| 442 downloadable: true |
| 443 }, function(subscriptions) |
| 444 { |
| 445 for (var i = 0; i < subscriptions.length; i++) |
| 446 MessageListeners.onSubscriptionMessage("added", subscriptions[i]); |
| 447 }); |
| 448 }); |
| 449 } |
| 450 |
| 451 function editOwnRulsBtnClick() |
| 452 { |
| 453 |
| 454 } |
| 455 |
| 456 var SendMessage = |
| 457 { |
| 458 getAcceptableAdsURL: function(callback) |
| 459 { |
| 460 ext.backgroundPage.sendMessage( |
| 461 { |
| 462 type: "prefs.get", |
| 463 key: "subscriptions_exceptionsurl" |
| 464 }, function(value) |
| 465 { |
| 466 SendMessage.getAcceptableAdsURL = function(callback) |
| 467 { |
| 468 callback(value); |
| 469 } |
| 470 SendMessage.getAcceptableAdsURL(callback); |
| 471 }); |
| 472 }, |
| 473 addSubscription: function(url, title, homepage) |
| 474 { |
| 475 var message = { |
| 476 type: "subscriptions.add", |
| 477 url: url |
| 478 }; |
| 479 if (title) |
| 480 message.title = title; |
| 481 if (homepage) |
| 482 message.homepage = homepage; |
| 483 |
| 484 ext.backgroundPage.sendMessage(message); |
| 485 }, |
| 486 removeSubscription: function(url) |
| 487 { |
| 488 ext.backgroundPage.sendMessage( |
| 489 { |
| 490 type: "subscriptions.remove", |
| 491 url: url |
| 492 }); |
| 493 }, |
| 494 addWhitelistedDomain: function(domain) |
| 495 { |
| 496 ext.backgroundPage.sendMessage( |
| 497 { |
| 498 type: "filters.add", |
| 499 text: "@@||" + domain.toLowerCase() + "^$document" |
| 500 }); |
| 501 }, |
| 502 removeFilter: function(filter) |
| 503 { |
| 504 ext.backgroundPage.sendMessage( |
| 505 { |
| 506 type: "filters.remove", |
| 507 text: filter |
| 508 }); |
| 509 } |
| 510 }; |
| 511 |
| 512 var MessageListeners = |
| 513 { |
| 514 onFilterMessage: function(action, filter) |
| 515 { |
| 516 switch (action) |
| 517 { |
| 518 case "added": |
| 519 optionObj.filters.update(filter); |
| 520 break; |
| 521 case "loaded": |
| 522 populateLists(); |
| 523 break; |
| 524 case "removed": |
| 525 optionObj.filters.remove(filter); |
| 526 break; |
| 527 } |
| 528 }, |
| 529 onSubscriptionMessage: function(action, subscription) |
| 530 { |
| 531 switch (action) |
| 532 { |
| 533 case "added": |
| 534 optionObj.subscriptions.update(subscription); |
| 535 break; |
| 536 case "disabled": |
| 537 break; |
| 538 case "homepage": |
| 539 // TODO: NYI |
| 540 break; |
| 541 case "removed": |
| 542 if (subscription.url == acceptableAdsUrl) |
| 543 { |
| 544 subscription.disabled = true; |
| 545 optionObj.subscriptions.update(subscription); |
| 546 } |
| 547 else |
| 548 optionObj.subscriptions.remove(subscription); |
| 549 break; |
| 550 case "title": |
| 551 // TODO: NYI |
| 552 break; |
| 553 } |
| 554 }, |
| 555 showAddSubscriptionDialog: function(subscription) |
| 556 { |
| 557 E("blockingList-textbox").value = subscription.url; |
| 558 openModal("customlist"); |
| 559 } |
| 560 }; |
| 561 |
| 562 function updateShareLink() |
| 563 { |
| 564 ext.backgroundPage.sendMessage( |
| 565 { |
| 566 type: "filters.blocked", |
| 567 url: "https://platform.twitter.com/widgets/", |
| 568 requestType: "SCRIPT", |
| 569 docDomain: "adblockplus.org", |
| 570 thirdParty: true |
| 571 }, function(blocked) |
| 572 { |
| 573 // TODO: modify "share" link accordingly |
| 574 }); |
| 575 } |
| 576 |
| 577 function getDocLink(link, callback) |
| 578 { |
| 579 ext.backgroundPage.sendMessage( |
| 580 { |
| 581 type: "app.get", |
| 582 what: "doclink", |
| 583 link: link |
| 584 }, callback); |
| 585 } |
| 586 |
| 587 function setLinks(id) |
| 588 { |
| 589 var element = E(id); |
| 590 if (!element) |
| 591 { |
| 592 return; |
| 593 } |
| 594 |
| 595 var links = element.getElementsByTagName("a"); |
| 596 |
| 597 for (var i = 0; i < links.length; i++) |
| 598 { |
| 599 if (typeof arguments[i + 1] == "string") |
| 600 { |
| 601 links[i].href = arguments[i + 1]; |
| 602 links[i].setAttribute("target", "_blank"); |
| 603 } |
| 604 else if (typeof arguments[i + 1] == "function") |
| 605 { |
| 606 links[i].href = "javascript:void(0);"; |
| 607 links[i].addEventListener("click", arguments[i + 1], false); |
| 608 } |
| 609 } |
| 610 } |
| 611 |
| 612 function E(id) |
| 613 { |
| 614 return document.getElementById(id); |
| 615 } |
| 616 |
| 617 ext.onMessage.addListener(function(message) |
| 618 { |
| 619 switch (message.type) |
| 620 { |
| 621 case "app.listen": |
| 622 if (message.action == "addSubscription") |
| 623 MessageListeners.showAddSubscriptionDialog(message.args[0]); |
| 624 break; |
| 625 case "filters.listen": |
| 626 MessageListeners.onFilterMessage(message.action, message.args[0]); |
| 627 break; |
| 628 case "subscriptions.listen": |
| 629 MessageListeners.onSubscriptionMessage(message.action, message.args[0]); |
| 630 break; |
| 631 } |
| 632 }); |
| 633 |
| 634 ext.backgroundPage.sendMessage( |
| 635 { |
| 636 type: "app.listen", |
| 637 filter: ["addSubscription"] |
| 638 }); |
| 639 ext.backgroundPage.sendMessage( |
| 640 { |
| 641 type: "filters.listen", |
| 642 filter: ["added", "loaded", "removed"] |
| 643 }); |
| 644 ext.backgroundPage.sendMessage( |
| 645 { |
| 646 type: "subscriptions.listen", |
| 647 filter: ["added", "disabled", "homepage", "removed", "title"] |
| 648 }); |
| 649 |
| 650 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); |
| 651 })(); |
OLD | NEW |