OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 cr.define('options', function() { | |
6 'use strict'; | |
7 | |
8 /** | |
9 * A lookup helper function to find the first node that has an id (starting | |
10 * at |node| and going up the parent chain). | |
11 * @param {Element} node The node to start looking at. | |
12 */ | |
13 function findIdNode(node) { | |
14 while (node && !node.id) { | |
15 node = node.parentNode; | |
16 } | |
17 return node; | |
18 } | |
19 | |
20 /** | |
21 * Creates a new list of extensions. | |
22 * @param {Object=} opt_propertyBag Optional properties. | |
23 * @constructor | |
24 * @extends {cr.ui.div} | |
25 */ | |
26 var ExtensionsList = cr.ui.define('div'); | |
27 | |
28 var handlersInstalled = false; | |
29 | |
30 /** | |
31 * @type {Object.<string, boolean>} A map from extension id to a boolean | |
32 * indicating whether its details section is expanded. This persists | |
33 * between calls to decorate. | |
34 */ | |
35 var showingDetails = {}; | |
36 | |
37 /** | |
38 * @type {Object.<string, boolean>} A map from extension id to a boolean | |
39 * indicating whether the incognito warning is showing. This persists | |
40 * between calls to decorate. | |
41 */ | |
42 var showingWarning = {}; | |
43 | |
44 ExtensionsList.prototype = { | |
45 __proto__: HTMLDivElement.prototype, | |
46 | |
47 /** @inheritDoc */ | |
48 decorate: function() { | |
49 this.initControlsAndHandlers_(); | |
50 | |
51 this.deleteExistingExtensionNodes_(); | |
52 | |
53 this.showExtensionNodes_(); | |
54 }, | |
55 | |
56 /** | |
57 * Initializes the controls (toggle section and button) and installs | |
58 * handlers. | |
59 * @private | |
60 */ | |
61 initControlsAndHandlers_: function() { | |
62 // Make sure developer mode section is set correctly as per saved setting. | |
63 var toggleButton = $('toggle-dev-on'); | |
64 var toggleSection = $('dev'); | |
65 if (this.data_.developerMode) { | |
66 toggleSection.classList.add('dev-open'); | |
67 toggleSection.classList.remove('dev-closed'); | |
68 toggleButton.checked = true; | |
69 } else { | |
70 toggleSection.classList.remove('dev-open'); | |
71 toggleSection.classList.add('dev-closed'); | |
72 } | |
73 | |
74 // Instal global event handlers. | |
75 if (!handlersInstalled) { | |
76 var searchPage = SearchPage.getInstance(); | |
77 searchPage.addEventListener('searchChanged', | |
78 this.searchChangedHandler_.bind(this)); | |
79 | |
80 // Support full keyboard accessibility without making things ugly | |
81 // for users who click, by hiding some focus outlines when the user | |
82 // clicks anywhere, but showing them when the user presses any key. | |
83 this.ownerDocument.body.classList.add('hide-some-focus-outlines'); | |
84 this.ownerDocument.addEventListener('click', (function(e) { | |
85 this.ownerDocument.body.classList.add('hide-some-focus-outlines'); | |
86 return true; | |
87 }).bind(this), true); | |
88 this.ownerDocument.addEventListener('keydown', (function(e) { | |
89 this.ownerDocument.body.classList.remove('hide-some-focus-outlines'); | |
90 return true; | |
91 }).bind(this), true); | |
92 | |
93 handlersInstalled = true; | |
94 } | |
95 }, | |
96 | |
97 /** | |
98 * Deletes the existing Extension nodes from the page to make room for new | |
99 * ones. | |
100 * @private | |
101 */ | |
102 deleteExistingExtensionNodes_: function() { | |
103 while (this.hasChildNodes()){ | |
104 this.removeChild(this.firstChild); | |
105 } | |
106 }, | |
107 | |
108 /** | |
109 * Handles decorating the details section. | |
110 * @param {Element} details The div that the details should be attached to. | |
111 * @param {Object} extension The extension we are showing the details for. | |
112 * @private | |
113 */ | |
114 showExtensionNodes_: function() { | |
115 // Iterate over the extension data and add each item to the list. | |
116 for (var i = 0; i < this.data_.extensions.length; i++) { | |
117 var extension = this.data_.extensions[i]; | |
118 var id = extension.id; | |
119 | |
120 var wrapper = this.ownerDocument.createElement('div'); | |
121 | |
122 var expanded = showingDetails[id]; | |
123 var butterbar = showingWarning[id]; | |
124 | |
125 wrapper.classList.add(expanded ? 'extension-list-item-expanded' : | |
126 'extension-list-item-collaped'); | |
127 if (!extension.enabled) | |
128 wrapper.classList.add('disabled'); | |
129 wrapper.id = id; | |
130 this.appendChild(wrapper); | |
131 | |
132 var vboxOuter = this.ownerDocument.createElement('div'); | |
133 vboxOuter.classList.add('vbox'); | |
134 vboxOuter.classList.add('extension-list-item'); | |
135 wrapper.appendChild(vboxOuter); | |
136 | |
137 var hbox = this.ownerDocument.createElement('div'); | |
138 hbox.classList.add('hbox'); | |
139 vboxOuter.appendChild(hbox); | |
140 | |
141 // Add a container div for the zippy, so we can extend the hit area. | |
142 var container = this.ownerDocument.createElement('div'); | |
143 // Clicking anywhere on the div expands/collapses the details. | |
144 container.classList.add('extension-zippy-container'); | |
145 container.title = expanded ? | |
146 localStrings.getString('extensionSettingsHideDetails') : | |
147 localStrings.getString('extensionSettingsShowDetails'); | |
148 container.tabIndex = 0; | |
149 container.setAttribute('role', 'button'); | |
150 container.setAttribute('aria-controls', extension.id + '_details'); | |
151 container.setAttribute('aria-expanded', expanded); | |
152 container.addEventListener('click', this.handleZippyClick_.bind(this)); | |
153 container.addEventListener('keydown', | |
154 this.handleZippyKeyDown_.bind(this)); | |
155 hbox.appendChild(container); | |
156 | |
157 // On the far left we have the zippy icon. | |
158 var div = this.ownerDocument.createElement('div'); | |
159 div.id = id + '_zippy'; | |
160 div.classList.add('extension-zippy-default'); | |
161 div.classList.add(expanded ? 'extension-zippy-expanded' : | |
162 'extension-zippy-collapsed'); | |
163 container.appendChild(div); | |
164 | |
165 // Next to it, we have the extension icon. | |
166 var icon = this.ownerDocument.createElement('img'); | |
167 icon.classList.add('extension-icon'); | |
168 icon.src = extension.icon; | |
169 hbox.appendChild(icon); | |
170 | |
171 // Start a vertical box for showing the details. | |
172 var vbox = this.ownerDocument.createElement('div'); | |
173 vbox.classList.add('vbox'); | |
174 vbox.classList.add('stretch'); | |
175 vbox.classList.add('details-view'); | |
176 hbox.appendChild(vbox); | |
177 | |
178 div = this.ownerDocument.createElement('div'); | |
179 vbox.appendChild(div); | |
180 | |
181 // Title comes next. | |
182 var title = this.ownerDocument.createElement('span'); | |
183 title.classList.add('extension-title'); | |
184 title.textContent = extension.name; | |
185 vbox.appendChild(title); | |
186 | |
187 // Followed by version. | |
188 var version = this.ownerDocument.createElement('span'); | |
189 version.classList.add('extension-version'); | |
190 version.textContent = extension.version; | |
191 vbox.appendChild(version); | |
192 | |
193 // And the additional info label (unpacked/crashed). | |
194 if (extension.terminated || extension.isUnpacked) { | |
195 var version = this.ownerDocument.createElement('span'); | |
196 version.classList.add('extension-version'); | |
197 version.textContent = extension.terminated ? | |
198 localStrings.getString('extensionSettingsCrashMessage') : | |
199 localStrings.getString('extensionSettingsInDevelopment'); | |
200 vbox.appendChild(version); | |
201 } | |
202 | |
203 div = this.ownerDocument.createElement('div'); | |
204 vbox.appendChild(div); | |
205 | |
206 // And below that we have description (if provided). | |
207 if (extension.description.length > 0) { | |
208 var description = this.ownerDocument.createElement('span'); | |
209 description.classList.add('extension-description'); | |
210 description.textContent = extension.description; | |
211 vbox.appendChild(description); | |
212 } | |
213 | |
214 // Immediately following the description, we have the | |
215 // Options link (optional). | |
216 if (extension.options_url) { | |
217 var link = this.ownerDocument.createElement('a'); | |
218 link.classList.add('extension-links-trailing'); | |
219 link.textContent = localStrings.getString('extensionSettingsOptions'); | |
220 link.href = '#'; | |
221 link.addEventListener('click', this.handleOptions_.bind(this)); | |
222 vbox.appendChild(link); | |
223 } | |
224 | |
225 if (extension.allow_activity) { | |
226 var link = this.ownerDocument.createElement('a'); | |
227 link.classList.add('extension-links-trailing'); | |
228 link.textContent = | |
229 localStrings.getString('extensionSettingsActivity'); | |
230 link.href = 'chrome://extension-activity?extensionId=' + extension.id; | |
231 vbox.appendChild(link); | |
232 } | |
233 | |
234 // Then the optional Visit Website link. | |
235 if (extension.homepageUrl) { | |
236 var link = this.ownerDocument.createElement('a'); | |
237 link.classList.add('extension-links-trailing'); | |
238 link.textContent = | |
239 localStrings.getString('extensionSettingsVisitWebsite'); | |
240 link.href = extension.homepageUrl; | |
241 vbox.appendChild(link); | |
242 } | |
243 | |
244 if (extension.warnings.length > 0) { | |
245 var warningsDiv = this.ownerDocument.createElement('div'); | |
246 warningsDiv.classList.add('extension-warnings'); | |
247 | |
248 var warningsHeader = this.ownerDocument.createElement('span'); | |
249 warningsHeader.classList.add('extension-warnings-title'); | |
250 warningsHeader.textContent = | |
251 localStrings.getString('extensionSettingsWarningsTitle'); | |
252 warningsDiv.appendChild(warningsHeader); | |
253 | |
254 var warningList = this.ownerDocument.createElement('ul'); | |
255 for (var j = 0; j < extension.warnings.length; ++j) { | |
256 var warningEntry = this.ownerDocument.createElement('li'); | |
257 warningEntry.textContent = extension.warnings[j]; | |
258 warningList.appendChild(warningEntry); | |
259 } | |
260 warningsDiv.appendChild(warningList); | |
261 | |
262 vbox.appendChild(warningsDiv); | |
263 } | |
264 | |
265 // And now the details section that is normally hidden. | |
266 var details = this.ownerDocument.createElement('div'); | |
267 details.classList.add('vbox'); | |
268 vbox.appendChild(details); | |
269 | |
270 this.decorateDetailsSection_(details, extension, expanded, butterbar); | |
271 | |
272 // And on the right of the details we have the Enable/Enabled checkbox. | |
273 div = this.ownerDocument.createElement('div'); | |
274 hbox.appendChild(div); | |
275 | |
276 var section = this.ownerDocument.createElement('section'); | |
277 section.classList.add('extension-enabling'); | |
278 div.appendChild(section); | |
279 | |
280 if (!extension.terminated) { | |
281 // The Enable checkbox. | |
282 var input = this.ownerDocument.createElement('input'); | |
283 input.addEventListener('click', this.handleEnable_.bind(this)); | |
284 input.type = 'checkbox'; | |
285 input.name = 'toggle-' + id; | |
286 input.disabled = !extension.mayDisable; | |
287 if (extension.enabled) | |
288 input.checked = true; | |
289 input.id = 'toggle-' + id; | |
290 section.appendChild(input); | |
291 var label = this.ownerDocument.createElement('label'); | |
292 label.classList.add('extension-enabling-label'); | |
293 if (extension.enabled) | |
294 label.classList.add('extension-enabling-label-bold'); | |
295 label.htmlFor = 'toggle-' + id; | |
296 label.id = 'toggle-' + id + '-label'; | |
297 if (extension.enabled) { | |
298 // Enabled (with a d). | |
299 label.textContent = | |
300 localStrings.getString('extensionSettingsEnabled'); | |
301 } else { | |
302 // Enable (no d). | |
303 label.textContent = | |
304 localStrings.getString('extensionSettingsEnable'); | |
305 } | |
306 section.appendChild(label); | |
307 } else { | |
308 // Extension has been terminated, show a Reload link. | |
309 var link = this.ownerDocument.createElement('a'); | |
310 link.classList.add('extension-links-trailing'); | |
311 link.id = extension.id; | |
312 link.textContent = | |
313 localStrings.getString('extensionSettingsReload'); | |
314 link.href = '#'; | |
315 link.addEventListener('click', this.handleReload_.bind(this)); | |
316 section.appendChild(link); | |
317 } | |
318 | |
319 // And, on the far right we have the uninstall button. | |
320 var button = this.ownerDocument.createElement('button'); | |
321 button.classList.add('extension-delete'); | |
322 button.id = id; | |
323 if (!extension.mayDisable) | |
324 button.disabled = true; | |
325 button.textContent = localStrings.getString('extensionSettingsRemove'); | |
326 button.addEventListener('click', this.handleUninstall_.bind(this)); | |
327 hbox.appendChild(button); | |
328 } | |
329 | |
330 // Do one pass to find what the size of the checkboxes should be. | |
331 var minCheckboxWidth = Infinity; | |
332 var maxCheckboxWidth = 0; | |
333 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
334 var label = $('toggle-' + this.data_.extensions[i].id + '-label'); | |
335 if (label.offsetWidth > maxCheckboxWidth) | |
336 maxCheckboxWidth = label.offsetWidth; | |
337 if (label.offsetWidth < minCheckboxWidth) | |
338 minCheckboxWidth = label.offsetWidth; | |
339 } | |
340 | |
341 // Do another pass, making sure checkboxes line up. | |
342 var difference = maxCheckboxWidth - minCheckboxWidth; | |
343 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
344 var label = $('toggle-' + this.data_.extensions[i].id + '-label'); | |
345 if (label.offsetWidth < maxCheckboxWidth) | |
346 label.style.WebkitMarginEnd = difference.toString() + 'px'; | |
347 } | |
348 }, | |
349 | |
350 /** | |
351 * Handles decorating the details section. | |
352 * @param {Element} details The div that the details should be attached to. | |
353 * @param {Object} extension The extension we are shoting the details for. | |
354 * @param {boolean} expanded Whether to show the details expanded or not. | |
355 * @param {boolean} showButterbar Whether to show the incognito warning or | |
356 * not. | |
357 * @private | |
358 */ | |
359 decorateDetailsSection_: function(details, extension, | |
360 expanded, showButterbar) { | |
361 // This container div is needed because vbox display | |
362 // overrides display:hidden. | |
363 var detailsContents = this.ownerDocument.createElement('div'); | |
364 detailsContents.classList.add(expanded ? 'extension-details-visible' : | |
365 'extension-details-hidden'); | |
366 detailsContents.id = extension.id + '_details'; | |
367 details.appendChild(detailsContents); | |
368 | |
369 var div = this.ownerDocument.createElement('div'); | |
370 div.classList.add('informative-text'); | |
371 detailsContents.appendChild(div); | |
372 | |
373 // Keep track of how many items we'll show in the details section. | |
374 var itemsShown = 0; | |
375 | |
376 if (this.data_.developerMode) { | |
377 // First we have the id. | |
378 var content = this.ownerDocument.createElement('div'); | |
379 content.textContent = | |
380 localStrings.getString('extensionSettingsExtensionId') + | |
381 ' ' + extension.id; | |
382 div.appendChild(content); | |
383 itemsShown++; | |
384 | |
385 // Then, the path, if provided by unpacked extension. | |
386 if (extension.isUnpacked) { | |
387 content = this.ownerDocument.createElement('div'); | |
388 content.textContent = | |
389 localStrings.getString('extensionSettingsExtensionPath') + | |
390 ' ' + extension.path; | |
391 div.appendChild(content); | |
392 itemsShown++; | |
393 } | |
394 | |
395 // Then, the 'managed, cannot uninstall/disable' message. | |
396 if (!extension.mayDisable) { | |
397 content = this.ownerDocument.createElement('div'); | |
398 content.textContent = | |
399 localStrings.getString('extensionSettingsPolicyControlled'); | |
400 div.appendChild(content); | |
401 itemsShown++; | |
402 } | |
403 | |
404 // Then active views: | |
405 if (extension.views.length > 0) { | |
406 var table = this.ownerDocument.createElement('table'); | |
407 table.classList.add('extension-inspect-table'); | |
408 div.appendChild(table); | |
409 var tr = this.ownerDocument.createElement('tr'); | |
410 table.appendChild(tr); | |
411 var td = this.ownerDocument.createElement('td'); | |
412 td.classList.add('extension-inspect-left-column'); | |
413 tr.appendChild(td); | |
414 var span = this.ownerDocument.createElement('span'); | |
415 td.appendChild(span); | |
416 span.textContent = | |
417 localStrings.getString('extensionSettingsInspectViews'); | |
418 | |
419 td = this.ownerDocument.createElement('td'); | |
420 for (var i = 0; i < extension.views.length; ++i) { | |
421 // Then active views: | |
422 content = this.ownerDocument.createElement('div'); | |
423 var link = this.ownerDocument.createElement('a'); | |
424 link.classList.add('extension-links-view'); | |
425 link.textContent = extension.views[i].path; | |
426 link.id = extension.id; | |
427 link.href = '#'; | |
428 link.addEventListener('click', this.sendInspectMessage_.bind(this)); | |
429 content.appendChild(link); | |
430 | |
431 if (extension.views[i].incognito) { | |
432 var incognito = this.ownerDocument.createElement('span'); | |
433 incognito.classList.add('extension-links-view'); | |
434 incognito.textContent = | |
435 localStrings.getString('viewIncognito'); | |
436 content.appendChild(incognito); | |
437 } | |
438 | |
439 td.appendChild(content); | |
440 tr.appendChild(td); | |
441 | |
442 itemsShown++; | |
443 } | |
444 } | |
445 } | |
446 | |
447 var content = this.ownerDocument.createElement('div'); | |
448 detailsContents.appendChild(content); | |
449 | |
450 // Then Reload: | |
451 if (extension.enabled && extension.allow_reload) { | |
452 this.addLinkTo_(content, | |
453 localStrings.getString('extensionSettingsReload'), | |
454 extension.id, | |
455 this.handleReload_.bind(this)); | |
456 itemsShown++; | |
457 } | |
458 | |
459 // Then Show (Browser Action) Button: | |
460 if (extension.enabled && extension.enable_show_button) { | |
461 this.addLinkTo_(content, | |
462 localStrings.getString('extensionSettingsShowButton'), | |
463 extension.id, | |
464 this.handleShowButton_.bind(this)); | |
465 itemsShown++; | |
466 } | |
467 | |
468 if (extension.enabled) { | |
469 // The 'allow in incognito' checkbox. | |
470 var label = this.ownerDocument.createElement('label'); | |
471 label.classList.add('extension-checkbox-label'); | |
472 content.appendChild(label); | |
473 var input = this.ownerDocument.createElement('input'); | |
474 input.addEventListener('click', | |
475 this.handleToggleEnableIncognito_.bind(this)); | |
476 input.id = extension.id; | |
477 input.type = 'checkbox'; | |
478 if (extension.enabledIncognito) | |
479 input.checked = true; | |
480 label.appendChild(input); | |
481 var span = this.ownerDocument.createElement('span'); | |
482 span.classList.add('extension-checkbox-span'); | |
483 span.textContent = | |
484 localStrings.getString('extensionSettingsEnableIncognito'); | |
485 label.appendChild(span); | |
486 itemsShown++; | |
487 } | |
488 | |
489 if (extension.enabled && extension.wantsFileAccess) { | |
490 // The 'allow access to file URLs' checkbox. | |
491 label = this.ownerDocument.createElement('label'); | |
492 label.classList.add('extension-checkbox-label'); | |
493 content.appendChild(label); | |
494 var input = this.ownerDocument.createElement('input'); | |
495 input.addEventListener('click', | |
496 this.handleToggleAllowFileUrls_.bind(this)); | |
497 input.id = extension.id; | |
498 input.type = 'checkbox'; | |
499 if (extension.allowFileAccess) | |
500 input.checked = true; | |
501 label.appendChild(input); | |
502 var span = this.ownerDocument.createElement('span'); | |
503 span.classList.add('extension-checkbox-span'); | |
504 span.textContent = | |
505 localStrings.getString('extensionSettingsAllowFileAccess'); | |
506 label.appendChild(span); | |
507 itemsShown++; | |
508 } | |
509 | |
510 if (extension.enabled && !extension.is_hosted_app) { | |
511 // And add a hidden warning message for allowInIncognito. | |
512 content = this.ownerDocument.createElement('div'); | |
513 content.id = extension.id + '_incognitoWarning'; | |
514 content.classList.add('butter-bar'); | |
515 content.hidden = !showButterbar; | |
516 detailsContents.appendChild(content); | |
517 | |
518 var span = this.ownerDocument.createElement('span'); | |
519 span.innerHTML = | |
520 localStrings.getString('extensionSettingsIncognitoWarning'); | |
521 content.appendChild(span); | |
522 itemsShown++; | |
523 } | |
524 | |
525 var zippy = extension.id + '_zippy'; | |
526 $(zippy).hidden = !itemsShown; | |
527 | |
528 // If this isn't expanded now, make sure the newly-added controls | |
529 // are not part of the tab order. | |
530 if (!expanded) { | |
531 var detailsControls = details.querySelectorAll('a, input'); | |
532 for (var i = 0; i < detailsControls.length; i++) | |
533 detailsControls[i].tabIndex = -1; | |
534 } | |
535 }, | |
536 | |
537 /** | |
538 * A helper function to add contextual actions for extensions (action links) | |
539 * to the page. | |
540 */ | |
541 addLinkTo_: function(parent, linkText, id, handler) { | |
542 var link = this.ownerDocument.createElement('a'); | |
543 link.className = 'extension-links-trailing'; | |
544 link.textContent = linkText; | |
545 link.id = id; | |
546 link.href = '#'; | |
547 link.addEventListener('click', handler); | |
548 parent.appendChild(link); | |
549 }, | |
550 | |
551 /** | |
552 * A lookup helper function to find an extension based on an id. | |
553 * @param {string} id The |id| of the extension to look up. | |
554 * @private | |
555 */ | |
556 getExtensionWithId_: function(id) { | |
557 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
558 if (this.data_.extensions[i].id == id) | |
559 return this.data_.extensions[i]; | |
560 } | |
561 return null; | |
562 }, | |
563 | |
564 /** | |
565 * Handles a key down on the zippy icon. | |
566 * @param {Event} e Key event. | |
567 * @private | |
568 */ | |
569 handleZippyKeyDown_: function(e) { | |
570 if (e.keyCode == 13 || e.keyCode == 32) // Enter or Space. | |
571 this.handleZippyClick_(e); | |
572 }, | |
573 | |
574 /** | |
575 * Handles the mouseclick on the zippy icon (that expands and collapses the | |
576 * details section). | |
577 * @param {Event} e Mouse event. | |
578 * @private | |
579 */ | |
580 handleZippyClick_: function(e) { | |
581 var node = findIdNode(e.target.parentNode); | |
582 var iter = this.firstChild; | |
583 while (iter) { | |
584 var zippy = $(iter.id + '_zippy'); | |
585 var details = $(iter.id + '_details'); | |
586 var container = zippy.parentElement; | |
587 if (iter.id == node.id) { | |
588 // Toggle visibility. | |
589 if (iter.classList.contains('extension-list-item-expanded')) { | |
590 // Hide yo kids! Hide yo wife! | |
591 showingDetails[iter.id] = false; | |
592 zippy.classList.remove('extension-zippy-expanded'); | |
593 zippy.classList.add('extension-zippy-collapsed'); | |
594 details.classList.remove('extension-details-visible'); | |
595 details.classList.add('extension-details-hidden'); | |
596 iter.classList.remove('extension-list-item-expanded'); | |
597 iter.classList.add('extension-list-item-collaped'); | |
598 container.setAttribute('aria-expanded', 'false'); | |
599 container.title = | |
600 localStrings.getString('extensionSettingsShowDetails'); | |
601 var detailsControls = details.querySelectorAll('a, input'); | |
602 for (var i = 0; i < detailsControls.length; i++) | |
603 detailsControls[i].tabIndex = -1; | |
604 | |
605 // Hide yo incognito warning. | |
606 var butterBar = | |
607 this.querySelector('#' + iter.id + '_incognitoWarning'); | |
608 if (butterBar !== null) { | |
609 butterBar.hidden = true; | |
610 showingWarning[iter.id] = false; | |
611 } | |
612 } else { | |
613 // Show the contents. | |
614 showingDetails[iter.id] = true; | |
615 zippy.classList.remove('extension-zippy-collapsed'); | |
616 zippy.classList.add('extension-zippy-expanded'); | |
617 details.classList.remove('extension-details-hidden'); | |
618 details.classList.add('extension-details-visible'); | |
619 iter.classList.remove('extension-list-item-collaped'); | |
620 iter.classList.add('extension-list-item-expanded'); | |
621 container.setAttribute('aria-expanded', 'true'); | |
622 container.title = | |
623 localStrings.getString('extensionSettingsHideDetails'); | |
624 var detailsControls = details.querySelectorAll('a, input'); | |
625 for (var i = 0; i < detailsControls.length; i++) | |
626 detailsControls[i].tabIndex = 0; | |
627 } | |
628 } | |
629 iter = iter.nextSibling; | |
630 } | |
631 }, | |
632 | |
633 /** | |
634 * Handles the 'searchChanged' event. This is used to limit the number of | |
635 * items to show in the list, when the user is searching for items with the | |
636 * search box. Otherwise, if one match is found, the whole list of | |
637 * extensions would be shown when we only want the matching items to be | |
638 * found. | |
639 * @param {Event} e Change event. | |
640 * @private | |
641 */ | |
642 searchChangedHandler_: function(e) { | |
643 var searchString = e.searchText; | |
644 var child = this.firstChild; | |
645 while (child) { | |
646 var extension = this.getExtensionWithId_(child.id); | |
647 if (searchString.length == 0) { | |
648 // Show all. | |
649 child.classList.remove('search-suppress'); | |
650 } else { | |
651 // If the search string does not appear within the text of the | |
652 // extension, then hide it. | |
653 if ((extension.name.toLowerCase().indexOf(searchString) < 0) && | |
654 (extension.version.toLowerCase().indexOf(searchString) < 0) && | |
655 (extension.description.toLowerCase().indexOf(searchString) < 0)) { | |
656 // Hide yo extension! | |
657 child.classList.add('search-suppress'); | |
658 } else { | |
659 // Show yourself! | |
660 child.classList.remove('search-suppress'); | |
661 } | |
662 } | |
663 child = child.nextSibling; | |
664 } | |
665 }, | |
666 | |
667 /** | |
668 * Handles the Reload Extension functionality. | |
669 * @param {Event} e Change event. | |
670 * @private | |
671 */ | |
672 handleReload_: function(e) { | |
673 var node = findIdNode(e.target); | |
674 chrome.send('extensionSettingsReload', [node.id]); | |
675 }, | |
676 | |
677 /** | |
678 * Handles the Show (Browser Action) Button functionality. | |
679 * @param {Event} e Change event. | |
680 * @private | |
681 */ | |
682 handleShowButton_: function(e) { | |
683 var node = findIdNode(e.target); | |
684 chrome.send('extensionSettingsShowButton', [node.id]); | |
685 }, | |
686 | |
687 /** | |
688 * Handles the Enable/Disable Extension functionality. | |
689 * @param {Event} e Change event. | |
690 * @private | |
691 */ | |
692 handleEnable_: function(e) { | |
693 var node = findIdNode(e.target.parentNode); | |
694 var extension = this.getExtensionWithId_(node.id); | |
695 chrome.send('extensionSettingsEnable', | |
696 [node.id, extension.enabled ? 'false' : 'true']); | |
697 chrome.send('extensionSettingsRequestExtensionsData'); | |
698 }, | |
699 | |
700 /** | |
701 * Handles the Uninstall Extension functionality. | |
702 * @param {Event} e Change event. | |
703 * @private | |
704 */ | |
705 handleUninstall_: function(e) { | |
706 var node = findIdNode(e.target.parentNode); | |
707 chrome.send('extensionSettingsUninstall', [node.id]); | |
708 chrome.send('extensionSettingsRequestExtensionsData'); | |
709 }, | |
710 | |
711 /** | |
712 * Handles the View Options link. | |
713 * @param {Event} e Change event. | |
714 * @private | |
715 */ | |
716 handleOptions_: function(e) { | |
717 var node = findIdNode(e.target.parentNode); | |
718 var extension = this.getExtensionWithId_(node.id); | |
719 chrome.send('extensionSettingsOptions', [extension.id]); | |
720 e.preventDefault(); | |
721 }, | |
722 | |
723 /** | |
724 * Handles the Enable Extension In Incognito functionality. | |
725 * @param {Event} e Change event. | |
726 * @private | |
727 */ | |
728 handleToggleEnableIncognito_: function(e) { | |
729 var node = findIdNode(e.target); | |
730 var butterBar = document.getElementById(node.id + '_incognitoWarning'); | |
731 butterBar.hidden = !e.target.checked; | |
732 showingWarning[node.id] = e.target.checked; | |
733 chrome.send('extensionSettingsEnableIncognito', | |
734 [node.id, String(e.target.checked)]); | |
735 }, | |
736 | |
737 /** | |
738 * Handles the Allow On File URLs functionality. | |
739 * @param {Event} e Change event. | |
740 * @private | |
741 */ | |
742 handleToggleAllowFileUrls_: function(e) { | |
743 var node = findIdNode(e.target); | |
744 chrome.send('extensionSettingsAllowFileAccess', | |
745 [node.id, String(e.target.checked)]); | |
746 }, | |
747 | |
748 /** | |
749 * Tell the C++ ExtensionDOMHandler to inspect the page detailed in | |
750 * |viewData|. | |
751 * @param {Event} e Change event. | |
752 * @private | |
753 */ | |
754 sendInspectMessage_: function(e) { | |
755 var extension = this.getExtensionWithId_(e.srcElement.id); | |
756 for (var i = 0; i < extension.views.length; ++i) { | |
757 if (extension.views[i].path == e.srcElement.innerText) { | |
758 // TODO(aa): This is ghetto, but WebUIBindings doesn't support sending | |
759 // anything other than arrays of strings, and this is all going to get | |
760 // replaced with V8 extensions soon anyway. | |
761 chrome.send('extensionSettingsInspect', [ | |
762 String(extension.views[i].renderProcessId), | |
763 String(extension.views[i].renderViewId) | |
764 ]); | |
765 } | |
766 } | |
767 }, | |
768 }; | |
769 | |
770 return { | |
771 ExtensionsList: ExtensionsList | |
772 }; | |
773 }); | |
OLD | NEW |