diff options
author | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 16:46:29 +0000 |
---|---|---|
committer | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 16:46:29 +0000 |
commit | a18a7ebb718206f6242ad81f4446414ba75bc6c2 (patch) | |
tree | df9d08af5dec58efbac423c84105dfd17088d4e3 /chrome/browser/resources/help | |
parent | 4a58c42d044631d9ca3e1f80747e3089a8a87c05 (diff) | |
download | chromium_src-a18a7ebb718206f6242ad81f4446414ba75bc6c2.zip chromium_src-a18a7ebb718206f6242ad81f4446414ba75bc6c2.tar.gz chromium_src-a18a7ebb718206f6242ad81f4446414ba75bc6c2.tar.bz2 |
Fixed {overlay|focus|scrolling} handling on the help page.
BUG=305736
TEST=manual tests on Linux ChromeOS build.
Review URL: https://codereview.chromium.org/50853002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232414 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/resources/help')
-rw-r--r-- | chrome/browser/resources/help/channel_change_page.html | 2 | ||||
-rw-r--r-- | chrome/browser/resources/help/channel_change_page.js | 4 | ||||
-rw-r--r-- | chrome/browser/resources/help/help.html | 4 | ||||
-rw-r--r-- | chrome/browser/resources/help/help.js | 48 | ||||
-rw-r--r-- | chrome/browser/resources/help/help_base_page.js | 245 | ||||
-rw-r--r-- | chrome/browser/resources/help/help_focus_manager.js | 27 |
6 files changed, 295 insertions, 35 deletions
diff --git a/chrome/browser/resources/help/channel_change_page.html b/chrome/browser/resources/help/channel_change_page.html index 0b4de9f..d911b2e 100644 --- a/chrome/browser/resources/help/channel_change_page.html +++ b/chrome/browser/resources/help/channel_change_page.html @@ -3,7 +3,7 @@ <h1 i18n-content="channelChangePageTitle"></h1> <div class="content-area"> <div class="channel-change-page-channel"> - <input id="channel-change-page-stable-optiop" + <input id="channel-change-page-stable-option" type="radio" name="channel" value="stable-channel"> <label for="channel-change-page-stable-optiop" i18n-content="stable"> </label> diff --git a/chrome/browser/resources/help/channel_change_page.js b/chrome/browser/resources/help/channel_change_page.js index 4f22ce8..1449923 100644 --- a/chrome/browser/resources/help/channel_change_page.js +++ b/chrome/browser/resources/help/channel_change_page.js @@ -11,7 +11,7 @@ cr.define('help', function() { cr.addSingletonGetter(ChannelChangePage); ChannelChangePage.prototype = { - __proto__: HTMLDivElement.prototype, + __proto__: help.HelpBasePage.prototype, /** * Name of the channel the device is currently on. @@ -50,6 +50,8 @@ cr.define('help', function() { * Perform initial setup. */ initialize: function() { + help.HelpBasePage.prototype.initialize.call(this, 'channel-change-page'); + var self = this; $('channel-change-page-cancel-button').onclick = function() { diff --git a/chrome/browser/resources/help/help.html b/chrome/browser/resources/help/help.html index 045d206..299551a 100644 --- a/chrome/browser/resources/help/help.html +++ b/chrome/browser/resources/help/help.html @@ -17,6 +17,8 @@ <script src="chrome://resources/js/util.js"></script> <script src="chrome://resources/js/cr/ui.js"></script> <script src="chrome://resources/js/cr/ui/focus_manager.js"></script> + <script src="chrome://help-frame/help_focus_manager.js"></script> + <script src="chrome://help-frame/help_base_page.js"></script> <if expr="pp_ifdef('chromeos')"> <script src="chrome://resources/js/cr/ui/bubble.js"></script> <script src="chrome://resources/js/cr/ui/overlay.js"></script> @@ -32,7 +34,7 @@ <include src="channel_change_page.html"> </if> </div> - <div class="page"> + <div id="help-page" class="page"> <header> <h1 i18n-content="aboutTitle"></h1> </header> diff --git a/chrome/browser/resources/help/help.js b/chrome/browser/resources/help/help.js index b538fc2..d28094d 100644 --- a/chrome/browser/resources/help/help.js +++ b/chrome/browser/resources/help/help.js @@ -13,7 +13,7 @@ cr.define('help', function() { cr.addSingletonGetter(HelpPage); HelpPage.prototype = { - __proto__: HTMLDivElement.prototype, + __proto__: help.HelpBasePage.prototype, /** * True if after update powerwash button should be displayed. @@ -49,6 +49,8 @@ cr.define('help', function() { * Perform initial setup. */ initialize: function() { + help.HelpBasePage.prototype.initialize.call(this, 'help-page'); + var self = this; uber.onContentFrameLoaded(); @@ -114,13 +116,16 @@ cr.define('help', function() { } if (cr.isChromeOS) { + help.ChannelChangePage.getInstance().initialize(); + this.registerOverlay(help.ChannelChangePage.getInstance()); + cr.ui.overlay.setupOverlay($('overlay-container')); cr.ui.overlay.globalInitialization(); $('overlay-container').addEventListener('cancelOverlay', function() { - self.showOverlay_(null); + self.closeOverlay(); }); $('change-channel').onclick = function() { - self.showOverlay_($('channel-change-page')); + self.showOverlay('channel-change-page'); }; var channelChangeDisallowedError = document.createElement('div'); @@ -146,6 +151,7 @@ cr.define('help', function() { } cr.ui.FocusManager.disableMouseFocusOnButtons(); + help.HelpFocusManager.getInstance().initialize(); // Attempt to update. chrome.send('onPageLoaded'); @@ -217,15 +223,6 @@ cr.define('help', function() { }, /** - * Returns current overlay. - * @return {HTMLElement} Current overlay - * @private - */ - getCurrentOverlay_: function() { - return document.querySelector('#overlay .page.showing'); - }, - - /** * @return {boolean} True, if new channel switcher UI is used, * false otherwise. * @private @@ -359,21 +356,6 @@ cr.define('help', function() { }, /** - * Sets the given overlay to show. This hides whatever overlay is currently - * showing, if any. - * @param {HTMLElement} node The overlay page to show. If null, all - * overlays are hidden. - */ - showOverlay_: function(node) { - var currentlyShowingOverlay = this.getCurrentOverlay_(); - if (currentlyShowingOverlay) - currentlyShowingOverlay.classList.remove('showing'); - if (node) - node.classList.add('showing'); - $('overlay-container').hidden = !node; - }, - - /** * Updates name of the current channel, i.e. the name of the * channel the device is currently on. * @param {string} channel The name of the current channel @@ -486,12 +468,16 @@ cr.define('help', function() { HelpPage.getInstance().setOSFirmware_(firmware); }; - HelpPage.showOverlay = function(node) { - HelpPage.getInstance().showOverlay_(node); + HelpPage.showOverlay = function(name) { + HelpPage.getInstance().showOverlay(name); }; HelpPage.cancelOverlay = function() { - HelpPage.getInstance().showOverlay_(null); + HelpPage.getInstance().closeOverlay(); + }; + + HelpPage.getTopmostVisiblePage = function() { + return HelpPage.getInstance().getTopmostVisiblePage(); }; HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) { @@ -539,6 +525,4 @@ cr.define('help', function() { */ window.onload = function() { help.HelpPage.getInstance().initialize(); - if (cr.isChromeOS) - help.ChannelChangePage.getInstance().initialize(); }; diff --git a/chrome/browser/resources/help/help_base_page.js b/chrome/browser/resources/help/help_base_page.js new file mode 100644 index 0000000..8ebd48e --- /dev/null +++ b/chrome/browser/resources/help/help_base_page.js @@ -0,0 +1,245 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Helper base class for all help pages and overlays, which controls +// overlays, focus and scroll. This class is partially based on +// OptionsPage, but simpler and contains only overlay- and focus- +// handling logic. As in OptionsPage each page can be an overlay itself, +// but each page contains its own list of registered overlays which can be +// displayed over it. +// +// TODO (ygorshenin@): crbug.com/313244. +cr.define('help', function() { + function HelpBasePage() { + } + + HelpBasePage.prototype = { + __proto__: HTMLDivElement.prototype, + + /** + * name of the page, should be the same as an id of the + * corresponding HTMLDivElement. + */ + name: null, + + /** + * HTML counterpart of this page. + */ + pageDiv: null, + + /** + * True if current page is overlay. + */ + isOverlay: false, + + /** + * HTMLElement that was last focused when this page was the + * topmost. + */ + lastFocusedElement: null, + + /** + * State of vertical scrollbars when this page was the topmost. + */ + lastScrollTop: 0, + + /** + * Dictionary of registered overlays. + */ + registeredOverlays: {}, + + /** + * Stores currently focused element. + * @private + */ + storeLastFocusedElement_: function() { + if (this.pageDiv.contains(document.activeElement)) + this.lastFocusedElement = document.activeElement; + }, + + /** + * Restores focus to the last focused element on this page. + * @private + */ + restoreLastFocusedElement_: function() { + if (this.lastFocusedElement) + this.lastFocusedElement.focus(); + else + this.focus(); + }, + + /** + * Shows or hides current page iff it's an overlay. + * @param {boolean} visible True if overlay should be displayed. + * @private + */ + setOverlayVisible_: function(visible) { + assert(this.isOverlay); + var pageDiv = this.pageDiv; + this.container.hidden = !visible; + if (visible) + pageDiv.classList.add('showing'); + else + pageDiv.classList.remove('showing'); + }, + + /** + * @return {HTMLDivElement} visible non-overlay page or + * null, if there are no visible non-overlay pages. + * @private + */ + getVisibleNonOverlay_: function() { + if (this.isOverlay || !this.visible) + return null; + return this; + }, + + /** + * @return {HTMLDivElement} Visible overlay page, or null, + * if there are no visible overlay pages. + * @private + */ + getVisibleOverlay_: function() { + for (var name in this.registeredOverlays) { + var overlay = this.registeredOverlays[name]; + if (overlay.visible) + return overlay; + } + return null; + }, + + /** + * Freezes current page, makes it impossible to scroll it. + * @param {boolean} freeze True if the page should be frozen. + * @private + */ + freeze_: function(freeze) { + if (freeze) { + this.lastScrollTop = document.documentElement.scrollTop; + document.body.style.overflow = 'hidden'; + window.scroll(document.body.scrollLeft, 0); + } else { + document.body.style.overflow = 'auto'; + window.scroll(document.body.scrollLeft, this.lastScrollTop); + } + }, + + /** + * Initializes current page. + * @param {string} name Name of the current page. + */ + initialize: function(name) { + this.name = name; + this.pageDiv = $(name); + }, + + /** + * @return {HTMLDivElement} Topmost visible page, or null, if + * there are no visible pages. + */ + getTopmostVisiblePage: function() { + return this.getVisibleOverlay_() || this.getVisibleNonOverlay_(); + }, + + /** + * Registers overlay. + * @param {HelpBasePage} overlay Overlay that should be registered. + */ + registerOverlay: function(overlay) { + this.registeredOverlays[overlay.name] = overlay; + overlay.isOverlay = true; + }, + + /** + * Shows or hides current page. + * @param {boolean} visible True if current page should be displayed. + */ + set visible(visible) { + if (this.visible == visible) + return; + + if (!visible) + this.storeLastFocusedElement_(); + + if (this.isOverlay) + this.setOverlayVisible_(visible); + else + this.pageDiv.hidden = !visible; + + if (visible) + this.restoreLastFocusedElement_(); + }, + + /** + * Returns true if current page is visible. + * @return {boolean} True if current page is visible. + */ + get visible() { + if (this.isOverlay) + return this.pageDiv.classList.contains('showing'); + return !this.pageDiv.hidden; + }, + + /** + * This method returns overlay container, it should be called only + * on overlays. + * @return {HTMLDivElement} overlay container. + */ + get container() { + assert(this.isOverlay); + return this.pageDiv.parentNode; + }, + + /** + * Shows registered overlay. + * @param {string} name Name of registered overlay to show. + */ + showOverlay: function(name) { + var currentPage = this.getTopmostVisiblePage(); + currentPage.storeLastFocusedElement_(); + currentPage.freeze_(true); + + var overlay = this.registeredOverlays[name]; + if (!overlay) + return; + overlay.visible = true; + }, + + /** + * Hides currently displayed overlay. + */ + closeOverlay: function() { + var overlay = this.getVisibleOverlay_(); + if (!overlay) + return; + overlay.visible = false; + + var currentPage = this.getTopmostVisiblePage(); + currentPage.restoreLastFocusedElement_(); + currentPage.freeze_(false); + }, + + /** + * If the page does not contain focused elements, focuses on the + * first appropriate. + */ + focus: function() { + if (this.pageDiv.contains(document.activeElement)) + return; + var elements = this.pageDiv.querySelectorAll( + 'input, list, select, textarea, button'); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.focus(); + if (document.activeElement == element) + return; + } + }, + }; + + // Export + return { + HelpBasePage: HelpBasePage + }; +}); diff --git a/chrome/browser/resources/help/help_focus_manager.js b/chrome/browser/resources/help/help_focus_manager.js new file mode 100644 index 0000000..335f8fd --- /dev/null +++ b/chrome/browser/resources/help/help_focus_manager.js @@ -0,0 +1,27 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Helper class for help page, that controls focus transition between +// elements on the help page and overlays. +cr.define('help', function() { + function HelpFocusManager() { + } + + cr.addSingletonGetter(HelpFocusManager); + + HelpFocusManager.prototype = { + __proto__: cr.ui.FocusManager.prototype, + + getFocusParent: function() { + var page = help.HelpPage.getTopmostVisiblePage(); + if (!page) + return null; + return page.pageDiv; + }, + }; + + return { + HelpFocusManager: HelpFocusManager, + }; +}); |