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