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

Side by Side Diff: new-options.js

Issue 29334038: Issue 2802/2358 - Dynamically generate tooltips in options page (Closed)
Patch Set: Rebased to 75534a4a1e0e and addressed comments Created May 31, 2016, 4:57 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 | « new-options.html ('k') | skin/new-options.css » ('j') | 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 "use strict"; 18 "use strict";
19 19
20 (function() 20 (function()
21 { 21 {
22 var subscriptionsMap = Object.create(null); 22 var subscriptionsMap = Object.create(null);
23 var recommendationsMap = Object.create(null);
24 var filtersMap = Object.create(null); 23 var filtersMap = Object.create(null);
25 var collections = Object.create(null); 24 var collections = Object.create(null);
26 var acceptableAdsUrl = null; 25 var acceptableAdsUrl = null;
27 var maxLabelId = 0; 26 var maxLabelId = 0;
28 var getMessage = ext.i18n.getMessage; 27 var getMessage = ext.i18n.getMessage;
29 var filterErrors = 28 var filterErrors =
30 { 29 {
31 "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL", 30 "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL",
32 "synchronize_connection_error": "options_filterList_lastDownload_connectionE rror", 31 "synchronize_connection_error": "options_filterList_lastDownload_connectionE rror",
33 "synchronize_invalid_data": "options_filterList_lastDownload_invalidData", 32 "synchronize_invalid_data": "options_filterList_lastDownload_invalidData",
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 for (var i = 0; i < arguments.length; i++) 100 for (var i = 0; i < arguments.length; i++)
102 { 101 {
103 var item = arguments[i]; 102 var item = arguments[i];
104 var listItem = document.createElement("li"); 103 var listItem = document.createElement("li");
105 listItem.appendChild(document.importNode(template.content, true)); 104 listItem.appendChild(document.importNode(template.content, true));
106 listItem.setAttribute("data-access", item.url || item.text); 105 listItem.setAttribute("data-access", item.url || item.text);
107 106
108 var labelId = "label-" + (++maxLabelId); 107 var labelId = "label-" + (++maxLabelId);
109 var label = listItem.querySelector(".display"); 108 var label = listItem.querySelector(".display");
110 label.setAttribute("id", labelId); 109 label.setAttribute("id", labelId);
110 if (item.recommended && label.hasAttribute("data-tooltip"))
111 {
112 var tooltipId = label.getAttribute("data-tooltip");
113 tooltipId = tooltipId.replace("%value%", item.recommended);
114 label.setAttribute("data-tooltip", tooltipId);
115 }
111 116
112 var control = listItem.querySelector(".control"); 117 var control = listItem.querySelector(".control");
113 if (control) 118 if (control)
114 { 119 {
115 control.setAttribute("aria-labelledby", labelId); 120 control.setAttribute("aria-labelledby", labelId);
116 control.addEventListener("click", this.details[j].onClick, false); 121 control.addEventListener("click", this.details[j].onClick, false);
117 122
118 var role = control.getAttribute("role"); 123 var role = control.getAttribute("role");
119 if (role == "checkbox" && !label.hasAttribute("data-action")) 124 if (role == "checkbox" && !label.hasAttribute("data-action"))
120 { 125 {
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 [ 386 [
382 { 387 {
383 id: "all-filter-lists-table", 388 id: "all-filter-lists-table",
384 onClick: toggleDisableSubscription, 389 onClick: toggleDisableSubscription,
385 useOriginalTitle: true 390 useOriginalTitle: true
386 } 391 }
387 ]); 392 ]);
388 393
389 function updateLanguageCollections(subscription) 394 function updateLanguageCollections(subscription)
390 { 395 {
391 var recommendation = recommendationsMap[subscription.url]; 396 if (subscription.recommended == "ads")
392
393 if (recommendation && recommendation.type == "ads")
394 { 397 {
395 if (subscription.disabled) 398 if (subscription.disabled)
396 { 399 {
397 collections.allLangs.addItems(subscription); 400 collections.allLangs.addItems(subscription);
398 collections.langs.removeItem(subscription); 401 collections.langs.removeItem(subscription);
399 } 402 }
400 else 403 else
401 { 404 {
402 collections.allLangs.removeItem(subscription); 405 collections.allLangs.removeItem(subscription);
403 collections.langs.addItems(subscription); 406 collections.langs.addItems(subscription);
404 } 407 }
405 } 408 }
406 } 409 }
407 410
408 function addSubscription(subscription) 411 function addSubscription(subscription)
409 { 412 {
410 var collection; 413 var collection;
411 if (subscription.url in recommendationsMap) 414 if (subscription.recommended)
412 { 415 {
413 var recommendation = recommendationsMap[subscription.url]; 416 if (subscription.recommended != "ads")
414 if (recommendation.type != "ads")
415 collection = collections.popular; 417 collection = collections.popular;
416 else if (subscription.disabled == false) 418 else if (subscription.disabled == false)
417 collection = collections.langs; 419 collection = collections.langs;
418 else 420 else
419 collection = collections.allLangs; 421 collection = collections.allLangs;
420 } 422 }
421 else if (subscription.url == acceptableAdsUrl) 423 else if (subscription.url == acceptableAdsUrl)
422 collection = collections.acceptableAds; 424 collection = collections.acceptableAds;
423 else 425 else
424 collection = collections.custom; 426 collection = collections.custom;
425 427
426 collection.addItems(subscription); 428 collection.addItems(subscription);
427 subscriptionsMap[subscription.url] = subscription; 429 subscriptionsMap[subscription.url] = subscription;
430 updateTooltips();
428 } 431 }
429 432
430 function updateSubscription(subscription) 433 function updateSubscription(subscription)
431 { 434 {
432 var knownSubscription = subscriptionsMap[subscription.url]; 435 var knownSubscription = subscriptionsMap[subscription.url];
433 for (var property in subscription) 436 for (var property in subscription)
434 { 437 {
435 if (property == "title" && subscription.url in recommendationsMap) 438 if (property == "title" && subscription.recommended)
436 knownSubscription.originalTitle = subscription.title; 439 knownSubscription.originalTitle = subscription.title;
437 else 440 else
438 knownSubscription[property] = subscription[property]; 441 knownSubscription[property] = subscription[property];
439 } 442 }
440 443
441 for (var name in collections) 444 for (var name in collections)
442 collections[name].updateItem(knownSubscription); 445 collections[name].updateItem(knownSubscription);
443 446
444 return knownSubscription; 447 return knownSubscription;
445 } 448 }
(...skipping 20 matching lines...) Expand all
466 return response.text(); 469 return response.text();
467 }) 470 })
468 .then(function(text) 471 .then(function(text)
469 { 472 {
470 var list = document.getElementById("subscriptionSelector"); 473 var list = document.getElementById("subscriptionSelector");
471 var doc = new DOMParser().parseFromString(text, "application/xml"); 474 var doc = new DOMParser().parseFromString(text, "application/xml");
472 var elements = doc.documentElement.getElementsByTagName("subscription"); 475 var elements = doc.documentElement.getElementsByTagName("subscription");
473 for (var i = 0; i < elements.length; i++) 476 for (var i = 0; i < elements.length; i++)
474 { 477 {
475 var element = elements[i]; 478 var element = elements[i];
476 var subscription = Object.create(null); 479 var type = element.getAttribute("type");
477 subscription.originalTitle = element.getAttribute("title"); 480 var subscription = {
478 subscription.url = element.getAttribute("url"); 481 disabled: null,
479 subscription.disabled = null; 482 downloadStatus: null,
480 subscription.downloadStatus = null; 483 homepage: null,
481 subscription.homepage = null; 484 originalTitle: element.getAttribute("title"),
482 var recommendation = Object.create(null); 485 recommended: type,
483 recommendation.type = element.getAttribute("type"); 486 url: element.getAttribute("url")
487 };
488
484 var prefix = element.getAttribute("prefixes"); 489 var prefix = element.getAttribute("prefixes");
485 if (prefix) 490 if (prefix)
486 { 491 {
487 prefix = prefix.replace(/\W/g, "_"); 492 prefix = prefix.replace(/\W/g, "_");
488 subscription.title = getMessage("options_language_" + prefix); 493 subscription.title = getMessage("options_language_" + prefix);
489 } 494 }
490 else 495 else
491 { 496 {
492 var type = recommendation.type.replace(/\W/g, "_"); 497 type = type.replace(/\W/g, "_");
493 subscription.title = getMessage("common_feature_" + type + "_title") ; 498 subscription.title = getMessage("common_feature_" + type + "_title") ;
494 } 499 }
495 500
496 recommendationsMap[subscription.url] = recommendation;
497 addSubscription(subscription); 501 addSubscription(subscription);
498 } 502 }
499 }); 503 });
500 } 504 }
501 505
502 function findParentData(element, dataName, returnElement) 506 function findParentData(element, dataName, returnElement)
503 { 507 {
504 while (element) 508 while (element)
505 { 509 {
506 if (element.hasAttribute("data-" + dataName)) 510 if (element.hasAttribute("data-" + dataName))
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 { 676 {
673 E("link-version").setAttribute("href", link); 677 E("link-version").setAttribute("href", link);
674 }); 678 });
675 679
676 getDocLink("contribute", function(link) 680 getDocLink("contribute", function(link)
677 { 681 {
678 document.querySelector("#tab-contribute a").setAttribute("href", link); 682 document.querySelector("#tab-contribute a").setAttribute("href", link);
679 }); 683 });
680 684
681 updateShareLink(); 685 updateShareLink();
686 updateTooltips();
682 687
683 // Initialize interactive UI elements 688 // Initialize interactive UI elements
684 document.body.addEventListener("click", onClick, false); 689 document.body.addEventListener("click", onClick, false);
685 var placeholderValue = getMessage("options_dialog_language_find"); 690 var placeholderValue = getMessage("options_dialog_language_find");
686 E("find-language").setAttribute("placeholder", placeholderValue); 691 E("find-language").setAttribute("placeholder", placeholderValue);
687 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 692 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
688 E("whitelisting-textbox").addEventListener("keypress", function(e) 693 E("whitelisting-textbox").addEventListener("keypress", function(e)
689 { 694 {
690 if (getKey(e) == "Enter") 695 if (getKey(e) == "Enter")
691 addWhitelistedDomain(); 696 addWhitelistedDomain();
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 dialog.setAttribute("aria-hidden", true); 798 dialog.setAttribute("aria-hidden", true);
794 dialog.removeAttribute("aria-labelledby"); 799 dialog.removeAttribute("aria-labelledby");
795 document.body.removeAttribute("data-dialog"); 800 document.body.removeAttribute("data-dialog");
796 focusedBeforeDialog.focus(); 801 focusedBeforeDialog.focus();
797 } 802 }
798 803
799 function populateLists() 804 function populateLists()
800 { 805 {
801 subscriptionsMap = Object.create(null); 806 subscriptionsMap = Object.create(null);
802 filtersMap = Object.create(null); 807 filtersMap = Object.create(null);
803 recommendationsMap = Object.create(null);
804 808
805 // Empty collections and lists 809 // Empty collections and lists
806 for (var property in collections) 810 for (var property in collections)
807 collections[property].clearAll(); 811 collections[property].clearAll();
808 812
809 ext.backgroundPage.sendMessage( 813 ext.backgroundPage.sendMessage(
810 { 814 {
811 type: "subscriptions.get", 815 type: "subscriptions.get",
812 special: true 816 special: true
813 }, 817 },
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 subscription = updateSubscription(subscription); 947 subscription = updateSubscription(subscription);
944 else 948 else
945 addSubscription(subscription); 949 addSubscription(subscription);
946 950
947 collections.filterLists.addItems(subscription); 951 collections.filterLists.addItems(subscription);
948 updateLanguageCollections(subscription); 952 updateLanguageCollections(subscription);
949 break; 953 break;
950 case "removed": 954 case "removed":
951 var knownSubscription = subscriptionsMap[subscription.url]; 955 var knownSubscription = subscriptionsMap[subscription.url];
952 956
953 if (subscription.url == acceptableAdsUrl || 957 if (subscription.url == acceptableAdsUrl || subscription.recommended)
954 subscription.url in recommendationsMap)
955 { 958 {
956 subscription.disabled = true; 959 subscription.disabled = true;
957 onSubscriptionMessage("disabled", subscription); 960 onSubscriptionMessage("disabled", subscription);
958 } 961 }
959 else 962 else
960 { 963 {
961 collections.custom.removeItem(knownSubscription); 964 collections.custom.removeItem(knownSubscription);
962 delete subscriptionsMap[subscription.url]; 965 delete subscriptionsMap[subscription.url];
963 } 966 }
964 collections.filterLists.removeItem(knownSubscription); 967 collections.filterLists.removeItem(knownSubscription);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 } 1063 }
1061 else 1064 else
1062 tab.addEventListener("click", onShareLinkClick, false); 1065 tab.addEventListener("click", onShareLinkClick, false);
1063 } 1066 }
1064 } 1067 }
1065 1068
1066 for (var i = 0; i < shareResources.length; i++) 1069 for (var i = 0; i < shareResources.length; i++)
1067 checkShareResource(shareResources[i], onResult); 1070 checkShareResource(shareResources[i], onResult);
1068 } 1071 }
1069 1072
1073 function getMessages(id)
1074 {
1075 var messages = [];
1076 for (var i = 1; true; i++)
1077 {
1078 var message = ext.i18n.getMessage(id + "_" + i);
1079 if (!message)
1080 break;
1081
1082 messages.push(message);
1083 }
1084 return messages;
1085 }
1086
1087 function updateTooltips()
1088 {
1089 var anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]");
1090 for (var i = 0; i < anchors.length; i++)
1091 {
1092 var anchor = anchors[i];
1093 var id = anchor.getAttribute("data-tooltip");
1094
1095 var wrapper = document.createElement("div");
1096 wrapper.className = "tooltip";
1097 anchor.parentNode.replaceChild(wrapper, anchor);
1098 wrapper.appendChild(anchor);
1099
1100 var topTexts = getMessages(id);
1101 var bottomTexts = getMessages(id + "_notes");
1102
1103 // We have to use native tooltips to avoid issues when attaching a tooltip
1104 // to an element in a scrollable list or otherwise it might get cut off
1105 if (anchor.hasAttribute("data-tooltip-native"))
1106 {
1107 var title = topTexts.concat(bottomTexts).join("\n\n");
1108 anchor.setAttribute("title", title);
1109 continue;
1110 }
1111
1112 var tooltip = document.createElement("div");
1113 tooltip.setAttribute("role", "tooltip");
1114
1115 var flip = anchor.getAttribute("data-tooltip-flip");
1116 if (flip)
1117 tooltip.className = "flip-" + flip;
1118
1119 var imageSource = anchor.getAttribute("data-tooltip-image");
1120 if (imageSource)
1121 {
1122 var image = document.createElement("img");
1123 image.src = imageSource;
1124 image.alt = "";
1125 tooltip.appendChild(image);
1126 }
1127
1128 for (var j = 0; j < topTexts.length; j++)
1129 {
1130 var paragraph = document.createElement("p");
1131 paragraph.innerHTML = topTexts[j];
1132 tooltip.appendChild(paragraph);
1133 }
1134 if (bottomTexts.length > 0)
1135 {
1136 var notes = document.createElement("div");
1137 notes.className = "notes";
1138 for (var j = 0; j < bottomTexts.length; j++)
1139 {
1140 var paragraph = document.createElement("p");
1141 paragraph.innerHTML = bottomTexts[j];
1142 notes.appendChild(paragraph);
1143 }
1144 tooltip.appendChild(notes);
1145 }
1146
1147 wrapper.appendChild(tooltip);
1148 }
1149 }
1150
1070 ext.onMessage.addListener(function(message) 1151 ext.onMessage.addListener(function(message)
1071 { 1152 {
1072 switch (message.type) 1153 switch (message.type)
1073 { 1154 {
1074 case "app.respond": 1155 case "app.respond":
1075 switch (message.action) 1156 switch (message.action)
1076 { 1157 {
1077 case "addSubscription": 1158 case "addSubscription":
1078 var subscription = message.args[0]; 1159 var subscription = message.args[0];
1079 var dialog = E("dialog-content-predefined"); 1160 var dialog = E("dialog-content-predefined");
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 }); 1198 });
1118 ext.backgroundPage.sendMessage( 1199 ext.backgroundPage.sendMessage(
1119 { 1200 {
1120 type: "subscriptions.listen", 1201 type: "subscriptions.listen",
1121 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1202 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1122 "title", "downloadStatus", "downloading"] 1203 "title", "downloadStatus", "downloading"]
1123 }); 1204 });
1124 1205
1125 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1206 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1126 })(); 1207 })();
OLDNEW
« no previous file with comments | « new-options.html ('k') | skin/new-options.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld