OLD | NEW |
1 <!-- | 1 <!-- |
2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | 2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | 3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | 4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | 5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
6 Code distributed by Google as part of the polymer project is also | 6 Code distributed by Google as part of the polymer project is also |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
8 --> | 8 --> |
9 <link rel="import" href="../observe-js/observe-js.html"> | 9 <link rel="import" href="emitter.html"> |
| 10 <link rel="import" href="params.html"> |
10 | 11 |
11 <script> | 12 <script> |
12 (function(scope) { | 13 (function(scope) { |
13 var MoreRouting = scope.MoreRouting = scope.MoreRouting || {}; | 14 var MoreRouting = scope.MoreRouting = scope.MoreRouting || {}; |
14 MoreRouting.Route = Route; | 15 MoreRouting.Route = Route; |
15 | 16 |
16 // Note that this can differ from the part separator defined by the driver. The | 17 // Note that this can differ from the part separator defined by the driver. The |
17 // driver's separator is used when parsing/generating URLs given to the client, | 18 // driver's separator is used when parsing/generating URLs given to the client, |
18 // whereas this one is for route definitions. | 19 // whereas this one is for route definitions. |
19 var PART_SEPARATOR = '/'; | 20 var PART_SEPARATOR = '/'; |
20 var PARAM_SENTINEL = ':'; | 21 var PARAM_SENTINEL = ':'; |
21 var SEPARATOR_CLEANER = /\/\/+/g; | 22 var SEPARATOR_CLEANER = /\/\/+/g; |
22 | 23 |
23 /** | 24 /** |
24 * TODO(nevir): Docs. | 25 * TODO(nevir): Docs. |
25 */ | 26 */ |
26 function Route(path, parent) { | 27 function Route(path, parent) { |
| 28 // For `MoreRouting.Emitter`; Emits changes for `active`. |
| 29 this.__listeners = []; |
| 30 |
27 this.path = path; | 31 this.path = path; |
28 this.parent = parent; | 32 this.parent = parent; |
29 this.fullPath = path; | 33 this.fullPath = path; |
30 this.compiled = this._compile(this.path); | 34 this.compiled = this._compile(this.path); |
31 this.active = false; | 35 this.active = false; |
32 this.driver = null; | 36 this.driver = null; |
33 | 37 |
| 38 var params = MoreRouting.Params(namedParams(this.compiled), this.parent && thi
s.parent.params); |
| 39 params.__subscribe(this._navigateToParams.bind(this)); |
| 40 Object.defineProperty(this, 'params', { |
| 41 get: function() { return params; }, |
| 42 set: function() { throw new Error('Route#params cannot be overwritten'); }, |
| 43 }); |
| 44 |
34 this.parts = []; | 45 this.parts = []; |
35 this.children = []; | 46 this.children = []; |
36 | 47 |
37 // Param values matching the current URL, or an empty object if not `active`. | 48 // Param values matching the current URL, or an empty object if not `active`. |
38 // | 49 // |
39 // To make data "binding" easy, `Route` guarantees that `params` will always | 50 // To make data "binding" easy, `Route` guarantees that `params` will always |
40 // be the same object; just make a reference to it. | 51 // be the same object; just make a reference to it. |
41 if (this.parent) { | 52 if (this.parent) { |
42 this.params = Object.create(this.parent.params); | |
43 this.parent.children.push(this); | 53 this.parent.children.push(this); |
44 this.fullPath = this.parent.fullPath + this.fullPath; | 54 this.fullPath = this.parent.fullPath + this.fullPath; |
45 this.depth = this.parent.depth + this.compiled.length; | 55 this.depth = this.parent.depth + this.compiled.length; |
46 this.numParams = this.parent.numParams + countParams(this.compiled); | 56 this.numParams = this.parent.numParams + countParams(this.compiled); |
47 } else { | 57 } else { |
48 this.params = {}; | |
49 this.depth = this.compiled.length; | 58 this.depth = this.compiled.length; |
50 this.numParams = countParams(this.compiled); | 59 this.numParams = countParams(this.compiled); |
51 } | 60 } |
| 61 } |
| 62 Route.prototype = Object.create(MoreRouting.Emitter); |
52 | 63 |
53 this._paramObserver = new ObjectObserver(this.params); | 64 Object.defineProperty(Route.prototype, 'active', { |
54 this._paramObserver.open(this._navigateToParams.bind(this)); | 65 get: function() { |
55 } | 66 return this._active; |
| 67 }, |
| 68 set: function(value) { |
| 69 if (value !== this._active); |
| 70 this._active = value; |
| 71 this.__notify('active', value); |
| 72 }, |
| 73 }); |
56 | 74 |
57 Route.isPath = function isPath(pathOrName) { | 75 Route.isPath = function isPath(pathOrName) { |
58 return pathOrName.indexOf(PART_SEPARATOR) === 0; | 76 return pathOrName.indexOf(PART_SEPARATOR) === 0; |
59 }; | 77 }; |
60 | 78 |
61 Route.joinPath = function joinPath(paths) { | 79 Route.joinPath = function joinPath(paths) { |
62 var joined = Array.prototype.join.call(arguments, PART_SEPARATOR); | 80 var joined = Array.prototype.join.call(arguments, PART_SEPARATOR); |
63 joined = joined.replace(SEPARATOR_CLEANER, PART_SEPARATOR); | 81 joined = joined.replace(SEPARATOR_CLEANER, PART_SEPARATOR); |
64 | 82 |
65 var minLength = joined.length - PART_SEPARATOR.length; | 83 var minLength = joined.length - PART_SEPARATOR.length; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 | 136 |
119 /** | 137 /** |
120 * Called by the driver whenever it has detected a change to the URL. | 138 * Called by the driver whenever it has detected a change to the URL. |
121 * | 139 * |
122 * @param {Array.<String>|null} parts The parts of the URL, or null if the | 140 * @param {Array.<String>|null} parts The parts of the URL, or null if the |
123 * route should be disabled. | 141 * route should be disabled. |
124 */ | 142 */ |
125 Route.prototype.processPathParts = function processPathParts(parts) { | 143 Route.prototype.processPathParts = function processPathParts(parts) { |
126 this.parts = parts; | 144 this.parts = parts; |
127 this.active = this.matchesPathParts(parts); | 145 this.active = this.matchesPathParts(parts); |
| 146 |
| 147 // We don't want to notify of these changes; they'd be no-op noise. |
| 148 this.params.__silent = true; |
| 149 |
128 if (this.active) { | 150 if (this.active) { |
129 var keys = Object.keys(this.params); | 151 var keys = Object.keys(this.params); |
130 for (var i = 0; i < keys.length; i++) { | 152 for (var i = 0; i < keys.length; i++) { |
131 delete this.params[keys[i]]; | 153 delete this.params[keys[i]]; |
132 } | 154 } |
133 for (var i = 0, config; config = this.compiled[i]; i++) { | 155 for (var i = 0, config; config = this.compiled[i]; i++) { |
134 if (config.type === 'param') { | 156 if (config.type === 'param') { |
135 this.params[config.name] = parts[i]; | 157 this.params[config.name] = parts[i]; |
136 } | 158 } |
137 } | 159 } |
138 } else { | 160 } else { |
139 for (key in this.params) { | 161 for (key in this.params) { |
140 this.params[key] = undefined; | 162 this.params[key] = undefined; |
141 } | 163 } |
142 } | 164 } |
143 this._paramObserver.discardChanges(); | 165 |
| 166 delete this.params.__silent; |
144 }; | 167 }; |
145 | 168 |
146 Route.prototype.matchesPathParts = function matchesPathParts(parts) { | 169 Route.prototype.matchesPathParts = function matchesPathParts(parts) { |
147 if (!parts) return false; | 170 if (!parts) return false; |
148 if (parts.length < this.compiled.length) return false; | 171 if (parts.length < this.compiled.length) return false; |
149 for (var i = 0, config; config = this.compiled[i]; i++) { | 172 for (var i = 0, config; config = this.compiled[i]; i++) { |
150 if (config.type === 'static' && parts[i] !== config.part) { | 173 if (config.type === 'static' && parts[i] !== config.part) { |
151 return false; | 174 return false; |
152 } | 175 } |
153 } | 176 } |
(...skipping 29 matching lines...) Expand all Loading... |
183 if (!parts) return; | 206 if (!parts) return; |
184 this.driver.navigateToParts(parts); | 207 this.driver.navigateToParts(parts); |
185 }; | 208 }; |
186 | 209 |
187 function countParams(compiled) { | 210 function countParams(compiled) { |
188 return compiled.reduce(function(count, part) { | 211 return compiled.reduce(function(count, part) { |
189 return count + (part.type === 'param' ? 1 : 0); | 212 return count + (part.type === 'param' ? 1 : 0); |
190 }, 0); | 213 }, 0); |
191 } | 214 } |
192 | 215 |
| 216 function namedParams(compiled) { |
| 217 var result = []; |
| 218 compiled.forEach(function(part) { |
| 219 if (part.type === 'static') return; |
| 220 result.push(part.name); |
| 221 }); |
| 222 return result; |
| 223 } |
| 224 |
193 })(window); | 225 })(window); |
194 </script> | 226 </script> |
OLD | NEW |