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

Side by Side Diff: chrome/browser/resources/settings/route.js

Issue 2957153003: MD Settings: remove unsupported routes from guest-mode. (Closed)
Patch Set: fix compiler error Created 3 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 /**
6 * Specifies all possible routes in settings.
7 *
8 * @typedef {{
9 * ABOUT: (undefined|!settings.Route),
10 * ABOUT_ABOUT: (undefined|!settings.Route),
11 * ACCESSIBILITY: (undefined|!settings.Route),
12 * ACCOUNTS: (undefined|!settings.Route),
13 * ADVANCED: (undefined|!settings.Route),
14 * ANDROID_APPS: (undefined|!settings.Route),
15 * ANDROID_APPS_DETAILS: (undefined|!settings.Route),
16 * APPEARANCE: (undefined|!settings.Route),
17 * AUTOFILL: (undefined|!settings.Route),
18 * BASIC: (undefined|!settings.Route),
19 * BLUETOOTH: (undefined|!settings.Route),
20 * BLUETOOTH_DEVICES: (undefined|!settings.Route),
21 * CERTIFICATES: (undefined|!settings.Route),
22 * CHANGE_PICTURE: (undefined|!settings.Route),
23 * CLEAR_BROWSER_DATA: (undefined|!settings.Route),
24 * CLOUD_PRINTERS: (undefined|!settings.Route),
25 * CUPS_PRINTER_DETAIL: (undefined|!settings.Route),
26 * CUPS_PRINTERS: (undefined|!settings.Route),
27 * DATETIME: (undefined|!settings.Route),
28 * DEFAULT_BROWSER: (undefined|!settings.Route),
29 * DETAILED_BUILD_INFO: (undefined|!settings.Route),
30 * DEVICE: (undefined|!settings.Route),
31 * DISPLAY: (undefined|!settings.Route),
32 * DOWNLOADS: (undefined|!settings.Route),
33 * EDIT_DICTIONARY: (undefined|!settings.Route),
34 * FINGERPRINT: (undefined|!settings.Route),
35 * FONTS: (undefined|!settings.Route),
36 * IMPORT_DATA: (undefined|!settings.Route),
37 * INPUT_METHODS: (undefined|!settings.Route),
38 * INTERNET: (undefined|!settings.Route),
39 * INTERNET_NETWORKS: (undefined|!settings.Route),
40 * KEYBOARD: (undefined|!settings.Route),
41 * KNOWN_NETWORKS: (undefined|!settings.Route),
42 * LANGUAGES: (undefined|!settings.Route),
43 * LOCK_SCREEN: (undefined|!settings.Route),
44 * MANAGE_ACCESSIBILITY: (undefined|!settings.Route),
45 * MANAGE_PASSWORDS: (undefined|!settings.Route),
46 * MANAGE_PROFILE: (undefined|!settings.Route),
47 * NETWORK_CONFIG: (undefined|!settings.Route),
48 * NETWORK_DETAIL: (undefined|!settings.Route),
49 * ON_STARTUP: (undefined|!settings.Route),
50 * PASSWORDS: (undefined|!settings.Route),
51 * PEOPLE: (undefined|!settings.Route),
52 * POINTERS: (undefined|!settings.Route),
53 * POWER: (undefined|!settings.Route),
54 * PRINTING: (undefined|!settings.Route),
55 * PRIVACY: (undefined|!settings.Route),
56 * RESET: (undefined|!settings.Route),
57 * RESET_DIALOG: (undefined|!settings.Route),
58 * SEARCH: (undefined|!settings.Route),
59 * SEARCH_ENGINES: (undefined|!settings.Route),
60 * SIGN_OUT: (undefined|!settings.Route),
61 * SITE_SETTINGS: (undefined|!settings.Route),
62 * SITE_SETTINGS_ADS: (undefined|!settings.Route),
63 * SITE_SETTINGS_ALL: (undefined|!settings.Route),
64 * SITE_SETTINGS_AUTOMATIC_DOWNLOADS: (undefined|!settings.Route),
65 * SITE_SETTINGS_BACKGROUND_SYNC: (undefined|!settings.Route),
66 * SITE_SETTINGS_CAMERA: (undefined|!settings.Route),
67 * SITE_SETTINGS_COOKIES: (undefined|!settings.Route),
68 * SITE_SETTINGS_DATA_DETAILS: (undefined|!settings.Route),
69 * SITE_SETTINGS_FLASH: (undefined|!settings.Route),
70 * SITE_SETTINGS_HANDLERS: (undefined|!settings.Route),
71 * SITE_SETTINGS_IMAGES: (undefined|!settings.Route),
72 * SITE_SETTINGS_JAVASCRIPT: (undefined|!settings.Route),
73 * SITE_SETTINGS_LOCATION: (undefined|!settings.Route),
74 * SITE_SETTINGS_MICROPHONE: (undefined|!settings.Route),
75 * SITE_SETTINGS_MIDI_DEVICES: (undefined|!settings.Route),
76 * SITE_SETTINGS_NOTIFICATIONS: (undefined|!settings.Route),
77 * SITE_SETTINGS_PDF_DOCUMENTS: (undefined|!settings.Route),
78 * SITE_SETTINGS_POPUPS: (undefined|!settings.Route),
79 * SITE_SETTINGS_PROTECTED_CONTENT: (undefined|!settings.Route),
80 * SITE_SETTINGS_SITE_DETAILS: (undefined|!settings.Route),
81 * SITE_SETTINGS_UNSANDBOXED_PLUGINS: (undefined|!settings.Route),
82 * SITE_SETTINGS_USB_DEVICES: (undefined|!settings.Route),
83 * SITE_SETTINGS_ZOOM_LEVELS: (undefined|!settings.Route),
84 * STORAGE: (undefined|!settings.Route),
85 * STYLUS: (undefined|!settings.Route),
86 * SYNC: (undefined|!settings.Route),
87 * SYSTEM: (undefined|!settings.Route),
88 * TRIGGERED_RESET_DIALOG: (undefined|!settings.Route),
89 * }}
90 */
91 var SettingsRoutes;
92
5 cr.define('settings', function() { 93 cr.define('settings', function() {
94
6 /** 95 /**
7 * Class for navigable routes. May only be instantiated within this file. 96 * Class for navigable routes. May only be instantiated within this file.
8 * @constructor
9 * @param {string} path
10 * @private
11 */ 97 */
12 var Route = function(path) { 98 class Route {
13 this.path = path; 99 /** @param {string} path */
100 constructor(path) {
101 /** @type {string} */
102 this.path = path;
14 103
15 /** @type {?settings.Route} */ 104 /** @type {?settings.Route} */
16 this.parent = null; 105 this.parent = null;
17 106
18 /** @type {number} */ 107 /** @type {number} */
19 this.depth = 0; 108 this.depth = 0;
20 109
21 /** 110 /**
22 * @type {boolean} Whether this route corresponds to a navigable 111 * @type {boolean} Whether this route corresponds to a navigable
23 * dialog. Those routes don't belong to a "section". 112 * dialog. Those routes don't belong to a "section".
24 */ 113 */
25 this.isNavigableDialog = false; 114 this.isNavigableDialog = false;
26 115
27 // Below are all legacy properties to provide compatibility with the old 116 // Below are all legacy properties to provide compatibility with the old
28 // routing system. 117 // routing system.
29 118
30 /** @type {string} */ 119 /** @type {string} */
31 this.section = ''; 120 this.section = '';
32 }; 121 }
33 122
34 Route.prototype = {
35 /** 123 /**
36 * Returns a new Route instance that's a child of this route. 124 * Returns a new Route instance that's a child of this route.
37 * @param {string} path Extends this route's path if it doesn't contain a 125 * @param {string} path Extends this route's path if it doesn't contain a
38 * leading slash. 126 * leading slash.
39 * @return {!settings.Route} 127 * @return {!settings.Route}
40 * @private 128 * @private
41 */ 129 */
42 createChild: function(path) { 130 createChild(path) {
43 assert(path); 131 assert(path);
44 132
45 // |path| extends this route's path if it doesn't have a leading slash. 133 // |path| extends this route's path if it doesn't have a leading slash.
46 // If it does have a leading slash, it's just set as the new route's URL. 134 // If it does have a leading slash, it's just set as the new route's URL.
47 var newUrl = path[0] == '/' ? path : this.path + '/' + path; 135 var newUrl = path[0] == '/' ? path : this.path + '/' + path;
48 136
49 var route = new Route(newUrl); 137 var route = new Route(newUrl);
50 route.parent = this; 138 route.parent = this;
51 route.section = this.section; 139 route.section = this.section;
52 route.depth = this.depth + 1; 140 route.depth = this.depth + 1;
53 141
54 return route; 142 return route;
55 }, 143 }
56 144
57 /** 145 /**
58 * Returns a new Route instance that's a child section of this route. 146 * Returns a new Route instance that's a child section of this route.
59 * TODO(tommycli): Remove once we've obsoleted the concept of sections. 147 * TODO(tommycli): Remove once we've obsoleted the concept of sections.
60 * @param {string} path 148 * @param {string} path
61 * @param {string} section 149 * @param {string} section
62 * @return {!settings.Route} 150 * @return {!settings.Route}
63 * @private 151 * @private
64 */ 152 */
65 createSection: function(path, section) { 153 createSection(path, section) {
66 var route = this.createChild(path); 154 var route = this.createChild(path);
67 route.section = section; 155 route.section = section;
68 return route; 156 return route;
69 }, 157 }
70 158
71 /** 159 /**
72 * Returns true if this route matches or is an ancestor of the parameter. 160 * Returns true if this route matches or is an ancestor of the parameter.
73 * @param {!settings.Route} route 161 * @param {!settings.Route} route
74 * @return {boolean} 162 * @return {boolean}
75 */ 163 */
76 contains: function(route) { 164 contains(route) {
77 for (var r = route; r != null; r = r.parent) { 165 for (var r = route; r != null; r = r.parent) {
78 if (this == r) 166 if (this == r)
79 return true; 167 return true;
80 } 168 }
81 return false; 169 return false;
82 }, 170 }
83 171
84 /** 172 /**
85 * Returns true if this route is a subpage of a section. 173 * Returns true if this route is a subpage of a section.
86 * @return {boolean} 174 * @return {boolean}
87 */ 175 */
88 isSubpage: function() { 176 isSubpage() {
89 return !!this.parent && !!this.section && 177 return !!this.parent && !!this.section &&
90 this.parent.section == this.section; 178 this.parent.section == this.section;
91 }, 179 }
180 }
181
182 /**
183 * Computes and return all available routes based on settings.pageVisibility.
184 * @return {!SettingsRoutes}
185 */
186 var computeAvailableRoutes = function() {
187 var pageVisibility = settings.pageVisibility || {};
188
189 /** @type {!SettingsRoutes} */
190 var r = {};
191
192 // Root pages.
193 r.BASIC = new Route('/');
194 r.ABOUT = new Route('/help');
195
196 // Navigable dialogs. These are the only non-section children of root
197 // pages. These are disfavored. If we add anymore, we should add explicit
198 // support.
199 r.IMPORT_DATA = r.BASIC.createChild('/importData');
200 r.IMPORT_DATA.isNavigableDialog = true;
201 r.SIGN_OUT = r.BASIC.createChild('/signOut');
202 r.SIGN_OUT.isNavigableDialog = true;
203
204 // <if expr="chromeos">
205 r.INTERNET = r.BASIC.createSection('/internet', 'internet');
206 r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks');
207 r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig');
208 r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail');
209 r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks');
210 r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth');
211 r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices');
212 // </if>
213
214 if (pageVisibility.appearance !== false) {
215 r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance');
216 r.FONTS = r.APPEARANCE.createChild('/fonts');
217 }
218
219 if (pageVisibility.defaultBrowser !== false) {
220 r.DEFAULT_BROWSER =
221 r.BASIC.createSection('/defaultBrowser', 'defaultBrowser');
222 }
223
224 r.SEARCH = r.BASIC.createSection('/search', 'search');
225 r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines');
226
227 // <if expr="chromeos">
228 r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps');
229 r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details');
230 // </if>
231
232 if (pageVisibility.onStartup !== false) {
233 r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup');
234 }
235
236 if (pageVisibility.people !== false) {
237 r.PEOPLE = r.BASIC.createSection('/people', 'people');
238 r.SYNC = r.PEOPLE.createChild('/syncSetup');
239 // <if expr="not chromeos">
240 r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
241 // </if>
242 // <if expr="chromeos">
243 r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture');
244 r.ACCOUNTS = r.PEOPLE.createChild('/accounts');
245 r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen');
246 r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint');
247 // </if>
248 }
249
250 // <if expr="chromeos">
251 r.DEVICE = r.BASIC.createSection('/device', 'device');
252 r.POINTERS = r.DEVICE.createChild('/pointer-overlay');
253 r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay');
254 r.STYLUS = r.DEVICE.createChild('/stylus');
255 r.DISPLAY = r.DEVICE.createChild('/display');
256 r.STORAGE = r.DEVICE.createChild('/storage');
257 r.POWER = r.DEVICE.createChild('/power');
258 // </if>
259
260 // Advacned Routes
261 if (pageVisibility.advancedSettings !== false) {
262 r.ADVANCED = new Route('/advanced');
263
264 r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData');
265 r.CLEAR_BROWSER_DATA.isNavigableDialog = true;
266
267 if (pageVisibility.privacy !== false) {
268 r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy');
269 r.CERTIFICATES = r.PRIVACY.createChild('/certificates');
270 r.SITE_SETTINGS = r.PRIVACY.createChild('/content');
271 }
272
273 if (loadTimeData.getBoolean('enableSiteSettings')) {
274 r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all');
275 r.SITE_SETTINGS_SITE_DETAILS =
276 r.SITE_SETTINGS_ALL.createChild('/content/siteDetails');
277 } else if (loadTimeData.getBoolean('enableSiteDetails')) {
278 // When there is no "All Sites", pressing 'back' from "Site Details"
279 // should return to "Content Settings". This should only occur when
280 // |kSiteSettings| is off and |kSiteDetails| is on.
281 r.SITE_SETTINGS_SITE_DETAILS =
282 r.SITE_SETTINGS.createChild('/content/siteDetails');
283 }
284
285 r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers');
286
287 // TODO(tommycli): Find a way to refactor these repetitive category
288 // routes.
289 r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads');
290 r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS =
291 r.SITE_SETTINGS.createChild('automaticDownloads');
292 r.SITE_SETTINGS_BACKGROUND_SYNC =
293 r.SITE_SETTINGS.createChild('backgroundSync');
294 r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
295 r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies');
296 r.SITE_SETTINGS_DATA_DETAILS =
297 r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail');
298 r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
299 r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
300 r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location');
301 r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone');
302 r.SITE_SETTINGS_NOTIFICATIONS =
303 r.SITE_SETTINGS.createChild('notifications');
304 r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash');
305 r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups');
306 r.SITE_SETTINGS_UNSANDBOXED_PLUGINS =
307 r.SITE_SETTINGS.createChild('unsandboxedPlugins');
308 r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices');
309 r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices');
310 r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels');
311 r.SITE_SETTINGS_PDF_DOCUMENTS =
312 r.SITE_SETTINGS.createChild('pdfDocuments');
313 r.SITE_SETTINGS_PROTECTED_CONTENT =
314 r.SITE_SETTINGS.createChild('protectedContent');
315
316 // <if expr="chromeos">
317 if (pageVisibility.dateTime !== false) {
318 r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
319 }
320 // </if>
321
322 if (pageVisibility.passwordsAndForms !== false) {
323 r.PASSWORDS =
324 r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms');
325 r.AUTOFILL = r.PASSWORDS.createChild('/autofill');
326 r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords');
327 }
328
329 r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages');
330 // <if expr="chromeos">
331 r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods');
332 // </if>
333 // <if expr="not is_macosx">
334 r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary');
335 // </if>
336
337 if (pageVisibility.downloads !== false) {
338 r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads');
339 }
340
341 r.PRINTING = r.ADVANCED.createSection('/printing', 'printing');
342 r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters');
343 // <if expr="chromeos">
344 r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters');
345 r.CUPS_PRINTER_DETAIL =
346 r.CUPS_PRINTERS.createChild('/cupsPrinterDetails');
347 // </if>
348
349 r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
350 // <if expr="chromeos">
351 r.MANAGE_ACCESSIBILITY =
352 r.ACCESSIBILITY.createChild('/manageAccessibility');
353 // </if>
354
355 r.SYSTEM = r.ADVANCED.createSection('/system', 'system');
356
357 if (pageVisibility.reset !== false) {
358 r.RESET = r.ADVANCED.createSection('/reset', 'reset');
359 r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings');
360 r.RESET_DIALOG.isNavigableDialog = true;
361 r.TRIGGERED_RESET_DIALOG =
362 r.ADVANCED.createChild('/triggeredResetProfileSettings');
363 r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true;
364 }
365 }
366
367 // <if expr="chromeos">
368 // "About" is the only section in About, but we still need to create the
369 // route in order to show the subpage on Chrome OS.
370 r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about');
371 r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details');
372 // </if>
373
374 return r;
92 }; 375 };
93 376
94 // Abbreviated variable for easier definitions. 377 class Router {
95 var r = Route; 378 constructor() {
96 379 /**
97 // Root pages. 380 * List of available routes. This is populated taking into account current
98 r.BASIC = new Route('/'); 381 * state (like guest mode).
99 r.ADVANCED = new Route('/advanced'); 382 * @private {!SettingsRoutes}
100 r.ABOUT = new Route('/help'); 383 */
101 384 this.routes_ = computeAvailableRoutes();
102 // Navigable dialogs. These are the only non-section children of root pages. 385
103 // These are disfavored. If we add anymore, we should add explicit support. 386 /**
104 r.IMPORT_DATA = r.BASIC.createChild('/importData'); 387 * The current active route. This updated is only by settings.navigateTo
105 r.IMPORT_DATA.isNavigableDialog = true; 388 * or settings.initializeRouteFromUrl.
106 r.SIGN_OUT = r.BASIC.createChild('/signOut'); 389 * @type {!settings.Route}
107 r.SIGN_OUT.isNavigableDialog = true; 390 */
108 r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData'); 391 this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC);
109 r.CLEAR_BROWSER_DATA.isNavigableDialog = true; 392
110 r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings'); 393 /**
111 r.RESET_DIALOG.isNavigableDialog = true; 394 * The current query parameters. This is updated only by
112 r.TRIGGERED_RESET_DIALOG = 395 * settings.navigateTo or settings.initializeRouteFromUrl.
113 r.ADVANCED.createChild('/triggeredResetProfileSettings'); 396 * @private {!URLSearchParams}
114 r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true; 397 */
115 398 this.currentQueryParameters_ = new URLSearchParams();
116 // <if expr="chromeos"> 399
117 r.INTERNET = r.BASIC.createSection('/internet', 'internet'); 400 /** @private {boolean} */
118 r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks'); 401 this.wasLastRouteChangePopstate_ = false;
119 r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig'); 402
120 r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail'); 403 /** @private {boolean}*/
121 r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks'); 404 this.initializeRouteFromUrlCalled_ = false;
122 r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth'); 405 }
123 r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices'); 406
124 // </if> 407 /** @return {settings.Route} */
125 408 getRoute(routeName) {
126 r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance'); 409 return this.routes_[routeName];
127 r.FONTS = r.APPEARANCE.createChild('/fonts'); 410 }
128 411
129 r.DEFAULT_BROWSER = 412 /** @return {!SettingsRoutes} */
130 r.BASIC.createSection('/defaultBrowser', 'defaultBrowser'); 413 getRoutes() {
131 414 return this.routes_;
132 r.SEARCH = r.BASIC.createSection('/search', 'search'); 415 }
133 r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines'); 416
134 417 /**
135 // <if expr="chromeos"> 418 * Helper function to set the current route and notify all observers.
136 r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps'); 419 * @param {!settings.Route} route
137 r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details'); 420 * @param {!URLSearchParams} queryParameters
138 // </if> 421 * @param {boolean} isPopstate
139 422 */
140 r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup'); 423 setCurrentRoute(route, queryParameters, isPopstate) {
141 424 var oldRoute = this.currentRoute;
142 r.PEOPLE = r.BASIC.createSection('/people', 'people'); 425 this.currentRoute = route;
143 r.SYNC = r.PEOPLE.createChild('/syncSetup'); 426 this.currentQueryParameters_ = queryParameters;
144 // <if expr="not chromeos"> 427 this.wasLastRouteChangePopstate_ = isPopstate;
145 r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile'); 428 routeObservers.forEach(function(observer) {
146 // </if> 429 observer.currentRouteChanged(this.currentRoute, oldRoute);
147 // <if expr="chromeos"> 430 }.bind(this));
148 r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture'); 431 }
149 r.ACCOUNTS = r.PEOPLE.createChild('/accounts'); 432
150 r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen'); 433 /** @return {!settings.Route} */
151 r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint'); 434 getCurrentRoute() {
152 435 return this.currentRoute;
153 r.DEVICE = r.BASIC.createSection('/device', 'device'); 436 }
154 r.POINTERS = r.DEVICE.createChild('/pointer-overlay'); 437
155 r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay'); 438 /** @return {!URLSearchParams} */
156 r.STYLUS = r.DEVICE.createChild('/stylus'); 439 getQueryParameters() {
157 r.DISPLAY = r.DEVICE.createChild('/display'); 440 return new URLSearchParams(
158 r.STORAGE = r.DEVICE.createChild('/storage'); 441 this.currentQueryParameters_); // Defensive copy.
159 r.POWER = r.DEVICE.createChild('/power'); 442 }
160 // </if> 443
161 444 /** @return {boolean} */
162 r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy'); 445 lastRouteChangeWasPopstate() {
163 r.CERTIFICATES = r.PRIVACY.createChild('/certificates'); 446 return this.wasLastRouteChangePopstate_;
164 447 }
165 r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); 448
166 449 /**
167 if (loadTimeData.getBoolean('enableSiteSettings')) { 450 * @param {string} path
168 r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); 451 * @return {?settings.Route} The matching canonical route, or null if none
169 r.SITE_SETTINGS_SITE_DETAILS = 452 * matches.
170 r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); 453 */
171 } else if (loadTimeData.getBoolean('enableSiteDetails')) { 454 getRouteForPath(path) {
172 // When there is no "All Sites", pressing 'back' from "Site Details" should 455 // Allow trailing slash in paths.
173 // return to "Content Settings". This should only occur when |kSiteSettings| 456 var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2');
174 // is off and |kSiteDetails| is on. 457
175 r.SITE_SETTINGS_SITE_DETAILS = 458 // TODO(tommycli): Use Object.values once Closure compilation supports it.
176 r.SITE_SETTINGS.createChild('/content/siteDetails'); 459 var matchingKey = Object.keys(this.routes_).find(function(key) {
460 return this.routes_[key].path == canonicalPath;
461 }.bind(this));
462
463 return !!matchingKey ? this.routes_[matchingKey] : null;
464 }
465
466 /**
467 * Navigates to a canonical route and pushes a new history entry.
468 * @param {!settings.Route} route
469 * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same
470 * URL parameters in a different order will still push to history.
471 * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL
472 * parameter during navigation. Defaults to false.
473 */
474 navigateTo(route, opt_dynamicParameters, opt_removeSearch) {
475 // The ADVANCED route only serves as a parent of subpages, and should not
476 // be possible to navigate to it directly.
477 if (route == this.routes_.ADVANCED)
478 route = /** @type {!settings.Route} */ (this.routes_.BASIC);
479
480 var params = opt_dynamicParameters || new URLSearchParams();
481 var removeSearch = !!opt_removeSearch;
482
483 var oldSearchParam = this.getQueryParameters().get('search') || '';
484 var newSearchParam = params.get('search') || '';
485
486 if (!removeSearch && oldSearchParam && !newSearchParam)
487 params.append('search', oldSearchParam);
488
489 var url = route.path;
490 var queryString = params.toString();
491 if (queryString)
492 url += '?' + queryString;
493
494 // History serializes the state, so we don't push the actual route object.
495 window.history.pushState(this.currentRoute.path, '', url);
496 this.setCurrentRoute(route, params, false);
497 }
498
499 /**
500 * Navigates to the previous route if it has an equal or lesser depth.
501 * If there is no previous route in history meeting those requirements,
502 * this navigates to the immediate parent. This will never exit Settings.
503 */
504 navigateToPreviousRoute() {
505 var previousRoute = window.history.state &&
506 assert(this.getRouteForPath(
507 /** @type {string} */ (window.history.state)));
508
509 if (previousRoute && previousRoute.depth <= this.currentRoute.depth)
510 window.history.back();
511 else
512 this.navigateTo(
513 this.currentRoute.parent ||
514 /** @type {!settings.Route} */ (this.routes_.BASIC));
515 }
516
517 /**
518 * Initialize the route and query params from the URL.
519 */
520 initializeRouteFromUrl() {
521 assert(!this.initializeRouteFromUrlCalled_);
522 this.initializeRouteFromUrlCalled_ = true;
523
524 var route = this.getRouteForPath(window.location.pathname);
525 // Never allow direct navigation to ADVANCED.
526 if (route && route != this.routes_.ADVANCED) {
527 this.currentRoute = route;
528 this.currentQueryParameters_ =
529 new URLSearchParams(window.location.search);
530 } else {
531 window.history.replaceState(undefined, '', this.routes_.BASIC.path);
532 }
533 }
534
535 resetRouteForTesting() {
536 this.initializeRouteFromUrlCalled_ = false;
537 this.wasLastRouteChangePopstate_ = false;
538 this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC);
539 this.currentQueryParameters_ = new URLSearchParams();
540 }
177 } 541 }
178 542
179 r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers'); 543 var routerInstance = new Router();
180
181 // TODO(tommycli): Find a way to refactor these repetitive category routes.
182 r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads');
183 r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS =
184 r.SITE_SETTINGS.createChild('automaticDownloads');
185 r.SITE_SETTINGS_BACKGROUND_SYNC =
186 r.SITE_SETTINGS.createChild('backgroundSync');
187 r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
188 r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies');
189 r.SITE_SETTINGS_DATA_DETAILS =
190 r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail');
191 r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
192 r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
193 r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location');
194 r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone');
195 r.SITE_SETTINGS_NOTIFICATIONS = r.SITE_SETTINGS.createChild('notifications');
196 r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash');
197 r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups');
198 r.SITE_SETTINGS_UNSANDBOXED_PLUGINS =
199 r.SITE_SETTINGS.createChild('unsandboxedPlugins');
200 r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices');
201 r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices');
202 r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels');
203 r.SITE_SETTINGS_PDF_DOCUMENTS = r.SITE_SETTINGS.createChild('pdfDocuments');
204 r.SITE_SETTINGS_PROTECTED_CONTENT =
205 r.SITE_SETTINGS.createChild('protectedContent');
206
207 // <if expr="chromeos">
208 r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
209 // </if>
210
211 r.PASSWORDS =
212 r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms');
213 r.AUTOFILL = r.PASSWORDS.createChild('/autofill');
214 r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords');
215
216 r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages');
217 // <if expr="chromeos">
218 r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods');
219 // </if>
220 // <if expr="not is_macosx">
221 r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary');
222 // </if>
223
224 r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads');
225
226 r.PRINTING = r.ADVANCED.createSection('/printing', 'printing');
227 r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters');
228 // <if expr="chromeos">
229 r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters');
230 r.CUPS_PRINTER_DETAIL = r.CUPS_PRINTERS.createChild('/cupsPrinterDetails');
231 // </if>
232
233 r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
234 // <if expr="chromeos">
235 r.MANAGE_ACCESSIBILITY = r.ACCESSIBILITY.createChild('/manageAccessibility');
236 // </if>
237
238 r.SYSTEM = r.ADVANCED.createSection('/system', 'system');
239 r.RESET = r.ADVANCED.createSection('/reset', 'reset');
240
241 // <if expr="chromeos">
242 // "About" is the only section in About, but we still need to create the route
243 // in order to show the subpage on Chrome OS.
244 r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about');
245 r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details');
246 // </if>
247 544
248 var routeObservers = new Set(); 545 var routeObservers = new Set();
249 546
250 /** @polymerBehavior */ 547 /** @polymerBehavior */
251 var RouteObserverBehavior = { 548 var RouteObserverBehavior = {
252 /** @override */ 549 /** @override */
253 attached: function() { 550 attached: function() {
254 assert(!routeObservers.has(this)); 551 assert(!routeObservers.has(this));
255 routeObservers.add(this); 552 routeObservers.add(this);
256 553
257 // Emulating Polymer data bindings, the observer is called when the 554 // Emulating Polymer data bindings, the observer is called when the
258 // element starts observing the route. 555 // element starts observing the route.
259 this.currentRouteChanged(currentRoute, undefined); 556 this.currentRouteChanged(routerInstance.currentRoute, undefined);
260 }, 557 },
261 558
262 /** @override */ 559 /** @override */
263 detached: function() { 560 detached: function() {
264 assert(routeObservers.delete(this)); 561 assert(routeObservers.delete(this));
265 }, 562 },
266 563
267 /** 564 /**
268 * @param {!settings.Route|undefined} opt_newRoute 565 * @param {!settings.Route|undefined} opt_newRoute
269 * @param {!settings.Route|undefined} opt_oldRoute 566 * @param {!settings.Route|undefined} opt_oldRoute
270 * @abstract 567 * @abstract
271 */ 568 */
272 currentRouteChanged: function(opt_newRoute, opt_oldRoute) { 569 currentRouteChanged: function(opt_newRoute, opt_oldRoute) {
273 assertNotReached(); 570 assertNotReached();
274 }, 571 },
275 }; 572 };
276 573
277 /** 574 /**
278 * Regular expression that captures the leading slash, the content and the 575 * Regular expression that captures the leading slash, the content and the
279 * trailing slash in three different groups. 576 * trailing slash in three different groups.
280 * @const {!RegExp} 577 * @const {!RegExp}
281 */ 578 */
282 var CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/; 579 var CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
283 580
284 /**
285 * @param {string} path
286 * @return {?settings.Route} The matching canonical route, or null if none
287 * matches.
288 */
289 var getRouteForPath = function(path) {
290 // Allow trailing slash in paths.
291 var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2');
292
293 // TODO(tommycli): Use Object.values once Closure compilation supports it.
294 var matchingKey = Object.keys(Route).find(function(key) {
295 return Route[key].path == canonicalPath;
296 });
297
298 return !!matchingKey ? Route[matchingKey] : null;
299 };
300
301 /**
302 * The current active route. This updated is only by settings.navigateTo or
303 * settings.initializeRouteFromUrl.
304 * @private {!settings.Route}
305 */
306 var currentRoute = Route.BASIC;
307
308 /**
309 * The current query parameters. This is updated only by settings.navigateTo
310 * or settings.initializeRouteFromUrl.
311 * @private {!URLSearchParams}
312 */
313 var currentQueryParameters = new URLSearchParams();
314
315 /** @private {boolean} */
316 var wasLastRouteChangePopstate = false;
317
318 /** @private */
319 var initializeRouteFromUrlCalled = false;
320
321 /**
322 * Initialize the route and query params from the URL.
323 */
324 var initializeRouteFromUrl = function() {
325 assert(!initializeRouteFromUrlCalled);
326 initializeRouteFromUrlCalled = true;
327
328 var route = getRouteForPath(window.location.pathname);
329 // Never allow direct navigation to ADVANCED.
330 if (route && route != Route.ADVANCED) {
331 currentRoute = route;
332 currentQueryParameters = new URLSearchParams(window.location.search);
333 } else {
334 window.history.replaceState(undefined, '', Route.BASIC.path);
335 }
336 };
337
338 function resetRouteForTesting() {
339 initializeRouteFromUrlCalled = false;
340 wasLastRouteChangePopstate = false;
341 currentRoute = Route.BASIC;
342 currentQueryParameters = new URLSearchParams();
343 }
344
345 /**
346 * Helper function to set the current route and notify all observers.
347 * @param {!settings.Route} route
348 * @param {!URLSearchParams} queryParameters
349 * @param {boolean} isPopstate
350 */
351 var setCurrentRoute = function(route, queryParameters, isPopstate) {
352 var oldRoute = currentRoute;
353 currentRoute = route;
354 currentQueryParameters = queryParameters;
355 wasLastRouteChangePopstate = isPopstate;
356 routeObservers.forEach(function(observer) {
357 observer.currentRouteChanged(currentRoute, oldRoute);
358 });
359 };
360
361 /** @return {!settings.Route} */
362 var getCurrentRoute = function() {
363 return currentRoute;
364 };
365
366 /** @return {!URLSearchParams} */
367 var getQueryParameters = function() {
368 return new URLSearchParams(currentQueryParameters); // Defensive copy.
369 };
370
371 /** @return {boolean} */
372 var lastRouteChangeWasPopstate = function() {
373 return wasLastRouteChangePopstate;
374 };
375
376 /**
377 * Navigates to a canonical route and pushes a new history entry.
378 * @param {!settings.Route} route
379 * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same
380 * URL parameters in a different order will still push to history.
381 * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL
382 * parameter during navigation. Defaults to false.
383 */
384 var navigateTo = function(route, opt_dynamicParameters, opt_removeSearch) {
385 // The ADVANCED route only serves as a parent of subpages, and should not
386 // be possible to navigate to it directly.
387 if (route == settings.Route.ADVANCED)
388 route = settings.Route.BASIC;
389
390 var params = opt_dynamicParameters || new URLSearchParams();
391 var removeSearch = !!opt_removeSearch;
392
393 var oldSearchParam = getQueryParameters().get('search') || '';
394 var newSearchParam = params.get('search') || '';
395
396 if (!removeSearch && oldSearchParam && !newSearchParam)
397 params.append('search', oldSearchParam);
398
399 var url = route.path;
400 var queryString = params.toString();
401 if (queryString)
402 url += '?' + queryString;
403
404 // History serializes the state, so we don't push the actual route object.
405 window.history.pushState(currentRoute.path, '', url);
406 setCurrentRoute(route, params, false);
407 };
408
409 /**
410 * Navigates to the previous route if it has an equal or lesser depth.
411 * If there is no previous route in history meeting those requirements,
412 * this navigates to the immediate parent. This will never exit Settings.
413 */
414 var navigateToPreviousRoute = function() {
415 var previousRoute = window.history.state &&
416 assert(getRouteForPath(/** @type {string} */ (window.history.state)));
417
418 if (previousRoute && previousRoute.depth <= currentRoute.depth)
419 window.history.back();
420 else
421 navigateTo(currentRoute.parent || Route.BASIC);
422 };
423
424 window.addEventListener('popstate', function(event) { 581 window.addEventListener('popstate', function(event) {
425 // On pop state, do not push the state onto the window.history again. 582 // On pop state, do not push the state onto the window.history again.
426 setCurrentRoute( 583 routerInstance.setCurrentRoute(
427 getRouteForPath(window.location.pathname) || Route.BASIC, 584 /** @type {!settings.Route} */ (
585 routerInstance.getRouteForPath(window.location.pathname) ||
586 routerInstance.getRoutes().BASIC),
428 new URLSearchParams(window.location.search), true); 587 new URLSearchParams(window.location.search), true);
429 }); 588 });
430 589
590 // TODO(scottchen): Change to 'get routes() {}' in export when we fix a bug in
591 // ChromePass that limits the syntax of what can be returned from cr.define().
592 var routes = routerInstance.getRoutes();
593
594 // TODO(scottchen): Stop exposing all those methods directly on settings.*,
595 // and instead update all clients to use the singleton instance directly
596 var getCurrentRoute = routerInstance.getCurrentRoute.bind(routerInstance);
597 var getRouteForPath = routerInstance.getRouteForPath.bind(routerInstance);
598 var initializeRouteFromUrl =
599 routerInstance.initializeRouteFromUrl.bind(routerInstance);
600 var resetRouteForTesting =
601 routerInstance.resetRouteForTesting.bind(routerInstance);
602 var getQueryParameters =
603 routerInstance.getQueryParameters.bind(routerInstance);
604 var lastRouteChangeWasPopstate =
605 routerInstance.lastRouteChangeWasPopstate.bind(routerInstance);
606 var navigateTo = routerInstance.navigateTo.bind(routerInstance);
607 var navigateToPreviousRoute =
608 routerInstance.navigateToPreviousRoute.bind(routerInstance);
609
431 return { 610 return {
432 Route: Route, 611 Route: Route, // The class definition.
612 Router: Router, // The class definition.
stevenjb 2017/07/10 18:01:25 tiny nit: S/The class/Class/ for both of these sin
scottchen 2017/07/10 20:54:35 Acknowledged.
613 router: routerInstance, // the singleton.
614 routes: routes,
433 RouteObserverBehavior: RouteObserverBehavior, 615 RouteObserverBehavior: RouteObserverBehavior,
434 getRouteForPath: getRouteForPath, 616 getRouteForPath: getRouteForPath,
435 initializeRouteFromUrl: initializeRouteFromUrl, 617 initializeRouteFromUrl: initializeRouteFromUrl,
436 resetRouteForTesting: resetRouteForTesting, 618 resetRouteForTesting: resetRouteForTesting,
437 getCurrentRoute: getCurrentRoute, 619 getCurrentRoute: getCurrentRoute,
438 getQueryParameters: getQueryParameters, 620 getQueryParameters: getQueryParameters,
439 lastRouteChangeWasPopstate: lastRouteChangeWasPopstate, 621 lastRouteChangeWasPopstate: lastRouteChangeWasPopstate,
440 navigateTo: navigateTo, 622 navigateTo: navigateTo,
441 navigateToPreviousRoute: navigateToPreviousRoute, 623 navigateToPreviousRoute: navigateToPreviousRoute,
442 }; 624 };
443 }); 625 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698