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

Powered by Google App Engine
This is Rietveld