| Index: polymer_1.0.4/bower_components/app-router/src/app-router.js
|
| diff --git a/polymer_0.5.4/bower_components/app-router/src/app-router.js b/polymer_1.0.4/bower_components/app-router/src/app-router.js
|
| similarity index 80%
|
| copy from polymer_0.5.4/bower_components/app-router/src/app-router.js
|
| copy to polymer_1.0.4/bower_components/app-router/src/app-router.js
|
| index f4f3df833d97ce94d77b3913214020b4fb62eed7..b41e97382a00824b98f586c371ff786a27d2ae0e 100644
|
| --- a/polymer_0.5.4/bower_components/app-router/src/app-router.js
|
| +++ b/polymer_1.0.4/bower_components/app-router/src/app-router.js
|
| @@ -5,11 +5,26 @@
|
| var isIE = 'ActiveXObject' in window;
|
| var previousUrl = {};
|
|
|
| - // <app-router [init="auto|manual"] [mode="auto|hash|pushstate"] [trailingSlash="strict|ignore"] [shadow]></app-router>
|
| + // <app-router
|
| + // init="auto|manual"
|
| + // mode="auto|hash|hashbang|pushstate"
|
| + // trailingSlash="strict|ignore"
|
| + // typecast="auto|string"
|
| + // bindRouter
|
| + // ></app-router>
|
| var AppRouter = Object.create(HTMLElement.prototype);
|
| AppRouter.util = utilities;
|
|
|
| - // <app-route path="/path" [import="/page/cust-el.html"] [element="cust-el"] [template]></app-route>
|
| + // <app-route
|
| + // path="/path"
|
| + // import="/page/cust-el.html"
|
| + // element[="cust-el"]
|
| + // template[="template-id"]
|
| + // regex
|
| + // redirect="/path"
|
| + // onUrlChange="reload|updateModel|noop"
|
| + // bindRouter
|
| + // ></app-route>
|
| document.registerElement('app-route', {
|
| prototype: Object.create(HTMLElement.prototype)
|
| });
|
| @@ -35,7 +50,7 @@
|
| router.setAttribute('trailingSlash', 'strict');
|
| }
|
|
|
| - // mode="auto|hash|pushstate"
|
| + // mode="auto|hash|hashbang|pushstate"
|
| if (!router.hasAttribute('mode')) {
|
| router.setAttribute('mode', 'auto');
|
| }
|
| @@ -78,7 +93,12 @@
|
| // when a transition finishes, remove the previous route's content. there is a temporary overlap where both
|
| // the new and old route's content is in the DOM to animate the transition.
|
| router.coreAnimatedPages.addEventListener('core-animated-pages-transition-end', function() {
|
| - transitionAnimationEnd(router.previousRoute);
|
| + // with core-animated-pages, navigating to the same route twice quickly will set the new route to both the
|
| + // activeRoute and the previousRoute before the animation finishes. we don't want to delete the route content
|
| + // if it's actually the active route.
|
| + if (router.previousRoute && !router.previousRoute.hasAttribute('active')) {
|
| + deactivateRoute(router.previousRoute);
|
| + }
|
| });
|
| }
|
|
|
| @@ -110,8 +130,12 @@
|
| // }
|
| AppRouter.go = function(path, options) {
|
| if (this.getAttribute('mode') !== 'pushstate') {
|
| - // mode == auto or hash
|
| - path = '#' + path;
|
| + // mode == auto, hash or hashbang
|
| + if (this.getAttribute('mode') === 'hashbang') {
|
| + path = '#!' + path;
|
| + } else {
|
| + path = '#' + path;
|
| + }
|
| }
|
| if (options && options.replace === true) {
|
| window.history.replaceState(null, null, path);
|
| @@ -165,6 +189,7 @@
|
| // don't load a new route if only the hash fragment changed
|
| if (url.hash !== previousUrl.hash && url.path === previousUrl.path && url.search === previousUrl.search && url.isHashPath === previousUrl.isHashPath) {
|
| scrollToHash(url.hash);
|
| + previousUrl = url;
|
| return;
|
| }
|
| previousUrl = url;
|
| @@ -197,6 +222,11 @@
|
| return;
|
| }
|
|
|
| + // if we're on the same route and `onUrlChange="noop"` then don't reload the route or update the model
|
| + if (route === router.activeRoute && route.getAttribute('onUrlChange') === 'noop') {
|
| + return;
|
| + }
|
| +
|
| var eventDetail = {
|
| path: url.path,
|
| route: route,
|
| @@ -209,21 +239,15 @@
|
| return;
|
| }
|
|
|
| - // update the references to the activeRoute and previousRoute. if you switch between routes quickly you may go to a
|
| - // new route before the previous route's transition animation has completed. if that's the case we need to remove
|
| - // the previous route's content before we replace the reference to the previous route.
|
| - if (router.previousRoute && router.previousRoute.transitionAnimationInProgress) {
|
| - transitionAnimationEnd(router.previousRoute);
|
| - }
|
| - if (router.activeRoute) {
|
| - router.activeRoute.removeAttribute('active');
|
| - }
|
| - router.previousRoute = router.activeRoute;
|
| - router.activeRoute = route;
|
| - router.activeRoute.setAttribute('active', 'active');
|
| + // keep track of the route currently being loaded
|
| + router.loadingRoute = route;
|
|
|
| + // if we're on the same route and `onUrlChange="updateModel"` then update the model but don't replace the page content
|
| + if (route === router.activeRoute && route.getAttribute('onUrlChange') === 'updateModel') {
|
| + updateModelAndActivate(router, route, url, eventDetail);
|
| + }
|
| // import custom element or template
|
| - if (route.hasAttribute('import')) {
|
| + else if (route.hasAttribute('import')) {
|
| importAndActivate(router, route.getAttribute('import'), route, url, eventDetail);
|
| }
|
| // pre-loaded custom element
|
| @@ -232,45 +256,74 @@
|
| }
|
| // inline template
|
| else if (route.firstElementChild && route.firstElementChild.tagName === 'TEMPLATE') {
|
| + // mark the route as an inline template so we know how to clean it up when we remove the route's content
|
| + route.isInlineTemplate = true;
|
| activateTemplate(router, route.firstElementChild, route, url, eventDetail);
|
| }
|
| }
|
|
|
| + // If we are only hiding and showing the route, update the model and activate the route
|
| + function updateModelAndActivate(router, route, url, eventDetail) {
|
| + var model = createModel(router, route, url, eventDetail);
|
| +
|
| + if (route.hasAttribute('template') || route.isInlineTemplate) {
|
| + // update the template model
|
| + setObjectProperties(route.lastElementChild.templateInstance.model, model);
|
| + } else {
|
| + // update the custom element model
|
| + setObjectProperties(route.firstElementChild, model);
|
| + }
|
| +
|
| + fire('activate-route-end', eventDetail, router);
|
| + fire('activate-route-end', eventDetail, eventDetail.route);
|
| + }
|
| +
|
| // Import and activate a custom element or template
|
| function importAndActivate(router, importUri, route, url, eventDetail) {
|
| var importLink;
|
| function importLoadedCallback() {
|
| + importLink.loaded = true;
|
| activateImport(router, importLink, importUri, route, url, eventDetail);
|
| }
|
|
|
| if (!importedURIs.hasOwnProperty(importUri)) {
|
| // hasn't been imported yet
|
| - importedURIs[importUri] = true;
|
| importLink = document.createElement('link');
|
| importLink.setAttribute('rel', 'import');
|
| importLink.setAttribute('href', importUri);
|
| + importLink.setAttribute('async', 'async');
|
| importLink.addEventListener('load', importLoadedCallback);
|
| + importLink.loaded = false;
|
| document.head.appendChild(importLink);
|
| + importedURIs[importUri] = importLink;
|
| } else {
|
| // previously imported. this is an async operation and may not be complete yet.
|
| - importLink = document.querySelector('link[href="' + importUri + '"]');
|
| - if (importLink.import) {
|
| - // import complete
|
| - importLoadedCallback();
|
| - } else {
|
| - // wait for `onload`
|
| + importLink = importedURIs[importUri];
|
| + if (!importLink.loaded) {
|
| importLink.addEventListener('load', importLoadedCallback);
|
| + } else {
|
| + activateImport(router, importLink, importUri, route, url, eventDetail);
|
| }
|
| }
|
| }
|
|
|
| // Activate the imported custom element or template
|
| function activateImport(router, importLink, importUri, route, url, eventDetail) {
|
| + // allow referencing the route's import link in the activate-route-end callback
|
| + route.importLink = importLink;
|
| +
|
| // make sure the user didn't navigate to a different route while it loaded
|
| - if (route.hasAttribute('active')) {
|
| + if (route === router.loadingRoute) {
|
| if (route.hasAttribute('template')) {
|
| // template
|
| - activateTemplate(router, importLink.import.querySelector('template'), route, url, eventDetail);
|
| + var templateId = route.getAttribute('template');
|
| + var template;
|
| + if (templateId) {
|
| + template = importLink.import.getElementById(templateId);
|
| + } else {
|
| + template = importLink.import.querySelector('template');
|
| + }
|
| + activateTemplate(router, template, route, url, eventDetail);
|
| } else {
|
| // custom element
|
| activateCustomElement(router, route.getAttribute('element') || importUri.split('/').slice(-1)[0].replace('.html', ''), route, url, eventDetail);
|
| @@ -282,11 +335,7 @@
|
| function activateCustomElement(router, elementName, route, url, eventDetail) {
|
| var customElement = document.createElement(elementName);
|
| var model = createModel(router, route, url, eventDetail);
|
| - for (var property in model) {
|
| - if (model.hasOwnProperty(property)) {
|
| - customElement[property] = model[property];
|
| - }
|
| - }
|
| + setObjectProperties(customElement, model);
|
| activateElement(router, customElement, url, eventDetail);
|
| }
|
|
|
| @@ -316,15 +365,38 @@
|
| return eventDetail.model;
|
| }
|
|
|
| + // Copy properties from one object to another
|
| + function setObjectProperties(object, model) {
|
| + for (var property in model) {
|
| + if (model.hasOwnProperty(property)) {
|
| + object[property] = model[property];
|
| + }
|
| + }
|
| + }
|
| +
|
| // Replace the active route's content with the new element
|
| function activateElement(router, element, url, eventDetail) {
|
| - // core-animated-pages temporarily needs the old and new route in the DOM at the same time to animate the transition,
|
| - // otherwise we can remove the old route's content right away.
|
| - // UNLESS
|
| - // if the route we're navigating to matches the same app-route (ex: path="/article/:id" navigating from /article/0 to
|
| - // /article/1), then we have to simply replace the route's content instead of animating a transition.
|
| + // when using core-animated-pages, the router doesn't remove the previousRoute's content right away. if you
|
| + // navigate between 3 routes quickly (ex: /a -> /b -> /c) you might set previousRoute to '/b' before '/a' is
|
| + // removed from the DOM. this verifies old content is removed before switching the reference to previousRoute.
|
| + deactivateRoute(router.previousRoute);
|
| +
|
| + // update references to the activeRoute, previousRoute, and loadingRoute
|
| + router.previousRoute = router.activeRoute;
|
| + router.activeRoute = router.loadingRoute;
|
| + router.loadingRoute = null;
|
| + if (router.previousRoute) {
|
| + router.previousRoute.removeAttribute('active');
|
| + }
|
| + router.activeRoute.setAttribute('active', 'active');
|
| +
|
| + // remove the old route's content before loading the new route. core-animated-pages temporarily needs the old and
|
| + // new route in the DOM at the same time to animate the transition, otherwise we can remove the old route's content
|
| + // right away. there is one exception for core-animated-pages where the route we're navigating to matches the same
|
| + // route (ex: path="/article/:id" navigating from /article/0 to /article/1). in this case we have to simply replace
|
| + // the route's content instead of animating a transition.
|
| if (!router.hasAttribute('core-animated-pages') || eventDetail.route === eventDetail.oldRoute) {
|
| - removeRouteContent(router.previousRoute);
|
| + deactivateRoute(router.previousRoute);
|
| }
|
|
|
| // add the new content
|
| @@ -333,13 +405,7 @@
|
| // animate the transition if core-animated-pages are being used
|
| if (router.hasAttribute('core-animated-pages')) {
|
| router.coreAnimatedPages.selected = router.activeRoute.getAttribute('path');
|
| -
|
| - // we already wired up transitionAnimationEnd() in init()
|
| -
|
| - // use to check if the previous route has finished animating before being removed
|
| - if (router.previousRoute) {
|
| - router.previousRoute.transitionAnimationInProgress = true;
|
| - }
|
| + // the 'core-animated-pages-transition-end' event handler in init() will call deactivateRoute() on the previousRoute
|
| }
|
|
|
| // scroll to the URL hash if it's present
|
| @@ -351,24 +417,21 @@
|
| fire('activate-route-end', eventDetail, eventDetail.route);
|
| }
|
|
|
| - // Call when the previousRoute has finished the transition animation out
|
| - function transitionAnimationEnd(previousRoute) {
|
| - if (previousRoute) {
|
| - previousRoute.transitionAnimationInProgress = false;
|
| - removeRouteContent(previousRoute);
|
| - }
|
| - }
|
| -
|
| - // Remove the route's content (but not the <template> if it exists)
|
| - function removeRouteContent(route) {
|
| + // Remove the route's content
|
| + function deactivateRoute(route) {
|
| if (route) {
|
| + // remove the route content
|
| var node = route.firstChild;
|
| +
|
| + // don't remove an inline <template>
|
| + if (route.isInlineTemplate) {
|
| + node = route.querySelector('template').nextSibling;
|
| + }
|
| +
|
| while (node) {
|
| var nodeToRemove = node;
|
| node = node.nextSibling;
|
| - if (nodeToRemove.tagName !== 'TEMPLATE') {
|
| - route.removeChild(nodeToRemove);
|
| - }
|
| + route.removeChild(nodeToRemove);
|
| }
|
| }
|
| }
|
| @@ -559,7 +622,7 @@
|
| if (routePath.charAt(0) !== '/') {
|
| routePath = '/**/' + routePath;
|
| }
|
| -
|
| +
|
| // get path variables
|
| // urlPath '/customer/123'
|
| // routePath '/customer/:id'
|
|
|