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

Side by Side Diff: issue-reporter.js

Issue 29583568: Issue 5880 - Basic issue reporter implementation (Closed) Base URL: https://hg.adblockplus.org/adblockpluschrome
Patch Set: Created Oct. 19, 2017, 12:28 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 | « issue-reporter.html ('k') | polyfill.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 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20 window.ext = {};
21
22 let reportData = new DOMParser().parseFromString("<report></report>", "text/xml" );
23
24 let pages = {
25 "typeSelectorPage": [initTypeSelector, leaveTypeSelector],
26 "commentPage": [initCommentPage, leaveCommentPage],
27 "sendPage": [initSendPage, leaveSendPage]
28 };
29
30 document.addEventListener("DOMContentLoaded", () =>
31 {
32 document.getElementById("cancel").addEventListener("click", () =>
33 {
34 window.close();
35 });
36
37 document.getElementById("continue").addEventListener("click", () =>
38 {
39 if (!document.getElementById("continue").disabled)
40 pages[getCurrentPage()][1]();
41 });
42
43 document.addEventListener("keydown", event =>
44 {
45 let blacklistedElements = new Set(["textarea", "button", "a"])
46
47 if (event.key == "Enter" && !blacklistedElements.has(event.target.localName) )
48 document.getElementById("continue").click();
49 else if (event.key == "Escape")
50 document.getElementById("cancel").click();
51 });
52
53 browser.runtime.sendMessage({
54 type: "app.get",
55 what: "doclink",
56 link: "reporter_privacy"
57 }).then(url =>
58 {
59 document.getElementById("privacyPolicy").href = url;
60 });
61
62 initDataCollector();
63 });
64
65 function getCurrentPage()
66 {
67 return document.querySelector(".page:not([hidden])").id;
68 }
69
70 function setCurrentPage(pageId)
71 {
72 if (!pages.hasOwnProperty(pageId))
73 return;
74
75 let previousPage = document.querySelector(".page:not([hidden])");
76 if (previousPage)
77 previousPage.hidden = true;
78
79 document.getElementById(pageId).hidden = false;
80 pages[pageId][0]();
81 }
82
83 function censorURL(url)
84 {
85 return url.replace(/([?;&\/#][^?;&\/#]+?=)[^?;&\/#]+/g, "$1*");
86 }
87
88 function encodeHTML(str)
89 {
90 return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"). replace(/"/g, "&quot;");
91 }
92
93 function serializeReportData()
94 {
95 let result = new XMLSerializer().serializeToString(reportData);
96
97 // Insert line breaks before each new tag
98 result = result.replace(/(<[^\/]([^"<>]*|"[^"]*")*>)/g, "\n$1");
99 result = result.replace(/^\n+/, "");
100 return result;
101 }
102
103 function retrieveAddonInfo()
104 {
105 let element = reportData.createElement("adblock-plus");
106 return browser.runtime.sendMessage({
107 type: "app.get",
108 what: "addonVersion"
109 }).then(addonVersion =>
110 {
111 element.setAttribute("version", addonVersion);
112 return browser.runtime.sendMessage({
113 type: "app.get",
114 what: "localeInfo"
115 });
116 }).then(({locale}) =>
117 {
118 element.setAttribute("locale", locale);
119 reportData.documentElement.appendChild(element);
120 });
121 }
122
123 function retrieveApplicationInfo()
124 {
125 let element = reportData.createElement("application");
126 return browser.runtime.sendMessage({
127 type: "app.get",
128 what: "application"
129 }).then(application =>
130 {
131 element.setAttribute("name", application);
132 return browser.runtime.sendMessage({
133 type: "app.get",
134 what: "applicationVersion"
135 });
136 }).then(applicationVersion =>
137 {
138 element.setAttribute("version", applicationVersion);
139 element.setAttribute("userAgent", navigator.userAgent);
140 reportData.documentElement.appendChild(element);
141 });
142 }
143
144 function retrievePlatformInfo()
145 {
146 let element = reportData.createElement("platform");
147 return browser.runtime.sendMessage({
148 type: "app.get",
149 what: "platform"
150 }).then(platform =>
151 {
152 element.setAttribute("name", platform);
153 return browser.runtime.sendMessage({
154 type: "app.get",
155 what: "platformVersion"
156 });
157 }).then(platformVersion =>
158 {
159 element.setAttribute("version", platformVersion);
160 reportData.documentElement.appendChild(element);
161 });
162 }
163
164 function retrieveTabURL(tabId)
165 {
166 return browser.tabs.get(tabId).then(tab =>
167 {
168 let element = reportData.createElement("window");
169 if (tab.url)
170 element.setAttribute("url", censorURL(tab.url));
171 reportData.documentElement.appendChild(element);
172 });
173 }
174
175 function retrieveSubscriptions()
176 {
177 return browser.runtime.sendMessage({
178 type: "subscriptions.get",
179 ignoreDisabled: true,
180 downloadable: true
181 }).then(subscriptions =>
182 {
183 let element = reportData.createElement("subscriptions");
184 for (let subscription of subscriptions)
185 {
186 if (!/^(http|https|ftp):/.test(subscription.url))
187 continue;
188
189 let now = Math.round(Date.now() / 1000);
190 let subscriptionElement = reportData.createElement("subscription");
191 subscriptionElement.setAttribute("id", subscription.url);
192 if (subscription.lastDownload)
193 subscriptionElement.setAttribute("lastDownloadAttempt", subscription.las tDownload - now);
194 subscriptionElement.setAttribute("downloadStatus", subscription.downloadSt atus);
195 element.appendChild(subscriptionElement);
196 }
197 reportData.documentElement.appendChild(element);
198 });
199 }
200
201 function initDataCollector()
202 {
203 Promise.resolve().then(() =>
204 {
205 let tabId = parseInt(location.search.replace(/^\?/, ""), 10) || 0;
206 let handlers = [
207 retrieveAddonInfo(),
208 retrieveApplicationInfo(),
209 retrievePlatformInfo(),
210 retrieveTabURL(tabId),
211 retrieveSubscriptions()
212 ];
213 return Promise.all(handlers);
214 }).then(() =>
215 {
216 setCurrentPage("typeSelectorPage");
217 }).catch(e =>
218 {
219 if (!e.name && e.message)
220 e = e.message;
221 alert(e);
222 window.close();
223 });
224 }
225
226 function initTypeSelector()
227 {
228 document.getElementById("typeFalsePositive").focus();
229
230
231 for (let checkbox of document.querySelectorAll("input[name='type']"))
232 {
233 checkbox.addEventListener("click", () =>
234 {
235 if (document.querySelector("input[name='type']:checked"))
236 document.getElementById("continue").disabled = false;
237 });
238 }
239 }
240
241 function leaveTypeSelector()
242 {
243 let checkbox = document.querySelector("input[name='type']:checked");
244 reportData.documentElement.setAttribute("type", checkbox.value);
245 setCurrentPage("commentPage");
246 }
247
248 function initCommentPage()
249 {
250 let continueButton = document.getElementById("continue");
251 continueButton.disabled = true;
252 continueButton.textContent = browser.i18n.getMessage("issueReporter_sendButton _label");
253
254 let emailElement = reportData.createElement("email");
255 let emailField = document.getElementById("email");
256 let anonymousSubmissionField = document.getElementById("anonymousSubmission");
257 let validateEmail = () =>
258 {
259 document.getElementById("anonymousSubmissionWarning").setAttribute("data-inv isible", !anonymousSubmissionField.checked);
260 if (anonymousSubmissionField.checked)
261 {
262 emailField.value = "";
263 emailField.disabled = true;
264 continueButton.disabled = false;
265 if (emailElement.parentNode)
266 emailElement.parentNode.removeChild(emailElement);
267 }
268 else
269 {
270 emailField.disabled = false;
271
272 let value = emailField.value.trim();
273 emailElement.textContent = value;
274 reportData.documentElement.appendChild(emailElement);
275 continueButton.disabled = value == "" || !emailField.validity.valid;
276 }
277 };
278 emailField.addEventListener("input", validateEmail);
279 anonymousSubmissionField.addEventListener("click", validateEmail);
280
281 let commentElement = reportData.createElement("comment");
282 document.getElementById("comment").addEventListener("input", event =>
283 {
284 if (commentElement.parentNode)
285 commentElement.parentNode.removeChild(commentElement);
286
287 let value = event.target.value.trim();
288 commentElement.textContent = value.substr(0, 1000);
289 if (value)
290 reportData.documentElement.appendChild(commentElement);
291 document.getElementById("commentLengthWarning").setAttribute("data-invisible ", value.length <= 1000);
292 });
293
294 document.getElementById("showData").addEventListener("click", event =>
295 {
296 event.preventDefault();
297
298 // window.open() won't open data: URIs in Chrome
299 browser.tabs.getCurrent().then(tab =>
300 {
301 browser.tabs.create({
302 url: "data:text/xml;charset=utf-8," + encodeURIComponent(serializeReport Data()),
303 openerTabId: tab.id
304 });
305 })
306 });
307
308 emailField.focus();
309 }
310
311 function leaveCommentPage()
312 {
313 setCurrentPage("sendPage");
314 }
315
316 function initSendPage()
317 {
318 document.getElementById("cancel").hidden = true;
319
320 let continueButton = document.getElementById("continue");
321 continueButton.textContent = browser.i18n.getMessage("issueReporter_doneButton _label");
322 continueButton.disabled = true;
323
324 let uuid = new Uint16Array(8);
325 window.crypto.getRandomValues(uuid);
326 uuid[3] = uuid[3] & 0x0FFF | 0x4000; // version 4
327 uuid[4] = uuid[4] & 0x3FFF | 0x8000; // variant 1
328
329 let uuidString = "";
330 for (let i = 0; i < uuid.length; i++)
331 {
332 let component = uuid[i].toString(16);
333 while (component.length < 4)
334 component = "0" + component;
335 uuidString += component;
336 if (i >= 1 && i<= 4)
337 uuidString += "-";
338 }
339
340 let params = new URLSearchParams({
341 version: 1,
342 guid: uuidString,
343 lang: reportData.getElementsByTagName("adblock-plus")[0].getAttribute("local e")
344 });
345 let url = "https://reports.adblockplus.org/submitReport?" + params;
346
347 let reportSent = event =>
348 {
349 let success;
350 let errorMessage;
351 try
352 {
353 success = request.status == 200;
354 errorMessage = request.status + " " + request.statusText;
355 }
356 catch (e)
357 {
358 // No request status, connection wasn't established.
359 success = false;
360 errorMessage = browser.i18n.getMessage("filters_subscription_lastDownload_ connectionError");
361 }
362
363 let result;
364 try
365 {
366 result = request.responseText;
367 }
368 catch (e)
369 {
370 result = "";
371 }
372
373 result = result.replace(/%CONFIRMATION%/g, encodeHTML(browser.i18n.getMessag e("issueReporter_confirmationMessage")));
374 result = result.replace(/%KNOWNISSUE%/g, encodeHTML(browser.i18n.getMessage( "issueReporter_knownIssueMessage")));
375 result = result.replace(/(<html)\b/, '$1 dir="' + encodeHTML(window.getCompu tedStyle(document.documentElement, "").direction + '"'));
376
377 document.getElementById("sendingProgressContainer").hidden = true;
378
379 let resultFrame = document.getElementById("result");
380 resultFrame.setAttribute("src", "data:text/html;charset=utf-8," + encodeURIC omponent(result));
381 resultFrame.hidden = false;
382
383 document.getElementById("continue").disabled = false;
384 };
385
386 let request = new XMLHttpRequest();
387 request.open("POST", url);
388 request.setRequestHeader("Content-Type", "text/xml");
389 request.setRequestHeader("X-Adblock-Plus", "1");
390 request.addEventListener("load", reportSent);
391 request.addEventListener("error", reportSent);
392 request.upload.addEventListener("progress", event =>
393 {
394 if (!event.lengthComputable)
395 return;
396
397 let progress = Math.round(event.loaded / event.total * 100);
398 if (event.loaded > 0)
399 {
400 let progress = document.getElementById("sendingProgress");
401 progress.max = event.total;
402 progress.value = event.loaded;
403 }
404 });
405 request.send(serializeReportData());
406 }
407
408 function leaveSendPage()
409 {
410 window.close();
411 }
OLDNEW
« no previous file with comments | « issue-reporter.html ('k') | polyfill.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld