OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 // Then the optional Visit Website link. | |
226 if (extension.homepageUrl) { | |
227 var link = this.ownerDocument.createElement('a'); | |
228 link.classList.add('extension-links-trailing'); | |
229 link.textContent = | |
230 localStrings.getString('extensionSettingsVisitWebsite'); | |
231 link.href = extension.homepageUrl; | |
232 vbox.appendChild(link); | |
233 } | |
234 | |
235 if (extension.warnings.length > 0) { | |
236 var warningsDiv = this.ownerDocument.createElement('div'); | |
237 warningsDiv.classList.add('extension-warnings'); | |
238 | |
239 var warningsHeader = this.ownerDocument.createElement('span'); | |
240 warningsHeader.classList.add('extension-warnings-title'); | |
241 warningsHeader.textContent = | |
242 localStrings.getString('extensionSettingsWarningsTitle'); | |
243 warningsDiv.appendChild(warningsHeader); | |
244 | |
245 var warningList = this.ownerDocument.createElement('ul'); | |
246 for (var j = 0; j < extension.warnings.length; ++j) { | |
247 var warningEntry = this.ownerDocument.createElement('li'); | |
248 warningEntry.textContent = extension.warnings[j]; | |
249 warningList.appendChild(warningEntry); | |
250 } | |
251 warningsDiv.appendChild(warningList); | |
252 | |
253 vbox.appendChild(warningsDiv); | |
254 } | |
255 | |
256 // And now the details section that is normally hidden. | |
257 var details = this.ownerDocument.createElement('div'); | |
258 details.classList.add('vbox'); | |
259 vbox.appendChild(details); | |
260 | |
261 this.decorateDetailsSection_(details, extension, expanded, butterbar); | |
262 | |
263 // And on the right of the details we have the Enable/Enabled checkbox. | |
264 div = this.ownerDocument.createElement('div'); | |
265 hbox.appendChild(div); | |
266 | |
267 var section = this.ownerDocument.createElement('section'); | |
268 section.classList.add('extension-enabling'); | |
269 div.appendChild(section); | |
270 | |
271 if (!extension.terminated) { | |
272 // The Enable checkbox. | |
273 var input = this.ownerDocument.createElement('input'); | |
274 input.addEventListener('click', this.handleEnable_.bind(this)); | |
275 input.type = 'checkbox'; | |
276 input.name = 'toggle-' + id; | |
277 input.disabled = !extension.mayDisable; | |
278 if (extension.enabled) | |
279 input.checked = true; | |
280 input.id = 'toggle-' + id; | |
281 section.appendChild(input); | |
282 var label = this.ownerDocument.createElement('label'); | |
283 label.classList.add('extension-enabling-label'); | |
284 if (extension.enabled) | |
285 label.classList.add('extension-enabling-label-bold'); | |
286 label.htmlFor = 'toggle-' + id; | |
287 label.id = 'toggle-' + id + '-label'; | |
288 if (extension.enabled) { | |
289 // Enabled (with a d). | |
290 label.textContent = | |
291 localStrings.getString('extensionSettingsEnabled'); | |
292 } else { | |
293 // Enable (no d). | |
294 label.textContent = | |
295 localStrings.getString('extensionSettingsEnable'); | |
296 } | |
297 section.appendChild(label); | |
298 } else { | |
299 // Extension has been terminated, show a Reload link. | |
300 var link = this.ownerDocument.createElement('a'); | |
301 link.classList.add('extension-links-trailing'); | |
302 link.id = extension.id; | |
303 link.textContent = | |
304 localStrings.getString('extensionSettingsReload'); | |
305 link.href = '#'; | |
306 link.addEventListener('click', this.handleReload_.bind(this)); | |
307 section.appendChild(link); | |
308 } | |
309 | |
310 // And, on the far right we have the uninstall button. | |
311 var button = this.ownerDocument.createElement('button'); | |
312 button.classList.add('extension-delete'); | |
313 button.id = id; | |
314 if (!extension.mayDisable) | |
315 button.disabled = true; | |
316 button.textContent = localStrings.getString('extensionSettingsRemove'); | |
317 button.addEventListener('click', this.handleUninstall_.bind(this)); | |
318 hbox.appendChild(button); | |
319 } | |
320 | |
321 // Do one pass to find what the size of the checkboxes should be. | |
322 var minCheckboxWidth = Infinity; | |
323 var maxCheckboxWidth = 0; | |
324 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
325 var label = $('toggle-' + this.data_.extensions[i].id + '-label'); | |
326 if (label.offsetWidth > maxCheckboxWidth) | |
327 maxCheckboxWidth = label.offsetWidth; | |
328 if (label.offsetWidth < minCheckboxWidth) | |
329 minCheckboxWidth = label.offsetWidth; | |
330 } | |
331 | |
332 // Do another pass, making sure checkboxes line up. | |
333 var difference = maxCheckboxWidth - minCheckboxWidth; | |
334 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
335 var label = $('toggle-' + this.data_.extensions[i].id + '-label'); | |
336 if (label.offsetWidth < maxCheckboxWidth) | |
337 label.style.WebkitMarginEnd = difference.toString() + 'px'; | |
338 } | |
339 }, | |
340 | |
341 /** | |
342 * Handles decorating the details section. | |
343 * @param {Element} details The div that the details should be attached to. | |
344 * @param {Object} extension The extension we are shoting the details for. | |
345 * @param {boolean} expanded Whether to show the details expanded or not. | |
346 * @param {boolean} showButterbar Whether to show the incognito warning or | |
347 * not. | |
348 * @private | |
349 */ | |
350 decorateDetailsSection_: function(details, extension, | |
351 expanded, showButterbar) { | |
352 // This container div is needed because vbox display | |
353 // overrides display:hidden. | |
354 var detailsContents = this.ownerDocument.createElement('div'); | |
355 detailsContents.classList.add(expanded ? 'extension-details-visible' : | |
356 'extension-details-hidden'); | |
357 detailsContents.id = extension.id + '_details'; | |
358 details.appendChild(detailsContents); | |
359 | |
360 var div = this.ownerDocument.createElement('div'); | |
361 div.classList.add('informative-text'); | |
362 detailsContents.appendChild(div); | |
363 | |
364 // Keep track of how many items we'll show in the details section. | |
365 var itemsShown = 0; | |
366 | |
367 if (this.data_.developerMode) { | |
368 // First we have the id. | |
369 var content = this.ownerDocument.createElement('div'); | |
370 content.textContent = | |
371 localStrings.getString('extensionSettingsExtensionId') + | |
372 ' ' + extension.id; | |
373 div.appendChild(content); | |
374 itemsShown++; | |
375 | |
376 // Then, the path, if provided by unpacked extension. | |
377 if (extension.isUnpacked) { | |
378 content = this.ownerDocument.createElement('div'); | |
379 content.textContent = | |
380 localStrings.getString('extensionSettingsExtensionPath') + | |
381 ' ' + extension.path; | |
382 div.appendChild(content); | |
383 itemsShown++; | |
384 } | |
385 | |
386 // Then, the 'managed, cannot uninstall/disable' message. | |
387 if (!extension.mayDisable) { | |
388 content = this.ownerDocument.createElement('div'); | |
389 content.textContent = | |
390 localStrings.getString('extensionSettingsPolicyControlled'); | |
391 div.appendChild(content); | |
392 itemsShown++; | |
393 } | |
394 | |
395 // Then active views: | |
396 if (extension.views.length > 0) { | |
397 var table = this.ownerDocument.createElement('table'); | |
398 table.classList.add('extension-inspect-table'); | |
399 div.appendChild(table); | |
400 var tr = this.ownerDocument.createElement('tr'); | |
401 table.appendChild(tr); | |
402 var td = this.ownerDocument.createElement('td'); | |
403 td.classList.add('extension-inspect-left-column'); | |
404 tr.appendChild(td); | |
405 var span = this.ownerDocument.createElement('span'); | |
406 td.appendChild(span); | |
407 span.textContent = | |
408 localStrings.getString('extensionSettingsInspectViews'); | |
409 | |
410 td = this.ownerDocument.createElement('td'); | |
411 for (var i = 0; i < extension.views.length; ++i) { | |
412 // Then active views: | |
413 content = this.ownerDocument.createElement('div'); | |
414 var link = this.ownerDocument.createElement('a'); | |
415 link.classList.add('extension-links-view'); | |
416 link.textContent = extension.views[i].path; | |
417 link.id = extension.id; | |
418 link.href = '#'; | |
419 link.addEventListener('click', this.sendInspectMessage_.bind(this)); | |
420 content.appendChild(link); | |
421 | |
422 if (extension.views[i].incognito) { | |
423 var incognito = this.ownerDocument.createElement('span'); | |
424 incognito.classList.add('extension-links-view'); | |
425 incognito.textContent = | |
426 localStrings.getString('viewIncognito'); | |
427 content.appendChild(incognito); | |
428 } | |
429 | |
430 td.appendChild(content); | |
431 tr.appendChild(td); | |
432 | |
433 itemsShown++; | |
434 } | |
435 } | |
436 } | |
437 | |
438 var content = this.ownerDocument.createElement('div'); | |
439 detailsContents.appendChild(content); | |
440 | |
441 // Then Reload: | |
442 if (extension.enabled && extension.allow_reload) { | |
443 this.addLinkTo_(content, | |
444 localStrings.getString('extensionSettingsReload'), | |
445 extension.id, | |
446 this.handleReload_.bind(this)); | |
447 itemsShown++; | |
448 } | |
449 | |
450 // Then Show (Browser Action) Button: | |
451 if (extension.enabled && extension.enable_show_button) { | |
452 this.addLinkTo_(content, | |
453 localStrings.getString('extensionSettingsShowButton'), | |
454 extension.id, | |
455 this.handleShowButton_.bind(this)); | |
456 itemsShown++; | |
457 } | |
458 | |
459 if (extension.enabled) { | |
460 // The 'allow in incognito' checkbox. | |
461 var label = this.ownerDocument.createElement('label'); | |
462 label.classList.add('extension-checkbox-label'); | |
463 content.appendChild(label); | |
464 var input = this.ownerDocument.createElement('input'); | |
465 input.addEventListener('click', | |
466 this.handleToggleEnableIncognito_.bind(this)); | |
467 input.id = extension.id; | |
468 input.type = 'checkbox'; | |
469 if (extension.enabledIncognito) | |
470 input.checked = true; | |
471 label.appendChild(input); | |
472 var span = this.ownerDocument.createElement('span'); | |
473 span.classList.add('extension-checkbox-span'); | |
474 span.textContent = | |
475 localStrings.getString('extensionSettingsEnableIncognito'); | |
476 label.appendChild(span); | |
477 itemsShown++; | |
478 } | |
479 | |
480 if (extension.enabled && extension.wantsFileAccess) { | |
481 // The 'allow access to file URLs' checkbox. | |
482 label = this.ownerDocument.createElement('label'); | |
483 label.classList.add('extension-checkbox-label'); | |
484 content.appendChild(label); | |
485 var input = this.ownerDocument.createElement('input'); | |
486 input.addEventListener('click', | |
487 this.handleToggleAllowFileUrls_.bind(this)); | |
488 input.id = extension.id; | |
489 input.type = 'checkbox'; | |
490 if (extension.allowFileAccess) | |
491 input.checked = true; | |
492 label.appendChild(input); | |
493 var span = this.ownerDocument.createElement('span'); | |
494 span.classList.add('extension-checkbox-span'); | |
495 span.textContent = | |
496 localStrings.getString('extensionSettingsAllowFileAccess'); | |
497 label.appendChild(span); | |
498 itemsShown++; | |
499 } | |
500 | |
501 if (extension.enabled && !extension.is_hosted_app) { | |
502 // And add a hidden warning message for allowInIncognito. | |
503 content = this.ownerDocument.createElement('div'); | |
504 content.id = extension.id + '_incognitoWarning'; | |
505 content.classList.add('butter-bar'); | |
506 content.hidden = !showButterbar; | |
507 detailsContents.appendChild(content); | |
508 | |
509 var span = this.ownerDocument.createElement('span'); | |
510 span.innerHTML = | |
511 localStrings.getString('extensionSettingsIncognitoWarning'); | |
512 content.appendChild(span); | |
513 itemsShown++; | |
514 } | |
515 | |
516 var zippy = extension.id + '_zippy'; | |
517 $(zippy).hidden = !itemsShown; | |
518 | |
519 // If this isn't expanded now, make sure the newly-added controls | |
520 // are not part of the tab order. | |
521 if (!expanded) { | |
522 var detailsControls = details.querySelectorAll('a, input'); | |
523 for (var i = 0; i < detailsControls.length; i++) | |
524 detailsControls[i].tabIndex = -1; | |
525 } | |
526 }, | |
527 | |
528 /** | |
529 * A helper function to add contextual actions for extensions (action links) | |
530 * to the page. | |
531 */ | |
532 addLinkTo_: function(parent, linkText, id, handler) { | |
533 var link = this.ownerDocument.createElement('a'); | |
534 link.className = 'extension-links-trailing'; | |
535 link.textContent = linkText; | |
536 link.id = id; | |
537 link.href = '#'; | |
538 link.addEventListener('click', handler); | |
539 parent.appendChild(link); | |
540 }, | |
541 | |
542 /** | |
543 * A lookup helper function to find an extension based on an id. | |
544 * @param {string} id The |id| of the extension to look up. | |
545 * @private | |
546 */ | |
547 getExtensionWithId_: function(id) { | |
548 for (var i = 0; i < this.data_.extensions.length; ++i) { | |
549 if (this.data_.extensions[i].id == id) | |
550 return this.data_.extensions[i]; | |
551 } | |
552 return null; | |
553 }, | |
554 | |
555 /** | |
556 * Handles a key down on the zippy icon. | |
557 * @param {Event} e Key event. | |
558 * @private | |
559 */ | |
560 handleZippyKeyDown_: function(e) { | |
561 if (e.keyCode == 13 || e.keyCode == 32) // Enter or Space. | |
562 this.handleZippyClick_(e); | |
563 }, | |
564 | |
565 /** | |
566 * Handles the mouseclick on the zippy icon (that expands and collapses the | |
567 * details section). | |
568 * @param {Event} e Mouse event. | |
569 * @private | |
570 */ | |
571 handleZippyClick_: function(e) { | |
572 var node = findIdNode(e.target.parentNode); | |
573 var iter = this.firstChild; | |
574 while (iter) { | |
575 var zippy = $(iter.id + '_zippy'); | |
576 var details = $(iter.id + '_details'); | |
577 var container = zippy.parentElement; | |
578 if (iter.id == node.id) { | |
579 // Toggle visibility. | |
580 if (iter.classList.contains('extension-list-item-expanded')) { | |
581 // Hide yo kids! Hide yo wife! | |
582 showingDetails[iter.id] = false; | |
583 zippy.classList.remove('extension-zippy-expanded'); | |
584 zippy.classList.add('extension-zippy-collapsed'); | |
585 details.classList.remove('extension-details-visible'); | |
586 details.classList.add('extension-details-hidden'); | |
587 iter.classList.remove('extension-list-item-expanded'); | |
588 iter.classList.add('extension-list-item-collaped'); | |
589 container.setAttribute('aria-expanded', 'false'); | |
590 container.title = | |
591 localStrings.getString('extensionSettingsShowDetails'); | |
592 var detailsControls = details.querySelectorAll('a, input'); | |
593 for (var i = 0; i < detailsControls.length; i++) | |
594 detailsControls[i].tabIndex = -1; | |
595 | |
596 // Hide yo incognito warning. | |
597 var butterBar = | |
598 this.querySelector('#' + iter.id + '_incognitoWarning'); | |
599 if (butterBar !== null) { | |
600 butterBar.hidden = true; | |
601 showingWarning[iter.id] = false; | |
602 } | |
603 } else { | |
604 // Show the contents. | |
605 showingDetails[iter.id] = true; | |
606 zippy.classList.remove('extension-zippy-collapsed'); | |
607 zippy.classList.add('extension-zippy-expanded'); | |
608 details.classList.remove('extension-details-hidden'); | |
609 details.classList.add('extension-details-visible'); | |
610 iter.classList.remove('extension-list-item-collaped'); | |
611 iter.classList.add('extension-list-item-expanded'); | |
612 container.setAttribute('aria-expanded', 'true'); | |
613 container.title = | |
614 localStrings.getString('extensionSettingsHideDetails'); | |
615 var detailsControls = details.querySelectorAll('a, input'); | |
616 for (var i = 0; i < detailsControls.length; i++) | |
617 detailsControls[i].tabIndex = 0; | |
618 } | |
619 } | |
620 iter = iter.nextSibling; | |
621 } | |
622 }, | |
623 | |
624 /** | |
625 * Handles the 'searchChanged' event. This is used to limit the number of | |
626 * items to show in the list, when the user is searching for items with the | |
627 * search box. Otherwise, if one match is found, the whole list of | |
628 * extensions would be shown when we only want the matching items to be | |
629 * found. | |
630 * @param {Event} e Change event. | |
631 * @private | |
632 */ | |
633 searchChangedHandler_: function(e) { | |
634 var searchString = e.searchText; | |
635 var child = this.firstChild; | |
636 while (child) { | |
637 var extension = this.getExtensionWithId_(child.id); | |
638 if (searchString.length == 0) { | |
639 // Show all. | |
640 child.classList.remove('search-suppress'); | |
641 } else { | |
642 // If the search string does not appear within the text of the | |
643 // extension, then hide it. | |
644 if ((extension.name.toLowerCase().indexOf(searchString) < 0) && | |
645 (extension.version.toLowerCase().indexOf(searchString) < 0) && | |
646 (extension.description.toLowerCase().indexOf(searchString) < 0)) { | |
647 // Hide yo extension! | |
648 child.classList.add('search-suppress'); | |
649 } else { | |
650 // Show yourself! | |
651 child.classList.remove('search-suppress'); | |
652 } | |
653 } | |
654 child = child.nextSibling; | |
655 } | |
656 }, | |
657 | |
658 /** | |
659 * Handles the Reload Extension functionality. | |
660 * @param {Event} e Change event. | |
661 * @private | |
662 */ | |
663 handleReload_: function(e) { | |
664 var node = findIdNode(e.target); | |
665 chrome.send('extensionSettingsReload', [node.id]); | |
666 }, | |
667 | |
668 /** | |
669 * Handles the Show (Browser Action) Button functionality. | |
670 * @param {Event} e Change event. | |
671 * @private | |
672 */ | |
673 handleShowButton_: function(e) { | |
674 var node = findIdNode(e.target); | |
675 chrome.send('extensionSettingsShowButton', [node.id]); | |
676 }, | |
677 | |
678 /** | |
679 * Handles the Enable/Disable Extension functionality. | |
680 * @param {Event} e Change event. | |
681 * @private | |
682 */ | |
683 handleEnable_: function(e) { | |
684 var node = findIdNode(e.target.parentNode); | |
685 var extension = this.getExtensionWithId_(node.id); | |
686 chrome.send('extensionSettingsEnable', | |
687 [node.id, extension.enabled ? 'false' : 'true']); | |
688 chrome.send('extensionSettingsRequestExtensionsData'); | |
689 }, | |
690 | |
691 /** | |
692 * Handles the Uninstall Extension functionality. | |
693 * @param {Event} e Change event. | |
694 * @private | |
695 */ | |
696 handleUninstall_: function(e) { | |
697 var node = findIdNode(e.target.parentNode); | |
698 chrome.send('extensionSettingsUninstall', [node.id]); | |
699 chrome.send('extensionSettingsRequestExtensionsData'); | |
700 }, | |
701 | |
702 /** | |
703 * Handles the View Options link. | |
704 * @param {Event} e Change event. | |
705 * @private | |
706 */ | |
707 handleOptions_: function(e) { | |
708 var node = findIdNode(e.target.parentNode); | |
709 var extension = this.getExtensionWithId_(node.id); | |
710 chrome.send('extensionSettingsOptions', [extension.id]); | |
711 e.preventDefault(); | |
712 }, | |
713 | |
714 /** | |
715 * Handles the Enable Extension In Incognito functionality. | |
716 * @param {Event} e Change event. | |
717 * @private | |
718 */ | |
719 handleToggleEnableIncognito_: function(e) { | |
720 var node = findIdNode(e.target); | |
721 var butterBar = document.getElementById(node.id + '_incognitoWarning'); | |
722 butterBar.hidden = !e.target.checked; | |
723 showingWarning[node.id] = e.target.checked; | |
724 chrome.send('extensionSettingsEnableIncognito', | |
725 [node.id, String(e.target.checked)]); | |
726 }, | |
727 | |
728 /** | |
729 * Handles the Allow On File URLs functionality. | |
730 * @param {Event} e Change event. | |
731 * @private | |
732 */ | |
733 handleToggleAllowFileUrls_: function(e) { | |
734 var node = findIdNode(e.target); | |
735 chrome.send('extensionSettingsAllowFileAccess', | |
736 [node.id, String(e.target.checked)]); | |
737 }, | |
738 | |
739 /** | |
740 * Tell the C++ ExtensionDOMHandler to inspect the page detailed in | |
741 * |viewData|. | |
742 * @param {Event} e Change event. | |
743 * @private | |
744 */ | |
745 sendInspectMessage_: function(e) { | |
746 var extension = this.getExtensionWithId_(e.srcElement.id); | |
747 for (var i = 0; i < extension.views.length; ++i) { | |
748 if (extension.views[i].path == e.srcElement.innerText) { | |
749 // TODO(aa): This is ghetto, but WebUIBindings doesn't support sending | |
750 // anything other than arrays of strings, and this is all going to get | |
751 // replaced with V8 extensions soon anyway. | |
752 chrome.send('extensionSettingsInspect', [ | |
753 String(extension.views[i].renderProcessId), | |
754 String(extension.views[i].renderViewId) | |
755 ]); | |
756 } | |
757 } | |
758 }, | |
759 }; | |
760 | |
761 return { | |
762 ExtensionsList: ExtensionsList | |
763 }; | |
764 }); | |
OLD | NEW |