1<!--
2@license
3Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9-->
10<link rel="import" href="../polymer/polymer.html">
11<link rel="import" href="../iron-location/iron-location.html">
12<link rel="import" href="../iron-location/iron-query-params.html">
13<link rel="import" href="app-route-converter-behavior.html">
14
15<!--
16`app-location` is an element that provides synchronization between the
17browser location bar and the state of an app. When created, `app-location`
18elements will automatically watch the global location for changes. As changes
19occur, `app-location` produces and updates an object called `route`. This
20`route` object is suitable for passing into a `app-route`, and other similar
21elements.
22
23An example of the public API of a route object that describes the URL
24`https://elements.polymer-project.org/elements/app-location`:
25
26    {
27      prefix: '',
28      path: '/elements/app-location'
29    }
30
31Example Usage:
32
33    <app-location route="{{route}}"></app-location>
34    <app-route route="{{route}}" pattern="/:page" data="{{data}}"></app-route>
35
36As you can see above, the `app-location` element produces a `route` and that
37property is then bound into the `app-route` element. The bindings are two-
38directional, so when changes to the `route` object occur within `app-route`,
39they automatically reflect back to the global location.
40
41### Hashes vs Paths
42
43By default `app-location` routes using the pathname portion of the URL. This has
44broad browser support but it does require cooperation of the backend server. An
45`app-location` can be configured to use the hash part of a URL instead using
46the `use-hash-as-path` attribute, like so:
47
48    <app-location route="{{route}}" use-hash-as-path></app-location>
49
50### Integrating with other routing code
51
52There is no standard event that is fired when window.location is modified.
53`app-location` fires a `location-changed` event on `window` when it updates the
54location. It also listens for that same event, and re-reads the URL when it's
55fired. This makes it very easy to interop with other routing code.
56
57So for example if you want to navigate to `/new_path` imperatively you could
58call `window.location.pushState` or `window.location.replaceState` followed by
59firing a `location-changed` event on `window`. i.e.
60
61    window.history.pushState({}, null, '/new_path');
62    window.dispatchEvent(new CustomEvent('location-changed'));
63
64@element app-location
65@demo demo/index.html
66-->
67<dom-module id="app-location">
68  <template>
69    <iron-location
70        path="{{__path}}"
71        query="{{__query}}"
72        hash="{{__hash}}"
73        url-space-regex={{urlSpaceRegex}}>
74    </iron-location>
75    <iron-query-params
76        params-string="{{__query}}"
77        params-object="{{queryParams}}">
78    </iron-query-params>
79  </template>
80  <script>
81    (function() {
82      'use strict';
83
84      Polymer({
85        is: 'app-location',
86
87        properties: {
88          /**
89           * A model representing the deserialized path through the route tree, as
90           * well as the current queryParams.
91           */
92          route: {
93            type: Object,
94            notify: true
95          },
96
97          /**
98           * In many scenarios, it is convenient to treat the `hash` as a stand-in
99           * alternative to the `path`. For example, if deploying an app to a static
100           * web server (e.g., Github Pages) - where one does not have control over
101           * server-side routing - it is usually a better experience to use the hash
102           * to represent paths through one's app.
103           *
104           * When this property is set to true, the `hash` will be used in place of
105
106           * the `path` for generating a `route`.
107           */
108          useHashAsPath: {
109            type: Boolean,
110            value: false
111          },
112
113          /**
114           * A regexp that defines the set of URLs that should be considered part
115           * of this web app.
116           *
117           * Clicking on a link that matches this regex won't result in a full page
118           * navigation, but will instead just update the URL state in place.
119           *
120           * This regexp is given everything after the origin in an absolute
121           * URL. So to match just URLs that start with /search/ do:
122           *     url-space-regex="^/search/"
123           *
124           * @type {string|RegExp}
125           */
126          urlSpaceRegex: {
127            type: String,
128            notify: true
129          },
130
131          /**
132           * A set of key/value pairs that are universally accessible to branches
133           * of the route tree.
134           */
135          __queryParams: {
136            type: Object
137          },
138
139          /**
140           * The pathname component of the current URL.
141           */
142          __path: {
143            type: String
144          },
145
146          /**
147           * The query string portion of the current URL.
148           */
149          __query: {
150            type: String
151          },
152
153          /**
154           * The hash portion of the current URL.
155           */
156          __hash: {
157            type: String
158          },
159
160          /**
161           * The route path, which will be either the hash or the path, depending
162           * on useHashAsPath.
163           */
164          path: {
165            type: String,
166            observer: '__onPathChanged'
167          }
168        },
169
170        behaviors: [Polymer.AppRouteConverterBehavior],
171
172        observers: [
173          '__computeRoutePath(useHashAsPath, __hash, __path)'
174        ],
175
176        __computeRoutePath: function() {
177          this.path = this.useHashAsPath ? this.__hash : this.__path;
178        },
179
180        __onPathChanged: function() {
181          if (!this._readied) {
182            return;
183          }
184
185          if (this.useHashAsPath) {
186            this.__hash = this.path;
187          } else {
188            this.__path = this.path;
189          }
190        }
191      });
192    })();
193  </script>
194</dom-module>
195