UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing system. It is developed to power our online editing platform [Substance](http://substance.io).

138 lines (121 loc) 3.16 kB
import DefaultDOMElement from '../dom/DefaultDOMElement' import EventEmitter from '../util/EventEmitter' import forEach from '../util/forEach' import isNil from '../util/isNil' export default class Router extends EventEmitter { constructor (...args) { super(...args) this.__isStarted__ = false } /* Starts listening for hash-changes */ start () { const window = DefaultDOMElement.getBrowserWindow() window.on('hashchange', this._onHashChange, this) this.__isStarted__ = true } /* Reads out the current route */ readRoute () { if (!this.__isStarted__) this.start() return this.parseRoute(this.getRouteString()) } /* Writes out a given route as a string url */ writeRoute (route, opts = {}) { const routeString = this.stringifyRoute(route) if (!routeString) { this.clearRoute(opts) } else { this._writeRoute(routeString, opts) } } dispose () { const window = DefaultDOMElement.getBrowserWindow() window.off(this) } /* Maps a route URL to a route object @abstract @param String route content of the URL's hash fragment */ parseRoute (routeString) { return Router.routeStringToObject(routeString) } /* Maps a route object to a route URL This can be overriden by an application specific router. @abstract */ stringifyRoute (route) { return Router.objectToRouteString(route) } getRouteString () { const window = DefaultDOMElement.getBrowserWindow().getNativeElement() return window.location.hash.slice(1) } _writeRoute (route, opts) { const window = DefaultDOMElement.getBrowserWindow().getNativeElement() this.__isSaving__ = true try { if (opts.replace) { window.history.replaceState({}, '', `#${route}`) } else { window.history.pushState({}, '', `#${route}`) } } finally { this.__isSaving__ = false } } clearRoute (opts = {}) { this._writeRoute('', opts) } _onHashChange () { // console.log('_onHashChange'); if (this.__isSaving__) { return } if (this.__isLoading__) { console.error('FIXME: router is currently applying a route.') return } this.__isLoading__ = true try { const routeString = this.getRouteString() const route = this.parseRoute(routeString) this.emit('route:changed', route) } finally { this.__isLoading__ = false } } static objectToRouteString (obj) { const frags = [] forEach(obj, (val, key) => { if (!isNil(val)) { frags.push(`${key}=${val}`) } }) return frags.join(',') } static routeStringToObject (routeStr) { const obj = {} // Empty route maps to empty route object if (!routeStr) return obj const params = routeStr.split(',') for (const param of params) { if (param.indexOf('=') >= 0) { const tuple = param.split('=') if (tuple.length !== 2) { throw new Error('Illegal route.') } obj[tuple[0].trim()] = tuple[1].trim() } else { obj[param] = true } } return obj } }