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

Delta Between Two Patch Sets: static/js/main.js

Issue 29559620: Issue 5692 - Create Browser Selector with Browser Detection Component for help.eyeo.com (Closed) Base URL: https://hg.adblockplus.org/help.eyeo.com
Left Patch Set: Created Sept. 29, 2017, 12:02 p.m.
Right Patch Set: Re-add browser-select include, add scripts block Created Nov. 2, 2017, 2:29 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 (function(){ 1 (function()
2 {
2 document.addEventListener("DOMContentLoaded", function() 3 document.addEventListener("DOMContentLoaded", function()
3 { 4 {
4 5
6 /**************************************************************************
7 * General
8 **************************************************************************/
9
5 // Change html class name from "no-js" to "js" 10 // Change html class name from "no-js" to "js"
6 document.documentElement.className = "js"; 11 document.documentElement.className = "js";
7 12
8 // Toggle Navbar Collapse 13 /**************************************************************************
14 * Navbar
15 **************************************************************************/
16
9 function toggleNavbarCollapse() 17 function toggleNavbarCollapse()
10 { 18 {
11 var navbarCollapseEls = this.parentElement.getElementsByClassName("navbar- collapse"); 19 var navbarCollapseEls = this.parentElement.getElementsByClassName("navbar- collapse");
12 for (var i = 0; i < navbarCollapseEls.length; i++) 20 for (var i = 0; i < navbarCollapseEls.length; i++)
13 { 21 {
14 navbarCollapseEls[i] 22 navbarCollapseEls[i]
15 .classList.toggle("open") 23 .classList.toggle("open")
16 } 24 }
17 } 25 }
18 26
19 var toggleNavbarCollapseEls = document.getElementsByClassName("toggle-navbar -collapse"); 27 var toggleNavbarCollapseEls = document.getElementsByClassName("toggle-navbar -collapse");
20 for (var i = 0; i < toggleNavbarCollapseEls.length; i++) 28 for (var i = 0; i < toggleNavbarCollapseEls.length; i++)
21 { 29 {
22 toggleNavbarCollapseEls[i] 30 toggleNavbarCollapseEls[i]
23 .addEventListener("click", toggleNavbarCollapse, false); 31 .addEventListener("click", toggleNavbarCollapse, false);
24 } 32 }
25 33
26 // Custom Select 34 /**************************************************************************
27 function onClickCustomSelect() 35 * CustomSelect
28 { 36 **************************************************************************/
29 var options = this.nextElementSibling; 37
30 if (options.getAttribute("aria-hidden") == "true") 38 function CustomSelect(select)
31 { 39 {
32 options.removeAttribute("aria-hidden"); 40 this.select = select;
33 this.setAttribute("aria-expanded", "true"); 41 this.close();
42 this.select
43 .addEventListener("click", this._onClick.bind(this), false);
44 this.select
45 .addEventListener("focusout", this._onFocusOut.bind(this), false);
46 }
47
48 CustomSelect.prototype._onFocusOut = function()
49 {
50 // setTimeout to allow document.activeElement
51 // to move to newly focused element
52 setTimeout(function()
53 {
54 var newFocus = document.activeElement;
55
56 if (newFocus
57 .classList.contains("custom-select-selected") ||
58 newFocus
59 .classList.contains("custom-select-option") ||
60 newFocus
61 .parentElement
62 .classList.contains("custom-select-option"))
63 {
64 return;
65 }
66
67 this.close();
68
69 }.bind(this), 1);
70 }
71
72 CustomSelect.prototype._onClick = function(event)
73 {
74 if (event.target.classList.contains("custom-select-selected"))
75 {
76 var options = this.select.querySelector(".custom-select-options");
77 if (options.getAttribute("aria-hidden") == "true")
78 {
79 this.open();
80 }
81 else
82 {
83 this.close();
84 }
85 }
86 }
87
88 CustomSelect.prototype.open = function()
89 {
90 this.select
91 .querySelector(".custom-select-selected")
92 .setAttribute("aria-expanded", "true");
93
94 this.select
95 .querySelector(".custom-select-options")
96 .removeAttribute("aria-hidden");
97 }
98
99 CustomSelect.prototype.close = function()
100 {
101 this.select
102 .querySelector(".custom-select-selected")
103 .setAttribute("aria-expanded", "false");
104
105 this.select
106 .querySelector(".custom-select-options")
107 .setAttribute("aria-hidden", "true");
108 }
109
110 new CustomSelect(document.getElementById("language-select"));
111
112 /**************************************************************************
113 * Accordion
114 **************************************************************************/
115
116 function Accordion(accordion)
117 {
118 this.accordion = accordion;
119
120 var accordionButtons = this.accordion.getElementsByClassName('accordion-to ggle-button');
121 for (var i = 0; i < accordionButtons.length; i++)
122 {
123 // Close all sections except the first
124 if (i !== 0)
125 {
126 accordionButtons[i].setAttribute("aria-expanded", "false");
127 document
128 .getElementById( accordionButtons[i].getAttribute("aria-controls") )
129 .setAttribute("hidden", "true");
130 }
131 }
132
133 this.accordion
134 .addEventListener("click", this._onClick.bind(this), false);
135 this.accordion
136 .addEventListener("keydown", this._onKeyDown.bind(this), false);
137 }
138
139 Accordion.prototype.toggleSection = function(clickedButton)
140 {
141 // Hide currently expanded section
142 var expandedButton = this.accordion.querySelector("button[aria-expanded='t rue']");
143 if (expandedButton)
144 {
145 expandedButton.setAttribute("aria-expanded", "false");
146 document
147 .getElementById( expandedButton.getAttribute("aria-controls") )
148 .setAttribute("hidden", "true");
149 }
150
151 // If currently expanded section is clicked
152 if (expandedButton === clickedButton) return;
153
154 // Expand new section
155 clickedButton.setAttribute("aria-expanded", "true");
156 document
157 .getElementById( clickedButton.getAttribute("aria-controls") )
158 .removeAttribute("hidden");
159 }
160
161 Accordion.prototype.focusNextSection = function()
162 {
163 var currentFocus = document.activeElement;
164 var nextheading = currentFocus.parentElement.nextElementSibling.nextElemen tSibling;
165
166 if (nextheading)
167 {
168 nextheading // .accordion-heading
169 .firstElementChild // .accordion-toggle-button
170 .focus();
34 } 171 }
35 else 172 else
36 { 173 {
37 options.setAttribute("aria-hidden", "true"); 174 this.accordion
38 this.setAttribute("aria-expanded", "false"); 175 .firstElementChild // .accordion-heading
39 } 176 .firstElementChild // .accordion-toggle-button
40 } 177 .focus();
41 178 }
42 var customSelectEls = document.getElementsByClassName('custom-select-selecte d'); 179 }
43 for (var i = 0; i < customSelectEls.length; i++) 180
44 { 181 Accordion.prototype.focusPrevSection = function()
45 customSelectEls[i] 182 {
46 .addEventListener("click", onClickCustomSelect, false); 183 var currentFocus = document.activeElement;
47 customSelectEls[i] 184 var prevAccordionBody = currentFocus.parentElement.previousElementSibling;
48 .nextElementSibling 185
49 .setAttribute("aria-hidden", "true"); 186 if (prevAccordionBody)
50 } 187 {
51 188 prevAccordionBody // .accordion-body
52 // Browser Select 189 .previousElementSibling // .accordion-heading
190 .firstElementChild // .accordion-toggle-button
191 .focus();
192 }
193 else
194 {
195 this.accordion
196 .lastElementChild // .accordion-body
197 .previousElementSibling // .accordion-heading
198 .firstElementChild // .accordion-toggle-button
199 .focus();
200 }
201 }
202
203 Accordion.prototype._onKeyDown = function(event)
204 {
205 if (!event.target.classList.contains("accordion-toggle-button")) return;
206
207 if (event.key == "ArrowUp" || event.keyCode == 38)
208 {
209 this.focusPrevSection();
210 }
211 else if (event.key == "ArrowDown" || event.keyCode == 40)
212 {
213 this.focusNextSection();
214 }
215 }
216
217 Accordion.prototype._onClick = function(event)
218 {
219 if (!event.target.classList.contains("accordion-toggle-button")) return;
220
221 this.toggleSection(event.target);
222 }
223
224 var productTopicsAccordion = document.getElementById('product-topics-accordi on');
225 if (productTopicsAccordion)
226 {
227 new Accordion(productTopicsAccordion);
228 }
229
230 /**************************************************************************
231 * BrowserSelect
232 **************************************************************************/
233
53 function BrowserSelect(select) 234 function BrowserSelect(select)
54 { 235 {
55 this.browserSelect = select; 236 this.select = select;
56 237 CustomSelect.apply(this, [this.select]);
57 this.DEFAULT_BROWSER = "chrome"; 238
ire 2017/09/29 12:09:18 This is an arbitrary decision. We can change this
58 this.BROWSER_STORAGE_KEY = "BROWSER"; 239 this.BROWSER_STORAGE_KEY = "BROWSER";
59 this.BROWSER_AUTODETECTED_STORAGE_KEY = "BROWSER_AUTODETECTED"; 240 this.BROWSER_AUTODETECTED_STORAGE_KEY = "BROWSER_AUTODETECTED";
60 241 this.SUPPORTED_BROWSERS = ["chrome", "opera", "samsungBrowser",
61 this.browserSelect 242 "yandexbrowser", "maxthon", "msie",
243 "msedge", "firefox", "ios", "safari"];
244 this.DEFAULT_BROWSER = "chrome";
245
246 this.select
62 .addEventListener("click", this._onClickOrKeyDown.bind(this), false); 247 .addEventListener("click", this._onClickOrKeyDown.bind(this), false);
63 248
64 this.browserSelect 249 this.select
65 .addEventListener("keydown", this._onClickOrKeyDown.bind(this), false); 250 .addEventListener("keydown", this._onClickOrKeyDown.bind(this), false);
66 251
67 var storedBrowser = localStorage.getItem(this.BROWSER_STORAGE_KEY); 252 var storedBrowser = localStorage.getItem(this.BROWSER_STORAGE_KEY);
68 if (storedBrowser) 253 if (storedBrowser) this.selectOption(storedBrowser);
69 { 254 else this.detectBrowser();
70 this.selectOption(storedBrowser); 255 }
71 } 256
72 else 257 BrowserSelect.prototype = Object.create(CustomSelect.prototype);
73 { 258 BrowserSelect.prototype.constructor = BrowserSelect;
74 this.detectBrowser();
75 }
76 }
77 259
78 BrowserSelect.prototype.detectBrowser = function() 260 BrowserSelect.prototype.detectBrowser = function()
79 { 261 {
80 localStorage.setItem(this.BROWSER_AUTODETECTED_STORAGE_KEY, "true"); 262 for (var i = 0; i < this.SUPPORTED_BROWSERS.length; i++)
81 263 {
82 var browser; 264 var supportedBrowser = this.SUPPORTED_BROWSERS[i];
83 if (bowser.chrome) browser = "chrome"; 265 if (bowser[supportedBrowser])
ire 2017/09/29 12:09:18 I decided to go with bowser unless we have some ot
84 else if (bowser.opera) browser = "opera"; 266 {
85 else if (bowser.coast) browser = "opera"; 267 localStorage.setItem(this.BROWSER_AUTODETECTED_STORAGE_KEY, "true");
86 else if (bowser.samsungBrowser) browser = "samsung"; 268 return this.selectOption(supportedBrowser);
87 else if (bowser.yandexbrowser) browser = "yandex"; 269 }
88 else if (bowser.maxthon) browser = "maxthon"; 270 }
89 else if (bowser.msie) browser = "ie"; 271
90 else if (bowser.msedge) browser = "edge"; 272 this.selectOption(this.DEFAULT_BROWSER);
91 else if (bowser.firefox) browser = "firefox"; 273 };
92 else if (bowser.ios) browser = "ios";
93 else if (bowser.safari) browser = "safari";
94 else
95 {
96 localStorage.removeItem(this.BROWSER_AUTODETECTED_STORAGE_KEY);
97 browser = this.DEFAULT_BROWSER;
98 }
99
100 this.selectOption(browser);
101 }
102 274
103 BrowserSelect.prototype.selectOption = function(browser) 275 BrowserSelect.prototype.selectOption = function(browser)
104 { 276 {
105 // Save value to Local Storage
106 localStorage.setItem(this.BROWSER_STORAGE_KEY, browser); 277 localStorage.setItem(this.BROWSER_STORAGE_KEY, browser);
107 278
108 // Change body class 279 // Change body class
109 document.body.className = "ua-"+browser; 280 var bodyClassList = Array.prototype.slice.call(document.body.classList);
281 for (var i = 0; i < bodyClassList.length; i++)
282 {
283 if (bodyClassList[i].indexOf('ua-') > -1)
284 {
285 document.body.classList.remove(bodyClassList[i]);
286 }
287 }
288 document.body.classList.add("ua-" + browser);
289
290 // Check selected option
291 var selectedItem = this.select
292 .querySelector("[data-value='" + browser + "']");
293 selectedItem.setAttribute("aria-checked", "true");
110 294
111 // Set selected option 295 // Set selected option
112 var selectedOption = document.createElement('li'); 296 var selectedOption = selectedItem.innerHTML;
113 selectedOption.innerHTML = this
114 .browserSelect
115 .querySelector("[data-value='"+browser+"']")
116 .innerHTML;
117 297
118 if (localStorage.getItem(this.BROWSER_AUTODETECTED_STORAGE_KEY)) 298 if (localStorage.getItem(this.BROWSER_AUTODETECTED_STORAGE_KEY))
119 { 299 {
120 selectedOption.innerHTML += "<span class='muted'>(autodetected)</span>"; 300 var autodetected = document
121 } 301 .getElementById('browser-select-autodetected')
122 302 .innerHTML;
123 this.browserSelect 303 selectedOption += "<span class='muted'>(" + autodetected + ")</span>";
124 .querySelector('.custom-select-selected') 304 }
125 .innerHTML = selectedOption.innerHTML; 305
126 } 306 this.select
307 .querySelector(".custom-select-selected")
308 .innerHTML = selectedOption;
309 };
127 310
128 BrowserSelect.prototype._onClickOrKeyDown = function(event) 311 BrowserSelect.prototype._onClickOrKeyDown = function(event)
129 { 312 {
130 if (!event.target.classList.contains('custom-select-option')) return; 313 if (!event.target.classList.contains("custom-select-option")) return;
131 314
132 var IS_ENTER_KEY = event.key == "Enter" || event.keyCode == 13; 315 var IS_ENTER_KEY = event.key == "Enter" || event.keyCode == 13;
133 if (event.keyCode && !IS_ENTER_KEY) return; 316 if (event.keyCode && !IS_ENTER_KEY) return;
134 317
135 localStorage.removeItem(this.BROWSER_AUTODETECTED_STORAGE_KEY); 318 localStorage.removeItem(this.BROWSER_AUTODETECTED_STORAGE_KEY);
136 319
137 this.selectOption(event.target.getAttribute('data-value')); 320 // Uncheck previously checked option
138 321 this.select
139 // Close Select 322 .querySelector("[aria-checked='true']")
ire 2017/09/29 12:09:17 I think I should refactor the way the custom selec
ire 2017/10/11 17:21:45 Done.
140 document 323 .setAttribute("aria-checked", "false");
141 .querySelector('#browser-select .custom-select-selected') 324
142 .setAttribute("aria-expanded", "false"); 325 this.selectOption(event.target.getAttribute("data-value"));
143 326
144 document 327 this.close();
145 .querySelector('#browser-select .custom-select-options') 328 };
146 .setAttribute("aria-hidden", "true"); 329
147 } 330 var browserSelect = document.getElementById("browser-select");
148
149 var browserSelect = document.getElementById('browser-select');
150 if (browserSelect) 331 if (browserSelect)
151 { 332 {
152 new BrowserSelect(document.getElementById('browser-select')); 333 new BrowserSelect(browserSelect);
153 } 334 }
154 335
155 }, false); 336 }, false);
156 }()); 337 }());
LEFTRIGHT

Powered by Google App Engine
This is Rietveld