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

Side by Side Diff: new-options.js

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

Powered by Google App Engine
This is Rietveld