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

Side by Side Diff: options.js

Issue 6088024630755328: issue 1526 - Implement new options page design for Chrome/Opera/Safari (Closed)
Patch Set: Created Feb. 13, 2015, 10:52 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(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');
Thomas Greiner 2015/02/18 17:19:27 You're using `document.getElementById()` here but
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 })();
OLDNEW

Powered by Google App Engine
This is Rietveld