@jack-henry/web-component-router
Advanced tools
Comparing version 1.0.3 to 2.0.0
@@ -21,6 +21,5 @@ /** | ||
import page from 'page'; | ||
const Context = page.Context; | ||
import {Context} from './page.js'; | ||
import RouteData from './route-data.js'; | ||
import BasicRoutingInterface from '../routing-interface.js'; | ||
import BasicRoutingInterface from './routing-interface.js'; | ||
@@ -101,5 +100,6 @@ class RouteTreeNode { | ||
getRoot() { | ||
/** @type {!RouteTreeNode} */ | ||
let root = this; | ||
while (root.getParent()) { | ||
root = root.getParent(); | ||
root = /** @type {!RouteTreeNode} */ (root.getParent()); | ||
} | ||
@@ -134,3 +134,3 @@ return root; | ||
* @param {function(this:RouteTreeNode, !RouteTreeNode): | ||
* (boolean|undefined)} f Callback function. It takes the node as argument. | ||
* (boolean|undefined|void)} f Callback function. It takes the node as argument. | ||
* The children of this node will be visited if the callback returns true or | ||
@@ -259,3 +259,3 @@ * undefined, and will be skipped if the callback returns false. | ||
// Ancestors are a path from the parent up the tree to the root | ||
const entryNodes = [this].concat(this.getAncestors()); | ||
const entryNodes = [/** @type {!RouteTreeNode} */ (this)].concat(this.getAncestors()); | ||
entryNodes.reverse(); | ||
@@ -315,3 +315,3 @@ let exitNodes = []; | ||
/** @param {boolean=} isNotCancelled */ | ||
/** @param {(boolean|void)=} isNotCancelled */ | ||
async function nextEntry(isNotCancelled) { | ||
@@ -327,3 +327,5 @@ if (isNotCancelled === false) { | ||
} else if (currentEntryNode.getValue().element) { | ||
const routingElem = /** @type {!BasicRoutingInterface} */ (currentEntryNode.getValue().element); | ||
const routingElem = /** @type {!BasicRoutingInterface} */ ( | ||
/** @type {?} */ (currentEntryNode.getValue().element) | ||
); | ||
if (!routingElem.routeEnter) { | ||
@@ -330,0 +332,0 @@ throw new Error(`Element '${currentEntryNode.getValue().tagName}' does not implement routeEnter`); |
{ | ||
"name": "@jack-henry/web-component-router", | ||
"version": "1.0.3", | ||
"version": "2.0.0", | ||
"description": "Web Components Router", | ||
@@ -10,2 +10,3 @@ "main": "router.js", | ||
"*.js", | ||
"*.d.ts", | ||
"package.json", | ||
@@ -15,2 +16,5 @@ "README.md" | ||
"scripts": { | ||
"build": "tsc", | ||
"clean": "rimraf './lib/**/*.d.ts' && rimraf './*.d.ts'", | ||
"prepublish": "yarn clean && yarn build", | ||
"test": "karma start test/karma.config.cjs --single-run" | ||
@@ -29,13 +33,13 @@ }, | ||
"dependencies": { | ||
"page": "1.7.x", | ||
"qs": "6.5.0" | ||
"path-to-regexp": "^6.2.1" | ||
}, | ||
"devDependencies": { | ||
"@polymer/polymer": "^3.4.1", | ||
"jasmine-core": "3.x", | ||
"jasmine-core": "4.x", | ||
"karma": "6.x", | ||
"karma-chrome-launcher": "^3.1.0", | ||
"karma-jasmine": "4.x", | ||
"karma-spec-reporter": "^0.0.32" | ||
"karma-jasmine": "5.x", | ||
"karma-spec-reporter": "^0.0.34", | ||
"typescript": "^4.8.0-beta" | ||
} | ||
} |
@@ -75,4 +75,3 @@ # @jack-henry/web-component-router | ||
import RouteData from '@jack-henry/web-component-router/lib/route-data.js'; | ||
import RouteTreeNode from '@jack-henry/web-component-router/lib/route-tree-node.js'; | ||
import {RouteData, RouteTreeNode} from '@jack-henry/web-component-router'; | ||
@@ -210,7 +209,5 @@ const dashboard = new RouteTreeNode( | ||
import myAppRouteTree from './route-tree.js'; | ||
import router from '@jack-henry/web-component-router'; | ||
import routeMixin from '@jack-henry/web-component-router/routing-mixin.js'; | ||
import pageJs from 'page'; | ||
import router, {Context, routingMixin} from '@jack-henry/web-component-router'; | ||
class AppElement extends routeMixin(Polymer.Element) { | ||
class AppElement extends routingMixin(Polymer.Element) { | ||
static get is() { return 'app-element'; } | ||
@@ -264,6 +261,5 @@ | ||
import myAppRouteTree from './route-tree.js'; | ||
import router from '@jack-henry/web-component-router'; | ||
import routeMixin from '@jack-henry/web-component-router/routing-mixin.js'; | ||
import router, {routingMixin} from '@jack-henry/web-component-router'; | ||
class AppElement extends routeMixin(Polymer.Element) { | ||
class AppElement extends routingMixin(Polymer.Element) { | ||
static get is() { return 'app-element'; } | ||
@@ -286,3 +282,3 @@ | ||
/** | ||
* @param {!pageJs.Context} context | ||
* @param {!Context} context | ||
* @param {function(boolean=)} next | ||
@@ -345,3 +341,3 @@ * @private | ||
* Register an exit callback to be invoked on every route change | ||
* @param {function(!pageJs.Context, function(boolean=))} callback | ||
* @param {function(!Context, function(boolean=))} callback | ||
*/ | ||
@@ -380,3 +376,3 @@ router.addGlobalExitHandler(callback); | ||
* | ||
* @param {!pageJs.Context} context route enter context | ||
* @param {!Context} context route enter context | ||
* @return {!string} | ||
@@ -383,0 +379,0 @@ */ |
191
router.js
@@ -18,43 +18,9 @@ /** | ||
import pageJs from 'page'; | ||
import qsParse from 'qs/lib/parse.js'; | ||
import {Context, Page} from './lib/page.js'; | ||
import RouteTreeNode from './lib/route-tree-node.js'; | ||
import routingMixin from './lib/routing-mixin.js'; | ||
import animatedRoutingMixin from './lib/animated-routing-mixin.js'; | ||
import BasicRoutingInterface from './lib/routing-interface.js'; | ||
import RouteData from './lib/route-data.js'; | ||
/** | ||
* @param {!URL|!HTMLAnchorElement} url | ||
* @return {!{ | ||
* protocol: string, | ||
* hostname: string, | ||
* port: string | ||
* }} | ||
*/ | ||
function urlParts(url) { | ||
const parts = { | ||
protocol: url.protocol, | ||
hostname: url.hostname, | ||
port: url.port | ||
}; | ||
if (url.port.trim().length > 0) { | ||
parts.port = url.port; | ||
} else if (/^https:$/i.test(url.protocol)) { | ||
parts.port = '443'; | ||
} else if (/^http:$/i.test(url.protocol)) { | ||
parts.port = '80'; | ||
} | ||
return parts; | ||
} | ||
/** | ||
* @param {string} href1 | ||
* @param {string} href2 | ||
* @return {boolean} | ||
*/ | ||
function compareOrigins(href1, href2) { | ||
const url1 = urlParts(new URL(href1, location.toString())); | ||
const url2 = urlParts(new URL(href2, location.toString())); | ||
return url1.protocol === url2.protocol && | ||
url1.hostname === url2.hostname && | ||
url1.port === url2.port; | ||
} | ||
class Router { | ||
@@ -78,6 +44,8 @@ constructor() { | ||
/** @type {!Set<!function()>} */ | ||
/** @type {!Set<!function():?>} */ | ||
this.routeChangeStartCallbacks_ = new Set(); | ||
/** @type {!Set<!function(!Error=)>} */ | ||
/** @type {!Set<!function(!Error=):?>} */ | ||
this.routeChangeCompleteCallbacks_ = new Set(); | ||
this.page = new Page(); | ||
} | ||
@@ -107,3 +75,3 @@ | ||
* Build the routing tree and begin routing | ||
* @return {undefined} | ||
* @return {void} | ||
*/ | ||
@@ -113,10 +81,12 @@ start() { | ||
document.addEventListener('tap', Router.navigationEvent_, false); | ||
document.addEventListener('click', Router.navigationEvent_, false); | ||
document.addEventListener('tap', this.page.clickHandler.bind(this.page), false); | ||
document.addEventListener('click', this.page.clickHandler.bind(this.page), false); | ||
pageJs.start({ | ||
this.page.start({ | ||
click: false, | ||
popstate: true, | ||
hashbang: false, | ||
decodeURLComponents: true | ||
decodeURLComponents: true, | ||
window: undefined, | ||
dispatch: undefined | ||
}); | ||
@@ -132,3 +102,3 @@ } | ||
path = this.url(path, params); | ||
pageJs.show(path); | ||
this.page.show(path); | ||
} | ||
@@ -144,3 +114,3 @@ | ||
path = this.url(path, params); | ||
pageJs.replace(path); | ||
this.page.replace(path); | ||
} | ||
@@ -190,6 +160,6 @@ | ||
* Register an exit callback to be invoked on every route change | ||
* @param {function(!pageJs.Context, function(boolean=))} callback | ||
* @param {function(!Context, function(boolean=):?):?} callback | ||
*/ | ||
addGlobalExitHandler(callback) { | ||
pageJs.exit('*', callback); | ||
this.page.exit('*', callback); | ||
} | ||
@@ -200,6 +170,6 @@ | ||
* @param {!string} route | ||
* @param {function(!pageJs.Context, function(boolean=))} callback | ||
* @param {function(!Context, function(boolean=):?):?} callback | ||
*/ | ||
addExitHandler(route, callback) { | ||
pageJs.exit(route, callback); | ||
this.page.exit(route, callback); | ||
} | ||
@@ -210,9 +180,9 @@ | ||
* @param {!string} route | ||
* @param {function(!pageJs.Context, function(boolean=))} callback | ||
* @param {function(!Context, function(boolean=):?):?} callback | ||
*/ | ||
addRouteHandler(route, callback) { | ||
pageJs(route, callback); | ||
this.page.register(route, callback); | ||
} | ||
/** @param {!function()} callback */ | ||
/** @param {!function():?} callback */ | ||
addRouteChangeStartCallback(callback) { | ||
@@ -222,3 +192,3 @@ this.routeChangeStartCallbacks_.add(callback); | ||
/** @param {!function()} callback */ | ||
/** @param {!function():?} callback */ | ||
removeRouteChangeStartCallback(callback) { | ||
@@ -228,3 +198,3 @@ this.routeChangeStartCallbacks_.delete(callback); | ||
/** @param {!function(!Error=)} callback */ | ||
/** @param {!function(!Error=):?} callback */ | ||
addRouteChangeCompleteCallback(callback) { | ||
@@ -234,3 +204,3 @@ this.routeChangeCompleteCallbacks_.add(callback); | ||
/** @param {!function(!Error=)} callback */ | ||
/** @param {!function(!Error=):?} callback */ | ||
removeRouteChangeCompleteCallback(callback) { | ||
@@ -241,98 +211,10 @@ this.routeChangeCompleteCallbacks_.delete(callback); | ||
/** | ||
* A modified copy of the pagejs onclick function. | ||
* Properly handles Polymer "tap" events. | ||
* | ||
* @param {!Event} e | ||
*/ | ||
static navigationEvent_(e) { | ||
if (e.type !== 'tap' && (e.which === null ? e.button : e.which) !== 1) { | ||
return; | ||
} | ||
if (e.metaKey || e.ctrlKey || e.shiftKey) { | ||
return; | ||
} | ||
if (e.defaultPrevented) { | ||
return; | ||
} | ||
// ensure link | ||
// use shadow dom when available | ||
let el = e.target; | ||
if (el.nodeName !== 'A') { | ||
const composedPath = e.composedPath(); | ||
for (let i = 0; i < composedPath.length; i++) { | ||
el = composedPath[i]; | ||
if (el.nodeName === 'A') { | ||
break; | ||
} | ||
} | ||
} | ||
if (!el || el.nodeName !== 'A') { | ||
return; | ||
} | ||
// Ignore if tag has | ||
// 1. "download" attribute | ||
// 2. rel="external" attribute | ||
if (el.hasAttribute('download') || el.getAttribute('rel') === 'external') { | ||
return; | ||
} | ||
// ensure a href exists and non-hash for the same path | ||
const link = el.getAttribute('href'); | ||
if (!link || ((el.pathname === location.pathname || el.pathname === '') && (el.hash || link === '#'))) { | ||
return; | ||
} | ||
// Check for mailto: in the href | ||
if (el.protocol && el.protocol.length > 0 && !/^https?:$/.test(el.protocol)) { | ||
return; | ||
} | ||
// check target | ||
if (el.target) { | ||
return; | ||
} | ||
// x-origin | ||
// IE anchor tags have default ports ":80", ":443", ete, | ||
// but the location url does not. | ||
// Normalize the location href and compare. | ||
if (!compareOrigins(location.href, el.href)) { | ||
return; | ||
} | ||
// rebuild path | ||
const path = el.pathname + el.search + (el.hash || ''); | ||
/* If we ever support running the app in a subfolder, we'll need this block | ||
// same page | ||
var orig = path; | ||
let base = ''; | ||
if (path.indexOf(base) === 0) { | ||
path = path.substr(base.length); | ||
} | ||
if (base && orig === path) { | ||
return; | ||
} | ||
*/ | ||
e.preventDefault(); | ||
// pageJs.show(orig); | ||
pageJs.show(path); | ||
} | ||
/** | ||
* Adds the query parameters to the Page.js context. | ||
* | ||
* @param {!pageJs.Context} context | ||
* @param {function()} next | ||
* @param {!Context} context | ||
* @param {function():?} next | ||
* @private | ||
*/ | ||
parseQueryString_(context, next) { | ||
context.query = qsParse(context.querystring, {}); | ||
context.query = new URLSearchParams(context.querystring); | ||
next(); | ||
@@ -348,3 +230,3 @@ } | ||
registerRoutes_() { | ||
pageJs('*', this.parseQueryString_); | ||
this.page.register('*', this.parseQueryString_); | ||
@@ -364,3 +246,3 @@ this.routeTree_.traverse((node) => { | ||
pageJs(routeData.path, this.routeChangeCallback_.bind(this, node)); | ||
this.page.register(routeData.path, this.routeChangeCallback_.bind(this, node)); | ||
}); | ||
@@ -371,4 +253,4 @@ } | ||
* @param {!RouteTreeNode} routeTreeNode | ||
* @param {!pageJs.Context} context | ||
* @param {function()} next | ||
* @param {!Context} context | ||
* @param {function():?} next | ||
* @private | ||
@@ -396,3 +278,3 @@ */ | ||
* | ||
* @param {!pageJs.Context} context route enter context | ||
* @param {!Context} context route enter context | ||
* @return {!string} | ||
@@ -422,1 +304,2 @@ */ | ||
export default Router; | ||
export {animatedRoutingMixin, BasicRoutingInterface, Context, RouteData, RouteTreeNode, routingMixin}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
117438
1
16
2732
7
376
1
+ Addedpath-to-regexp@^6.2.1
+ Addedpath-to-regexp@6.3.0(transitive)
- Removedpage@1.7.x
- Removedqs@6.5.0
- Removedisarray@0.0.1(transitive)
- Removedpage@1.7.3(transitive)
- Removedpath-to-regexp@1.2.1(transitive)
- Removedqs@6.5.0(transitive)