OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 cr.define('options', function() { | 5 cr.define('options', function() { |
6 'use strict'; | 6 'use strict'; |
7 | 7 |
8 /** | 8 /** |
9 * A lookup helper function to find the first node that has an id (starting | 9 * A lookup helper function to find the first node that has an id (starting |
10 * at |node| and going up the parent chain). | 10 * at |node| and going up the parent chain). |
11 * @param {Element} node The node to start looking at. | 11 * @param {Element} node The node to start looking at. |
12 */ | 12 */ |
13 function findIdNode(node) { | 13 function findIdNode(node) { |
14 while (node && !node.id) { | 14 while (node && !node.id) { |
15 node = node.parentNode; | 15 node = node.parentNode; |
16 } | 16 } |
17 return node; | 17 return node; |
18 } | 18 } |
19 | 19 |
20 /** | 20 /** |
21 * Creates a new list of extensions. | 21 * Creates a new list of extensions. |
22 * @param {Object=} opt_propertyBag Optional properties. | 22 * @param {Object=} opt_propertyBag Optional properties. |
23 * @constructor | 23 * @constructor |
24 * @extends {cr.ui.div} | 24 * @extends {cr.ui.div} |
25 */ | 25 */ |
26 var ExtensionsList = cr.ui.define('div'); | 26 var ExtensionsList = cr.ui.define('div'); |
27 | 27 |
28 var handleInstalled = false; | 28 var handlersInstalled = false; |
29 | 29 |
30 ExtensionsList.prototype = { | 30 ExtensionsList.prototype = { |
31 __proto__: HTMLDivElement.prototype, | 31 __proto__: HTMLDivElement.prototype, |
32 | 32 |
33 /** @inheritDoc */ | 33 /** @inheritDoc */ |
34 decorate: function() { | 34 decorate: function() { |
35 this.initControlsAndHandlers_(); | 35 this.initControlsAndHandlers_(); |
36 | 36 |
37 var showingDetails = []; | 37 var showingDetails = []; |
38 var showingWarning = []; | 38 var showingWarning = []; |
(...skipping 13 matching lines...) Expand all Loading... |
52 var toggleSection = $('dev'); | 52 var toggleSection = $('dev'); |
53 if (this.data_.developerMode) { | 53 if (this.data_.developerMode) { |
54 toggleSection.classList.add('dev-open'); | 54 toggleSection.classList.add('dev-open'); |
55 toggleSection.classList.remove('dev-closed'); | 55 toggleSection.classList.remove('dev-closed'); |
56 toggleButton.checked = true; | 56 toggleButton.checked = true; |
57 } else { | 57 } else { |
58 toggleSection.classList.remove('dev-open'); | 58 toggleSection.classList.remove('dev-open'); |
59 toggleSection.classList.add('dev-closed'); | 59 toggleSection.classList.add('dev-closed'); |
60 } | 60 } |
61 | 61 |
62 // Install handler for key presses. | 62 // Instal global event handlers. |
63 if (!handleInstalled) { | 63 if (!handlersInstalled) { |
64 this.ownerDocument.addEventListener('keyup', | 64 this.ownerDocument.addEventListener('keyup', |
65 this.upEventHandler_.bind(this)); | 65 this.upEventHandler_.bind(this)); |
66 this.ownerDocument.addEventListener('mouseup', | 66 this.ownerDocument.addEventListener('mouseup', |
67 this.upEventHandler_.bind(this)); | 67 this.upEventHandler_.bind(this)); |
68 handleInstalled = true; | 68 |
| 69 // Support full keyboard accessibility without making things ugly |
| 70 // for users who click, by hiding some focus outlines when the user |
| 71 // clicks anywhere, but showing them when the user presses any key. |
| 72 this.ownerDocument.body.classList.add('hide-some-focus-outlines'); |
| 73 this.ownerDocument.addEventListener('click', (function(e) { |
| 74 this.ownerDocument.body.classList.add('hide-some-focus-outlines'); |
| 75 return true; |
| 76 }).bind(this), true); |
| 77 this.ownerDocument.addEventListener('keydown', (function(e) { |
| 78 this.ownerDocument.body.classList.remove('hide-some-focus-outlines'); |
| 79 return true; |
| 80 }).bind(this), true); |
| 81 |
| 82 handlersInstalled = true; |
69 } | 83 } |
70 }, | 84 }, |
71 | 85 |
72 /** | 86 /** |
73 * Deletes the existing Extension nodes from the page to make room for new | 87 * Deletes the existing Extension nodes from the page to make room for new |
74 * ones. It also keeps track of who was showing details so when the | 88 * ones. It also keeps track of who was showing details so when the |
75 * extension list gets recreated we can recreate that state. | 89 * extension list gets recreated we can recreate that state. |
76 * @param {Array} showingDetails An array that will contain the list of | 90 * @param {Array} showingDetails An array that will contain the list of |
77 * id's of extension that had the details section | 91 * id's of extension that had the details section |
78 * expanded. | 92 * expanded. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 wrapper.appendChild(vboxOuter); | 165 wrapper.appendChild(vboxOuter); |
152 | 166 |
153 var hbox = this.ownerDocument.createElement('div'); | 167 var hbox = this.ownerDocument.createElement('div'); |
154 hbox.classList.add('hbox'); | 168 hbox.classList.add('hbox'); |
155 vboxOuter.appendChild(hbox); | 169 vboxOuter.appendChild(hbox); |
156 | 170 |
157 // Add a container div for the zippy, so we can extend the hit area. | 171 // Add a container div for the zippy, so we can extend the hit area. |
158 var container = this.ownerDocument.createElement('div'); | 172 var container = this.ownerDocument.createElement('div'); |
159 // Clicking anywhere on the div expands/collapses the details. | 173 // Clicking anywhere on the div expands/collapses the details. |
160 container.classList.add('extension-zippy-container'); | 174 container.classList.add('extension-zippy-container'); |
| 175 container.title = expanded ? |
| 176 localStrings.getString('extensionSettingsHideDetails') : |
| 177 localStrings.getString('extensionSettingsShowDetails'); |
| 178 container.tabIndex = 0; |
| 179 container.setAttribute('role', 'button'); |
| 180 container.setAttribute('aria-controls', extension.id + '_details'); |
| 181 container.setAttribute('aria-expanded', expanded); |
161 container.addEventListener('click', this.handleZippyClick_.bind(this)); | 182 container.addEventListener('click', this.handleZippyClick_.bind(this)); |
| 183 container.addEventListener('keydown', |
| 184 this.handleZippyKeyDown_.bind(this)); |
162 hbox.appendChild(container); | 185 hbox.appendChild(container); |
163 | 186 |
164 // On the far left we have the zippy icon. | 187 // On the far left we have the zippy icon. |
165 var div = this.ownerDocument.createElement('div'); | 188 var div = this.ownerDocument.createElement('div'); |
166 div.id = id + '_zippy'; | 189 div.id = id + '_zippy'; |
167 div.classList.add('extension-zippy-default'); | 190 div.classList.add('extension-zippy-default'); |
168 div.classList.add(expanded ? 'extension-zippy-expanded' : | 191 div.classList.add(expanded ? 'extension-zippy-expanded' : |
169 'extension-zippy-collapsed'); | 192 'extension-zippy-collapsed'); |
170 container.appendChild(div); | 193 container.appendChild(div); |
171 | 194 |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 | 538 |
516 var span = this.ownerDocument.createElement('span'); | 539 var span = this.ownerDocument.createElement('span'); |
517 span.innerHTML = | 540 span.innerHTML = |
518 localStrings.getString('extensionSettingsIncognitoWarning'); | 541 localStrings.getString('extensionSettingsIncognitoWarning'); |
519 content.appendChild(span); | 542 content.appendChild(span); |
520 itemsShown++; | 543 itemsShown++; |
521 } | 544 } |
522 | 545 |
523 var zippy = extension.id + '_zippy'; | 546 var zippy = extension.id + '_zippy'; |
524 $(zippy).hidden = !itemsShown; | 547 $(zippy).hidden = !itemsShown; |
| 548 |
| 549 // If this isn't expanded now, make sure the newly-added controls |
| 550 // are not part of the tab order. |
| 551 if (!expanded) { |
| 552 var detailsControls = details.querySelectorAll('a, input'); |
| 553 for (var i = 0; i < detailsControls.length; i++) |
| 554 detailsControls[i].tabIndex = -1; |
| 555 } |
525 }, | 556 }, |
526 | 557 |
527 /** | 558 /** |
528 * A helper function to add contextual actions for extensions (action links) | 559 * A helper function to add contextual actions for extensions (action links) |
529 * to the page. | 560 * to the page. |
530 */ | 561 */ |
531 addLinkTo_: function(parent, linkText, id, handler) { | 562 addLinkTo_: function(parent, linkText, id, handler) { |
532 var link = this.ownerDocument.createElement('a'); | 563 var link = this.ownerDocument.createElement('a'); |
533 link.className = 'extension-links-trailing'; | 564 link.className = 'extension-links-trailing'; |
534 link.textContent = linkText; | 565 link.textContent = linkText; |
(...skipping 10 matching lines...) Expand all Loading... |
545 */ | 576 */ |
546 getExtensionWithId_: function(id) { | 577 getExtensionWithId_: function(id) { |
547 for (var i = 0; i < this.data_.extensions.length; ++i) { | 578 for (var i = 0; i < this.data_.extensions.length; ++i) { |
548 if (this.data_.extensions[i].id == id) | 579 if (this.data_.extensions[i].id == id) |
549 return this.data_.extensions[i]; | 580 return this.data_.extensions[i]; |
550 } | 581 } |
551 return null; | 582 return null; |
552 }, | 583 }, |
553 | 584 |
554 /** | 585 /** |
| 586 * Handles a key down on the zippy icon. |
| 587 * @param {Event} e Key event. |
| 588 * @private |
| 589 */ |
| 590 handleZippyKeyDown_: function(e) { |
| 591 if (e.keyCode == 13 || e.keyCode == 32) // Enter or Space. |
| 592 this.handleZippyClick_(e); |
| 593 }, |
| 594 |
| 595 /** |
555 * Handles the mouseclick on the zippy icon (that expands and collapses the | 596 * Handles the mouseclick on the zippy icon (that expands and collapses the |
556 * details section). | 597 * details section). |
557 * @param {Event} e Change event. | 598 * @param {Event} e Mouse event. |
558 * @private | 599 * @private |
559 */ | 600 */ |
560 handleZippyClick_: function(e) { | 601 handleZippyClick_: function(e) { |
561 var node = findIdNode(e.target.parentNode); | 602 var node = findIdNode(e.target.parentNode); |
562 var iter = this.firstChild; | 603 var iter = this.firstChild; |
563 while (iter) { | 604 while (iter) { |
564 var zippy = $(iter.id + '_zippy'); | 605 var zippy = $(iter.id + '_zippy'); |
565 var details = $(iter.id + '_details'); | 606 var details = $(iter.id + '_details'); |
| 607 var container = zippy.parentElement; |
566 if (iter.id == node.id) { | 608 if (iter.id == node.id) { |
567 // Toggle visibility. | 609 // Toggle visibility. |
568 if (iter.classList.contains('extension-list-item-expanded')) { | 610 if (iter.classList.contains('extension-list-item-expanded')) { |
569 // Hide yo kids! Hide yo wife! | 611 // Hide yo kids! Hide yo wife! |
570 zippy.classList.remove('extension-zippy-expanded'); | 612 zippy.classList.remove('extension-zippy-expanded'); |
571 zippy.classList.add('extension-zippy-collapsed'); | 613 zippy.classList.add('extension-zippy-collapsed'); |
572 details.classList.remove('extension-details-visible'); | 614 details.classList.remove('extension-details-visible'); |
573 details.classList.add('extension-details-hidden'); | 615 details.classList.add('extension-details-hidden'); |
574 iter.classList.remove('extension-list-item-expanded'); | 616 iter.classList.remove('extension-list-item-expanded'); |
575 iter.classList.add('extension-list-item-collaped'); | 617 iter.classList.add('extension-list-item-collaped'); |
| 618 container.setAttribute('aria-expanded', 'false'); |
| 619 container.title = |
| 620 localStrings.getString('extensionSettingsShowDetails'); |
| 621 var detailsControls = details.querySelectorAll('a, input'); |
| 622 for (var i = 0; i < detailsControls.length; i++) |
| 623 detailsControls[i].tabIndex = -1; |
576 | 624 |
577 // Hide yo incognito warning. | 625 // Hide yo incognito warning. |
578 var butterBar = | 626 var butterBar = |
579 this.querySelector('#' + iter.id + '_incognitoWarning'); | 627 this.querySelector('#' + iter.id + '_incognitoWarning'); |
580 if (!(butterBar === null)) | 628 if (!(butterBar === null)) |
581 butterBar.hidden = true; | 629 butterBar.hidden = true; |
582 } else { | 630 } else { |
583 // Show the contents. | 631 // Show the contents. |
584 zippy.classList.remove('extension-zippy-collapsed'); | 632 zippy.classList.remove('extension-zippy-collapsed'); |
585 zippy.classList.add('extension-zippy-expanded'); | 633 zippy.classList.add('extension-zippy-expanded'); |
586 details.classList.remove('extension-details-hidden'); | 634 details.classList.remove('extension-details-hidden'); |
587 details.classList.add('extension-details-visible'); | 635 details.classList.add('extension-details-visible'); |
588 iter.classList.remove('extension-list-item-collaped'); | 636 iter.classList.remove('extension-list-item-collaped'); |
589 iter.classList.add('extension-list-item-expanded'); | 637 iter.classList.add('extension-list-item-expanded'); |
| 638 container.setAttribute('aria-expanded', 'true'); |
| 639 container.title = |
| 640 localStrings.getString('extensionSettingsHideDetails'); |
| 641 var detailsControls = details.querySelectorAll('a, input'); |
| 642 for (var i = 0; i < detailsControls.length; i++) |
| 643 detailsControls[i].tabIndex = 0; |
590 } | 644 } |
591 } | 645 } |
592 iter = iter.nextSibling; | 646 iter = iter.nextSibling; |
593 } | 647 } |
594 }, | 648 }, |
595 | 649 |
596 /** | 650 /** |
597 * Handles the mouse-up and keyboard-up events. This is used to limit the | 651 * Handles the mouse-up and keyboard-up events. This is used to limit the |
598 * number of items to show in the list, when the user is searching for items | 652 * number of items to show in the list, when the user is searching for items |
599 * with the search box. Otherwise, if one match is found, the whole list of | 653 * with the search box. Otherwise, if one match is found, the whole list of |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 ]); | 780 ]); |
727 } | 781 } |
728 } | 782 } |
729 }, | 783 }, |
730 }; | 784 }; |
731 | 785 |
732 return { | 786 return { |
733 ExtensionsList: ExtensionsList | 787 ExtensionsList: ExtensionsList |
734 }; | 788 }; |
735 }); | 789 }); |
OLD | NEW |