OLD | NEW |
| (Empty) |
1 | |
2 | |
3 Polymer({ | |
4 | |
5 is: 'more-route-selection', | |
6 | |
7 behaviors: [ | |
8 MoreRouting.ContextAware, | |
9 ], | |
10 | |
11 properties: { | |
12 | |
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 }, | |
25 | |
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 }, | |
37 | |
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 }, | |
48 | |
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 }, | |
57 | |
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 }, | |
66 | |
67 }, | |
68 | |
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 */ | |
78 | |
79 routingReady: function() { | |
80 this._routesChanged(); | |
81 }, | |
82 | |
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))); | |
95 | |
96 this._observeRoutes(); | |
97 this._evaluate(); | |
98 }, | |
99 | |
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 } | |
109 | |
110 this._routeListeners = this._routeInfo.map(function(routeInfo) { | |
111 return routeInfo.model.__subscribe(this._evaluate.bind(this)); | |
112 }.bind(this)); | |
113 }, | |
114 | |
115 _evaluate: function() { | |
116 var newIndex = -1; | |
117 var newRoute = null; | |
118 var oldIndex = this.selectedIndex; | |
119 | |
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; | |
128 | |
129 var oldRoute = this.selectedRoute; | |
130 var oldPath = this.selectedPath; | |
131 var oldParams = this.selectedParams; | |
132 | |
133 var newPath = newRoute ? newRoute.fullPath : null; | |
134 var newParams = newRoute ? newRoute.params : {}; | |
135 | |
136 this._setSelectedRoute(newRoute); | |
137 this._setSelectedIndex(newIndex); | |
138 this._setSelectedPath(newPath); | |
139 this._setSelectedParams(newParams); | |
140 | |
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 { | |
164 | |
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 }, | |
179 | |
180 }); | |
OLD | NEW |