Skip to content

Commit

Permalink
[refactor] rewrite based on WebCell v2 beta & MobX 5
Browse files Browse the repository at this point in the history
  • Loading branch information
TechQuery committed Oct 4, 2019
1 parent bced0c3 commit f3fb4a4
Show file tree
Hide file tree
Showing 17 changed files with 292 additions and 211 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
package-lock.json
dist/
.cache/
.cache/
.rts2_cache_*/
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test/
dist/
.rts2_cache_*/
12 changes: 12 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Cell Router

[Web Component][1] Router based on [WebCell][2] & [MobX][3]

[![](https://data.jsdelivr.com/v1/package/npm/cell-router/badge?style=rounded)][3]

[![NPM](https://nodei.co/npm/cell-router.png?downloads=true&downloadRank=true&stars=true)][4]

[1]: https://www.webcomponents.org/
[2]: https://web-cell.dev/
[3]: https://mobx.js.org/
[4]: https://nodei.co/npm/cell-router/
125 changes: 73 additions & 52 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,55 +1,76 @@
{
"name": "cell-router",
"version": "2.0.0-alpha.1",
"license": "AGPL-3.0",
"description": "",
"keywords": [],
"author": "shiy2008@gmail.com",
"homepage": "https://github.com/EasyWebApp/cell-router#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/EasyWebApp/cell-router.git"
},
"bugs": {
"url": "https://github.com/EasyWebApp/cell-router/issues"
},
"main": "dist/index.js",
"module": "source/index.ts",
"devDependencies": {
"@types/jest": "^24.0.18",
"@types/jsdom": "^12.2.4",
"@types/mocha": "^5.2.7",
"husky": "^3.0.7",
"jest": "^24.9.0",
"jsdom": "^15.1.1",
"lint-staged": "^9.4.1",
"parcel-bundler": "^1.12.3",
"prettier": "^1.18.2",
"ts-jest": "^24.1.0",
"typescript": "^3.6.3"
},
"scripts": {
"test": "lint-staged && jest",
"build": "parcel build source/index.ts"
},
"prettier": {
"singleQuote": true,
"tabWidth": 4
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
},
"lint-staged": {
"*.ts": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "npm test",
"pre-push": "npm run build"
"name": "cell-router",
"version": "2.0.0-beta.0",
"license": "LGPL-3.0",
"description": "Web Component Router based on WebCell & MobX",
"keywords": [
"Web",
"component",
"router",
"WebCell",
"MobX"
],
"author": "shiy2008@gmail.com",
"homepage": "https://web-cell.dev/cell-router/",
"repository": {
"type": "git",
"url": "git+https://github.com/EasyWebApp/cell-router.git"
},
"bugs": {
"url": "https://github.com/EasyWebApp/cell-router/issues"
},
"source": "source/index.ts",
"types": "dist/index.d.ts",
"main": "dist/cell-router.umd.js",
"module": "dist/cell-router.js",
"peerDependencies": {
"mobx": "^5.14.0",
"mobx-web-cell": "^0.1.1",
"web-cell": "^2.0.0-beta.1"
},
"devDependencies": {
"@types/jest": "^24.0.18",
"@types/puppeteer-core": "^1.9.0",
"husky": "^3.0.8",
"jest": "^24.9.0",
"koapache": "^1.0.6",
"lint-staged": "^9.4.1",
"microbundle": "^0.11.0",
"mobx": "^5.14.0",
"mobx-web-cell": "^0.1.1",
"parcel-bundler": "^1.12.3",
"prettier": "^1.18.2",
"puppeteer-core": "^1.20.0",
"ts-jest": "^24.1.0",
"typescript": "^3.6.3",
"web-cell": "^2.0.0-beta.1"
},
"scripts": {
"debug": "cd test/ && parcel source/index.html",
"lint": "lint-staged",
"pack-test": "cd test/ && parcel build source/index.html",
"test": "npm run lint && npm run pack-test && jest --forceExit",
"build": "microbundle --external web-cell,mobx --globals web-cell=WebCell --name CellRouter",
"prepublishOnly": "npm test && npm run build"
},
"prettier": {
"singleQuote": true,
"tabWidth": 4
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
},
"lint-staged": {
"*.{html,md,js,json,ts,tsx}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "npm run lint",
"pre-push": "npm test && npm run build"
}
}
}
}
26 changes: 26 additions & 0 deletions source/HTMLRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { mixin, delegate } from 'web-cell';

import History from './History';

const NonRoute = /^((\w+:)?\/\/|#|javascript:)/;

export default abstract class HTMLRouter extends mixin() {
protected abstract history: History;

constructor() {
super();

this.addEventListener('click', delegate('a[href]', this.handleLink));
}

handleLink = (event: MouseEvent, link: HTMLAnchorElement) => {
if ((link.target || '_self') !== '_self') return;

event.preventDefault(), event.stopPropagation();

const path = link.getAttribute('href');

if (path && !NonRoute.test(path))
this.history.push(path, link.title || link.textContent.trim());
};
}
112 changes: 19 additions & 93 deletions source/History.ts
Original file line number Diff line number Diff line change
@@ -1,109 +1,35 @@
export enum HistoryMode {
hash = '#',
path = '/'
}

enum HistoryEvent {
push = 'push',
pop = 'pop'
}

type HistoryHandler = (path: string, data: any) => void;

interface RouterStore {
[type: string]: Map<string | RegExp, HistoryHandler[]>;
}

const { location } = window;

const NonRoute = /^((\w+:)?\/\/|#|javascript:)/;
import { observable } from 'mobx';

export default class History {
readonly root = location.pathname;
mode = HistoryMode.hash;

private router: RouterStore = {
push: new Map(),
pop: new Map()
};

constructor(mode?: HistoryMode) {
this.mode = mode || this.mode;

document.addEventListener('click', (event: MouseEvent) => {
const link = event.target as (HTMLAnchorElement | HTMLAreaElement);
static get path() {
return window.location.hash.slice(1);
}
static get title() {
return (window.history.state || '').title || document.title;
}

if ((link.target || '_self') !== '_self') return;
@observable
path = History.path;

const path = link.getAttribute('href');
constructor() {
const { title } = History;

if (!path || NonRoute.test(path)) return;
window.history.replaceState({ title }, (document.title = title));

event.preventDefault();
window.addEventListener('popstate', () => {
document.title = History.title;

this.push(path, link.title || (link.textContent as string));
this.path = History.path;
});

window.addEventListener('popstate', () => this.emit('pop'));
}

get path() {
const base =
location.origin + (this.root + this.mode).replace(/\/{2,}/g, '/');

return location.href.indexOf(base)
? ''
: location.href.slice(base.length);
}

push(path: string, title = document.title, data = {}) {
push(path: string, title = document.title, data?: any) {
window.history.pushState(
data,
{ ...data, title },
(document.title = title),
(this.root + this.mode + path).replace(/\/{2,}/g, '/')
'#' + path
);

this.emit('push');
}

static match(path: string, pattern: string | RegExp) {
return pattern instanceof RegExp
? path.match(pattern)
: !path.indexOf(pattern);
}

protected emit(type: keyof typeof HistoryEvent) {
const router = this.router[type],
{ path } = this;

if (path)
for (const [pattern, handlers] of router) {
const data = History.match(path, pattern);

if (data) {
for (const callback of handlers) callback(path, data);
break;
}
}
}

on(
type: keyof typeof HistoryEvent,
path: string | RegExp,
callback: HistoryHandler
) {
const router = this.router[type];

var handlers: HistoryHandler[] = [];

for (const [pattern, handler] of router)
if (pattern + '' === path + '') {
handlers = handler;
break;
}

if (!handlers[0]) router.set(path, (handlers = []));

handlers.push(callback);
this.path = path;
}
}
3 changes: 2 additions & 1 deletion source/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './History';
export { default as History } from './History';
export { default as HTMLRouter } from './HTMLRouter';
42 changes: 0 additions & 42 deletions test/History.spec.ts

This file was deleted.

29 changes: 29 additions & 0 deletions test/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import WebServer from 'koapache';
import { Browser, Page, launch } from 'puppeteer-core';
import { join } from 'path';

export async function bootServer() {
const server = new WebServer('test/dist/');

const { address, port } = await server.workerHost();

return `http://${address}:${port}/`;
}

const { npm_config_chrome } = process.env;

var browser: Browser, page: Page;

export async function getPage(path: string) {
browser = browser || (await launch({ executablePath: npm_config_chrome }));

page = page || (await browser.pages())[0];

await page.goto(path);

return page;
}

export function delay(seconds = 0.1) {
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}
Loading

0 comments on commit f3fb4a4

Please sign in to comment.