Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 ///////////////////////////////////////////////////////////////////////////// | 6 ///////////////////////////////////////////////////////////////////////////// |
| 7 // OptionsPage class: | 7 // OptionsPage class: |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Base class for options page. | 10 * Base class for options page. |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 this.registeredOverlayPages[overlayName].visible = true; | 122 this.registeredOverlayPages[overlayName].visible = true; |
| 123 } | 123 } |
| 124 }; | 124 }; |
| 125 | 125 |
| 126 /** | 126 /** |
| 127 * Returns whether or not an overlay is visible. | 127 * Returns whether or not an overlay is visible. |
| 128 * @return {boolean} True if an overlay is visible. | 128 * @return {boolean} True if an overlay is visible. |
| 129 * @private | 129 * @private |
| 130 */ | 130 */ |
| 131 OptionsPage.isOverlayVisible_ = function() { | 131 OptionsPage.isOverlayVisible_ = function() { |
| 132 for (var name in this.registeredOverlayPages) { | 132 return this.getVisibleOverlay_() != null; |
| 133 if (this.registeredOverlayPages[name].visible) | |
| 134 return true; | |
| 135 } | |
| 136 return false; | |
| 137 }; | 133 }; |
| 138 | 134 |
| 139 /** | 135 /** |
| 136 * Returns the currently visible overlay, or null if no page is visible. | |
| 137 * @return {OptionPage} The visible overlay. | |
| 138 */ | |
| 139 OptionsPage.getVisibleOverlay_ = function() { | |
| 140 for (var name in this.registeredOverlayPages) { | |
| 141 var page = this.registeredOverlayPages[name]; | |
| 142 if (page.visible) | |
| 143 return page; | |
| 144 } | |
| 145 return null; | |
| 146 }; | |
| 147 | |
| 148 /** | |
| 140 * Clears overlays (i.e. hide all overlays). | 149 * Clears overlays (i.e. hide all overlays). |
| 141 */ | 150 */ |
| 142 OptionsPage.clearOverlays = function() { | 151 OptionsPage.clearOverlays = function() { |
| 143 for (var name in this.registeredOverlayPages) { | 152 for (var name in this.registeredOverlayPages) { |
| 144 var page = this.registeredOverlayPages[name]; | 153 var page = this.registeredOverlayPages[name]; |
| 145 page.visible = false; | 154 page.visible = false; |
| 146 } | 155 } |
| 147 }; | 156 }; |
| 148 | 157 |
| 149 /** | 158 /** |
| 150 * Returns the topmost visible page, or null if no page is visible. | 159 * Returns the topmost visible page, or null if no page is visible. |
| 151 * @return {OptionPage} The topmost visible page. | 160 * @return {OptionPage} The topmost visible page. |
| 152 */ | 161 */ |
| 153 OptionsPage.getTopmostVisiblePage = function() { | 162 OptionsPage.getTopmostVisiblePage = function() { |
| 154 var topPage = null; | 163 var topPage = null; |
| 155 for (var name in this.registeredPages) { | 164 for (var name in this.registeredPages) { |
| 156 var page = this.registeredPages[name]; | 165 var page = this.registeredPages[name]; |
| 157 if (page.visible && | 166 if (page.visible && |
| 158 (!topPage || page.nestingLevel > topPage.nestingLevel)) | 167 (!topPage || page.nestingLevel > topPage.nestingLevel)) |
| 159 topPage = page; | 168 topPage = page; |
| 160 } | 169 } |
| 161 return topPage; | 170 return topPage; |
| 162 } | 171 }; |
| 163 | 172 |
| 164 /** | 173 /** |
| 165 * Closes the topmost open subpage, if any. | 174 * Closes the topmost open subpage, if any. |
| 166 */ | 175 */ |
| 167 OptionsPage.closeTopSubPage = function() { | 176 OptionsPage.closeTopSubPage = function() { |
| 168 var topPage = this.getTopmostVisiblePage(); | 177 var topPage = this.getTopmostVisiblePage(); |
| 169 if (topPage && topPage.parentPage) | 178 if (topPage && topPage.parentPage) |
| 170 topPage.visible = false; | 179 topPage.visible = false; |
| 171 }; | 180 }; |
| 172 | 181 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 // Hook up the close buttons. | 351 // Hook up the close buttons. |
| 343 subpageCloseButtons = document.querySelectorAll('.close-subpage'); | 352 subpageCloseButtons = document.querySelectorAll('.close-subpage'); |
| 344 for (var i = 0; i < subpageCloseButtons.length; i++) { | 353 for (var i = 0; i < subpageCloseButtons.length; i++) { |
| 345 subpageCloseButtons[i].onclick = function() { | 354 subpageCloseButtons[i].onclick = function() { |
| 346 self.closeTopSubPage(); | 355 self.closeTopSubPage(); |
| 347 }; | 356 }; |
| 348 }; | 357 }; |
| 349 | 358 |
| 350 // Install handler for key presses. | 359 // Install handler for key presses. |
| 351 document.addEventListener('keydown', this.keyDownEventHandler_.bind(this)); | 360 document.addEventListener('keydown', this.keyDownEventHandler_.bind(this)); |
| 361 | |
| 362 document.addEventListener('focus', this.manageFocusChange_.bind(this), | |
|
James Hawkins
2011/01/26 01:29:41
nit: All params on one line or lined up in one col
stuartmorgan
2011/01/26 17:27:03
The style guide explicitly allows either form.
James Hawkins
2011/01/26 18:08:25
Interesting. I had been told otherwise by a reputa
| |
| 363 true); | |
| 352 }; | 364 }; |
| 353 | 365 |
| 354 /** | 366 /** |
| 355 * Returns a function to handle clicks behind a subpage at level |level| by | 367 * Returns a function to handle clicks behind a subpage at level |level| by |
| 356 * closing all subpages down to |level| - 1. | 368 * closing all subpages down to |level| - 1. |
| 357 * @param {number} level The level of the subpage being handled. | 369 * @param {number} level The level of the subpage being handled. |
| 358 * @return {Function} a function to handle clicks outside the given subpage. | 370 * @return {Function} a function to handle clicks outside the given subpage. |
| 359 * @private | 371 * @private |
| 360 */ | 372 */ |
| 361 OptionsPage.subPageClosingClickHandler_ = function(level) { | 373 OptionsPage.subPageClosingClickHandler_ = function(level) { |
| 362 var self = this; | 374 var self = this; |
| 363 return function(event) { | 375 return function(event) { |
| 364 // Clicks on the narrow strip between the left of the subpage sheet and | 376 // Clicks on the narrow strip between the left of the subpage sheet and |
| 365 // that shows part of the parent page should close the overlay, but | 377 // that shows part of the parent page should close the overlay, but |
| 366 // not fall through to the parent page. | 378 // not fall through to the parent page. |
| 367 if (!$('subpage-sheet-' + level).contains(event.target)) { | 379 if (!$('subpage-sheet-' + level).contains(event.target)) { |
| 368 self.closeSubPagesToLevel(level - 1); | 380 self.closeSubPagesToLevel(level - 1); |
| 369 event.stopPropagation(); | 381 event.stopPropagation(); |
| 370 event.preventDefault(); | 382 event.preventDefault(); |
| 371 } | 383 } |
| 372 }; | 384 }; |
| 373 }; | 385 }; |
| 374 | 386 |
| 375 /** | 387 /** |
| 388 * Called when focus changes; ensures that focus doesn't move outside | |
| 389 * the topmost subpage/overlay. | |
| 390 * @param {Event} e The focus change event. | |
| 391 * @private | |
| 392 */ | |
| 393 OptionsPage.manageFocusChange_ = function(e) { | |
| 394 var tabLoopRoot = null; | |
|
James Hawkins
2011/01/26 01:29:41
This var name is a little confusing.
stuartmorgan
2011/01/26 17:27:03
Changed to focusableItemsRoot; hopefully that's a
| |
| 395 // If an overlay is visible, that defines the tab loop | |
|
James Hawkins
2011/01/26 01:29:41
nit: Period at end of sentence.
stuartmorgan
2011/01/26 17:27:03
Done.
| |
| 396 var topPage = this.getVisibleOverlay_(); | |
| 397 if (topPage) | |
| 398 tabLoopRoot = topPage.pageDiv; | |
| 399 // If a subpage is visible, use its parent as the tab loop constraint. | |
| 400 // (The parent is used because it contains the close button.) | |
| 401 if (!topPage) { | |
| 402 var topPage = this.getTopmostVisiblePage(); | |
| 403 if (topPage && topPage.nestingLevel > 0) | |
| 404 tabLoopRoot = topPage.pageDiv.parentNode; | |
| 405 } | |
| 406 | |
| 407 if (tabLoopRoot && !tabLoopRoot.contains(e.target)) { | |
|
James Hawkins
2011/01/26 01:29:41
nit: No need for braces.
stuartmorgan
2011/01/26 17:27:03
Done.
| |
| 408 topPage.focusFirstElement(); | |
| 409 } | |
| 410 }; | |
| 411 | |
| 412 /** | |
| 376 * A function to handle mouse events (mousedown or click) on the html body by | 413 * A function to handle mouse events (mousedown or click) on the html body by |
| 377 * closing subpages and/or stopping event propagation. | 414 * closing subpages and/or stopping event propagation. |
| 378 * @return {Event} a mousedown or click event. | 415 * @return {Event} a mousedown or click event. |
| 379 * @private | 416 * @private |
| 380 */ | 417 */ |
| 381 OptionsPage.bodyMouseEventHandler_ = function(event) { | 418 OptionsPage.bodyMouseEventHandler_ = function(event) { |
| 382 // Do nothing if a subpage isn't showing. | 419 // Do nothing if a subpage isn't showing. |
| 383 var topPage = this.getTopmostVisiblePage(); | 420 var topPage = this.getTopmostVisiblePage(); |
| 384 if (!(topPage && topPage.parentPage)) | 421 if (!(topPage && topPage.parentPage)) |
| 385 return; | 422 return; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 } | 572 } |
| 536 if (this.tab) { | 573 if (this.tab) { |
| 537 this.tab.classList.remove('navbar-item-selected'); | 574 this.tab.classList.remove('navbar-item-selected'); |
| 538 } | 575 } |
| 539 } | 576 } |
| 540 | 577 |
| 541 cr.dispatchPropertyChange(this, 'visible', visible, !visible); | 578 cr.dispatchPropertyChange(this, 'visible', visible, !visible); |
| 542 }, | 579 }, |
| 543 | 580 |
| 544 /** | 581 /** |
| 582 * Focuses the first control on the page. | |
| 583 */ | |
| 584 focusFirstElement: function() { | |
| 585 // Sets focus on the first interactive element in the page. | |
| 586 focusElement = this.pageDiv.querySelector('button, input, list, select'); | |
| 587 if (focusElement) | |
| 588 focusElement.focus(); | |
| 589 }, | |
| 590 | |
| 591 /** | |
| 545 * The nesting level of this page. | 592 * The nesting level of this page. |
| 546 * @type {number} The nesting level of this page (0 for top-level page) | 593 * @type {number} The nesting level of this page (0 for top-level page) |
| 547 */ | 594 */ |
| 548 get nestingLevel() { | 595 get nestingLevel() { |
| 549 var level = 0; | 596 var level = 0; |
| 550 var parent = this.parentPage; | 597 var parent = this.parentPage; |
| 551 while (parent) { | 598 while (parent) { |
| 552 level++; | 599 level++; |
| 553 parent = parent.parentPage; | 600 parent = parent.parentPage; |
| 554 } | 601 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 591 OptionsPage.showOverlay(hash); | 638 OptionsPage.showOverlay(hash); |
| 592 }, | 639 }, |
| 593 }; | 640 }; |
| 594 | 641 |
| 595 // Export | 642 // Export |
| 596 return { | 643 return { |
| 597 OptionsPage: OptionsPage | 644 OptionsPage: OptionsPage |
| 598 }; | 645 }; |
| 599 | 646 |
| 600 }); | 647 }); |
| OLD | NEW |