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

Side by Side Diff: bower_components/app-router/src/app-router.js

Issue 786953007: npm_modules: Fork bower_components into Polymer 0.4.0 and 0.5.0 versions (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Created 5 years, 11 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
« no previous file with comments | « bower_components/app-router/src/app-router.html ('k') | bower_components/chai/.bower.json » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 (function(window, document) {
2 // <app-route path="/path" [import="/page/cust-el.html"] [element="cust-el"] [ template]></app-route>
3 document.registerElement('app-route', {
4 prototype: Object.create(HTMLElement.prototype)
5 });
6
7 // <active-route></active-route> holds the active route's content when `shadow ` is not enabled
8 document.registerElement('active-route', {
9 prototype: Object.create(HTMLElement.prototype)
10 });
11
12 // <app-router [shadow] [trailingSlash="strict|ignore"] [init="auto|manual"]>< /app-router>
13 var router = Object.create(HTMLElement.prototype);
14
15 var importedURIs = {};
16 var isIE = 'ActiveXObject' in window;
17
18 // fire(type, detail, node) - Fire a new CustomEvent(type, detail) on the node
19 //
20 // listen with document.querySelector('app-router').addEventListener(type, fun ction(event) {
21 // event.detail, event.preventDefault()
22 // })
23 function fire(type, detail, node) {
24 // create a CustomEvent the old way for IE9/10 support
25 var event = document.createEvent('CustomEvent');
26
27 // initCustomEvent(type, bubbles, cancelable, detail)
28 event.initCustomEvent(type, false, true, detail);
29
30 // returns false when event.preventDefault() is called, true otherwise
31 return node.dispatchEvent(event);
32 }
33
34 // Initial set up when attached
35 router.attachedCallback = function() {
36 if(this.getAttribute('init') !== 'manual') {
37 this.init();
38 }
39 };
40
41 // Initialize the router
42 router.init = function() {
43 if (this.isInitialized) {
44 return;
45 }
46 this.isInitialized = true;
47 this.activeRoute = document.createElement('app-route');
48
49 // Listen for URL change events.
50 this.stateChangeHandler = this.go.bind(this);
51 window.addEventListener('popstate', this.stateChangeHandler, false);
52 if (isIE) {
53 // IE is truly special! A hashchange is supposed to trigger a popstate, ma king popstate the only
54 // even you should need to listen to. Not the case in IE! Make another eve nt listener for it!
55 window.addEventListener('hashchange', this.stateChangeHandler, false);
56 }
57
58 // set up an <active-route> element for the active route's content
59 this.activeRouteContent = document.createElement('active-route');
60 this.appendChild(this.activeRouteContent);
61 if (this.hasAttribute('shadow')) {
62 this.activeRouteContent = this.activeRouteContent.createShadowRoot();
63 }
64
65 // load the web component for the active route
66 this.go();
67 };
68
69 // clean up global event listeners
70 router.detachedCallback = function() {
71 window.removeEventListener('popstate', this.stateChangeHandler, false);
72 if (isIE) {
73 window.removeEventListener('hashchange', this.stateChangeHandler, false);
74 }
75 };
76
77 // go() - Find the first <app-route> that matches the current URL and change t he active route
78 router.go = function() {
79 var urlPath = this.parseUrlPath(window.location.href);
80 var eventDetail = {
81 path: urlPath
82 };
83 if (!fire('state-change', eventDetail, this)) {
84 return;
85 }
86 var routes = this.querySelectorAll('app-route');
87 for (var i = 0; i < routes.length; i++) {
88 if (this.testRoute(routes[i].getAttribute('path'), urlPath, this.getAttrib ute('trailingSlash'), routes[i].hasAttribute('regex'))) {
89 this.activateRoute(routes[i], urlPath);
90 return;
91 }
92 }
93 fire('not-found', eventDetail, this);
94 };
95
96 // activateRoute(route, urlPath) - Activate the route
97 router.activateRoute = function(route, urlPath) {
98 var eventDetail = {
99 path: urlPath,
100 route: route,
101 oldRoute: this.activeRoute
102 };
103 if (!fire('activate-route-start', eventDetail, this)) {
104 return;
105 }
106 if (!fire('activate-route-start', eventDetail, route)) {
107 return;
108 }
109
110 this.activeRoute.removeAttribute('active');
111 route.setAttribute('active', 'active');
112 this.activeRoute = route;
113
114 var importUri = route.getAttribute('import');
115 var routePath = route.getAttribute('path');
116 var isRegExp = route.hasAttribute('regex');
117 var elementName = route.getAttribute('element');
118 var isTemplate = route.hasAttribute('template');
119 var isElement = !isTemplate;
120
121 // import custom element
122 if (isElement && importUri) {
123 this.importAndActivateCustomElement(importUri, elementName, routePath, url Path, isRegExp, eventDetail);
124 }
125 // pre-loaded custom element
126 else if (isElement && !importUri && elementName) {
127 this.activateCustomElement(elementName, routePath, urlPath, isRegExp, even tDetail);
128 }
129 // import template
130 else if (isTemplate && importUri) {
131 this.importAndActivateTemplate(importUri, route, eventDetail);
132 }
133 // pre-loaded template
134 else if (isTemplate && !importUri) {
135 this.activateTemplate(route, eventDetail);
136 }
137 };
138
139 // importAndActivateCustomElement(importUri, elementName, routePath, urlPath, isRegExp, eventDetail) - Import the custom element then replace the active route
140 // with a new instance of the custom element
141 router.importAndActivateCustomElement = function(importUri, elementName, route Path, urlPath, isRegExp, eventDetail) {
142 if (!importedURIs.hasOwnProperty(importUri)) {
143 importedURIs[importUri] = true;
144 var elementLink = document.createElement('link');
145 elementLink.setAttribute('rel', 'import');
146 elementLink.setAttribute('href', importUri);
147 document.head.appendChild(elementLink);
148 }
149 this.activateCustomElement(elementName || importUri.split('/').slice(-1)[0]. replace('.html', ''), routePath, urlPath, isRegExp, eventDetail);
150 };
151
152 // activateCustomElement(elementName, routePath, urlPath, isRegExp, eventDetai l) - Replace the active route with a new instance of the custom element
153 router.activateCustomElement = function(elementName, routePath, urlPath, isReg Exp, eventDetail) {
154 var resourceEl = document.createElement(elementName);
155 var routeArgs = this.routeArguments(routePath, urlPath, window.location.href , isRegExp);
156 for (var arg in routeArgs) {
157 if (routeArgs.hasOwnProperty(arg)) {
158 resourceEl[arg] = routeArgs[arg];
159 }
160 }
161 this.activeElement(resourceEl, eventDetail);
162 };
163
164 // importAndActivateTemplate(importUri, route, eventDetail) - Import the templ ate then replace the active route with a clone of the template's content
165 router.importAndActivateTemplate = function(importUri, route, eventDetail) {
166 if (importedURIs.hasOwnProperty(importUri)) {
167 // previously imported. this is an async operation and may not be complete yet.
168 var previousLink = document.querySelector('link[href="' + importUri + '"]' );
169 if (previousLink.import) {
170 // the import is complete
171 this.activeElement(document.importNode(previousLink.import.querySelector ('template').content, true), eventDetail);
172 } else {
173 // wait for `onload`
174 previousLink.onload = function() {
175 if (route.hasAttribute('active')) {
176 this.activeElement(document.importNode(previousLink.import.querySele ctor('template').content, true), eventDetail);
177 }
178 }.bind(this);
179 }
180 } else {
181 // template hasn't been loaded yet
182 importedURIs[importUri] = true;
183 var templateLink = document.createElement('link');
184 templateLink.setAttribute('rel', 'import');
185 templateLink.setAttribute('href', importUri);
186 templateLink.onload = function() {
187 if (route.hasAttribute('active')) {
188 this.activeElement(document.importNode(templateLink.import.querySelect or('template').content, true), eventDetail);
189 }
190 }.bind(this);
191 document.head.appendChild(templateLink);
192 }
193 };
194
195 // activateTemplate(route, eventDetail) - Replace the active route with a clon e of the template's content
196 router.activateTemplate = function(route, eventDetail) {
197 var clone = document.importNode(route.querySelector('template').content, tru e);
198 this.activeElement(clone, eventDetail);
199 };
200
201 // activeElement(element, eventDetail) - Replace the active route's content wi th the new element
202 router.activeElement = function(element, eventDetail) {
203 while (this.activeRouteContent.firstChild) {
204 this.activeRouteContent.removeChild(this.activeRouteContent.firstChild);
205 }
206 this.activeRouteContent.appendChild(element);
207 fire('activate-route-end', eventDetail, this);
208 fire('activate-route-end', eventDetail, eventDetail.route);
209 };
210
211 // urlPath(url) - Parses the url to get the path
212 //
213 // This will return the hash path if it exists or return the real path if no h ash path exists.
214 //
215 // Example URL = 'http://domain.com/other/path?queryParam3=false#/example/path ?queryParam1=true&queryParam2=example%20string'
216 // path = '/example/path'
217 //
218 // Note: The URL must contain the protocol like 'http(s)://'
219 router.parseUrlPath = function(url) {
220 // The relative URI is everything after the third slash including the third slash
221 // Example relativeUri = '/other/path?queryParam3=false#/example/path?queryP aram1=true&queryParam2=example%20string'
222 var splitUrl = url.split('/');
223 var relativeUri = '/' + splitUrl.splice(3, splitUrl.length - 3).join('/');
224
225 // The path is everything in the relative URI up to the first ? or #
226 // Example path = '/other/path'
227 var path = relativeUri.split(/[\?#]/)[0];
228
229 // The hash is everything from the first # up to the the search starting wit h ? if it exists
230 // Example hash = '#/example/path'
231 var hashIndex = relativeUri.indexOf('#');
232 if (hashIndex !== -1) {
233 var hash = relativeUri.substring(hashIndex).split('?')[0];
234 if (hash.substring(0, 2) === '#/') {
235 // Hash path
236 path = hash.substring(1);
237 } else if (hash.substring(0, 3) === '#!/') {
238 // Hashbang path
239 path = hash.substring(2);
240 }
241 }
242
243 return path;
244 };
245
246 // router.testRoute(routePath, urlPath, trailingSlashOption, isRegExp) - Test if the route's path matches the URL's path
247 //
248 // Example routePath: '/example/*'
249 // Example urlPath = '/example/path'
250 router.testRoute = function(routePath, urlPath, trailingSlashOption, isRegExp) {
251 // This algorithm tries to fail or succeed as quickly as possible for the mo st common cases.
252
253 // handle trailing slashes (options: strict (default), ignore)
254 if (trailingSlashOption === 'ignore') {
255 // remove trailing / from the route path and URL path
256 if(urlPath.slice(-1) === '/') {
257 urlPath = urlPath.slice(0, -1);
258 }
259 if(routePath.slice(-1) === '/' && !isRegExp) {
260 routePath = routePath.slice(0, -1);
261 }
262 }
263
264 if (isRegExp) {
265 // parse HTML attribute path="/^\/\w+\/\d+$/i" to a regular expression `ne w RegExp('^\/\w+\/\d+$', 'i')`
266 // note that 'i' is the only valid option. global 'g', multiline 'm', and sticky 'y' won't be valid matchers for a path.
267 if (routePath.charAt(0) !== '/') {
268 // must start with a slash
269 return false;
270 }
271 routePath = routePath.slice(1);
272 var options = '';
273 if (routePath.slice(-1) === '/') {
274 routePath = routePath.slice(0, -1);
275 }
276 else if (routePath.slice(-2) === '/i') {
277 routePath = routePath.slice(0, -2);
278 options = 'i';
279 }
280 else {
281 // must end with a slash followed by zero or more options
282 return false;
283 }
284 return new RegExp(routePath, options).test(urlPath);
285 }
286
287 // If the urlPath is an exact match or '*' then the route is a match
288 if (routePath === urlPath || routePath === '*') {
289 return true;
290 }
291
292 // Look for wildcards
293 if (routePath.indexOf('*') === -1 && routePath.indexOf(':') === -1) {
294 // No wildcards and we already made sure it wasn't an exact match so the t est fails
295 return false;
296 }
297
298 // Example urlPathSegments = ['', example', 'path']
299 var urlPathSegments = urlPath.split('/');
300
301 // Example routePathSegments = ['', 'example', '*']
302 var routePathSegments = routePath.split('/');
303
304 // There must be the same number of path segments or it isn't a match
305 if (urlPathSegments.length !== routePathSegments.length) {
306 return false;
307 }
308
309 // Check equality of each path segment
310 for (var i = 0; i < routePathSegments.length; i++) {
311 // The path segments must be equal, be a wildcard segment '*', or be a pat h parameter like ':id'
312 var routeSegment = routePathSegments[i];
313 if (routeSegment !== urlPathSegments[i] && routeSegment !== '*' && routeSe gment.charAt(0) !== ':') {
314 // The path segment wasn't the same string and it wasn't a wildcard or p arameter
315 return false;
316 }
317 }
318
319 // Nothing failed. The route matches the URL.
320 return true;
321 };
322
323 // router.routeArguments(routePath, urlPath, url, isRegExp) - Gets the path va riables and query parameter values from the URL
324 router.routeArguments = function routeArguments(routePath, urlPath, url, isReg Exp) {
325 var args = {};
326
327 // Example urlPathSegments = ['', example', 'path']
328 var urlPathSegments = urlPath.split('/');
329
330 if (!isRegExp) {
331 // Example routePathSegments = ['', 'example', '*']
332 var routePathSegments = routePath.split('/');
333
334 // Get path variables
335 // urlPath '/customer/123'
336 // routePath '/customer/:id'
337 // parses id = '123'
338 for (var index = 0; index < routePathSegments.length; index++) {
339 var routeSegment = routePathSegments[index];
340 if (routeSegment.charAt(0) === ':') {
341 args[routeSegment.substring(1)] = urlPathSegments[index];
342 }
343 }
344 }
345
346 // Get the query parameter values
347 // The search is the query parameters including the leading '?'
348 var searchIndex = url.indexOf('?');
349 var search = '';
350 if (searchIndex !== -1) {
351 search = url.substring(searchIndex);
352 var hashIndex = search.indexOf('#');
353 if (hashIndex !== -1) {
354 search = search.substring(0, hashIndex);
355 }
356 }
357 // If it's a hash URL we need to get the search from the hash
358 var hashPathIndex = url.indexOf('#/');
359 var hashBangPathIndex = url.indexOf('#!/');
360 if (hashPathIndex !== -1 || hashBangPathIndex !== -1) {
361 var hash = '';
362 if (hashPathIndex !== -1) {
363 hash = url.substring(hashPathIndex);
364 } else {
365 hash = url.substring(hashBangPathIndex);
366 }
367 searchIndex = hash.indexOf('?');
368 if (searchIndex !== -1) {
369 search = hash.substring(searchIndex);
370 }
371 }
372
373 var queryParameters = search.substring(1).split('&');
374 // split() on an empty string has a strange behavior of returning [''] inste ad of []
375 if (queryParameters.length === 1 && queryParameters[0] === '') {
376 queryParameters = [];
377 }
378 for (var i = 0; i < queryParameters.length; i++) {
379 var queryParameter = queryParameters[i];
380 var queryParameterParts = queryParameter.split('=');
381 args[queryParameterParts[0]] = queryParameterParts.splice(1, queryParamete rParts.length - 1).join('=');
382 }
383
384 // Parse the arguments into unescaped strings, numbers, or booleans
385 for (var arg in args) {
386 var value = args[arg];
387 if (value === 'true') {
388 args[arg] = true;
389 } else if (value === 'false') {
390 args[arg] = false;
391 } else if (!isNaN(value) && value !== '') {
392 // numeric
393 args[arg] = +value;
394 } else {
395 // string
396 args[arg] = decodeURIComponent(value);
397 }
398 }
399
400 return args;
401 };
402
403 document.registerElement('app-router', {
404 prototype: router
405 });
406 })(window, document);
OLDNEW
« no previous file with comments | « bower_components/app-router/src/app-router.html ('k') | bower_components/chai/.bower.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698