Add ICU message format support
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / more-routing / more-route-selection-extracted.js
blob9e76752a27a17c871c3ba548f1c6e798dc5e2a60
3   Polymer({
5     is: 'more-route-selection',
7     behaviors: [
8       MoreRouting.ContextAware,
9     ],
11     properties: {
13       /**
14        * Routes to select from, as either a path expression or route name.
15        *
16        * You can either specify routes via this attribute, or as child nodes
17        * to this element, but not both.
18        *
19        * @type {String|Array<string|MoreRouting.Route>}
20        */
21       routes: {
22         type:     String,
23         observer: '_routesChanged',
24       },
26       /**
27        * The selected `MoreRouting.Route` object, or `null`.
28        *
29        * @type {MoreRouting.Route}
30        */
31       selectedRoute: {
32         type:     Object,
33         value:    null,
34         readOnly: true,
35         notify:   true,
36       },
38       /**
39        * The index of the selected route (relative to `routes`). -1 when there
40        * is no active route.
41        */
42       selectedIndex: {
43         type:     Number,
44         value:    -1,
45         readOnly: true,
46         notify:   true,
47       },
49       /**
50        * The _full_ path expression of the selected route, or `null`.
51        */
52       selectedPath: {
53         type:     String,
54         readOnly: true,
55         notify:   true,
56       },
58       /**
59        * The params of the selected route, or an empty object if no route.
60        */
61       selectedParams: {
62         type:     Object,
63         readOnly: true,
64         notify:   true,
65       },
67     },
69     /**
70      * @event more-route-change fires when a new route is selected.
71      * @detail {{
72      *   newRoute:  MoreRouting.Route, oldRoute: MoreRouting.Route,
73      *   newIndex:  number,  oldIndex:  number,
74      *   newPath:   ?string, oldPath:   ?string,
75      *   newParams: Object,  oldParams: Object,
76      * }}
77      */
79     routingReady: function() {
80       this._routesChanged();
81     },
83     _routesChanged: function() {
84       if (!this.routingIsReady) return;
85       var routes = this.routes || [];
86       if (typeof routes === 'string') {
87         routes = routes.split(/\s+/);
88       }
89       this._routeInfo = this._sortIndexes(routes.map(function(route, index) {
90         return {
91           model: MoreRouting.getRoute(route, this.parentRoute),
92           index: index,
93         };
94       }.bind(this)));
96       this._observeRoutes();
97       this._evaluate();
98     },
100     /**
101      * Tracks changes to the routes.
102      */
103     _observeRoutes: function() {
104       if (this._routeListeners) {
105         for (var i = 0, listener; listener = this._routeListeners[i]; i++) {
106           listener.close();
107         }
108       }
110       this._routeListeners = this._routeInfo.map(function(routeInfo) {
111         return routeInfo.model.__subscribe(this._evaluate.bind(this));
112       }.bind(this));
113     },
115     _evaluate: function() {
116       var newIndex = -1;
117       var newRoute = null;
118       var oldIndex = this.selectedIndex;
120       for (var i = 0, routeInfo; routeInfo = this._routeInfo[i]; i++) {
121         if (routeInfo.model && routeInfo.model.active) {
122           newIndex = routeInfo.index;
123           newRoute = routeInfo.model;
124           break;
125         }
126       }
127       if (newIndex === oldIndex) return;
129       var oldRoute  = this.selectedRoute;
130       var oldPath   = this.selectedPath;
131       var oldParams = this.selectedParams;
133       var newPath   = newRoute ? newRoute.fullPath : null;
134       var newParams = newRoute ? newRoute.params   : {};
136       this._setSelectedRoute(newRoute);
137       this._setSelectedIndex(newIndex);
138       this._setSelectedPath(newPath);
139       this._setSelectedParams(newParams);
141       this.fire('more-route-change', {
142         newRoute:  newRoute,  oldRoute:  oldRoute,
143         newIndex:  newIndex,  oldIndex:  oldIndex,
144         newPath:   newPath,   oldPath:   oldPath,
145         newParams: newParams, oldParams: oldParams,
146       });
147     },
148     /**
149      * We want the most specific routes to match first, so we must create a
150      * mapping of indexes within `routes` that map
151      */
152     _sortIndexes: function(routeInfo) {
153       return routeInfo.sort(function(a, b) {
154         if (!a.model) {
155           return 1;
156         } else if (!b.model) {
157           return -1;
158         // Routes with more path parts are most definitely more specific.
159         } else if (a.model.depth < b.model.depth) {
160           return 1;
161         } if (a.model.depth > b.model.depth) {
162           return -1;
163         } else {
165           // Also, routes with fewer params are more specific. For example
166           // `/users/foo` is more specific than `/users/:id`.
167           if (a.model.numParams < b.model.numParams) {
168             return -1;
169           } else if (a.model.numParams > b.model.numParams) {
170             return 1;
171           } else {
172             // Equally specific; we fall back to the default (and hopefully
173             // stable) sort order.
174             return 0;
175           }
176         }
177       });
178     },
180   });