Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | |
3 * Copyright (C) 2006-2017 eyeo GmbH | |
4 * | |
5 * Adblock Plus is free software: you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License version 3 as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * Adblock Plus is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
16 */ | |
17 | |
18 /* globals getDocLink */ | |
19 | |
20 "use strict"; | |
21 | |
22 { | |
23 const {getMessage} = ext.i18n; | |
saroyanm
2017/08/27 17:44:01
Shouldn't the "ext", be declared as global ?
The e
Thomas Greiner
2017/08/28 12:04:21
We define `ext` as a global in .eslintrc.json so n
saroyanm
2017/08/28 12:27:20
Acknowledged.
| |
24 | |
25 const dialogSubscribe = "subscribe"; | |
26 let whitelistFilter = null; | |
27 let promisedAcceptableAdsUrl = getAcceptableAdsUrl(); | |
28 | |
29 /* Utility functions */ | |
30 | |
31 function get(selector, origin) | |
32 { | |
33 return (origin || document).querySelector(selector); | |
34 } | |
35 | |
36 function getAll(selector, origin) | |
37 { | |
38 return (origin || document).querySelectorAll(selector); | |
39 } | |
40 | |
41 function create(parent, tagName, content, attributes, onclick) | |
42 { | |
43 let element = document.createElement(tagName); | |
44 | |
45 if (typeof content == "string") | |
46 { | |
47 element.textContent = content; | |
48 } | |
49 | |
50 if (attributes) | |
51 { | |
52 for (let name in attributes) | |
53 { | |
54 element.setAttribute(name, attributes[name]); | |
55 } | |
56 } | |
57 | |
58 if (onclick) | |
saroyanm
2017/08/27 17:44:02
Considering the fact that we have "onclick" functi
saroyanm
2017/08/28 08:15:28
Nevermind it will not, local scope will override t
| |
59 { | |
60 element.addEventListener("click", (ev) => | |
61 { | |
62 onclick(ev); | |
63 ev.stopPropagation(); | |
64 }); | |
65 } | |
66 | |
67 parent.appendChild(element); | |
68 return element; | |
69 } | |
70 | |
71 /* Extension interactions */ | |
72 | |
73 function getInstalled() | |
74 { | |
75 return new Promise((resolve, reject) => | |
76 { | |
77 ext.backgroundPage.sendMessage( | |
78 {type: "subscriptions.get", downloadable: true}, | |
79 resolve | |
80 ); | |
81 }); | |
82 } | |
83 | |
84 function getAcceptableAdsUrl() | |
85 { | |
86 return new Promise((resolve, reject) => | |
87 { | |
88 ext.backgroundPage.sendMessage( | |
89 {type: "prefs.get", key: "subscriptions_exceptionsurl"}, | |
90 resolve | |
91 ); | |
92 }); | |
93 } | |
94 | |
95 function getRecommendedAds() | |
96 { | |
97 return fetch("subscriptions.xml") | |
98 .then((response) => response.text()) | |
99 .then((text) => | |
100 { | |
101 let doc = new DOMParser().parseFromString(text, "application/xml"); | |
102 let elements = Array.from(doc.getElementsByTagName("subscription")); | |
103 | |
104 return elements | |
105 .filter((element) => element.getAttribute("type") == "ads") | |
106 .map((element) => | |
107 { | |
108 return { | |
109 title: element.getAttribute("title"), | |
110 url: element.getAttribute("url") | |
111 }; | |
112 }); | |
113 }); | |
114 } | |
115 | |
116 function installSubscription(url, title) | |
117 { | |
118 ext.backgroundPage.sendMessage({type: "subscriptions.add", url, title}); | |
119 } | |
120 | |
121 function uninstallSubscription(url) | |
122 { | |
123 ext.backgroundPage.sendMessage({type: "subscriptions.remove", url}); | |
124 } | |
125 | |
126 /* Actions */ | |
127 | |
128 function setSubscription({disabled, title, url}, shouldAdd) | |
129 { | |
130 if (disabled) | |
131 return; | |
132 | |
133 promisedAcceptableAdsUrl.then((acceptableAdsUrl) => | |
134 { | |
135 if (url == acceptableAdsUrl) | |
136 { | |
137 get("#acceptableAds").checked = true; | |
saroyanm
2017/08/27 17:44:01
Detail: this ID is used couple of times, if you wi
Thomas Greiner
2017/08/28 12:04:20
See other comment for the reply.
| |
138 return; | |
139 } | |
140 | |
141 let listInstalled = get("#subscriptions-installed"); | |
142 let installed = get(`[data-url="${url}"]`, listInstalled); | |
143 | |
144 if (installed) | |
145 { | |
146 let titleElement = get("span", installed); | |
147 titleElement.textContent = title || url; | |
148 } | |
149 else if (shouldAdd) | |
150 { | |
151 let element = create(listInstalled, "li", null, {"data-url": url}); | |
152 create(element, "span", title || url); | |
153 create(element, "button", null, {class: "remove"}, | |
154 () => uninstallSubscription(url) | |
155 ); | |
156 | |
157 let recommended = get(`#subscriptions-recommended [data-url="${url}"]`); | |
saroyanm
2017/08/27 17:44:01
Detail: the "#subscriptions-recommended" ID is use
Thomas Greiner
2017/08/28 12:04:20
Not sure what the underlying argument is.
- If the
saroyanm
2017/08/28 12:27:19
Yes I was referring to this .
Thomas Greiner
2017/08/28 13:14:05
Acknowledged.
saroyanm
2017/08/28 13:52:05
Detail: this change didn't land, but it's trivial.
Thomas Greiner
2017/08/28 14:00:12
As I mentioned, throughout all of our code "we don
saroyanm
2017/08/28 14:05:24
I did commented under the line:
"If the issue is t
Thomas Greiner
2017/08/28 15:01:28
Ok, I only looked at the text below your message.
| |
158 if (recommended) | |
159 { | |
160 recommended.classList.add("installed"); | |
161 } | |
162 } | |
163 }); | |
164 } | |
165 | |
166 function removeSubscription(url) | |
167 { | |
168 promisedAcceptableAdsUrl.then((acceptableAdsUrl) => | |
169 { | |
170 if (url == acceptableAdsUrl) | |
171 { | |
172 get("#acceptableAds").checked = false; | |
173 return; | |
174 } | |
175 | |
176 let installed = get(`#subscriptions-installed [data-url="${url}"]`); | |
177 if (installed) | |
178 { | |
179 installed.parentNode.removeChild(installed); | |
180 } | |
181 | |
182 let recommended = get(`#subscriptions-recommended [data-url="${url}"]`); | |
183 if (recommended) | |
184 { | |
185 recommended.classList.remove("installed"); | |
186 } | |
187 }); | |
188 } | |
189 | |
190 function setDialog(id, options) | |
191 { | |
192 if (!id) | |
193 { | |
194 delete document.body.dataset.dialog; | |
195 return; | |
196 } | |
197 | |
198 let fields = getAll(`#dialog-${id} input`); | |
199 for (let field of fields) | |
200 { | |
201 field.value = (options && field.name in options) ? options[field.name] : " "; | |
saroyanm
2017/08/27 17:44:01
Detail: this exceeds the characters limit.
Thomas Greiner
2017/08/28 12:04:22
Done. As mentioned, I also fixed linter errors in
| |
202 } | |
203 setError(id, null); | |
204 | |
205 document.body.dataset.dialog = id; | |
206 } | |
207 | |
208 function setError(dialogId, fieldName) | |
209 { | |
210 let dialog = get(`#dialog-${dialogId}`); | |
211 if (fieldName) | |
212 { | |
213 dialog.dataset.error = fieldName; | |
214 } | |
215 else | |
216 { | |
217 delete dialog.dataset.error; | |
218 } | |
219 } | |
220 | |
221 function populateLists() | |
222 { | |
223 Promise.all([getInstalled(), getRecommendedAds()]) | |
224 .then(([installed, recommended]) => | |
225 { | |
226 let listRecommended = get("#subscriptions-recommended"); | |
227 for (let {title, url} of recommended) | |
228 { | |
229 create(listRecommended, "li", title, {"data-url": url}, | |
saroyanm
2017/08/27 17:44:00
Detail: I think we also should specify role="butto
Thomas Greiner
2017/08/28 12:04:22
We don't include Accessibility in the mobile optio
saroyanm
2017/08/28 12:27:20
Acknowledged.
| |
230 (ev) => | |
231 { | |
232 if (ev.target.classList.contains("installed")) | |
233 return; | |
234 | |
235 setDialog(dialogSubscribe, {title, url}); | |
236 } | |
237 ); | |
238 } | |
239 | |
240 for (let subscription of installed) | |
241 { | |
242 if (subscription.disabled) | |
243 continue; | |
244 | |
245 setSubscription(subscription, true); | |
246 } | |
247 }) | |
248 .catch((err) => console.error(err)); | |
249 } | |
250 | |
251 /* Listeners */ | |
252 | |
253 function onChange(ev) | |
254 { | |
255 if (ev.target.id != "acceptableAds") | |
256 return; | |
257 | |
258 promisedAcceptableAdsUrl.then((acceptableAdsUrl) => | |
259 { | |
260 if (ev.target.checked) | |
261 { | |
262 installSubscription(acceptableAdsUrl, null); | |
263 } | |
264 else | |
265 { | |
266 uninstallSubscription(acceptableAdsUrl); | |
267 } | |
268 }); | |
269 } | |
270 document.addEventListener("change", onChange); | |
271 | |
272 function toggleWhitelistFilter(toggle) | |
273 { | |
274 if (whitelistFilter) | |
275 { | |
276 ext.backgroundPage.sendMessage( | |
277 { | |
278 type: (toggle.checked) ? "filters.remove" : "filters.add", | |
279 text: whitelistFilter | |
280 }, (errors) => | |
281 { | |
282 if (errors.length < 1) | |
saroyanm
2017/08/27 17:44:02
This doesn't pass ESlint indentation chekck for so
Thomas Greiner
2017/08/28 12:04:21
I'm not getting an error here. What rule does it m
saroyanm
2017/08/28 12:27:19
Indent: "282:11 error Expected indentation of 8
Thomas Greiner
2017/08/28 13:14:04
Done. Seems like we updated eslint-config-eyeo. At
| |
283 return; | |
284 | |
285 console.error(errors); | |
286 toggle.checked = !toggle.checked; | |
287 } | |
288 ); | |
289 } | |
290 else | |
291 { | |
292 console.error("Whitelist filter hasn't been initialized yet"); | |
293 } | |
294 } | |
295 | |
296 function onClick(ev) | |
297 { | |
298 switch (ev.target.dataset.action) | |
299 { | |
300 case "close-dialog": | |
301 setDialog(null); | |
302 break; | |
303 case "open-dialog": | |
304 setDialog(ev.target.dataset.dialog); | |
305 break; | |
306 case "toggle-enabled": | |
307 toggleWhitelistFilter(ev.target); | |
308 ev.preventDefault(); | |
309 break; | |
310 } | |
311 } | |
312 document.addEventListener("click", onClick); | |
313 | |
314 function onSubmit(ev) | |
315 { | |
316 let fields = ev.target.elements; | |
317 let title = fields.title.value; | |
318 let url = fields.url.value; | |
319 | |
320 if (!title) | |
321 { | |
322 setError(dialogSubscribe, "title"); | |
323 } | |
324 else if (!url) | |
325 { | |
326 setError(dialogSubscribe, "url"); | |
327 } | |
328 else | |
329 { | |
330 installSubscription(url, title); | |
331 setDialog(null); | |
332 } | |
333 | |
334 ev.preventDefault(); | |
335 } | |
336 document.addEventListener("submit", onSubmit); | |
337 | |
338 function onMessage(msg) | |
339 { | |
340 switch (msg.type) | |
341 { | |
342 case "app.respond": { | |
343 switch (msg.action) | |
344 { | |
345 case "addSubscription": | |
346 let [subscription] = msg.args; | |
347 setDialog(dialogSubscribe, { | |
348 title: subscription.title, | |
349 url: subscription.url | |
350 }); | |
351 break; | |
352 case "showPageOptions": | |
353 let [{host, whitelisted}] = msg.args; | |
354 whitelistFilter = `@@||${host}^$document`; | |
355 | |
356 ext.i18n.setElementText( | |
357 get("#enabled-label"), | |
358 "mops_enabled_label", | |
359 [host] | |
360 ); | |
361 | |
362 let toggle = get("#enabled"); | |
363 toggle.checked = !whitelisted; | |
364 | |
365 get("#enabled-container").hidden = false; | |
366 break; | |
367 } | |
368 break; | |
369 } | |
370 case "filters.respond": { | |
371 let [filter] = msg.args; | |
372 if (!whitelistFilter || filter.text != whitelistFilter) | |
373 break; | |
374 | |
375 get("#enabled").checked = (msg.action == "removed"); | |
376 break; | |
377 } | |
378 case "subscriptions.respond": { | |
379 let [subscription] = msg.args; | |
380 switch (msg.action) | |
381 { | |
382 case "added": | |
383 setSubscription(subscription, true); | |
384 break; | |
385 case "disabled": | |
386 if (subscription.disabled) | |
387 { | |
388 removeSubscription(subscription.url); | |
389 } | |
390 else | |
391 { | |
392 setSubscription(subscription, true); | |
393 } | |
394 break; | |
395 case "removed": | |
396 removeSubscription(subscription.url); | |
397 break; | |
398 case "title": | |
399 // We're also receiving these messages for subscriptions that are no t | |
saroyanm
2017/08/27 17:44:01
Detail: exceeding 80 chars.
Thomas Greiner
2017/08/28 12:04:20
Done.
| |
400 // installed so we shouldn't add those by accident | |
401 setSubscription(subscription, false); | |
402 break; | |
403 } | |
404 break; | |
405 } | |
406 } | |
407 } | |
408 ext.onMessage.addListener(onMessage); | |
409 | |
410 ext.backgroundPage.sendMessage({ | |
411 type: "app.listen", | |
412 filter: ["addSubscription", "showPageOptions"] | |
413 }); | |
414 | |
415 ext.backgroundPage.sendMessage({ | |
416 type: "filters.listen", | |
417 filter: ["added", "removed"] | |
418 }); | |
419 | |
420 ext.backgroundPage.sendMessage({ | |
421 type: "subscriptions.listen", | |
422 filter: ["added", "disabled", "removed", "title"] | |
423 }); | |
424 | |
425 /* Initialization */ | |
426 | |
427 populateLists(); | |
428 | |
429 getDocLink("acceptable_ads", (link) => | |
430 { | |
431 get("#acceptableAds-more").href = link; | |
432 }); | |
433 | |
434 get("#dialog-subscribe [name='title']").setAttribute( | |
435 "placeholder", | |
436 getMessage("mops_subscribe_title") | |
437 ); | |
438 | |
439 get("#dialog-subscribe [name='url']").setAttribute( | |
440 "placeholder", | |
441 getMessage("mops_subscribe_url") | |
442 ); | |
443 } | |
OLD | NEW |