Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: options.js

Issue 29340737: Issue 3968 - Add "new-" prefix to option file names (Closed)
Patch Set: Updated sentence about firstRun parameters for consistency. Created April 22, 2016, 12:23 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « options.html ('k') | skin/new-options.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 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 subscriptionsMap = Object.create(null);
23 var recommendationsMap = Object.create(null);
24 var filtersMap = Object.create(null);
25 var collections = Object.create(null);
26 var acceptableAdsUrl = null;
27 var maxLabelId = 0;
28 var getMessage = ext.i18n.getMessage;
29 var filterErrors =
30 {
31 "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL",
32 "synchronize_connection_error": "options_filterList_lastDownload_connectionE rror",
33 "synchronize_invalid_data": "options_filterList_lastDownload_invalidData",
34 "synchronize_checksum_mismatch": "options_filterList_lastDownload_checksumMi smatch"
35 };
36
37 function Collection(details)
38 {
39 this.details = details;
40 this.items = [];
41 }
42
43 Collection.prototype._setEmpty = function(table, text)
44 {
45 var placeholder = table.querySelector(".empty-placeholder");
46 if (text && !placeholder)
47 {
48 placeholder = document.createElement("li");
49 placeholder.className = "empty-placeholder";
50 placeholder.textContent = getMessage(text);
51 table.appendChild(placeholder);
52 }
53 else if (placeholder)
54 table.removeChild(placeholder);
55 }
56
57 Collection.prototype._createElementQuery = function(item)
58 {
59 var access = (item.url || item.text).replace(/'/g, "\\'");
60 return function(container)
61 {
62 return container.querySelector("[data-access='" + access + "']");
63 };
64 };
65
66 Collection.prototype._getItemTitle = function(item, i)
67 {
68 if (item.url == acceptableAdsUrl)
69 return getMessage("options_acceptableAds_description");
70 if (this.details[i].useOriginalTitle && item.originalTitle)
71 return item.originalTitle;
72 return item.title || item.url || item.text;
73 };
74
75 Collection.prototype.addItems = function()
76 {
77 var length = Array.prototype.push.apply(this.items, arguments);
78 if (length == 0)
79 return;
80
81 this.items.sort(function(a, b)
82 {
83 // Make sure that Acceptable Ads is always last, since it cannot be
84 // disabled, but only be removed. That way it's grouped together with
85 // the "Own filter list" which cannot be disabled either at the bottom
86 // of the filter lists in the Advanced tab.
87 if (a.url == acceptableAdsUrl)
88 return 1;
89 if (b.url == acceptableAdsUrl)
90 return -1;
91
92 var aTitle = this._getItemTitle(a, 0).toLowerCase();
93 var bTitle = this._getItemTitle(b, 0).toLowerCase();
94 return aTitle.localeCompare(bTitle);
95 }.bind(this));
96
97 for (var j = 0; j < this.details.length; j++)
98 {
99 var table = E(this.details[j].id);
100 var template = table.querySelector("template");
101 for (var i = 0; i < arguments.length; i++)
102 {
103 var item = arguments[i];
104 var listItem = document.createElement("li");
105 listItem.appendChild(document.importNode(template.content, true));
106 listItem.setAttribute("data-access", item.url || item.text);
107
108 var labelId = "label-" + (++maxLabelId);
109 var label = listItem.querySelector(".display");
110 label.setAttribute("id", labelId);
111
112 var control = listItem.querySelector(".control");
113 if (control)
114 {
115 control.setAttribute("aria-labelledby", labelId);
116 control.addEventListener("click", this.details[j].onClick, false);
117
118 var role = control.getAttribute("role");
119 if (role == "checkbox" && !label.hasAttribute("data-action"))
120 {
121 var controlId = "control-" + maxLabelId;
122 control.setAttribute("id", controlId);
123 label.setAttribute("for", controlId);
124 }
125 }
126
127 this._setEmpty(table, null);
128 if (table.hasChildNodes())
129 {
130 table.insertBefore(listItem,
131 table.childNodes[this.items.indexOf(item)]);
132 }
133 else
134 table.appendChild(listItem);
135 this.updateItem(item);
136 }
137 }
138 return length;
139 };
140
141 Collection.prototype.removeItem = function(item)
142 {
143 var index = this.items.indexOf(item);
144 if (index == -1)
145 return;
146
147 this.items.splice(index, 1);
148 var getListElement = this._createElementQuery(item);
149 for (var i = 0; i < this.details.length; i++)
150 {
151 var table = E(this.details[i].id);
152 var element = getListElement(table);
153
154 // Element gets removed so make sure to handle focus appropriately
155 var control = element.querySelector(".control");
156 if (control && control == document.activeElement)
157 {
158 if (!focusNextElement(element.parentElement, control))
159 {
160 // Fall back to next focusable element within same tab or dialog
161 var focusableElement = element.parentElement;
162 while (focusableElement)
163 {
164 if (focusableElement.classList.contains("tab-content")
165 || focusableElement.classList.contains("dialog-content"))
166 break;
167
168 focusableElement = focusableElement.parentElement;
169 }
170 focusNextElement(focusableElement || document, control);
171 }
172 }
173
174 element.parentElement.removeChild(element);
175 if (this.items.length == 0)
176 this._setEmpty(table, this.details[i].emptyText);
177 }
178 };
179
180 Collection.prototype.updateItem = function(item)
181 {
182 var access = (item.url || item.text).replace(/'/g, "\\'");
183 for (var i = 0; i < this.details.length; i++)
184 {
185 var table = E(this.details[i].id);
186 var element = table.querySelector("[data-access='" + access + "']");
187 if (!element)
188 continue;
189
190 var title = this._getItemTitle(item, i);
191 element.querySelector(".display").textContent = title;
192 if (title)
193 element.setAttribute("data-search", title.toLowerCase());
194 var control = element.querySelector(".control[role='checkbox']");
195 if (control)
196 {
197 control.setAttribute("aria-checked", item.disabled == false);
198 if (item.url == acceptableAdsUrl && this.details[i].onClick ==
199 toggleDisableSubscription)
200 control.setAttribute("disabled", true);
201 }
202
203 var dateElement = element.querySelector(".date");
204 var timeElement = element.querySelector(".time");
205 if (dateElement && timeElement)
206 {
207 var message = element.querySelector(".message");
208 if (item.isDownloading)
209 {
210 var text = getMessage("options_filterList_lastDownload_inProgress");
211 message.textContent = text;
212 element.classList.add("show-message");
213 }
214 else if (item.downloadStatus != "synchronize_ok")
215 {
216 var error = filterErrors[item.downloadStatus];
217 if (error)
218 message.textContent = getMessage(error);
219 else
220 message.textContent = item.downloadStatus;
221 element.classList.add("show-message");
222 }
223 else if (item.lastDownload > 0)
224 {
225 var dateTime = i18n_formatDateTime(item.lastDownload * 1000);
226 dateElement.textContent = dateTime[0];
227 timeElement.textContent = dateTime[1];
228 element.classList.remove("show-message");
229 }
230 }
231
232 var websiteElement = element.querySelector(".context-menu .website");
233 if (websiteElement)
234 {
235 if (item.homepage)
236 websiteElement.setAttribute("href", item.homepage);
237 else
238 websiteElement.setAttribute("aria-hidden", true);
239 }
240
241 var sourceElement = element.querySelector(".context-menu .source");
242 if (sourceElement)
243 sourceElement.setAttribute("href", item.url);
244 }
245 };
246
247 Collection.prototype.clearAll = function()
248 {
249 this.items = [];
250 for (var i = 0; i < this.details.length; i++)
251 {
252 var table = E(this.details[i].id);
253 var element = table.firstChild;
254 while (element)
255 {
256 if (element.tagName == "LI" && !element.classList.contains("static"))
257 table.removeChild(element);
258 element = element.nextElementSibling;
259 }
260
261 this._setEmpty(table, this.details[i].emptyText);
262 }
263 };
264
265 function focusNextElement(container, currentElement)
266 {
267 var focusables = container.querySelectorAll("a, button, input, .control");
268 focusables = Array.prototype.slice.call(focusables);
269 var index = focusables.indexOf(currentElement);
270 index += (index == focusables.length - 1) ? -1 : 1;
271
272 var nextElement = focusables[index];
273 if (!nextElement)
274 return false;
275
276 nextElement.focus();
277 return true;
278 }
279
280 function toggleRemoveSubscription(e)
281 {
282 e.preventDefault();
283 var subscriptionUrl = findParentData(e.target, "access", false);
284 if (e.target.getAttribute("aria-checked") == "true")
285 {
286 ext.backgroundPage.sendMessage({
287 type: "subscriptions.remove",
288 url: subscriptionUrl
289 });
290 }
291 else
292 addEnableSubscription(subscriptionUrl);
293 }
294
295 function toggleDisableSubscription(e)
296 {
297 e.preventDefault();
298 var subscriptionUrl = findParentData(e.target, "access", false);
299 ext.backgroundPage.sendMessage(
300 {
301 type: "subscriptions.toggle",
302 keepInstalled: true,
303 url: subscriptionUrl
304 });
305 }
306
307 function onAddLanguageSubscriptionClick(e)
308 {
309 e.preventDefault();
310 var url = findParentData(this, "access", false);
311 addEnableSubscription(url);
312 }
313
314 function onRemoveFilterClick()
315 {
316 var filter = findParentData(this, "access", false);
317 ext.backgroundPage.sendMessage(
318 {
319 type: "filters.remove",
320 text: filter
321 });
322 }
323
324 collections.popular = new Collection(
325 [
326 {
327 id: "recommend-list-table",
328 onClick: toggleRemoveSubscription
329 }
330 ]);
331 collections.langs = new Collection(
332 [
333 {
334 id: "blocking-languages-table",
335 emptyText: "options_dialog_language_added_empty",
336 onClick: toggleRemoveSubscription
337 },
338 {
339 id: "blocking-languages-dialog-table",
340 emptyText: "options_dialog_language_added_empty"
341 }
342 ]);
343 collections.allLangs = new Collection(
344 [
345 {
346 id: "all-lang-table",
347 emptyText: "options_dialog_language_other_empty",
348 onClick: onAddLanguageSubscriptionClick
349 }
350 ]);
351 collections.acceptableAds = new Collection(
352 [
353 {
354 id: "acceptableads-table",
355 onClick: toggleRemoveSubscription
356 }
357 ]);
358 collections.custom = new Collection(
359 [
360 {
361 id: "custom-list-table",
362 onClick: toggleRemoveSubscription
363 }
364 ]);
365 collections.whitelist = new Collection(
366 [
367 {
368 id: "whitelisting-table",
369 emptyText: "options_whitelisted_empty",
370 onClick: onRemoveFilterClick
371 }
372 ]);
373 collections.customFilters = new Collection(
374 [
375 {
376 id: "custom-filters-table",
377 emptyText: "options_customFilters_empty"
378 }
379 ]);
380 collections.filterLists = new Collection(
381 [
382 {
383 id: "all-filter-lists-table",
384 onClick: toggleDisableSubscription,
385 useOriginalTitle: true
386 }
387 ]);
388
389 function observeSubscription(subscription)
390 {
391 function onObjectChanged(change)
392 {
393 for (var i = 0; i < change.length; i++)
394 {
395 if (change[i].name == "disabled")
396 {
397 var recommendation = recommendationsMap[subscription.url];
398 if (recommendation && recommendation.type == "ads")
399 {
400 if (subscription.disabled == false)
401 {
402 collections.allLangs.removeItem(subscription);
403 collections.langs.addItems(subscription);
404 }
405 else
406 {
407 collections.allLangs.addItems(subscription);
408 collections.langs.removeItem(subscription);
409 }
410 }
411 }
412 }
413
414 for (var name in collections)
415 collections[name].updateItem(subscription);
416 }
417
418 if (!Object.observe)
419 {
420 Object.keys(subscription).forEach(function(property)
421 {
422 var value = subscription[property];
423 Object.defineProperty(subscription, property,
424 {
425 get: function()
426 {
427 return value;
428 },
429 set: function(newValue)
430 {
431 if (value != newValue)
432 {
433 value = newValue;
434 onObjectChanged([{name: property}]);
435 }
436 }
437 });
438 });
439 }
440 else
441 {
442 Object.observe(subscription, onObjectChanged);
443 }
444 }
445
446 function updateSubscription(subscription)
447 {
448 var subscriptionUrl = subscription.url;
449 var knownSubscription = subscriptionsMap[subscriptionUrl];
450 if (knownSubscription)
451 {
452 for (var property in subscription)
453 {
454 if (property == "title" && subscriptionUrl in recommendationsMap)
455 knownSubscription.originalTitle = subscription.title;
456 else
457 knownSubscription[property] = subscription[property];
458 }
459 }
460 else
461 {
462 observeSubscription(subscription);
463
464 var collection;
465 if (subscriptionUrl in recommendationsMap)
466 {
467 var recommendation = recommendationsMap[subscriptionUrl];
468 if (recommendation.type != "ads")
469 collection = collections.popular;
470 else if (subscription.disabled == false)
471 collection = collections.langs;
472 else
473 collection = collections.allLangs;
474 }
475 else if (subscriptionUrl == acceptableAdsUrl)
476 collection = collections.acceptableAds;
477 else
478 collection = collections.custom;
479
480 collection.addItems(subscription);
481 subscriptionsMap[subscriptionUrl] = subscription;
482 }
483 }
484
485 function updateFilter(filter)
486 {
487 var match = filter.text.match(/^@@\|\|([^\/:]+)\^\$document$/);
488 if (match && !filtersMap[filter.text])
489 {
490 filter.title = match[1];
491 collections.whitelist.addItems(filter);
492 }
493 else
494 collections.customFilters.addItems(filter);
495
496 filtersMap[filter.text] = filter;
497 }
498
499 function loadRecommendations()
500 {
501 fetch("subscriptions.xml")
502 .then(function(response)
503 {
504 return response.text();
505 })
506 .then(function(text)
507 {
508 var list = document.getElementById("subscriptionSelector");
509 var doc = new DOMParser().parseFromString(text, "application/xml");
510 var elements = doc.documentElement.getElementsByTagName("subscription");
511 for (var i = 0; i < elements.length; i++)
512 {
513 var element = elements[i];
514 var subscription = Object.create(null);
515 subscription.originalTitle = element.getAttribute("title");
516 subscription.url = element.getAttribute("url");
517 subscription.disabled = null;
518 subscription.downloadStatus = null;
519 subscription.homepage = null;
520 var recommendation = Object.create(null);
521 recommendation.type = element.getAttribute("type");
522 var prefix = element.getAttribute("prefixes");
523 if (prefix)
524 {
525 prefix = prefix.replace(/\W/g, "_");
526 subscription.title = getMessage("options_language_" + prefix);
527 }
528 else
529 {
530 var type = recommendation.type.replace(/\W/g, "_");
531 subscription.title = getMessage("common_feature_" + type + "_title") ;
532 }
533
534 recommendationsMap[subscription.url] = recommendation;
535 updateSubscription(subscription);
536 }
537 });
538 }
539
540 function findParentData(element, dataName, returnElement)
541 {
542 while (element)
543 {
544 if (element.hasAttribute("data-" + dataName))
545 return returnElement ? element : element.getAttribute("data-" + dataName );
546
547 element = element.parentElement;
548 }
549 return null;
550 }
551
552 function sendMessageHandleErrors(message, onSuccess)
553 {
554 ext.backgroundPage.sendMessage(message, function(errors)
555 {
556 if (errors.length > 0)
557 alert(errors.join("\n"));
558 else if (onSuccess)
559 onSuccess();
560 });
561 }
562
563 function onClick(e)
564 {
565 var context = document.querySelector(".show-context-menu");
566 if (context)
567 context.classList.remove("show-context-menu");
568
569 var element = e.target;
570 while (true)
571 {
572 if (!element)
573 return;
574
575 if (element.hasAttribute("data-action"))
576 break;
577
578 element = element.parentElement;
579 }
580
581 var actions = element.getAttribute("data-action").split(",");
582 for (var i = 0; i < actions.length; i++)
583 {
584 switch (actions[i])
585 {
586 case "add-domain-exception":
587 addWhitelistedDomain();
588 break;
589 case "add-predefined-subscription":
590 var dialog = E("dialog-content-predefined");
591 var title = dialog.querySelector("h3").textContent;
592 var url = dialog.querySelector(".url").textContent;
593 addEnableSubscription(url, title);
594 closeDialog();
595 break;
596 case "cancel-custom-filters":
597 E("custom-filters").classList.remove("mode-edit");
598 break;
599 case "cancel-domain-exception":
600 E("whitelisting-textbox").value = "";
601 document.querySelector("#whitelisting .controls").classList.remove("mo de-edit");
602 break;
603 case "close-dialog":
604 closeDialog();
605 break;
606 case "edit-custom-filters":
607 E("custom-filters").classList.add("mode-edit");
608 editCustomFilters();
609 break;
610 case "edit-domain-exception":
611 document.querySelector("#whitelisting .controls").classList.add("mode- edit");
612 E("whitelisting-textbox").focus();
613 break;
614 case "import-subscription":
615 var url = E("blockingList-textbox").value;
616 addEnableSubscription(url);
617 closeDialog();
618 break;
619 case "open-dialog":
620 openDialog(element.getAttribute("data-dialog"));
621 break;
622 case "save-custom-filters":
623 sendMessageHandleErrors(
624 {
625 type: "filters.importRaw",
626 text: E("custom-filters-raw").value,
627 removeExisting: true
628 },
629 function()
630 {
631 E("custom-filters").classList.remove("mode-edit");
632 });
633 break;
634 case "switch-tab":
635 document.body.setAttribute("data-tab",
636 element.getAttribute("data-tab"));
637 break;
638 case "toggle-pref":
639 ext.backgroundPage.sendMessage(
640 {
641 type: "prefs.toggle",
642 key: findParentData(element, "pref", false)
643 });
644 break;
645 case "update-all-subscriptions":
646 ext.backgroundPage.sendMessage(
647 {
648 type: "subscriptions.update"
649 });
650 break;
651 case "open-context-menu":
652 var listItem = findParentData(element, "access", true);
653 if (listItem != context)
654 listItem.classList.add("show-context-menu");
655 break;
656 case "update-subscription":
657 ext.backgroundPage.sendMessage(
658 {
659 type: "subscriptions.update",
660 url: findParentData(element, "access", false)
661 });
662 break;
663 case "remove-subscription":
664 ext.backgroundPage.sendMessage(
665 {
666 type: "subscriptions.remove",
667 url: findParentData(element, "access", false)
668 });
669 break;
670 }
671 }
672 }
673
674 function onDOMLoaded()
675 {
676 populateLists();
677 function onFindLanguageKeyUp()
678 {
679 var searchStyle = E("search-style");
680 if (!this.value)
681 searchStyle.innerHTML = "";
682 else
683 searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this .value.toLowerCase() + "\"]) { display: none; }";
684 }
685
686 function getKey(e)
687 {
688 // e.keyCode has been deprecated so we attempt to use e.key
689 if ("key" in e)
690 return e.key;
691 return getKey.keys[e.keyCode];
692 }
693 getKey.keys = {
694 9: "Tab",
695 13: "Enter",
696 27: "Escape"
697 };
698
699 // Initialize navigation sidebar
700 ext.backgroundPage.sendMessage(
701 {
702 type: "app.get",
703 what: "addonVersion"
704 },
705 function(addonVersion)
706 {
707 E("abp-version").textContent = addonVersion;
708 });
709 getDocLink("releases", function(link)
710 {
711 E("link-version").setAttribute("href", link);
712 });
713
714 getDocLink("contribute", function(link)
715 {
716 document.querySelector("#tab-contribute a").setAttribute("href", link);
717 });
718
719 updateShareLink();
720
721 // Initialize interactive UI elements
722 document.body.addEventListener("click", onClick, false);
723 var placeholderValue = getMessage("options_dialog_language_find");
724 E("find-language").setAttribute("placeholder", placeholderValue);
725 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
726 E("whitelisting-textbox").addEventListener("keypress", function(e)
727 {
728 if (getKey(e) == "Enter")
729 addWhitelistedDomain();
730 }, false);
731
732 // Advanced tab
733 var tweaks = document.querySelectorAll("#tweaks li[data-pref]");
734 tweaks = Array.prototype.map.call(tweaks, function(checkbox)
735 {
736 return checkbox.getAttribute("data-pref");
737 });
738 tweaks.forEach(function(key)
739 {
740 getPref(key, function(value)
741 {
742 onPrefMessage(key, value, true);
743 });
744 });
745 ext.backgroundPage.sendMessage(
746 {
747 type: "app.get",
748 what: "features"
749 },
750 function(features)
751 {
752 hidePref("show_devtools_panel", !features.devToolsPanel);
753
754 // Only show option to switch between Safari Content Blockers
755 // and event based blocking if both are available.
756 hidePref("safari_contentblocker", !(
757 features.safariContentBlocker &&
758 "canLoad" in safari.self.tab &&
759 "onbeforeload" in Element.prototype
760 ));
761 });
762
763 var filterTextbox = document.querySelector("#custom-filters-add input");
764 placeholderValue = getMessage("options_customFilters_textbox_placeholder");
765 filterTextbox.setAttribute("placeholder", placeholderValue);
766 function addCustomFilters()
767 {
768 var filterText = filterTextbox.value;
769 sendMessageHandleErrors(
770 {
771 type: "filters.add",
772 text: filterText
773 },
774 function()
775 {
776 filterTextbox.value = "";
777 });
778 }
779 E("custom-filters-add").addEventListener("submit", function(e)
780 {
781 e.preventDefault();
782 addCustomFilters();
783 }, false);
784 var customFilterEditButtons = document.querySelectorAll("#custom-filters-edi t-wrapper button");
785
786 E("dialog").addEventListener("keydown", function(e)
787 {
788 switch (getKey(e))
789 {
790 case "Escape":
791 closeDialog();
792 break;
793 case "Tab":
794 if (e.shiftKey)
795 {
796 if (e.target.classList.contains("focus-first"))
797 {
798 e.preventDefault();
799 this.querySelector(".focus-last").focus();
800 }
801 }
802 else if (e.target.classList.contains("focus-last"))
803 {
804 e.preventDefault();
805 this.querySelector(".focus-first").focus();
806 }
807 break;
808 }
809 }, false);
810 }
811
812 var focusedBeforeDialog = null;
813 function openDialog(name)
814 {
815 var dialog = E("dialog");
816 dialog.setAttribute("aria-hidden", false);
817 dialog.setAttribute("aria-labelledby", "dialog-title-" + name);
818 document.body.setAttribute("data-dialog", name);
819
820 var defaultFocus = document.querySelector("#dialog-content-" + name
821 + " .default-focus");
822 if (!defaultFocus)
823 defaultFocus = dialog.querySelector(".focus-first");
824 focusedBeforeDialog = document.activeElement;
825 defaultFocus.focus();
826 }
827
828 function closeDialog()
829 {
830 var dialog = E("dialog");
831 dialog.setAttribute("aria-hidden", true);
832 dialog.removeAttribute("aria-labelledby");
833 document.body.removeAttribute("data-dialog");
834 focusedBeforeDialog.focus();
835 }
836
837 function populateLists()
838 {
839 subscriptionsMap = Object.create(null);
840 filtersMap = Object.create(null);
841 recommendationsMap = Object.create(null);
842
843 // Empty collections and lists
844 for (var property in collections)
845 collections[property].clearAll();
846
847 ext.backgroundPage.sendMessage(
848 {
849 type: "subscriptions.get",
850 special: true
851 },
852 function(subscriptions)
853 {
854 // Load filters
855 for (var i = 0; i < subscriptions.length; i++)
856 {
857 ext.backgroundPage.sendMessage(
858 {
859 type: "filters.get",
860 subscriptionUrl: subscriptions[i].url
861 },
862 function(filters)
863 {
864 for (var i = 0; i < filters.length; i++)
865 updateFilter(filters[i]);
866 });
867 }
868 });
869 loadRecommendations();
870 ext.backgroundPage.sendMessage(
871 {
872 type: "prefs.get",
873 key: "subscriptions_exceptionsurl"
874 },
875 function(url)
876 {
877 acceptableAdsUrl = url;
878 updateSubscription({
879 url: acceptableAdsUrl,
880 disabled: true
881 });
882
883 // Load user subscriptions
884 ext.backgroundPage.sendMessage(
885 {
886 type: "subscriptions.get",
887 downloadable: true
888 },
889 function(subscriptions)
890 {
891 for (var i = 0; i < subscriptions.length; i++)
892 onSubscriptionMessage("added", subscriptions[i]);
893 });
894 });
895 }
896
897 function addWhitelistedDomain()
898 {
899 var domain = E("whitelisting-textbox");
900 if (domain.value)
901 {
902 sendMessageHandleErrors(
903 {
904 type: "filters.add",
905 text: "@@||" + domain.value.toLowerCase() + "^$document"
906 });
907 }
908
909 domain.value = "";
910 document.querySelector("#whitelisting .controls").classList.remove("mode-edi t");
911 }
912
913 function editCustomFilters()
914 {
915 var customFilterItems = collections.customFilters.items;
916 var filterTexts = [];
917 for (var i = 0; i < customFilterItems.length; i++)
918 filterTexts.push(customFilterItems[i].text);
919 E("custom-filters-raw").value = filterTexts.join("\n");
920 }
921
922 function addEnableSubscription(url, title, homepage)
923 {
924 var messageType = null;
925 var knownSubscription = subscriptionsMap[url];
926 if (knownSubscription && knownSubscription.disabled == true)
927 messageType = "subscriptions.toggle"
928 else
929 messageType = "subscriptions.add"
930
931 var message = {
932 type: messageType,
933 url: url
934 };
935 if (title)
936 message.title = title;
937 if (homepage)
938 message.homepage = homepage;
939
940 ext.backgroundPage.sendMessage(message);
941 }
942
943 function onFilterMessage(action, filter)
944 {
945 switch (action)
946 {
947 case "added":
948 updateFilter(filter);
949 updateShareLink();
950 break;
951 case "loaded":
952 populateLists();
953 break;
954 case "removed":
955 var knownFilter = filtersMap[filter.text];
956 collections.whitelist.removeItem(knownFilter);
957 collections.customFilters.removeItem(knownFilter);
958 delete filtersMap[filter.text];
959 updateShareLink();
960 break;
961 }
962 }
963
964 function onSubscriptionMessage(action, subscription)
965 {
966 switch (action)
967 {
968 case "added":
969 updateSubscription(subscription);
970 updateShareLink();
971
972 var knownSubscription = subscriptionsMap[subscription.url];
973 if (knownSubscription)
974 collections.filterLists.addItems(knownSubscription);
975 else
976 collections.filterLists.addItems(subscription);
977 break;
978 case "disabled":
979 updateSubscription(subscription);
980 updateShareLink();
981 break;
982 case "removed":
983 var knownSubscription = subscriptionsMap[subscription.url];
984 if (subscription.url == acceptableAdsUrl)
985 {
986 subscription.disabled = true;
987 updateSubscription(subscription);
988 }
989 else
990 {
991 if (subscription.url in recommendationsMap)
992 knownSubscription.disabled = true;
993 else
994 {
995 collections.custom.removeItem(knownSubscription);
996 delete subscriptionsMap[subscription.url];
997 }
998 }
999 updateShareLink();
1000 collections.filterLists.removeItem(knownSubscription);
1001 break;
1002 default:
1003 updateSubscription(subscription);
1004 break;
1005 }
1006 }
1007
1008 function hidePref(key, value)
1009 {
1010 var element = document.querySelector("[data-pref='" + key + "']");
1011 if (element)
1012 element.setAttribute("aria-hidden", value);
1013 }
1014
1015 function getPref(key, callback)
1016 {
1017 var checkPref = getPref.checks[key] || getPref.checkNone;
1018 checkPref(function(isActive)
1019 {
1020 if (!isActive)
1021 {
1022 hidePref(key, !isActive);
1023 return;
1024 }
1025
1026 ext.backgroundPage.sendMessage(
1027 {
1028 type: "prefs.get",
1029 key: key
1030 }, callback);
1031 });
1032 }
1033
1034 getPref.checkNone = function(callback)
1035 {
1036 callback(true);
1037 };
1038
1039 getPref.checks =
1040 {
1041 notifications_ignoredcategories: function(callback)
1042 {
1043 getPref("notifications_showui", callback);
1044 }
1045 };
1046
1047 function onPrefMessage(key, value, initial)
1048 {
1049 switch (key)
1050 {
1051 case "notifications_ignoredcategories":
1052 value = value.indexOf("*") == -1;
1053 break;
1054
1055 case "notifications_showui":
1056 hidePref("notifications_ignoredcategories", !value);
1057 break;
1058
1059 case "safari_contentblocker":
1060 E("restart-safari").setAttribute("aria-hidden", value || initial);
1061 break;
1062 }
1063
1064 var checkbox = document.querySelector("[data-pref='" + key + "'] button[role ='checkbox']");
1065 if (checkbox)
1066 checkbox.setAttribute("aria-checked", value);
1067 }
1068
1069 function onShareLinkClick(e)
1070 {
1071 e.preventDefault();
1072
1073 getDocLink("share-general", function(link)
1074 {
1075 openSharePopup(link);
1076 });
1077 }
1078
1079 function updateShareLink()
1080 {
1081 var shareResources = [
1082 "https://facebook.com/plugins/like.php?",
1083 "https://platform.twitter.com/widgets/",
1084 "https://apis.google.com/se/0/_/+1/fastbutton?"
1085 ];
1086 var isAnyBlocked = false;
1087 var checksRemaining = shareResources.length;
1088
1089 function onResult(isBlocked)
1090 {
1091 isAnyBlocked |= isBlocked;
1092 if (!--checksRemaining)
1093 {
1094 // Hide the share tab if a script on the share page would be blocked
1095 var tab = E("tab-share");
1096 if (isAnyBlocked)
1097 {
1098 tab.hidden = true;
1099 tab.removeEventListener("click", onShareLinkClick, false);
1100 }
1101 else
1102 tab.addEventListener("click", onShareLinkClick, false);
1103 }
1104 }
1105
1106 for (var i = 0; i < shareResources.length; i++)
1107 checkShareResource(shareResources[i], onResult);
1108 }
1109
1110 ext.onMessage.addListener(function(message)
1111 {
1112 switch (message.type)
1113 {
1114 case "app.respond":
1115 switch (message.action)
1116 {
1117 case "addSubscription":
1118 var subscription = message.args[0];
1119 var dialog = E("dialog-content-predefined");
1120 dialog.querySelector("h3").textContent = subscription.title || "";
1121 dialog.querySelector(".url").textContent = subscription.url;
1122 openDialog("predefined");
1123 break;
1124 case "focusSection":
1125 document.body.setAttribute("data-tab", message.args[0]);
1126 break;
1127 }
1128 break;
1129 case "filters.respond":
1130 onFilterMessage(message.action, message.args[0]);
1131 break;
1132 case "prefs.respond":
1133 onPrefMessage(message.action, message.args[0], false);
1134 break;
1135 case "subscriptions.respond":
1136 onSubscriptionMessage(message.action, message.args[0]);
1137 break;
1138 }
1139 });
1140
1141 ext.backgroundPage.sendMessage(
1142 {
1143 type: "app.listen",
1144 filter: ["addSubscription", "focusSection"]
1145 });
1146 ext.backgroundPage.sendMessage(
1147 {
1148 type: "filters.listen",
1149 filter: ["added", "loaded", "removed"]
1150 });
1151 ext.backgroundPage.sendMessage(
1152 {
1153 type: "prefs.listen",
1154 filter: ["notifications_ignoredcategories", "notifications_showui",
1155 "safari_contentblocker", "show_devtools_panel",
1156 "shouldShowBlockElementMenu"]
1157 });
1158 ext.backgroundPage.sendMessage(
1159 {
1160 type: "subscriptions.listen",
1161 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1162 "title", "downloadStatus", "downloading"]
1163 });
1164
1165 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1166 })();
OLDNEW
« no previous file with comments | « options.html ('k') | skin/new-options.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld