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

Side by Side Diff: options.js

Issue 8560083: adblockplusopera: Port UI code from Chrome (Closed)
Patch Set: Created Oct. 12, 2012, 1:11 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
OLDNEW
(Empty)
1 var backgroundPage = opera.extension.bgProcess;
2 var imports = ["FilterStorage", "FilterNotifier", "Subscription", "SpecialSubscr iption",
3 "DownloadableSubscription", "Filter", "WhitelistFilter",
4 "Synchronizer", "Prefs", "Utils", "require"];
5 for (var i = 0; i < imports.length; i++)
6 window[imports[i]] = backgroundPage[imports[i]];
7
8 // Loads options from localStorage and sets UI elements accordingly
9 function loadOptions()
10 {
11 // Set page title to i18n version of "Adblock Plus Options"
12 document.title = i18n.getMessage("options");
13
14 // Set links
15 $("#acceptableAdsLink").attr("href", Prefs.subscriptions_exceptionsurl);
16 $("#acceptableAdsDocs").attr("href", Prefs.documentation_link.replace(/%LINK%/ g, "acceptable_ads").replace(/%LANG%/g, Utils.appLocale));
17
18 // Add event listeners
19 window.addEventListener("unload", unloadOptions, false);
20 $("#updateFilterLists").click(updateFilterLists);
21 $("#startSubscriptionSelection").click(startSubscriptionSelection);
22 $("#subscriptionSelector").change(updateSubscriptionSelection);
23 $("#addSubscription").click(addSubscription);
24 $("#acceptableAds").click(allowAcceptableAds);
25 $("#whitelistForm").submit(addWhitelistDomain);
26 $("#removeWhitelist").click(removeSelectedExcludedDomain);
27 $("#customFilterForm").submit(addTypedFilter);
28 $("#removeCustomFilter").click(removeSelectedFilters);
29 $("#rawFiltersButton").click(toggleFiltersInRawFormat);
30 $("#importRawFilters").click(importRawFiltersText);
31 FilterNotifier.addListener(onFilterChange);
32
33 // Display jQuery UI elements
34 $("#tabs").tabs();
35 $("button").button();
36 $(".refreshButton").button("option", "icons", {primary: "ui-icon-refresh"});
37 $(".addButton").button("option", "icons", {primary: "ui-icon-plus"});
38 $(".removeButton").button("option", "icons", {primary: "ui-icon-minus"});
39
40 // Popuplate option checkboxes
41 initCheckbox("shouldShowIcon");
42 initCheckbox("shouldShowBlockElementMenu");
43 initCheckbox("disableInlineTextAds");
44 initCheckbox("hidePlaceholders");
45
46 // Load recommended subscriptions
47 loadRecommendations();
48
49 // Show user's filters
50 reloadFilters();
51 }
52 $(loadOptions);
53
54 // Reloads the displayed subscriptions and filters
55 function reloadFilters()
56 {
57 // Load user filter URLs
58 var container = document.getElementById("filterLists");
59 while (container.lastChild)
60 container.removeChild(container.lastChild);
61
62 var hasAcceptable = false;
63 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
64 {
65 var subscription = FilterStorage.subscriptions[i];
66 if (subscription instanceof SpecialSubscription)
67 continue;
68
69 if (subscription.url == Prefs.subscriptions_exceptionsurl)
70 {
71 hasAcceptable = true;
72 continue;
73 }
74
75 addSubscriptionEntry(subscription);
76 }
77
78 $("#acceptableAds").prop("checked", hasAcceptable);
79
80 // User-entered filters
81 showUserFilters();
82 }
83
84 // Cleans up when the options window is closed
85 function unloadOptions()
86 {
87 FilterNotifier.removeListener(onFilterChange);
88 }
89
90 function initCheckbox(id)
91 {
92 var checkbox = document.getElementById(id);
93 checkbox.checked = typeof localStorage[id] == "undefined" ? true : localStorag e[id] == "true";
94 checkbox.addEventListener("click", function()
95 {
96 localStorage[id] = checkbox.checked;
97 }, false);
98 }
99
100 function showUserFilters()
101 {
102 var filters = [];
103 var exceptions = [];
104 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
105 {
106 var subscription = FilterStorage.subscriptions[i];
107 if (!(subscription instanceof SpecialSubscription))
108 continue;
109
110 for (var j = 0; j < subscription.filters.length; j++)
111 {
112 var filter = subscription.filters[j];
113 if (filter instanceof WhitelistFilter && /^@@\|\|([^\/:]+)\^\$document$/.t est(filter.text))
114 exceptions.push(RegExp.$1)
115 else
116 filters.push(filter.text);
117 }
118 }
119
120 populateList("userFiltersBox", filters);
121 populateList("excludedDomainsBox", exceptions);
122 }
123
124 var delayedSubscriptionSelection = null;
125
126 function loadRecommendations()
127 {
128 var request = new XMLHttpRequest();
129 request.open("GET", "subscriptions.xml");
130 request.onload = function()
131 {
132 var selectedIndex = 0;
133 var selectedPrefix = null;
134 var matchCount = 0;
135
136 var list = document.getElementById("subscriptionSelector");
137 var elements = request.responseXML.documentElement.getElementsByTagName("sub scription");
138 for (var i = 0; i < elements.length; i++)
139 {
140 var element = elements[i];
141 var option = document.createElement("option");
142 option.text = element.getAttribute("title") + " (" + element.getAttribute( "specialization") + ")";
143 option._data = {
144 title: element.getAttribute("title"),
145 url: element.getAttribute("url"),
146 homepage: element.getAttribute("homepage")
147 };
148
149 var prefix = require("utils").Utils.checkLocalePrefixMatch(element.getAttr ibute("prefixes"));
150 if (prefix)
151 {
152 option.style.fontWeight = "bold";
153 option.style.backgroundColor = "#E0FFE0";
154 option.style.color = "#000000";
155 if (!selectedPrefix || selectedPrefix.length < prefix.length)
156 {
157 selectedIndex = i;
158 selectedPrefix = prefix;
159 matchCount = 1;
160 }
161 else if (selectedPrefix && selectedPrefix.length == prefix.length)
162 {
163 matchCount++;
164
165 // If multiple items have a matching prefix of the same length:
166 // Select one of the items randomly, probability should be the same
167 // for all items. So we replace the previous match here with
168 // probability 1/N (N being the number of matches).
169 if (Math.random() * matchCount < 1)
170 {
171 selectedIndex = i;
172 selectedPrefix = prefix;
173 }
174 }
175 }
176 list.appendChild(option);
177 }
178
179 var option = document.createElement("option");
180 option.text = i18n.getMessage("filters_addSubscriptionOther_label") + "\u202 6";
181 option._data = null;
182 list.appendChild(option);
183
184 list.selectedIndex = selectedIndex;
185
186 if (delayedSubscriptionSelection)
187 startSubscriptionSelection.apply(null, delayedSubscriptionSelection);
188 };
189 request.send(null);
190 }
191
192 function startSubscriptionSelection(title, url)
193 {
194 var list = document.getElementById("subscriptionSelector");
195 if (list.length == 0)
196 {
197 delayedSubscriptionSelection = [title, url];
198 return;
199 }
200
201 $('#tabs').tabs('select', 0);
202 $("#addSubscriptionContainer").show();
203 $("#addSubscriptionButton").hide();
204 $("#subscriptionSelector").focus();
205 if (typeof url != "undefined")
206 {
207 list.selectedIndex = list.length - 1;
208 document.getElementById("customSubscriptionTitle").value = title;
209 document.getElementById("customSubscriptionLocation").value = url;
210 }
211 updateSubscriptionSelection();
212 document.getElementById("addSubscriptionContainer").scrollIntoView(true);
213 }
214
215 function updateSubscriptionSelection()
216 {
217 var list = document.getElementById("subscriptionSelector");
218 var data = list.options[list.selectedIndex]._data;
219 if (data)
220 $("#customSubscriptionContainer").hide();
221 else
222 {
223 $("#customSubscriptionContainer").show();
224 $("#customSubscriptionTitle").focus();
225 }
226 }
227
228 function addSubscription()
229 {
230 var list = document.getElementById("subscriptionSelector");
231 var data = list.options[list.selectedIndex]._data;
232 if (data)
233 doAddSubscription(data.url, data.title, data.homepage);
234 else
235 {
236 var url = document.getElementById("customSubscriptionLocation").value.replac e(/^\s+/, "").replace(/\s+$/, "");
237 if (!/^https?:/i.test(url))
238 {
239 alert(i18n.getMessage("global_subscription_invalid_location"));
240 $("#customSubscriptionLocation").focus();
241 return;
242 }
243
244 var title = document.getElementById("customSubscriptionTitle").value.replace (/^\s+/, "").replace(/\s+$/, "");
245 if (!title)
246 title = url;
247
248 doAddSubscription(url, title, null);
249 }
250
251 $("#addSubscriptionContainer").hide();
252 $("#customSubscriptionContainer").hide();
253 $("#addSubscriptionButton").show();
254 }
255
256 function doAddSubscription(url, title, homepage)
257 {
258 if (url in FilterStorage.knownSubscriptions)
259 return;
260
261 var subscription = Subscription.fromURL(url);
262 if (!subscription)
263 return;
264
265 subscription.title = title;
266 if (homepage)
267 subscription.homepage = homepage;
268 FilterStorage.addSubscription(subscription);
269
270 if (subscription instanceof DownloadableSubscription && !subscription.lastDown load)
271 Synchronizer.execute(subscription);
272 }
273
274 function allowAcceptableAds(event)
275 {
276 var subscription = Subscription.fromURL(Prefs.subscriptions_exceptionsurl);
277 if (!subscription)
278 return;
279
280 subscription.disabled = false;
281 subscription.title = "Allow non-intrusive advertising";
282 if ($("#acceptableAds").prop("checked"))
283 {
284 FilterStorage.addSubscription(subscription);
285 if (subscription instanceof DownloadableSubscription && !subscription.lastDo wnload)
286 Synchronizer.execute(subscription);
287 }
288 else
289 FilterStorage.removeSubscription(subscription);
290 }
291
292 function findSubscriptionElement(subscription)
293 {
294 var children = document.getElementById("filterLists").childNodes;
295 for (var i = 0; i < children.length; i++)
296 if (children[i]._subscription == subscription)
297 return children[i];
298 return null;
299 }
300
301 function updateSubscriptionInfo(element)
302 {
303 var subscription = element._subscription;
304
305 var title = element.getElementsByClassName("subscriptionTitle")[0];
306 title.textContent = subscription.title;
307 title.setAttribute("title", subscription.url);
308 if (subscription.homepage)
309 title.href = subscription.homepage;
310 else
311 title.href = subscription.url;
312
313 var enabled = element.getElementsByClassName("subscriptionEnabled")[0];
314 enabled.checked = !subscription.disabled;
315
316 var lastUpdate = element.getElementsByClassName("subscriptionUpdate")[0];
317 lastUpdate.classList.remove("error");
318 if (Synchronizer.isExecuting(subscription.url))
319 lastUpdate.textContent = i18n.getMessage("filters_subscription_lastDownload_ inProgress");
320 else if (subscription.downloadStatus && subscription.downloadStatus != "synchr onize_ok")
321 {
322 var map =
323 {
324 "synchronize_invalid_url": "filters_subscription_lastDownload_invalidURL",
325 "synchronize_connection_error": "filters_subscription_lastDownload_connect ionError",
326 "synchronize_invalid_data": "filters_subscription_lastDownload_invalidData ",
327 "synchronize_checksum_mismatch": "filters_subscription_lastDownload_checks umMismatch"
328 };
329 if (subscription.downloadStatus in map)
330 lastUpdate.textContent = i18n.getMessage(map[subscription.downloadStatus]) ;
331 else
332 lastUpdate.textContent = subscription.downloadStatus;
333 lastUpdate.classList.add("error");
334 }
335 else if (subscription.lastDownload > 0)
336 {
337 var timeDate = i18n_timeDateStrings(subscription.lastDownload * 1000);
338 var messageID = (timeDate[1] ? "last_updated_at" : "last_updated_at_today");
339 lastUpdate.textContent = i18n.getMessage(messageID, timeDate);
340 }
341 }
342
343 function onFilterChange(action, item, param1, param2)
344 {
345 switch (action)
346 {
347 case "load":
348 reloadFilters();
349 break;
350 case "subscription.title":
351 case "subscription.disabled":
352 case "subscription.homepage":
353 case "subscription.lastDownload":
354 case "subscription.downloadStatus":
355 var element = findSubscriptionElement(item);
356 if (element)
357 updateSubscriptionInfo(element);
358 break;
359 case "subscription.added":
360 if (!(item instanceof SpecialSubscription) && !findSubscriptionElement(ite m))
361 {
362 if (item.url == Prefs.subscriptions_exceptionsurl)
363 $("#acceptableAds").prop("checked", true);
364 else
365 addSubscriptionEntry(item);
366 }
367 break;
368 case "subscription.removed":
369 if (item.url == Prefs.subscriptions_exceptionsurl)
370 $("#acceptableAds").prop("checked", false);
371 else
372 {
373 var element = findSubscriptionElement(item);
374 if (element)
375 element.parentNode.removeChild(element);
376 }
377 break;
378 case "filter.added":
379 if (item instanceof WhitelistFilter && /^@@\|\|([^\/:]+)\^\$document$/.tes t(item.text))
380 appendToListBox("excludedDomainsBox", RegExp.$1);
381 else
382 appendToListBox("userFiltersBox", item.text);
383 break;
384 case "filter.removed":
385 if (item instanceof WhitelistFilter && /^@@\|\|([^\/:]+)\^\$document$/.tes t(item.text))
386 removeFromListBox("excludedDomainsBox", RegExp.$1);
387 else
388 removeFromListBox("userFiltersBox", item.text);
389 break;
390 }
391 }
392
393 // Populates a list box with a number of entries
394 function populateList(id, entries)
395 {
396 var list = document.getElementById(id);
397 while (list.lastChild)
398 list.removeChild(list.lastChild);
399
400 entries.sort();
401 for (var i = 0; i < entries.length; i++)
402 {
403 var option = document.createElement("option");
404 option.text = entries[i];
405 option.value = entries[i];
406 list.appendChild(option);
407 }
408 }
409
410 // Add a filter string to the list box.
411 function appendToListBox(boxId, text)
412 {
413 var elt = document.createElement("option");
414 elt.text = text;
415 elt.value = text;
416 document.getElementById(boxId).appendChild(elt);
417 }
418
419 // Remove a filter string from a list box.
420 function removeFromListBox(boxId, text)
421 {
422 var elt = document.createElement("option");
423 elt.text = text;
424 elt.value = text;
425 var list = document.getElementById(boxId);
426 for (var i = 0; i < list.length; i++)
427 if (list.options[i].value == text)
428 list.remove(i--);
429 }
430
431 function addWhitelistDomain(event)
432 {
433 event.preventDefault();
434
435 var domain = document.getElementById("newWhitelistDomain").value.replace(/\s/g , "");
436 document.getElementById("newWhitelistDomain").value = "";
437 if (!domain)
438 return;
439
440 var filterText = "@@||" + domain + "^$document";
441 FilterStorage.addFilter(Filter.fromText(filterText));
442 }
443
444 // Adds filter text that user typed to the selection box
445 function addTypedFilter(event)
446 {
447 event.preventDefault();
448
449 var filterText = Filter.normalize(document.getElementById("newFilter").value);
450 document.getElementById("newFilter").value = "";
451 if (!filterText)
452 return;
453
454 FilterStorage.addFilter(Filter.fromText(filterText));
455 }
456
457 // Removes currently selected whitelisted domains
458 function removeSelectedExcludedDomain()
459 {
460 var excludedDomainsBox = document.getElementById("excludedDomainsBox");
461 var remove = [];
462 for (var i = 0; i < excludedDomainsBox.length; i++)
463 if (excludedDomainsBox.options[i].selected)
464 remove.push(excludedDomainsBox.options[i].value);
465 if (!remove.length)
466 return;
467
468 for (var i = 0; i < remove.length; i++)
469 FilterStorage.removeFilter(Filter.fromText("@@||" + remove[i] + "^$document" ));
470 }
471
472 // Removes all currently selected filters
473 function removeSelectedFilters()
474 {
475 var userFiltersBox = document.getElementById("userFiltersBox");
476 var remove = [];
477 for (var i = 0; i < userFiltersBox.length; i++)
478 if (userFiltersBox.options[i].selected)
479 remove.push(userFiltersBox.options[i].value);
480 if (!remove.length)
481 return;
482
483 for (var i = 0; i < remove.length; i++)
484 FilterStorage.removeFilter(Filter.fromText(remove[i]));
485 }
486
487 // Shows raw filters box and fills it with the current user filters
488 function toggleFiltersInRawFormat(event)
489 {
490 event.preventDefault();
491
492 $("#rawFilters").toggle();
493 if ($("#rawFilters").is(":visible"))
494 {
495 var userFiltersBox = document.getElementById("userFiltersBox");
496 var text = "";
497 for (var i = 0; i < userFiltersBox.length; i++)
498 text += userFiltersBox.options[i].value + "\n";
499 document.getElementById("rawFiltersText").value = text;
500 }
501 }
502
503 // Imports filters in the raw text box
504 function importRawFiltersText()
505 {
506 $("#rawFilters").hide();
507 var filters = document.getElementById("rawFiltersText").value.split("\n");
508 var seenFilter = {__proto__: null};
509 for (var i = 0; i < filters.length; i++)
510 {
511 var text = Filter.normalize(filters[i]);
512 if (!text)
513 continue;
514
515 // Don't import filter list header
516 if (/^\[/.test(text))
517 continue;
518
519 FilterStorage.addFilter(Filter.fromText(text));
520 seenFilter[text] = true;
521 }
522
523 var remove = [];
524 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
525 {
526 var subscription = FilterStorage.subscriptions[i];
527 if (!(subscription instanceof SpecialSubscription))
528 continue;
529
530 for (var j = 0; j < subscription.filters.length; j++)
531 {
532 var filter = subscription.filters[j];
533 if (filter instanceof WhitelistFilter && /^@@\|\|([^\/:]+)\^\$document$/.t est(filter.text))
534 continue;
535
536 if (!(filter.text in seenFilter))
537 remove.push(filter);
538 }
539 }
540 for (var i = 0; i < remove.length; i++)
541 FilterStorage.removeFilter(remove[i]);
542 }
543
544 // Called when user explicitly requests filter list updates
545 function updateFilterLists()
546 {
547 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
548 {
549 var subscription = FilterStorage.subscriptions[i];
550 if (subscription instanceof DownloadableSubscription)
551 Synchronizer.execute(subscription, true, true);
552 }
553 }
554
555 // Adds a subscription entry to the UI.
556 function addSubscriptionEntry(subscription)
557 {
558 var template = document.getElementById("subscriptionTemplate");
559 var element = template.cloneNode(true);
560 element.removeAttribute("id");
561 element._subscription = subscription;
562
563 var removeButton = element.getElementsByClassName("subscriptionRemoveButton")[ 0];
564 removeButton.setAttribute("title", removeButton.textContent);
565 removeButton.textContent = "\xD7";
566 removeButton.addEventListener("click", function()
567 {
568 if (!confirm(i18n.getMessage("global_remove_subscription_warning")))
569 return;
570
571 FilterStorage.removeSubscription(subscription);
572 }, false);
573
574 var enabled = element.getElementsByClassName("subscriptionEnabled")[0];
575 enabled.addEventListener("click", function()
576 {
577 if (subscription.disabled == !enabled.checked)
578 return;
579
580 subscription.disabled = !enabled.checked;
581 }, false);
582
583 updateSubscriptionInfo(element);
584
585 document.getElementById("filterLists").appendChild(element);
586 }
OLDNEW
« options.html ('K') | « options.html ('k') | options/about.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld