Index: chrome/browser/resources/settings/route.js |
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js |
index ed960c672ae377ef30a2f1d1afbd794f174f451c..02add787caae967d8494e4a4c21296a9e1eddfae 100644 |
--- a/chrome/browser/resources/settings/route.js |
+++ b/chrome/browser/resources/settings/route.js |
@@ -2,36 +2,124 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+/** |
+ * Specifies all possible routes in settings. |
+ * |
+ * @typedef {{ |
+ * ABOUT: (undefined|!settings.Route), |
+ * ABOUT_ABOUT: (undefined|!settings.Route), |
+ * ACCESSIBILITY: (undefined|!settings.Route), |
+ * ACCOUNTS: (undefined|!settings.Route), |
+ * ADVANCED: (undefined|!settings.Route), |
+ * ANDROID_APPS: (undefined|!settings.Route), |
+ * ANDROID_APPS_DETAILS: (undefined|!settings.Route), |
+ * APPEARANCE: (undefined|!settings.Route), |
+ * AUTOFILL: (undefined|!settings.Route), |
+ * BASIC: (undefined|!settings.Route), |
+ * BLUETOOTH: (undefined|!settings.Route), |
+ * BLUETOOTH_DEVICES: (undefined|!settings.Route), |
+ * CERTIFICATES: (undefined|!settings.Route), |
+ * CHANGE_PICTURE: (undefined|!settings.Route), |
+ * CLEAR_BROWSER_DATA: (undefined|!settings.Route), |
+ * CLOUD_PRINTERS: (undefined|!settings.Route), |
+ * CUPS_PRINTER_DETAIL: (undefined|!settings.Route), |
+ * CUPS_PRINTERS: (undefined|!settings.Route), |
+ * DATETIME: (undefined|!settings.Route), |
+ * DEFAULT_BROWSER: (undefined|!settings.Route), |
+ * DETAILED_BUILD_INFO: (undefined|!settings.Route), |
+ * DEVICE: (undefined|!settings.Route), |
+ * DISPLAY: (undefined|!settings.Route), |
+ * DOWNLOADS: (undefined|!settings.Route), |
+ * EDIT_DICTIONARY: (undefined|!settings.Route), |
+ * FINGERPRINT: (undefined|!settings.Route), |
+ * FONTS: (undefined|!settings.Route), |
+ * IMPORT_DATA: (undefined|!settings.Route), |
+ * INPUT_METHODS: (undefined|!settings.Route), |
+ * INTERNET: (undefined|!settings.Route), |
+ * INTERNET_NETWORKS: (undefined|!settings.Route), |
+ * KEYBOARD: (undefined|!settings.Route), |
+ * KNOWN_NETWORKS: (undefined|!settings.Route), |
+ * LANGUAGES: (undefined|!settings.Route), |
+ * LOCK_SCREEN: (undefined|!settings.Route), |
+ * MANAGE_ACCESSIBILITY: (undefined|!settings.Route), |
+ * MANAGE_PASSWORDS: (undefined|!settings.Route), |
+ * MANAGE_PROFILE: (undefined|!settings.Route), |
+ * NETWORK_CONFIG: (undefined|!settings.Route), |
+ * NETWORK_DETAIL: (undefined|!settings.Route), |
+ * ON_STARTUP: (undefined|!settings.Route), |
+ * PASSWORDS: (undefined|!settings.Route), |
+ * PEOPLE: (undefined|!settings.Route), |
+ * POINTERS: (undefined|!settings.Route), |
+ * POWER: (undefined|!settings.Route), |
+ * PRINTING: (undefined|!settings.Route), |
+ * PRIVACY: (undefined|!settings.Route), |
+ * RESET: (undefined|!settings.Route), |
+ * RESET_DIALOG: (undefined|!settings.Route), |
+ * SEARCH: (undefined|!settings.Route), |
+ * SEARCH_ENGINES: (undefined|!settings.Route), |
+ * SIGN_OUT: (undefined|!settings.Route), |
+ * SITE_SETTINGS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_ADS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_ALL: (undefined|!settings.Route), |
+ * SITE_SETTINGS_AUTOMATIC_DOWNLOADS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_BACKGROUND_SYNC: (undefined|!settings.Route), |
+ * SITE_SETTINGS_CAMERA: (undefined|!settings.Route), |
+ * SITE_SETTINGS_COOKIES: (undefined|!settings.Route), |
+ * SITE_SETTINGS_DATA_DETAILS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_FLASH: (undefined|!settings.Route), |
+ * SITE_SETTINGS_HANDLERS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_IMAGES: (undefined|!settings.Route), |
+ * SITE_SETTINGS_JAVASCRIPT: (undefined|!settings.Route), |
+ * SITE_SETTINGS_LOCATION: (undefined|!settings.Route), |
+ * SITE_SETTINGS_MICROPHONE: (undefined|!settings.Route), |
+ * SITE_SETTINGS_MIDI_DEVICES: (undefined|!settings.Route), |
+ * SITE_SETTINGS_NOTIFICATIONS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_PDF_DOCUMENTS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_POPUPS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_PROTECTED_CONTENT: (undefined|!settings.Route), |
+ * SITE_SETTINGS_SITE_DETAILS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_UNSANDBOXED_PLUGINS: (undefined|!settings.Route), |
+ * SITE_SETTINGS_USB_DEVICES: (undefined|!settings.Route), |
+ * SITE_SETTINGS_ZOOM_LEVELS: (undefined|!settings.Route), |
+ * STORAGE: (undefined|!settings.Route), |
+ * STYLUS: (undefined|!settings.Route), |
+ * SYNC: (undefined|!settings.Route), |
+ * SYSTEM: (undefined|!settings.Route), |
+ * TRIGGERED_RESET_DIALOG: (undefined|!settings.Route), |
+ * }} |
+ */ |
+var SettingsRoutes; |
+ |
cr.define('settings', function() { |
+ |
/** |
* Class for navigable routes. May only be instantiated within this file. |
- * @constructor |
- * @param {string} path |
- * @private |
*/ |
- var Route = function(path) { |
- this.path = path; |
+ class Route { |
+ /** @param {string} path */ |
+ constructor(path) { |
+ /** @type {string} */ |
+ this.path = path; |
- /** @type {?settings.Route} */ |
- this.parent = null; |
+ /** @type {?settings.Route} */ |
+ this.parent = null; |
- /** @type {number} */ |
- this.depth = 0; |
+ /** @type {number} */ |
+ this.depth = 0; |
- /** |
- * @type {boolean} Whether this route corresponds to a navigable |
- * dialog. Those routes don't belong to a "section". |
- */ |
- this.isNavigableDialog = false; |
+ /** |
+ * @type {boolean} Whether this route corresponds to a navigable |
+ * dialog. Those routes don't belong to a "section". |
+ */ |
+ this.isNavigableDialog = false; |
- // Below are all legacy properties to provide compatibility with the old |
- // routing system. |
+ // Below are all legacy properties to provide compatibility with the old |
+ // routing system. |
- /** @type {string} */ |
- this.section = ''; |
- }; |
+ /** @type {string} */ |
+ this.section = ''; |
+ } |
- Route.prototype = { |
/** |
* Returns a new Route instance that's a child of this route. |
* @param {string} path Extends this route's path if it doesn't contain a |
@@ -39,7 +127,7 @@ cr.define('settings', function() { |
* @return {!settings.Route} |
* @private |
*/ |
- createChild: function(path) { |
+ createChild(path) { |
assert(path); |
// |path| extends this route's path if it doesn't have a leading slash. |
@@ -52,7 +140,7 @@ cr.define('settings', function() { |
route.depth = this.depth + 1; |
return route; |
- }, |
+ } |
/** |
* Returns a new Route instance that's a child section of this route. |
@@ -62,189 +150,398 @@ cr.define('settings', function() { |
* @return {!settings.Route} |
* @private |
*/ |
- createSection: function(path, section) { |
+ createSection(path, section) { |
var route = this.createChild(path); |
route.section = section; |
return route; |
- }, |
+ } |
/** |
* Returns true if this route matches or is an ancestor of the parameter. |
* @param {!settings.Route} route |
* @return {boolean} |
*/ |
- contains: function(route) { |
+ contains(route) { |
for (var r = route; r != null; r = r.parent) { |
if (this == r) |
return true; |
} |
return false; |
- }, |
+ } |
/** |
* Returns true if this route is a subpage of a section. |
* @return {boolean} |
*/ |
- isSubpage: function() { |
+ isSubpage() { |
return !!this.parent && !!this.section && |
this.parent.section == this.section; |
- }, |
+ } |
+ } |
+ |
+ /** |
+ * Computes and return all available routes based on settings.pageVisibility. |
+ * @return {!SettingsRoutes} |
+ */ |
+ var computeAvailableRoutes = function() { |
+ var pageVisibility = settings.pageVisibility || {}; |
+ |
+ /** @type {!SettingsRoutes} */ |
+ var r = {}; |
+ |
+ // Root pages. |
+ r.BASIC = new Route('/'); |
+ r.ABOUT = new Route('/help'); |
+ |
+ // Navigable dialogs. These are the only non-section children of root |
+ // pages. These are disfavored. If we add anymore, we should add explicit |
+ // support. |
+ r.IMPORT_DATA = r.BASIC.createChild('/importData'); |
+ r.IMPORT_DATA.isNavigableDialog = true; |
+ r.SIGN_OUT = r.BASIC.createChild('/signOut'); |
+ r.SIGN_OUT.isNavigableDialog = true; |
+ |
+ // <if expr="chromeos"> |
+ r.INTERNET = r.BASIC.createSection('/internet', 'internet'); |
+ r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks'); |
+ r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig'); |
+ r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail'); |
+ r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks'); |
+ r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth'); |
+ r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices'); |
+ // </if> |
+ |
+ if (pageVisibility.appearance !== false) { |
+ r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance'); |
+ r.FONTS = r.APPEARANCE.createChild('/fonts'); |
+ } |
+ |
+ if (pageVisibility.defaultBrowser !== false) { |
+ r.DEFAULT_BROWSER = |
+ r.BASIC.createSection('/defaultBrowser', 'defaultBrowser'); |
+ } |
+ |
+ r.SEARCH = r.BASIC.createSection('/search', 'search'); |
+ r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines'); |
+ |
+ // <if expr="chromeos"> |
+ r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps'); |
+ r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details'); |
+ // </if> |
+ |
+ if (pageVisibility.onStartup !== false) { |
+ r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup'); |
+ r.STARTUP_URLS = r.ON_STARTUP.createChild('/startupUrls'); |
+ } |
+ |
+ if (pageVisibility.people !== false) { |
+ r.PEOPLE = r.BASIC.createSection('/people', 'people'); |
+ r.SYNC = r.PEOPLE.createChild('/syncSetup'); |
+ // <if expr="not chromeos"> |
+ r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile'); |
+ // </if> |
+ // <if expr="chromeos"> |
+ r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture'); |
+ r.ACCOUNTS = r.PEOPLE.createChild('/accounts'); |
+ r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen'); |
+ r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint'); |
+ // </if> |
+ } |
+ |
+ // <if expr="chromeos"> |
+ r.DEVICE = r.BASIC.createSection('/device', 'device'); |
+ r.POINTERS = r.DEVICE.createChild('/pointer-overlay'); |
+ r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay'); |
+ r.STYLUS = r.DEVICE.createChild('/stylus'); |
+ r.DISPLAY = r.DEVICE.createChild('/display'); |
+ r.STORAGE = r.DEVICE.createChild('/storage'); |
+ r.POWER = r.DEVICE.createChild('/power'); |
+ // </if> |
+ |
+ // Advacned Routes |
+ if (pageVisibility.advancedSettings !== false) { |
+ r.ADVANCED = new Route('/advanced'); |
+ |
+ r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData'); |
+ r.CLEAR_BROWSER_DATA.isNavigableDialog = true; |
+ |
+ if (pageVisibility.privacy !== false) { |
+ r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy'); |
+ r.CERTIFICATES = r.PRIVACY.createChild('/certificates'); |
+ r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); |
+ } |
+ |
+ if (loadTimeData.getBoolean('enableSiteSettings')) { |
+ r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); |
+ r.SITE_SETTINGS_SITE_DETAILS = |
+ r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); |
+ } else if (loadTimeData.getBoolean('enableSiteDetails')) { |
+ // When there is no "All Sites", pressing 'back' from "Site Details" |
+ // should return to "Content Settings". This should only occur when |
+ // |kSiteSettings| is off and |kSiteDetails| is on. |
+ r.SITE_SETTINGS_SITE_DETAILS = |
+ r.SITE_SETTINGS.createChild('/content/siteDetails'); |
+ } |
+ |
+ r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers'); |
+ |
+ // TODO(tommycli): Find a way to refactor these repetitive category |
+ // routes. |
+ r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads'); |
+ r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS = |
+ r.SITE_SETTINGS.createChild('automaticDownloads'); |
+ r.SITE_SETTINGS_BACKGROUND_SYNC = |
+ r.SITE_SETTINGS.createChild('backgroundSync'); |
+ r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera'); |
+ r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies'); |
+ r.SITE_SETTINGS_DATA_DETAILS = |
+ r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail'); |
+ r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images'); |
+ r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript'); |
+ r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location'); |
+ r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone'); |
+ r.SITE_SETTINGS_NOTIFICATIONS = |
+ r.SITE_SETTINGS.createChild('notifications'); |
+ r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash'); |
+ r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups'); |
+ r.SITE_SETTINGS_UNSANDBOXED_PLUGINS = |
+ r.SITE_SETTINGS.createChild('unsandboxedPlugins'); |
+ r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices'); |
+ r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices'); |
+ r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels'); |
+ r.SITE_SETTINGS_PDF_DOCUMENTS = |
+ r.SITE_SETTINGS.createChild('pdfDocuments'); |
+ r.SITE_SETTINGS_PROTECTED_CONTENT = |
+ r.SITE_SETTINGS.createChild('protectedContent'); |
+ |
+ // <if expr="chromeos"> |
+ if (pageVisibility.dateTime !== false) { |
+ r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime'); |
+ } |
+ // </if> |
+ |
+ if (pageVisibility.passwordsAndForms !== false) { |
+ r.PASSWORDS = |
+ r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms'); |
+ r.AUTOFILL = r.PASSWORDS.createChild('/autofill'); |
+ r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords'); |
+ } |
+ |
+ r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages'); |
+ // <if expr="chromeos"> |
+ r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods'); |
+ // </if> |
+ // <if expr="not is_macosx"> |
+ r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary'); |
+ // </if> |
+ |
+ if (pageVisibility.downloads !== false) { |
+ r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads'); |
+ } |
+ |
+ r.PRINTING = r.ADVANCED.createSection('/printing', 'printing'); |
+ r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters'); |
+ // <if expr="chromeos"> |
+ r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters'); |
+ r.CUPS_PRINTER_DETAIL = |
+ r.CUPS_PRINTERS.createChild('/cupsPrinterDetails'); |
+ // </if> |
+ |
+ r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y'); |
+ // <if expr="chromeos"> |
+ r.MANAGE_ACCESSIBILITY = |
+ r.ACCESSIBILITY.createChild('/manageAccessibility'); |
+ // </if> |
+ |
+ r.SYSTEM = r.ADVANCED.createSection('/system', 'system'); |
+ |
+ if (pageVisibility.reset !== false) { |
+ r.RESET = r.ADVANCED.createSection('/reset', 'reset'); |
+ r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings'); |
+ r.RESET_DIALOG.isNavigableDialog = true; |
+ r.TRIGGERED_RESET_DIALOG = |
+ r.ADVANCED.createChild('/triggeredResetProfileSettings'); |
+ r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true; |
+ } |
+ } |
+ |
+ // <if expr="chromeos"> |
+ // "About" is the only section in About, but we still need to create the |
+ // route in order to show the subpage on Chrome OS. |
+ r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about'); |
+ r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details'); |
+ // </if> |
+ |
+ return r; |
}; |
- // Abbreviated variable for easier definitions. |
- var r = Route; |
- |
- // Root pages. |
- r.BASIC = new Route('/'); |
- r.ADVANCED = new Route('/advanced'); |
- r.ABOUT = new Route('/help'); |
- |
- // Navigable dialogs. These are the only non-section children of root pages. |
- // These are disfavored. If we add anymore, we should add explicit support. |
- r.IMPORT_DATA = r.BASIC.createChild('/importData'); |
- r.IMPORT_DATA.isNavigableDialog = true; |
- r.SIGN_OUT = r.BASIC.createChild('/signOut'); |
- r.SIGN_OUT.isNavigableDialog = true; |
- r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData'); |
- r.CLEAR_BROWSER_DATA.isNavigableDialog = true; |
- r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings'); |
- r.RESET_DIALOG.isNavigableDialog = true; |
- r.TRIGGERED_RESET_DIALOG = |
- r.ADVANCED.createChild('/triggeredResetProfileSettings'); |
- r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true; |
- |
- // <if expr="chromeos"> |
- r.INTERNET = r.BASIC.createSection('/internet', 'internet'); |
- r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks'); |
- r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig'); |
- r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail'); |
- r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks'); |
- r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth'); |
- r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices'); |
- // </if> |
- |
- r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance'); |
- r.FONTS = r.APPEARANCE.createChild('/fonts'); |
- |
- r.DEFAULT_BROWSER = |
- r.BASIC.createSection('/defaultBrowser', 'defaultBrowser'); |
- |
- r.SEARCH = r.BASIC.createSection('/search', 'search'); |
- r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines'); |
- |
- // <if expr="chromeos"> |
- r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps'); |
- r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details'); |
- // </if> |
- |
- r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup'); |
- r.STARTUP_URLS = r.ON_STARTUP.createChild('/startupUrls'); |
- |
- r.PEOPLE = r.BASIC.createSection('/people', 'people'); |
- r.SYNC = r.PEOPLE.createChild('/syncSetup'); |
- // <if expr="not chromeos"> |
- r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile'); |
- // </if> |
- // <if expr="chromeos"> |
- r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture'); |
- r.ACCOUNTS = r.PEOPLE.createChild('/accounts'); |
- r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen'); |
- r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint'); |
- |
- r.DEVICE = r.BASIC.createSection('/device', 'device'); |
- r.POINTERS = r.DEVICE.createChild('/pointer-overlay'); |
- r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay'); |
- r.STYLUS = r.DEVICE.createChild('/stylus'); |
- r.DISPLAY = r.DEVICE.createChild('/display'); |
- r.STORAGE = r.DEVICE.createChild('/storage'); |
- r.POWER = r.DEVICE.createChild('/power'); |
- // </if> |
- |
- r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy'); |
- r.CERTIFICATES = r.PRIVACY.createChild('/certificates'); |
- |
- r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); |
- |
- if (loadTimeData.getBoolean('enableSiteSettings')) { |
- r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); |
- r.SITE_SETTINGS_SITE_DETAILS = |
- r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); |
- } else if (loadTimeData.getBoolean('enableSiteDetails')) { |
- // When there is no "All Sites", pressing 'back' from "Site Details" should |
- // return to "Content Settings". This should only occur when |kSiteSettings| |
- // is off and |kSiteDetails| is on. |
- r.SITE_SETTINGS_SITE_DETAILS = |
- r.SITE_SETTINGS.createChild('/content/siteDetails'); |
+ class Router { |
+ constructor() { |
+ /** |
+ * List of available routes. This is populated taking into account current |
+ * state (like guest mode). |
+ * @private {!SettingsRoutes} |
+ */ |
+ this.routes_ = computeAvailableRoutes(); |
+ |
+ /** |
+ * The current active route. This updated is only by settings.navigateTo |
+ * or settings.initializeRouteFromUrl. |
+ * @type {!settings.Route} |
+ */ |
+ this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC); |
+ |
+ /** |
+ * The current query parameters. This is updated only by |
+ * settings.navigateTo or settings.initializeRouteFromUrl. |
+ * @private {!URLSearchParams} |
+ */ |
+ this.currentQueryParameters_ = new URLSearchParams(); |
+ |
+ /** @private {boolean} */ |
+ this.wasLastRouteChangePopstate_ = false; |
+ |
+ /** @private {boolean}*/ |
+ this.initializeRouteFromUrlCalled_ = false; |
+ } |
+ |
+ /** @return {settings.Route} */ |
+ getRoute(routeName) { |
+ return this.routes_[routeName]; |
+ } |
+ |
+ /** @return {!SettingsRoutes} */ |
+ getRoutes() { |
+ return this.routes_; |
+ } |
+ |
+ /** |
+ * Helper function to set the current route and notify all observers. |
+ * @param {!settings.Route} route |
+ * @param {!URLSearchParams} queryParameters |
+ * @param {boolean} isPopstate |
+ */ |
+ setCurrentRoute(route, queryParameters, isPopstate) { |
+ var oldRoute = this.currentRoute; |
+ this.currentRoute = route; |
+ this.currentQueryParameters_ = queryParameters; |
+ this.wasLastRouteChangePopstate_ = isPopstate; |
+ routeObservers.forEach(function(observer) { |
+ observer.currentRouteChanged(this.currentRoute, oldRoute); |
+ }.bind(this)); |
+ } |
+ |
+ /** @return {!settings.Route} */ |
+ getCurrentRoute() { |
+ return this.currentRoute; |
+ } |
+ |
+ /** @return {!URLSearchParams} */ |
+ getQueryParameters() { |
+ return new URLSearchParams( |
+ this.currentQueryParameters_); // Defensive copy. |
+ } |
+ |
+ /** @return {boolean} */ |
+ lastRouteChangeWasPopstate() { |
+ return this.wasLastRouteChangePopstate_; |
+ } |
+ |
+ /** |
+ * @param {string} path |
+ * @return {?settings.Route} The matching canonical route, or null if none |
+ * matches. |
+ */ |
+ getRouteForPath(path) { |
+ // Allow trailing slash in paths. |
+ var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2'); |
+ |
+ // TODO(tommycli): Use Object.values once Closure compilation supports it. |
+ var matchingKey = Object.keys(this.routes_).find(function(key) { |
+ return this.routes_[key].path == canonicalPath; |
+ }.bind(this)); |
+ |
+ return !!matchingKey ? this.routes_[matchingKey] : null; |
+ } |
+ |
+ /** |
+ * Navigates to a canonical route and pushes a new history entry. |
+ * @param {!settings.Route} route |
+ * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same |
+ * URL parameters in a different order will still push to history. |
+ * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL |
+ * parameter during navigation. Defaults to false. |
+ */ |
+ navigateTo(route, opt_dynamicParameters, opt_removeSearch) { |
+ // The ADVANCED route only serves as a parent of subpages, and should not |
+ // be possible to navigate to it directly. |
+ if (route == this.routes_.ADVANCED) |
+ route = /** @type {!settings.Route} */ (this.routes_.BASIC); |
+ |
+ var params = opt_dynamicParameters || new URLSearchParams(); |
+ var removeSearch = !!opt_removeSearch; |
+ |
+ var oldSearchParam = this.getQueryParameters().get('search') || ''; |
+ var newSearchParam = params.get('search') || ''; |
+ |
+ if (!removeSearch && oldSearchParam && !newSearchParam) |
+ params.append('search', oldSearchParam); |
+ |
+ var url = route.path; |
+ var queryString = params.toString(); |
+ if (queryString) |
+ url += '?' + queryString; |
+ |
+ // History serializes the state, so we don't push the actual route object. |
+ window.history.pushState(this.currentRoute.path, '', url); |
+ this.setCurrentRoute(route, params, false); |
+ } |
+ |
+ /** |
+ * Navigates to the previous route if it has an equal or lesser depth. |
+ * If there is no previous route in history meeting those requirements, |
+ * this navigates to the immediate parent. This will never exit Settings. |
+ */ |
+ navigateToPreviousRoute() { |
+ var previousRoute = window.history.state && |
+ assert(this.getRouteForPath( |
+ /** @type {string} */ (window.history.state))); |
+ |
+ if (previousRoute && previousRoute.depth <= this.currentRoute.depth) |
+ window.history.back(); |
+ else |
+ this.navigateTo( |
+ this.currentRoute.parent || |
+ /** @type {!settings.Route} */ (this.routes_.BASIC)); |
+ } |
+ |
+ /** |
+ * Initialize the route and query params from the URL. |
+ */ |
+ initializeRouteFromUrl() { |
+ assert(!this.initializeRouteFromUrlCalled_); |
+ this.initializeRouteFromUrlCalled_ = true; |
+ |
+ var route = this.getRouteForPath(window.location.pathname); |
+ // Never allow direct navigation to ADVANCED. |
+ if (route && route != this.routes_.ADVANCED) { |
+ this.currentRoute = route; |
+ this.currentQueryParameters_ = |
+ new URLSearchParams(window.location.search); |
+ } else { |
+ window.history.replaceState(undefined, '', this.routes_.BASIC.path); |
+ } |
+ } |
+ |
+ resetRouteForTesting() { |
+ this.initializeRouteFromUrlCalled_ = false; |
+ this.wasLastRouteChangePopstate_ = false; |
+ this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC); |
+ this.currentQueryParameters_ = new URLSearchParams(); |
+ } |
} |
- r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers'); |
- |
- // TODO(tommycli): Find a way to refactor these repetitive category routes. |
- r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads'); |
- r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS = |
- r.SITE_SETTINGS.createChild('automaticDownloads'); |
- r.SITE_SETTINGS_BACKGROUND_SYNC = |
- r.SITE_SETTINGS.createChild('backgroundSync'); |
- r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera'); |
- r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies'); |
- r.SITE_SETTINGS_DATA_DETAILS = |
- r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail'); |
- r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images'); |
- r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript'); |
- r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location'); |
- r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone'); |
- r.SITE_SETTINGS_NOTIFICATIONS = r.SITE_SETTINGS.createChild('notifications'); |
- r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash'); |
- r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups'); |
- r.SITE_SETTINGS_UNSANDBOXED_PLUGINS = |
- r.SITE_SETTINGS.createChild('unsandboxedPlugins'); |
- r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices'); |
- r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices'); |
- r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels'); |
- r.SITE_SETTINGS_PDF_DOCUMENTS = r.SITE_SETTINGS.createChild('pdfDocuments'); |
- r.SITE_SETTINGS_PROTECTED_CONTENT = |
- r.SITE_SETTINGS.createChild('protectedContent'); |
- |
- // <if expr="chromeos"> |
- r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime'); |
- // </if> |
- |
- r.PASSWORDS = |
- r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms'); |
- r.AUTOFILL = r.PASSWORDS.createChild('/autofill'); |
- r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords'); |
- |
- r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages'); |
- // <if expr="chromeos"> |
- r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods'); |
- // </if> |
- // <if expr="not is_macosx"> |
- r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary'); |
- // </if> |
- |
- r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads'); |
- |
- r.PRINTING = r.ADVANCED.createSection('/printing', 'printing'); |
- r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters'); |
- // <if expr="chromeos"> |
- r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters'); |
- r.CUPS_PRINTER_DETAIL = r.CUPS_PRINTERS.createChild('/cupsPrinterDetails'); |
- // </if> |
- |
- r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y'); |
- // <if expr="chromeos"> |
- r.MANAGE_ACCESSIBILITY = r.ACCESSIBILITY.createChild('/manageAccessibility'); |
- // </if> |
- |
- r.SYSTEM = r.ADVANCED.createSection('/system', 'system'); |
- r.RESET = r.ADVANCED.createSection('/reset', 'reset'); |
- |
- // <if expr="chromeos"> |
- // "About" is the only section in About, but we still need to create the route |
- // in order to show the subpage on Chrome OS. |
- r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about'); |
- r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details'); |
- // </if> |
+ var routerInstance = new Router(); |
var routeObservers = new Set(); |
@@ -257,7 +554,7 @@ cr.define('settings', function() { |
// Emulating Polymer data bindings, the observer is called when the |
// element starts observing the route. |
- this.currentRouteChanged(currentRoute, undefined); |
+ this.currentRouteChanged(routerInstance.currentRoute, undefined); |
}, |
/** @override */ |
@@ -282,155 +579,40 @@ cr.define('settings', function() { |
*/ |
var CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/; |
- /** |
- * @param {string} path |
- * @return {?settings.Route} The matching canonical route, or null if none |
- * matches. |
- */ |
- var getRouteForPath = function(path) { |
- // Allow trailing slash in paths. |
- var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2'); |
- |
- // TODO(tommycli): Use Object.values once Closure compilation supports it. |
- var matchingKey = Object.keys(Route).find(function(key) { |
- return Route[key].path == canonicalPath; |
- }); |
- |
- return !!matchingKey ? Route[matchingKey] : null; |
- }; |
- |
- /** |
- * The current active route. This updated is only by settings.navigateTo or |
- * settings.initializeRouteFromUrl. |
- * @private {!settings.Route} |
- */ |
- var currentRoute = Route.BASIC; |
- |
- /** |
- * The current query parameters. This is updated only by settings.navigateTo |
- * or settings.initializeRouteFromUrl. |
- * @private {!URLSearchParams} |
- */ |
- var currentQueryParameters = new URLSearchParams(); |
- |
- /** @private {boolean} */ |
- var wasLastRouteChangePopstate = false; |
- |
- /** @private */ |
- var initializeRouteFromUrlCalled = false; |
- |
- /** |
- * Initialize the route and query params from the URL. |
- */ |
- var initializeRouteFromUrl = function() { |
- assert(!initializeRouteFromUrlCalled); |
- initializeRouteFromUrlCalled = true; |
- |
- var route = getRouteForPath(window.location.pathname); |
- // Never allow direct navigation to ADVANCED. |
- if (route && route != Route.ADVANCED) { |
- currentRoute = route; |
- currentQueryParameters = new URLSearchParams(window.location.search); |
- } else { |
- window.history.replaceState(undefined, '', Route.BASIC.path); |
- } |
- }; |
- |
- function resetRouteForTesting() { |
- initializeRouteFromUrlCalled = false; |
- wasLastRouteChangePopstate = false; |
- currentRoute = Route.BASIC; |
- currentQueryParameters = new URLSearchParams(); |
- } |
- |
- /** |
- * Helper function to set the current route and notify all observers. |
- * @param {!settings.Route} route |
- * @param {!URLSearchParams} queryParameters |
- * @param {boolean} isPopstate |
- */ |
- var setCurrentRoute = function(route, queryParameters, isPopstate) { |
- var oldRoute = currentRoute; |
- currentRoute = route; |
- currentQueryParameters = queryParameters; |
- wasLastRouteChangePopstate = isPopstate; |
- routeObservers.forEach(function(observer) { |
- observer.currentRouteChanged(currentRoute, oldRoute); |
- }); |
- }; |
- |
- /** @return {!settings.Route} */ |
- var getCurrentRoute = function() { |
- return currentRoute; |
- }; |
- |
- /** @return {!URLSearchParams} */ |
- var getQueryParameters = function() { |
- return new URLSearchParams(currentQueryParameters); // Defensive copy. |
- }; |
- |
- /** @return {boolean} */ |
- var lastRouteChangeWasPopstate = function() { |
- return wasLastRouteChangePopstate; |
- }; |
- |
- /** |
- * Navigates to a canonical route and pushes a new history entry. |
- * @param {!settings.Route} route |
- * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same |
- * URL parameters in a different order will still push to history. |
- * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL |
- * parameter during navigation. Defaults to false. |
- */ |
- var navigateTo = function(route, opt_dynamicParameters, opt_removeSearch) { |
- // The ADVANCED route only serves as a parent of subpages, and should not |
- // be possible to navigate to it directly. |
- if (route == settings.Route.ADVANCED) |
- route = settings.Route.BASIC; |
- |
- var params = opt_dynamicParameters || new URLSearchParams(); |
- var removeSearch = !!opt_removeSearch; |
- |
- var oldSearchParam = getQueryParameters().get('search') || ''; |
- var newSearchParam = params.get('search') || ''; |
- |
- if (!removeSearch && oldSearchParam && !newSearchParam) |
- params.append('search', oldSearchParam); |
- |
- var url = route.path; |
- var queryString = params.toString(); |
- if (queryString) |
- url += '?' + queryString; |
- |
- // History serializes the state, so we don't push the actual route object. |
- window.history.pushState(currentRoute.path, '', url); |
- setCurrentRoute(route, params, false); |
- }; |
- |
- /** |
- * Navigates to the previous route if it has an equal or lesser depth. |
- * If there is no previous route in history meeting those requirements, |
- * this navigates to the immediate parent. This will never exit Settings. |
- */ |
- var navigateToPreviousRoute = function() { |
- var previousRoute = window.history.state && |
- assert(getRouteForPath(/** @type {string} */ (window.history.state))); |
- |
- if (previousRoute && previousRoute.depth <= currentRoute.depth) |
- window.history.back(); |
- else |
- navigateTo(currentRoute.parent || Route.BASIC); |
- }; |
- |
window.addEventListener('popstate', function(event) { |
// On pop state, do not push the state onto the window.history again. |
- setCurrentRoute( |
- getRouteForPath(window.location.pathname) || Route.BASIC, |
+ routerInstance.setCurrentRoute( |
+ /** @type {!settings.Route} */ ( |
+ routerInstance.getRouteForPath(window.location.pathname) || |
+ routerInstance.getRoutes().BASIC), |
new URLSearchParams(window.location.search), true); |
}); |
+ // TODO(scottchen): Change to 'get routes() {}' in export when we fix a bug in |
+ // ChromePass that limits the syntax of what can be returned from cr.define(). |
+ var routes = routerInstance.getRoutes(); |
+ |
+ // TODO(scottchen): Stop exposing all those methods directly on settings.*, |
+ // and instead update all clients to use the singleton instance directly |
+ var getCurrentRoute = routerInstance.getCurrentRoute.bind(routerInstance); |
+ var getRouteForPath = routerInstance.getRouteForPath.bind(routerInstance); |
+ var initializeRouteFromUrl = |
+ routerInstance.initializeRouteFromUrl.bind(routerInstance); |
+ var resetRouteForTesting = |
+ routerInstance.resetRouteForTesting.bind(routerInstance); |
+ var getQueryParameters = |
+ routerInstance.getQueryParameters.bind(routerInstance); |
+ var lastRouteChangeWasPopstate = |
+ routerInstance.lastRouteChangeWasPopstate.bind(routerInstance); |
+ var navigateTo = routerInstance.navigateTo.bind(routerInstance); |
+ var navigateToPreviousRoute = |
+ routerInstance.navigateToPreviousRoute.bind(routerInstance); |
+ |
return { |
- Route: Route, |
+ Route: Route, // The Route class definition. |
+ Router: Router, // The Router class definition. |
+ router: routerInstance, // the singleton. |
+ routes: routes, |
RouteObserverBehavior: RouteObserverBehavior, |
getRouteForPath: getRouteForPath, |
initializeRouteFromUrl: initializeRouteFromUrl, |