Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / resources / settings / settings_page / settings_router.js
blob3eb5eca9c8fd64f6b405942dbedb3913eb746118
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * @fileoverview
7  * 'settings-router' is a simple router for settings. Its responsibilites:
8  *  - Update the URL when the routing state changes.
9  *  - Initialize the routing state with the initial URL.
10  *  - Process and validate all routing state changes.
11  *
12  * Example:
13  *
14  *    <settings-router current-route="{{currentRoute}}">
15  *    </settings-router>
16  *
17  * @group Chrome Settings Elements
18  * @element settings-router
19  */
20 Polymer({
21   is: 'settings-router',
23   properties: {
24     /**
25      * The current active route. This is reflected to the URL. Updates to this
26      * property should replace the whole object.
27      *
28      * currentRoute.page refers to top-level pages such as Basic and Advanced.
29      *
30      * currentRoute.section is only non-empty when the user is on a subpage. If
31      * the user is on Basic, for instance, this is an empty string.
32      *
33      * currentRoute.subpage is an Array. The last element is the actual subpage
34      * the user is on. The previous elements are the ancestor subpages. This
35      * enables support for multiple paths to the same subpage. This is used by
36      * both the Back button and the Breadcrumb to determine ancestor subpages.
37      */
38     currentRoute: {
39       notify: true,
40       observer: 'currentRouteChanged_',
41       type: Object,
42       value: function() {
43         // Take the current URL, find a matching pre-defined route, and
44         // initialize the currentRoute to that pre-defined route.
45         for (var i = 0; i < this.routes_.length; ++i) {
46           var route = this.routes_[i];
47           if (route.url == window.location.pathname) {
48             return {
49               page: route.page,
50               section: route.section,
51               subpage: route.subpage,
52             };
53           }
54         }
56         // As a fallback return the default route.
57         return this.routes_[0];
58       },
59     },
61     /**
62      * Page titles for the currently active route. Updated by the currentRoute
63      * property observer.
64      * @type {{pageTitle: string, subpageTitles: Array<string>}}
65      */
66     currentRouteTitles: {
67       notify: true,
68       type: Object,
69       value: function() { return {}; },
70     },
71   },
74  /**
75   * @private
76   * The 'url' property is not accessible to other elements.
77   */
78  routes_: [
79     {
80       url: '/',
81       page: 'basic',
82       section: '',
83       subpage: [],
84       subpageTitles: [],
85     },
86     {
87       url: '/advanced',
88       page: 'advanced',
89       section: '',
90       subpage: [],
91       subpageTitles: [],
92     },
93     {
94       url: '/startup',
95       page: 'basic',
96       section: 'on-startup',
97       subpage: ['startup-urls'],
98       subpageTitles: ['onStartupSetPages'],
99     },
100     {
101       url: '/searchEngines',
102       page: 'basic',
103       section: 'search',
104       subpage: ['search-engines'],
105       subpageTitles: ['searchEnginesPageTitle'],
106     },
107     {
108       url: '/searchEngines/advanced',
109       page: 'basic',
110       section: 'search',
111       subpage: ['search-engines', 'search-engines-advanced'],
112       subpageTitles: ['searchEnginesPageTitle', 'advancedPageTitle'],
113     },
114     {
115       url: '/certificates',
116       page: 'advanced',
117       section: 'privacy',
118       subpage: ['manage-certificates'],
119       subpageTitles: ['manageCertificates'],
120     },
121     {
122       url: '/content',
123       page: 'advanced',
124       section: 'privacy',
125       subpage: ['site-settings'],
126       subpageTitles: ['siteSettings'],
127     },
128     {
129       url: '/clearBrowserData',
130       page: 'advanced',
131       section: 'privacy',
132       subpage: ['clear-browsing-data'],
133       subpageTitles: ['clearBrowsingData'],
134     },
135     {
136       url: '/networkDetail',
137       page: 'basic',
138       section: 'internet',
139       subpage: ['network-detail'],
140       subpageTitles: ['internetDetailPageTitle'],
141     },
142     {
143       url: '/knownNetworks',
144       page: 'basic',
145       section: 'internet',
146       subpage: ['known-networks'],
147       subpageTitles: ['internetKnownNetworksPageTitle'],
148     },
149   ],
151   /**
152    * Sets up a history popstate observer.
153    */
154   created: function() {
155     window.addEventListener('popstate', function(event) {
156       if (event.state && event.state.page)
157         this.currentRoute = event.state;
158     }.bind(this));
159   },
161   /**
162    * @private
163    * Is called when another element modifies the route. This observer validates
164    * the route change against the pre-defined list of routes, and updates the
165    * URL appropriately.
166    */
167   currentRouteChanged_: function(newRoute, oldRoute) {
168     for (var i = 0; i < this.routes_.length; ++i) {
169       var route = this.routes_[i];
170       if (route.page == newRoute.page && route.section == newRoute.section &&
171           route.subpage.length == newRoute.subpage.length &&
172           newRoute.subpage.every(function(value, index) {
173             return value == route.subpage[index];
174           })) {
176         // Update the property containing the titles for the current route.
177         this.currentRouteTitles = {
178           pageTitle: loadTimeData.getString(route.page + 'PageTitle'),
179           subpageTitles: route.subpageTitles.map(function(titleCode) {
180             return loadTimeData.getString(titleCode);
181           }),
182         };
184         // If we are restoring a state from history, don't push it again.
185         if (newRoute.inHistory)
186           return;
188         // Mark routes persisted in history as already stored in history.
189         var historicState = {
190           inHistory: true,
191           page: newRoute.page,
192           section: newRoute.section,
193           subpage: newRoute.subpage,
194         };
196         // Push the current route to the history state, so when the user
197         // navigates with the browser back button, we can recall the route.
198         if (oldRoute) {
199           history.pushState(historicState, null, route.url);
200         } else {
201           // For the very first route (oldRoute will be undefined), we replace
202           // the existing state instead of pushing a new one. This is to allow
203           // the user to use the browser back button to exit Settings entirely.
204           history.replaceState(historicState, null);
205         }
207         return;
208       }
209     }
211     assertNotReached('Route not found: ' + JSON.stringify(newRoute));
212   },