Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(863)

Unified Diff: ui/webui/resources/js/cr/ui/page_manager/page_manager.js

Issue 410293004: Split OptionsPage into Page and PageManager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: s/PageTree/PageManager/, s/pageHelper/pageManager/ Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/webui/resources/js/cr/ui/page_manager/page_manager.js
diff --git a/ui/webui/resources/js/cr/ui/page_manager/page_manager.js b/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
new file mode 100644
index 0000000000000000000000000000000000000000..85253c68a5df768ea86f63cdd7adb48603c9e0b2
--- /dev/null
+++ b/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
@@ -0,0 +1,691 @@
+// Copyright 2014 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.
+
stevenjb 2014/07/28 22:27:23 We should provide some sort of top level comment d
michaelpg 2014/07/29 01:08:31 How's this?
+cr.define('cr.ui.pageManager', function() {
+ /** @const */ var FocusOutlineManager = cr.ui.FocusOutlineManager;
+
+ var PageManager = {
+ /**
+ * Offset of page container in pixels, to allow room for side menu.
+ * Simplified settings pages can override this if they don't use the menu.
+ * The default (155) comes from -webkit-margin-start in uber_shared.css
+ * TODO(michaelpg@): Remove dependency on uber menu (crbug.com/313244).
stevenjb 2014/07/28 22:27:23 TODO(michaelpg)
michaelpg 2014/07/29 01:08:30 Done.
+ * @private
+ */
+ horizontalOffset: 155,
+
+ /**
+ * Main level option pages. Maps lower-case page names to the respective
+ * page object.
+ * @protected
+ */
+ registeredPages: {},
+
+ /**
+ * Pages which are meant to behave like modal dialogs. Maps lower-case
+ * overlay names to the respective overlay object.
+ * @protected
+ */
+ registeredOverlayPages: {},
+
+ /**
+ * True if page is served from a dialog.
+ */
+ isDialog: false,
+
+ /**
+ * Gets the default page (to be shown on initial load).
+ */
+ getDefaultPage: function() {
+ return options.BrowserOptions.getInstance();
Dan Beam 2014/07/28 20:57:59 this should probably be abstract (e.g. just assert
michaelpg 2014/07/29 01:08:31 I'd rather not derive from PageManager, instead Op
+ },
+
+ /**
+ * Shows the default page.
+ */
+ showDefaultPage: function() {
+ this.navigateToPage(this.getDefaultPage().name);
+ },
+
+ /**
+ * "Navigates" to a page, meaning that the page will be shown and the
+ * appropriate entry is placed in the history.
+ * @param {string} pageName Page name.
+ */
+ navigateToPage: function(pageName) {
+ this.showPageByName(pageName, true);
stevenjb 2014/07/28 22:27:22 JS novice question: Could this be done by giving u
michaelpg 2014/07/29 01:08:30 Done.
+ },
+
+ /**
+ * Shows a registered page. This handles both top-level and overlay pages.
+ * @param {string} pageName Page name.
+ * @param {boolean} updateHistory True if we should update the history after
+ * showing the page.
+ * @param {Object=} opt_propertyBag An optional bag of properties including
+ * replaceState (if history state should be replaced instead of pushed).
+ * @private
Dan Beam 2014/07/28 20:58:00 this isn't private
michaelpg 2014/07/29 01:08:31 Done.
+ */
+ showPageByName: function(pageName,
+ updateHistory,
+ opt_propertyBag) {
+ // If |opt_propertyBag| is non-truthy, homogenize to object.
+ opt_propertyBag = opt_propertyBag || {};
stevenjb 2014/07/28 22:27:23 JS novice question: Is this preferable to declarin
michaelpg 2014/07/29 01:08:30 Not sure what you are asking exactly: function(fo
Dan Beam 2014/07/30 01:00:01 opt_propertyBag = opt_propertyBag || {}; simplifi
stevenjb 2014/07/30 22:36:21 Nevermind. I somehow thought you could provide def
+
+ // If a bubble is currently being shown, hide it.
+ this.hideBubble();
+
+ // Find the currently visible root-level page.
+ var rootPage = null;
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (page.visible && !page.parentPage) {
+ rootPage = page;
+ break;
+ }
+ }
+
+ // Find the target page.
+ var targetPage = this.registeredPages[pageName.toLowerCase()];
+ if (!targetPage || !targetPage.canShowPage()) {
+ // If it's not a page, try it as an overlay.
+ if (!targetPage && this.showOverlay_(pageName, rootPage)) {
+ if (updateHistory)
+ this.updateHistoryState_(!!opt_propertyBag.replaceState);
+ this.updateTitle_();
+ return;
+ } else {
stevenjb 2014/07/28 22:27:23 nit: no else after return
michaelpg 2014/07/29 01:08:30 Done.
+ targetPage = this.getDefaultPage();
+ }
+ }
+
+ pageName = targetPage.name.toLowerCase();
+ var targetPageWasVisible = targetPage.visible;
+
+ // Determine if the root page is 'sticky', meaning that it
+ // shouldn't change when showing an overlay. This can happen for special
+ // pages like Search.
+ var isRootPageLocked =
+ rootPage && rootPage.sticky && targetPage.parentPage;
+
+ var allPageNames = Array.prototype.concat.call(
+ Object.keys(this.registeredPages),
+ Object.keys(this.registeredOverlayPages));
+
+ // Notify pages if they will be hidden.
+ for (var i = 0; i < allPageNames.length; ++i) {
+ var name = allPageNames[i];
+ var page = this.registeredPages[name] ||
+ this.registeredOverlayPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
+ if (page.willHidePage && name != pageName &&
+ !page.isAncestorOfPage(targetPage)) {
+ page.willHidePage();
+ }
+ }
+
+ // Update visibilities to show only the hierarchy of the target page.
+ for (var i = 0; i < allPageNames.length; ++i) {
+ var name = allPageNames[i];
+ var page = this.registeredPages[name] ||
+ this.registeredOverlayPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
+ page.visible = name == pageName || page.isAncestorOfPage(targetPage);
+ }
+
+ // Update the history and current location.
+ if (updateHistory)
+ this.updateHistoryState_(!!opt_propertyBag.replaceState);
+
+ // Update focus if any other control was focused on the previous page,
+ // or the previous page is not known.
+ if (document.activeElement != document.body &&
+ (!rootPage || rootPage.pageDiv.contains(document.activeElement))) {
+ targetPage.focus();
+ }
+
+ // Notify pages if they were shown.
+ for (var i = 0; i < allPageNames.length; ++i) {
+ var name = allPageNames[i];
+ var page = this.registeredPages[name] ||
+ this.registeredOverlayPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
stevenjb 2014/07/28 22:27:22 nit: We use the same pattern 3 times here, maybe c
michaelpg 2014/07/29 01:08:31 Sure. But I don't want to stray too far from the o
+ if (!targetPageWasVisible && page.didShowPage &&
+ (name == pageName || page.isAncestorOfPage(targetPage))) {
+ page.didShowPage();
+ }
+ }
+
+ // Update the document title. Do this after didShowPage was called, in
+ // case a page decides to change its title.
+ this.updateTitle_();
+ },
+
+ /**
+ * Scrolls the page to the correct position (the top when opening an
+ * overaly, or the old scroll position a previously hidden overlay
+ * becomes visible).
+ * @private
+ */
+ updateScrollPosition_: function() {
+ var container = $('page-container');
+ var scrollTop = container.oldScrollTop || 0;
+ container.oldScrollTop = undefined;
+ window.scroll(scrollLeftForDocument(document), scrollTop);
+ },
+
+ /**
+ * Updates the title to title of the current page.
+ * @private
+ */
+ updateTitle_: function() {
+ var page = this.getTopmostVisiblePage();
+ // TODO(michaelpg@): Remove dependency on uber (crbug.com/313244).
Dan Beam 2014/07/28 20:58:00 same thing regarding uber deps: you should be able
stevenjb 2014/07/28 22:27:23 TODO(michaelpg)
michaelpg 2014/07/29 01:08:30 Done.
michaelpg 2014/07/29 01:08:30 Yes, setting up an observer interface was my plan.
+ uber.setTitle(page.title);
+ },
+
+ /**
+ * Pushes the current page onto the history stack, replacing the current
+ * entry if appropriate.
+ * @param {boolean} replace If true, allow no history events to be created.
+ * @param {object=} opt_params A bag of optional params, including:
+ * {boolean} ignoreHash Whether to include the hash or not.
+ * @private
+ */
+ updateHistoryState_: function(replace, opt_params) {
+ if (PageManager.isDialog)
+ return;
+
+ var page = this.getTopmostVisiblePage();
+ var path = window.location.pathname + window.location.hash;
+ if (path) {
+ // Remove trailing slash.
+ path = path.slice(1).replace(/\/(?:#|$)/, '');
+ }
+
+ // If the page is already in history (the user may have clicked the same
+ // link twice, or this is the initial load), do nothing.
+ var hash = opt_params && opt_params.ignoreHash ?
+ '' : window.location.hash;
+ var newPath = (page == this.getDefaultPage() ? '' : page.name) + hash;
+ if (path == newPath)
+ return;
+
+ // TODO(michaelpg@): Remove dependency on uber (crbug.com/313244).
stevenjb 2014/07/28 22:27:22 TODO(michaelpg)
michaelpg 2014/07/29 01:08:30 Done.
+ var historyFunction = replace ? uber.replaceState : uber.pushState;
+ historyFunction.call(uber, {}, newPath);
+ },
+
+ /**
+ * Shows a registered Overlay page. Does not update history.
+ * @param {string} overlayName Page name.
+ * @param {OptionPage} rootPage The currently visible root-level page.
+ * @return {boolean} whether we showed an overlay.
Dan Beam 2014/07/28 20:57:59 all the methods that end with _ => @private
michaelpg 2014/07/29 01:08:30 Done.
+ */
+ showOverlay_: function(overlayName, rootPage) {
+ var overlay = this.registeredOverlayPages[overlayName.toLowerCase()];
+ if (!overlay || !overlay.canShowPage())
+ return false;
+
+ // Save the currently focused element in the page for restoration later.
+ var currentPage = this.getTopmostVisiblePage();
+ if (currentPage)
+ currentPage.lastFocusedElement = document.activeElement;
+
+ if ((!rootPage || !rootPage.sticky) &&
+ overlay.parentPage &&
+ !overlay.parentPage.visible) {
+ this.showPageByName(overlay.parentPage.name, false);
+ }
+
+ if (!overlay.visible) {
+ overlay.visible = true;
+ if (overlay.didShowPage) overlay.didShowPage();
stevenjb 2014/07/28 22:27:23 nit: two lines? (Or is that a C++ only thing?)
michaelpg 2014/07/29 01:08:30 This isn't my code, but I think two lines is the c
+ }
+
+ // Change focus to the overlay if any other control was focused by
+ // keyboard before. Otherwise, no one should have focus.
+ if (document.activeElement != document.body) {
+ if (FocusOutlineManager.forDocument(document).visible) {
+ overlay.focus();
+ } else if (!overlay.pageDiv.contains(document.activeElement)) {
+ document.activeElement.blur();
+ }
+ }
+
+ if ($('search-field') && $('search-field').value == '') {
+ var section = overlay.associatedSection;
+ if (section)
+ options.BrowserOptions.scrollToSection(section);
+ }
+
+ return true;
+ },
+
+ /**
+ * Returns whether or not an overlay is visible.
+ * @return {boolean} True if an overlay is visible.
+ * @private
+ */
+ isOverlayVisible_: function() {
+ return this.getVisibleOverlay_() != null;
+ },
+
+ /**
+ * Returns the currently visible overlay, or null if no page is visible.
+ * @return {OptionPage} The visible overlay.
+ */
+ getVisibleOverlay_: function() {
+ var topmostPage = null;
+ for (var name in this.registeredOverlayPages) {
+ var page = this.registeredOverlayPages[name];
+ if (page.visible &&
+ (!topmostPage || page.nestingLevel > topmostPage.nestingLevel)) {
+ topmostPage = page;
+ }
+ }
+ return topmostPage;
+ },
+
+ /**
+ * Restores the last focused element on a given page.
+ */
+ restoreLastFocusedElement_: function() {
+ var currentPage = this.getTopmostVisiblePage();
+ if (currentPage.lastFocusedElement)
+ currentPage.lastFocusedElement.focus();
+ },
+
+ /**
+ * Closes the visible overlay. Updates the history state after closing the
+ * overlay.
+ */
+ closeOverlay: function() {
+ var overlay = this.getVisibleOverlay_();
+ if (!overlay)
+ return;
+
+ overlay.visible = false;
+
+ if (overlay.didClosePage) overlay.didClosePage();
stevenjb 2014/07/28 22:27:22 two lines?
michaelpg 2014/07/29 01:08:30 Done.
Dan Beam 2014/07/30 01:00:01 for future reference, 2 lines is more common but 1
+ this.updateHistoryState_(false, {ignoreHash: true});
+ this.updateTitle_();
+
+ this.restoreLastFocusedElement_();
+ },
+
+ /**
+ * Closes all overlays and updates the history after each closed overlay.
+ */
+ closeAllOverlays: function() {
+ while (this.isOverlayVisible_()) {
+ this.closeOverlay();
+ }
+ },
+
+ /**
+ * Cancels (closes) the overlay, due to the user pressing <Esc>.
+ */
+ cancelOverlay: function() {
+ // Blur the active element to ensure any changed pref value is saved.
+ document.activeElement.blur();
+ var overlay = this.getVisibleOverlay_();
+ // Let the overlay handle the <Esc> if it wants to.
+ if (overlay.handleCancel) {
+ overlay.handleCancel();
+ this.restoreLastFocusedElement_();
+ } else {
+ this.closeOverlay();
+ }
+ },
+
+ /**
+ * Hides the visible overlay. Does not affect the history state.
+ * @private
+ */
+ hideOverlay_: function() {
+ var overlay = this.getVisibleOverlay_();
+ if (overlay)
+ overlay.visible = false;
+ },
+
+ /**
+ * Returns the pages which are currently visible, ordered by nesting level
+ * (ascending).
+ * @return {Array.OptionPage} The pages which are currently visible, ordered
+ * by nesting level (ascending).
+ */
+ getVisiblePages_: function() {
+ var visiblePages = [];
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (page.visible)
+ visiblePages[page.nestingLevel] = page;
+ }
+ return visiblePages;
+ },
+
+ /**
+ * Returns the topmost visible page (overlays excluded).
+ * @return {OptionPage} The topmost visible page aside any overlay.
+ * @private
+ */
+ getTopmostVisibleNonOverlayPage_: function() {
+ var topPage = null;
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (page.visible &&
+ (!topPage || page.nestingLevel > topPage.nestingLevel))
+ topPage = page;
+ }
+
+ return topPage;
+ },
+
+ /**
+ * Returns the topmost visible page, or null if no page is visible.
+ * @return {OptionPage} The topmost visible page.
+ */
+ getTopmostVisiblePage: function() {
+ // Check overlays first since they're top-most if visible.
+ return this.getVisibleOverlay_() ||
+ this.getTopmostVisibleNonOverlayPage_();
+ },
+
+ /**
+ * Returns the currently visible bubble, or null if no bubble is visible.
+ * @return {AutoCloseBubble} The bubble currently being shown.
+ */
+ getVisibleBubble: function() {
+ var bubble = PageManager.bubble_;
+ return bubble && !bubble.hidden ? bubble : null;
+ },
+
+ /**
+ * Shows an informational bubble displaying |content| and pointing at the
+ * |target| element. If |content| has focusable elements, they join the
+ * current page's tab order as siblings of |domSibling|.
+ * @param {HTMLDivElement} content The content of the bubble.
+ * @param {HTMLElement} target The element at which the bubble points.
+ * @param {HTMLElement} domSibling The element after which the bubble is
+ * added to the DOM.
+ * @param {cr.ui.ArrowLocation} location The arrow location.
+ */
+ showBubble: function(content, target, domSibling, location) {
+ PageManager.hideBubble();
+
+ var bubble = new cr.ui.AutoCloseBubble;
+ bubble.anchorNode = target;
+ bubble.domSibling = domSibling;
+ bubble.arrowLocation = location;
+ bubble.content = content;
+ bubble.show();
+ PageManager.bubble_ = bubble;
+ },
+
+ /**
+ * Hides the currently visible bubble, if any.
+ */
+ hideBubble: function() {
+ if (PageManager.bubble_)
+ PageManager.bubble_.hide();
+ },
+
+ /**
+ * Registers new page.
+ * @param {cr.ui.page_manager.Page} page Page to register.
+ */
+ register: function(page) {
+ this.registeredPages[page.name.toLowerCase()] = page;
+ page.initializePage();
+ },
+
+ /**
+ * Find an enclosing section for an element if it exists.
+ * @param {Element} element Element to search.
+ * @return {OptionPage} The section element, or null.
+ * @private
+ */
+ findSectionForNode_: function(node) {
+ while (node = node.parentNode) {
+ if (node.nodeName == 'SECTION')
+ return node;
+ }
+ return null;
+ },
+
+ /**
+ * Registers a new Overlay page.
+ * @param {cr.ui.page_manager.Page} overlay Overlay to register.
+ * @param {cr.ui.page_manager.Page} parentPage Associated parent page for
+ * this overlay.
+ * @param {Array} associatedControls Array of control elements associated
+ * with this page.
+ */
+ registerOverlay: function(overlay,
+ parentPage,
+ associatedControls) {
+ this.registeredOverlayPages[overlay.name.toLowerCase()] = overlay;
+ overlay.parentPage = parentPage;
+ if (associatedControls) {
+ overlay.associatedControls = associatedControls;
+ if (associatedControls.length) {
+ overlay.associatedSection =
+ this.findSectionForNode_(associatedControls[0]);
+ }
+
+ // Sanity check.
+ for (var i = 0; i < associatedControls.length; ++i) {
+ assert(associatedControls[i], 'Invalid element passed.');
+ }
+ }
+
+ // Reverse the button strip for Windows and CrOS. See the documentation of
+ // reverseButtonStripIfNecessary_() for an explanation of why this is
+ // done.
+ if (cr.isWindows || cr.isChromeOS)
+ this.reverseButtonStripIfNecessary_(overlay);
+
+ overlay.tab = undefined;
+ overlay.isOverlay = true;
+ overlay.initializePage();
+ },
+
+ /**
+ * Reverses the child elements of a button strip if it hasn't already been
+ * reversed. This is necessary because WebKit does not alter the tab order
+ * for elements that are visually reversed using
+ * -webkit-box-direction: reverse, and the button order is reversed for
+ * views. See http://webk.it/62664 for more information.
+ * @param {Object} overlay The overlay containing the button strip to
+ * reverse.
+ * @private
+ */
+ reverseButtonStripIfNecessary_: function(overlay) {
+ var buttonStrips =
+ overlay.pageDiv.querySelectorAll('.button-strip:not([reversed])');
+
+ // Reverse all button-strips in the overlay.
+ for (var j = 0; j < buttonStrips.length; j++) {
+ var buttonStrip = buttonStrips[j];
+
+ var childNodes = buttonStrip.childNodes;
+ for (var i = childNodes.length - 1; i >= 0; i--)
+ buttonStrip.appendChild(childNodes[i]);
+
+ buttonStrip.setAttribute('reversed', '');
+ }
+ },
+
+ /**
+ * Returns the name of the page from the current path.
+ */
+ getPageNameFromPath: function() {
+ var path = location.pathname;
+ if (path.length <= 1)
+ return this.getDefaultPage().name;
+
+ // Skip starting slash and remove trailing slash (if any).
+ return path.slice(1).replace(/\/$/, '');
+ },
+
+ /**
+ * Callback for window.onpopstate to handle back/forward navigations.
+ * @param {string} pageName The current page name.
+ * @param {Object} data State data pushed into history.
+ */
+ setState: function(pageName, data) {
+ var currentOverlay = this.getVisibleOverlay_();
+ var lowercaseName = pageName.toLowerCase();
+ var newPage = this.registeredPages[lowercaseName] ||
+ this.registeredOverlayPages[lowercaseName] ||
+ this.getDefaultPage();
+ if (currentOverlay && !currentOverlay.isAncestorOfPage(newPage)) {
+ currentOverlay.visible = false;
+ if (currentOverlay.didClosePage) currentOverlay.didClosePage();
+ }
+ this.showPageByName(pageName, false);
+ },
+
+ /**
+ * Callback for window.onbeforeunload. Used to notify overlays that they
+ * will be closed.
+ */
+ willClose: function() {
+ var overlay = this.getVisibleOverlay_();
+ if (overlay && overlay.didClosePage)
+ overlay.didClosePage();
+ },
+
+ /**
+ * Freezes/unfreezes the scroll position of the root page container.
+ * @param {boolean} freeze Whether the page should be frozen.
+ * @private
+ */
+ setRootPageFrozen_: function(freeze) {
+ var container = $('page-container');
+ if (container.classList.contains('frozen') == freeze)
+ return;
+
+ if (freeze) {
+ // Lock the width, since auto width computation may change.
+ container.style.width = window.getComputedStyle(container).width;
+ container.oldScrollTop = scrollTopForDocument(document);
+ container.classList.add('frozen');
+ var verticalPosition =
+ container.getBoundingClientRect().top - container.oldScrollTop;
+ container.style.top = verticalPosition + 'px';
+ this.updateFrozenElementHorizontalPosition_(container);
+ } else {
+ container.classList.remove('frozen');
+ container.style.top = '';
+ container.style.left = '';
+ container.style.right = '';
+ container.style.width = '';
+ }
+ },
+
+ /**
+ * Freezes/unfreezes the scroll position of the root page based on the
+ * current page stack.
+ */
+ updateRootPageFreezeState: function() {
+ var topPage = PageManager.getTopmostVisiblePage();
+ if (topPage)
+ this.setRootPageFrozen_(topPage.isOverlay);
+ },
+
+ /**
+ * Initializes the complete page.
+ */
+ initialize: function() {
+ FocusOutlineManager.forDocument(document);
+ document.addEventListener('scroll', this.handleScroll_.bind(this));
+
+ // Trigger the scroll handler manually to set the initial state.
+ this.handleScroll_();
+
+ // Shake the dialog if the user clicks outside the dialog bounds.
+ var containers = [$('overlay-container-1'), $('overlay-container-2')];
+ for (var i = 0; i < containers.length; i++) {
+ var overlay = containers[i];
+ cr.ui.overlay.setupOverlay(overlay);
+ overlay.addEventListener('cancelOverlay',
+ PageManager.cancelOverlay.bind(PageManager));
+ }
+
+ cr.ui.overlay.globalInitialization();
+ },
+
+ /**
+ * Does a bounds check for the element on the given x, y client coordinates.
+ * @param {Element} e The DOM element.
+ * @param {number} x The client X to check.
+ * @param {number} y The client Y to check.
+ * @return {boolean} True if the point falls within the element's bounds.
+ * @private
+ */
+ elementContainsPoint_: function(e, x, y) {
+ var clientRect = e.getBoundingClientRect();
+ return x >= clientRect.left && x <= clientRect.right &&
+ y >= clientRect.top && y <= clientRect.bottom;
+ },
+
+ /**
+ * Called when the page is scrolled; moves elements that are position:fixed
+ * but should only behave as if they are fixed for vertical scrolling.
+ * @private
+ */
+ handleScroll_: function() {
+ this.updateAllFrozenElementPositions_();
+ },
+
+ /**
+ * Updates all frozen pages to match the horizontal scroll position.
+ * @private
+ */
+ updateAllFrozenElementPositions_: function() {
+ var frozenElements = document.querySelectorAll('.frozen');
+ for (var i = 0; i < frozenElements.length; i++)
+ this.updateFrozenElementHorizontalPosition_(frozenElements[i]);
+ },
+
+ /**
+ * Updates the given frozen element to match the horizontal scroll position.
+ * @param {HTMLElement} e The frozen element to update.
+ * @private
+ */
+ updateFrozenElementHorizontalPosition_: function(e) {
+ if (isRTL()) {
+ e.style.right = PageManager.horizontalOffset + 'px';
+ } else {
+ var scrollLeft = scrollLeftForDocument(document);
+ e.style.left = PageManager.horizontalOffset - scrollLeft + 'px';
+ }
+ },
+
+ /**
+ * Change the horizontal offset used to reposition elements while showing an
+ * overlay from the default.
+ */
+ setHorizontalOffset: function(value) {
+ PageManager.horizontalOffset = value;
+ },
+
+ /**
+ * Whether the page is still loading (i.e. onload hasn't finished running).
+ * @return {boolean} Whether the page is still loading.
+ */
+ isLoading: function() {
+ return document.documentElement.classList.contains('loading');
+ },
Dan Beam 2014/07/28 20:58:00 arguably these methods should be in public => prot
michaelpg 2014/07/29 01:08:31 Done. And I tried to arrange related methods toget
+ };
+
+ // Export
+ return {
+ PageManager: PageManager
+ };
+});

Powered by Google App Engine
This is Rietveld 408576698