{"_id":"@akc42/akc-route","_rev":"1-9445aa6b4b0e460b73a35d4c6a5f2769","name":"@akc42/akc-route","dist-tags":{"latest":"3.0.0"},"versions":{"3.0.0":{"description":"A distributed router inspired by PolymerElements/app-route","keywords":["web-components","polymer","routing"],"repository":{"type":"git","url":"git://github.com/akc42/akc-route.git"},"license":"MIT","name":"@akc42/akc-route","version":"3.0.0","resolutions":{"inherits":"2.0.3","samsam":"1.1.3","supports-color":"3.1.2","type-detect":"1.0.0","@webcomponents/webcomponentsjs":"2.0.0-beta.2"},"author":{"name":"Alan Chandler"},"dependencies":{"@polymer/polymer":"^3.0.0"},"devDependencies":{"@polymer/iron-component-page":"^3.0.0-pre.18","@polymer/iron-demo-helpers":"^3.0.0-pre.18","@polymer/iron-selector":"^3.0.0-pre.18","@polymer/paper-icon-button":"^3.0.0-pre.18","wct-browser-legacy":"^0.0.1-pre.11","@webcomponents/webcomponentsjs":"^2.0.0"},"gitHead":"9bad8808adc8d36fe0ab4702dd83b8bc07d7b192","bugs":{"url":"https://github.com/akc42/akc-route/issues"},"homepage":"https://github.com/akc42/akc-route#readme","_id":"@akc42/akc-route@3.0.0","_npmVersion":"5.6.0","_nodeVersion":"10.1.0","_npmUser":{"name":"akc42","email":"alan@chandlerfamily.org.uk"},"dist":{"integrity":"sha512-o4mXcXdb8ecQZP9007N261XI0ALHwxNur4RYswDk8sxoVOd9su/3LTQOUqlRTD4QbjkFjKwJhnJ9ZJtpvqfvZQ==","shasum":"f794e8aa572454d70c6a8c1c30887798a46c3e97","tarball":"https://registry.npmjs.org/@akc42/akc-route/-/akc-route-3.0.0.tgz","fileCount":12,"unpackedSize":60577,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbAf9dCRA9TVsSAnZWagAA2EAP/iOZ56VLhN9eMEatazBe\ngDhrtLT5gbRKB+aRQ7wEml6o/1i1Geul6yQncTLI34gWDEtj8sadqQH8bDEr\nqesSnLwD23ZDtagkQ01V0nAGG3gHbfWmDU37Ww7FifVYnEOmz+BuWphHG5JN\nFiy7T5OSwBFztz3bxDvtUXRAUaUPK5EGsd7f+hBNC4p6/LzPn07F7T9P4Vh/\nO+80nAQ9h67JRtk9gAvg+HiXeCmYsr1LU7qX+TXwckybTq2sU5+V5eZbDoP9\nHPFHZ7beV0BhLRwTMLeHHJtr1poEYqNXIZ56iebCnl3KrsTliiRI+DZxkoKt\n4gGY4X88zf3ZMv/C3pKAfv29clWuShX4Q34LW7Yz52ezjgRsLu9kbrj/Gsro\ns01JaOWsImz2NMfn2oPnPZXPeLGGq/Te7ap95VqgpAKBj8Di+Xx17+BN0ODk\nYsacyI9BBNyWu1ISaXvgzzvQZavGdY+Vu3cMRJty6Bfrnf0yUusr5qngCWlm\nB/AFQMV4FAp+vDCe7K6gvUi2392KvQt6oqprHcUubuziZV3wcM0BFcz74q43\nNuIceeR87wj/Atu8nG8NIdKA4dLdJKgF0ymWWNecPyqDdWXvcnZYSeLalhBr\nRLLXbL7Jn+J0vM8XX2FVo29l+z3ZA0Ts81wpj4o9XEgBqex34GIis0aOWDhb\nJkAD\r\n=8nrY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID3U214Kg9d6Ei2QNIjl+bhdJHubwDJjre0glKQ2/4rwAiEAm2a+wklfaSS1OVnniD2yA5/5wxPofO3ZHZmtlt9VJTM="}]},"maintainers":[{"name":"akc42","email":"alan@chandlerfamily.org.uk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/akc-route_3.0.0_1526857565092_0.8234233321963345"},"_hasShrinkwrap":false}},"time":{"created":"2018-05-20T23:06:04.817Z","3.0.0":"2018-05-20T23:06:05.184Z","modified":"2022-04-04T12:29:01.070Z"},"maintainers":[{"name":"akc42","email":"alan@chandlerfamily.org.uk"}],"description":"A distributed router inspired by PolymerElements/app-route","homepage":"https://github.com/akc42/akc-route#readme","keywords":["web-components","polymer","routing"],"repository":{"type":"git","url":"git://github.com/akc42/akc-route.git"},"author":{"name":"Alan Chandler"},"bugs":{"url":"https://github.com/akc42/akc-route/issues"},"license":"MIT","readme":"# \\<akc-route\\>\n\nA distributed router inspired by PolymerElements/app-route\n\n## Introduction\n\nI am partway through a large project using Polymer to redevelop a Microsoft Access application to run as a Single Page web application.  I want to expose\nURLs to the user, so that they can represent points in the application which can be handed to other users.  This requires a client side router.\n\nI had several attempts at this, starting with two centralised solutions.  But eventually I started to use the Polymer teams `<app-route>` element (coupled with `<app-location>`) to provide routing.  The distributed nature of this was absolutely the right approach, and I continued to work with it.\n\nHowever, the more I have worked with it in detail the more it has exposed what I initially regarded as bugs. In particular, relying on a transition of a variable to cause an action after a url change is essential - but when it happens and some of the related variables in the application have not yet changed this sophisticated routing starts to break down. I have been working through each of these cases and supplying a fix back to the `<app-route>` team.\n\nHowever the last of these made me question the fundementals of how \n`<app-route>` works.  What is really needed is that all changes to routing take place as one atomic action.  By separately exposing properties `route`, `data`, `active` and `query-params`  this is impossible.\n\nSo `akc-route` and its accompanying `akc-location` is a rewrite of this `<app-route>` components to provide a single object property which will describe completely the distributed route at the point it is used in the application and to guarentee that any change to the property will be made in such a way that all related changes will be made at the same time.\n\n## `<akc-location>` element\n\nThe top of the routing chain is an element which is responsible for interacting with thr address bar in the brower.  This provides a two way linkage between the address bar and a `route` property which it exposes.\n\nthe route property contains the following fields.\n\n* `path` shows the url path that has not yet been consumed\n* `active` a boolean that indicates whether the path so far has been matched. For `<akc-location>` this always will be true after the app has fully initialised.\n* `params` further down the `<akc-route>` chain the `out-route.params`. property will contain an object of the matched parameters from the route. For this element it will always contain the empty object (ie {});\n* `query` will contain an object representation of the search parameters from the url.\n\nNote - changes are atomic.  That is if the url changes, all of the above properties of the `route` object will set before any observer on the object or one of its properties sees a change.\n\n`<akc-location>` will respond to an `akc-location` event and re-read the url. It will also fire this event just after it has updated `route` or the address bar\n\nTwo input properties (ie they are not notified) can be given to `akc-location`.  These are:-\n* `useHashAsPath` if present this property signifies that `<akc-location` should only use hash paths part of the url\n* `dwellTime` a timer which if the url changes within that time from the previous change this change is replaced on the history stack rather than pushing a new entry. \n\n## `<akc-route>` element\n\nThis element provides a matcher to segments of a url.  It is designed to exist in a chain with other `<akc-route>` elements, each one taking in a `route` object on its `inRoute` property consuming part of the url and exposing a different `route` object on an `outRoute` property. Two other properties define how this transformation is to take place:-\n* `ifMatched` is a optional preview switch which is a string consisting of a pair of strings seperated by a `':'`.  If `ifMatched` is present then the string to the left of the colon represents a parameter name and the string to the right a value.  If that parameter is present in incoming route **and** has the value given, that matching con proceed (see next property).  If it doesn't match then no matching will take place and the `outRoute.active` value will be set to `false`. If `ifMatched` is not present or an empty string, then this element will act as though `ifMatched` matched.\n* `match` is a string property which consists of a `'/'` seperated list of `segments` matching eqivalent `'/'` seperated segments of a url.  The initial `'/'` is manditory and will cause a warning to be given if not present since an initial `'/'` in the path that this `<akc-route>` is trying to match will nearly always be present (**even** if the previous `<akc-route>` in the chain consumed the remainder of the url and only **unless** the previous `<akc-route>`'s' `match` parameter contains a trailing `'/'`).  A trailing `'/'` in the `match` property means **only** match if the entire url is consumed by this element. If the property is missing all together then it is assumed to contain a single '/'.  See below for how that is interpreted\n\nWhen `inRoute` changes an `<akc-route>` element processes the changes by looking at the `path` portion of the route and seeing if it can match it with the `match` property. Subject to `inRoute`'s `active` property being `true`  and subject to possible the pre-check defined by a `ifMatched` property, if this match succeeds the `outRoute` property which contain an adjusted copy of `inRoute`. The **only** change to `outRoute` if the match doesn't succeed is its `active` property will be set `false` if it wasn't already set so.\n\nThe `match` consumes part of the url based on the number of segments it has and how may segments are provided in the `path` property of `inRoute`. Each segment can either be a literal string that is being matched in the url, or if it starts with a ':' character means it is a parameters which will be extracted from the url and placed within the `params` property of the `outRoute`.  An empty literal segment will only match an empty segment, a parameterised segment will match any string of characters up to the next '/' (or end of string) including the empty string. \n\nEach matched segment where the `match` property defines a parameter will be added to the `outRoute.params` object with the key defined by the `match` property name. If the matched portion of the url consists solely of the digits \"0\" to \"9\" with an optional leading \"-\" (they will be in string form) the paramater will be converted to an integer before being placed in the `params` property.  \n\nAs a route matches as described above the part of the url matched is removed from the `path` part of the url in `outRoute`. The main point to be made is that the removed part is  **before** a slash. **If** the last match was the end of the url, **and** `inRoute.path` is not already just a '/' **and** the `match` property did not end in a traling slash (or was a single '/' all on its own) then the `outRoute.path` becomes a single '/'\n\n## Rationale for this approach\n\nAs defined in the introduction this pair of elements was inspired by the work done by the Polymer team to produce the `<app-route>` and associated elements.  However, I felt that this approach was too locked in to the legacy interface to be able to deal with the issues as I saw the in relation to having all the values of a `route` in place at the next state after a url change before any observers on that `route` can fire.  The remainder of the differences are related to lessons learned along the way.\n\nConsider the following set of urls\n\n```\n/\n/appointments\n/appointents/5/0\n/appointments/5/-1\n/appointments/5/3456/20161001\n/reports\n/reports/bydate/20160101/20160630\n```\n\nand an application structure at the top level somthing like the following\n\n```\n<akc-location route=\"{{route}}\"></akc-location>\n<akc-route\n  in-route=\"{{route}}\"\n  match=\"/:page\"\n  out-route=\"{{subRoute}}\"></akc-route>\n<iron-pages selected=\"[[page]]\" attr-for-selected=\"name\">\n  <main-menu name=\"menu\"></main-menu>\n  <appointment-management name=\"appointments\" route=\"{{subRoute}}\"></appointment-management>\n  <my-reports name=\"reports\" route=\"{{subRoute}}\"></my-reports>\n</iron-pages>\n```\n\nThe first objective is to use different url's to switch pages. In the above scenario we need an observer on the combination of `subRoute.active` and `subRoute.params.page`. we can check for `subRoute.active` being `true` and  `subRoute.params.page` being `''` in order to set `page` to `'menu'`. At the top level this structure is fine, but at levels down (for instance in the `<my-reports>` element the exact same structure will be needed to match a menu at url /reports and a date reporting element at /reports/bydate ).  This is the reason for propagating one time a trailing `'/'`).\n\nThe reason for `ifMatched` is to provide support for the case where an `<akc-route>` element inside one of the two elements above (`appointment-management` and `my-reports`) can differenciate between a change meant for them or a change meant for the other url.  For instance the change from 0 to -1 in the third segment of the url could be related to change related to reports or a change related to appointments.  By using `ifMached` on the `<akc-route>` element inside either `<appointment-management>` or inside `<my-reports>`  It can be sure its meant for them.\n","readmeFilename":"README.md"}