Chromium Code Reviews| Index: chrome/browser/resources/md_extensions/page_state.js |
| diff --git a/chrome/browser/resources/md_extensions/page_state.js b/chrome/browser/resources/md_extensions/page_state.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b2f13ca165567c0f2095cf2d871781f3fc73c310 |
| --- /dev/null |
| +++ b/chrome/browser/resources/md_extensions/page_state.js |
| @@ -0,0 +1,112 @@ |
| +// Copyright 2017 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. |
| + |
| +/** |
| + * The different pages that can be shown at a time. |
| + * Note: This must remain in sync with the order in manager.html! |
| + * @enum {string} |
| + */ |
| +var Page = { |
| + LIST: '0', |
|
michaelpg
2017/04/14 20:23:53
could these values be IDs? neon-animated-pages sho
Devlin
2017/04/17 23:29:24
Using ids doesn't seem to work... I thought neon-
michaelpg
2017/04/18 22:03:11
it's using iron-selector, which has the "attrForSe
|
| + DETAILS: '1', |
| + SHORTCUTS: '2', |
| + ERRORS: '3', |
| +}; |
| + |
| +/** @enum {string} */ |
| +var Subpage = { |
| + OPTIONS: 'options', |
| +}; |
| + |
| +/** @typedef {{page: Page, |
| + id: (string|undefined), |
| + subpage: (!Subpage|undefined)}} */ |
| +var PageEntry; |
| + |
| +cr.define('extensions', function() { |
| + 'use strict'; |
| + |
| + /** @constructor */ |
|
michaelpg
2017/04/14 20:23:53
document what PageState is for.
also type and docu
Devlin
2017/04/17 23:29:24
Done.
|
| + function PageState(changePage) { |
|
michaelpg
2017/04/14 20:23:53
should this be a singleton, since it manipulates h
Devlin
2017/04/17 23:29:24
Conceptually, it should be a singleton (just as ma
michaelpg
2017/04/18 22:03:11
Sure. The new naming makes it clearer, too.
|
| + this.changePage_ = changePage; |
| + window.addEventListener('popstate', this.onPopState_.bind(this)); |
| + } |
| + |
| + PageState.prototype = { |
| + /** @private */ |
| + onPopState_: function() { |
| + var state = this.getCurrentPage(); |
|
michaelpg
2017/04/14 20:23:53
nit: skip variable declaration
Devlin
2017/04/17 23:29:24
Done.
|
| + this.changePage_(state, false); |
| + }, |
| + |
| + /** |
| + * Returns the page that should be displayed for the current URL. |
| + * @return {!PageEntry} |
| + */ |
| + getCurrentPage: function() { |
| + if (location.search == '' && location.pathname == '/') |
| + return {page: Page.LIST}; |
| + |
| + var search = new URLSearchParams(location.search); |
| + var id = search.get('id'); |
| + if (id) |
| + return {page: Page.DETAILS, id: id}; |
| + id = search.get('options'); |
| + if (id) |
| + return {page: Page.DETAILS, id: id, subpage: Subpage.OPTIONS}; |
| + var id = search.get('errors'); |
|
michaelpg
2017/04/14 20:23:53
remove "var"
Devlin
2017/04/17 23:29:24
Done.
|
| + if (id) |
| + return {page: Page.ERRORS, id: id}; |
| + |
| + if (location.pathname == '/shortcuts') |
| + return {page: Page.SHORTCUTS}; |
| + |
| + return {page: Page.LIST}; |
| + }, |
| + |
| + /** |
| + * Called when a page changes, and pushes state to history to reflect it. |
| + * @param {!PageEntry} entry |
| + */ |
| + onPageChange: function(entry) { |
| + var relative; |
| + switch (entry.page) { |
| + case Page.LIST: |
| + relative = '/'; |
| + break; |
| + case Page.DETAILS: |
| + if (entry.subpage) { |
| + assert(entry.subpage == Subpage.OPTIONS); |
| + relative = '/?options=' + entry.id; |
| + } else { |
| + relative = '/?id=' + entry.id; |
| + } |
| + break; |
| + case Page.SHORTCUTS: |
| + relative = '/shortcuts'; |
| + break; |
| + case Page.ERRORS: |
| + relative = '/?errors=' + entry.id; |
| + } |
| + if (relative) { |
| + var state = {url: relative}; |
| + var currentPage = this.getCurrentPage(); |
| + var isSubpageNavigation = |
| + currentPage.page == entry.page && |
| + currentPage.id == entry.id; |
| + // Navigating to a subpage doesn't visually change pages; it just opens |
| + // a dialog. As such, we replace state rather than pushing a new state |
| + // on the stack so that hitting the back button doesn't just toggle the |
| + // dialog. |
| + if (isSubpageNavigation) |
| + history.replaceState(state, '', relative); |
| + else |
| + history.pushState(state, '', relative); |
| + |
| + } |
| + }, |
| + }; |
| + |
| + return {PageState: PageState}; |
| +}); |