From 96fb5878f6dc3bc7362a7bed89c7c59d6e7c3217 Mon Sep 17 00:00:00 2001 From: Marek Piasecki Date: Tue, 24 Oct 2017 14:09:01 +0200 Subject: [PATCH] initial commit - moved from pro repo --- index.html | 10 ++++ package.json | 20 ++++++++ pro-router-standalone.min.js | 1 + pro-router.min.js | 1 + router.coffee | 84 +++++++++++++++++++++++++++++++ router.js | 96 +++++++++++++++++++++++++++++++++++ standalone.coffee | 85 +++++++++++++++++++++++++++++++ standalone.js | 97 ++++++++++++++++++++++++++++++++++++ 8 files changed, 394 insertions(+) create mode 100644 index.html create mode 100644 package.json create mode 100644 pro-router-standalone.min.js create mode 100644 pro-router.min.js create mode 100644 router.coffee create mode 100644 router.js create mode 100644 standalone.coffee create mode 100644 standalone.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..019c3eb --- /dev/null +++ b/index.html @@ -0,0 +1,10 @@ + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..a061780 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "pro-router", + "description": "Fully automated singleton router service for frontend. Use url as data store", + "version": "4.3.0", + "main": "router.js", + "repository": { + "type": "git", + "url": "git+https://github.com/madmaniak/pro.git" + }, + "keywords": [ + "frontend", + "router" + ], + "author": "Marek Piasecki", + "license": "ISC", + "bugs": { + "url": "https://github.com/madmaniak/pro/issues" + }, + "homepage": "https://github.com/madmaniak/pro/framework/components/router/npm_router_service" +} diff --git a/pro-router-standalone.min.js b/pro-router-standalone.min.js new file mode 100644 index 0000000..0621425 --- /dev/null +++ b/pro-router-standalone.min.js @@ -0,0 +1 @@ +window.R={_l:location,_r:history.replaceState.bind(history),_p:history.pushState.bind(history),_d:decodeURIComponent,_e:encodeURIComponent,init:function(o){if(o==null){o={}}this.root||(this.root=o.root||"root");this.views||(this.views=o.views||window.Views||[this.root]);this.render||(this.render=o.render||window.render);this.h||(this.h=o.helpers||window._);window.onpopstate=this.url_changed.bind(this);this.read()},cache:{},getters:{},setters:{},param:function(k){var base;if(this.getters[k]){return(base=this.cache)[k]||(base[k]=this.getters[k](this._d(this.params[k]||"")))}else{return this._d(this.params[k]||"")}},write:function(){var i,j,k,l,v;for(i=j=0,l=arguments.length;j + @root ||= opts.root || 'root' + @views ||= opts.views || window.Views || [@root] + @render ||= opts.render || window.render + @h ||= opts.helpers || window._ + window.onpopstate = @url_changed.bind(@) + @read() + + cache: {} + getters: {} + setters: {} + + #
+ + param: (key) -> + if @getters[key] + then @cache[key] ||= @getters[key]( @_decodeURIComponent(@params[key] || '') ) + else @_decodeURIComponent(@params[key] || '') + + write: -> + # accept arguments keeping key, value, key, value order + # serialize using setters + # if no argument given just refresh url and rerender + for k, i in arguments + unless i % 2 + v = arguments[i+1] + @_write(k,v) + + @_replaceState {}, + @_location.pathname, @to_path(@view, @params) + @url_changed() + + _write: (k,v) -> + value = if @setters[k] then @setters[k](v) else v + if value + then @params[k] = @_encodeURIComponent(value) + else delete @params[k] + + toggle: (flag, state) -> + @write flag, if state? + then ( 1 if state ) + else ( 1 if !@params[flag] ) + + go: (path) -> + @_pushState {}, null, path + @url_changed() + + #
+ + read: -> + [@view, @params] = @split_path @_location.pathname + @_safe_params() + + split_path: (path) -> + return [ @root, {} ] if path.length == 1 + list = @h.compact path.split("/") + view = @_existance list.shift() + params = @h.fromPairs @h.chunk(list, 2) + [ view, params ] + + _existance: (view) -> + if @h.includes(@views, view) then view else 'not_found' + + _safe_params: -> + @safe_params = @h.fromPairs @h.reject @h.toPairs(@params), (pair) -> + /^_/.test pair[0] + + to_path: (view = @view, params = @safe_params) -> + array = @h.flatten @h.toPairs(params) + '/' + view + '/' + array.join('/') + + url_changed: -> + @cache = {} + @read() + @render() diff --git a/router.js b/router.js new file mode 100644 index 0000000..79e246c --- /dev/null +++ b/router.js @@ -0,0 +1,96 @@ +module.exports = window.R = { + _location: location, + _replaceState: history.replaceState.bind(history), + _pushState: history.pushState.bind(history), + _decodeURIComponent: decodeURIComponent, + _encodeURIComponent: encodeURIComponent, + init: function(opts) { + if (opts == null) { + opts = {}; + } + this.root || (this.root = opts.root || 'root'); + this.views || (this.views = opts.views || window.Views || [this.root]); + this.render || (this.render = opts.render || window.render); + this.h || (this.h = opts.helpers || window._); + window.onpopstate = this.url_changed.bind(this) + this.read(); + }, + cache: {}, + getters: {}, + setters: {}, + param: function(key) { + var base; + if (this.getters[key]) { + return (base = this.cache)[key] || (base[key] = this.getters[key](this._decodeURIComponent(this.params[key] || ''))); + } else { + return this._decodeURIComponent(this.params[key] || ''); + } + }, + write: function() { + var i, j, k, len, v; + for (i = j = 0, len = arguments.length; j < len; i = ++j) { + k = arguments[i]; + if (!(i % 2)) { + v = arguments[i + 1]; + this._write(k, v); + } + } + this._replaceState({}, this._location.pathname, this.to_path(this.view, this.params)); + this.url_changed(); + }, + _write: function(k, v) { + var value = this.setters[k] ? this.setters[k](v) : v; + value ? this.params[k] = this._encodeURIComponent(value) : delete this.params[k]; + }, + toggle: function(flag, state) { + this.write(flag, state != null ? (state ? 1 : void 0) : (!this.params[flag] ? 1 : void 0)); + }, + go: function(path) { + this._pushState({}, null, path); + this.url_changed(); + }, + read: function() { + var ref; + ref = this.split_path(this._location.pathname), this.view = ref[0], this.params = ref[1]; + this._safe_params(); + }, + split_path: function(path) { + if (path.length == 1) { + return [this.root, {}]; + } + var list, params, view; + list = this.h.compact(path.split("/")); + view = this._existance(list.shift()); + params = this.h.fromPairs(this.h.chunk(list, 2)); + return [view, params]; + }, + _existance: function(view) { + if (this.h.includes(this.views, view)) { + return view; + } else { + return 'not_found'; + } + }, + _safe_params: function() { + return this.safe_params = this.h.fromPairs(this.h.reject(this.h.toPairs(this.params), function(pair) { + return /^_/.test(pair[0]); + })); + }, + to_path: function(view, params) { + var array; + if (view == null) { + view = this.view; + } + if (params == null) { + params = this.safe_params; + } + array = this.h.flatten(this.h.toPairs(params)); + return '/' + view + '/' + array.join('/'); + }, + url_changed: function() { + this.cache = {}; + this.read(); + this.render(); + } + +}; diff --git a/standalone.coffee b/standalone.coffee new file mode 100644 index 0000000..a45267a --- /dev/null +++ b/standalone.coffee @@ -0,0 +1,85 @@ +module.exports = window.R = + + # local cache + _location: location + _replaceState: history.replaceState.bind(history) + _pushState: history.pushState.bind(history) + _decodeURIComponent: decodeURIComponent + _encodeURIComponent: encodeURIComponent + + init: (opts = {}) -> + @root ||= opts.root || 'root' + @views ||= opts.views || window.Views || [@root] + @render ||= opts.render || window.render + @h ||= opts.helpers || window._ + window.onpopstate = @url_changed.bind(@) + @read() + + cache: {} + getters: {} + setters: {} + + #
+ + param: (key) -> + if @getters[key] + then @cache[key] ||= @getters[key]( @_decodeURIComponent(@params[key] || '') ) + else @_decodeURIComponent(@params[key] || '') + + write: -> + # accept arguments keeping key, value, key, value order + # serialize using setters + # if no argument given just refresh url and rerender + for k, i in arguments + unless i % 2 + v = arguments[i+1] + @_write(k,v) + + @_replaceState {}, + @_location.pathname, @to_path(@view, @params) + @url_changed() + + _write: (k,v) -> + value = if @setters[k] then @setters[k](v) else v + if value + then @params[k] = @_encodeURIComponent(value) + else delete @params[k] + + toggle: (flag, state) -> + @write flag, if state? + then ( 1 if state ) + else ( 1 if !@params[flag] ) + + go: (path) -> + @_pushState {}, null, path + @url_changed() + + #
+ + read: -> + [@view, @params] = @split_path @_location.hash + @_safe_params() + + split_path: (path) -> + path = path.slice(2) + return [ @root, {} ] unless path.length + list = @h.compact path.split("/") + view = @_existance list.shift() + params = @h.fromPairs @h.chunk(list, 2) + [ view, params ] + + _existance: (view) -> + if @h.includes(@views, view) then view else 'not_found' + + _safe_params: -> + @safe_params = @h.fromPairs @h.reject @h.toPairs(@params), (pair) -> + /^_/.test pair[0] + + to_path: (view = @view, params = @safe_params) -> + array = @h.flatten @h.toPairs(params) + '#/' + view + '/' + array.join('/') + + url_changed: -> + @cache = {} + @read() + @render() diff --git a/standalone.js b/standalone.js new file mode 100644 index 0000000..41c45e6 --- /dev/null +++ b/standalone.js @@ -0,0 +1,97 @@ +module.exports = window.R = { + _location: location, + _replaceState: history.replaceState.bind(history), + _pushState: history.pushState.bind(history), + _decodeURIComponent: decodeURIComponent, + _encodeURIComponent: encodeURIComponent, + init: function(opts) { + if (opts == null) { + opts = {}; + } + this.root || (this.root = opts.root || 'root'); + this.views || (this.views = opts.views || window.Views || [this.root]); + this.render || (this.render = opts.render || window.render); + this.h || (this.h = opts.helpers || window._); + window.onpopstate = this.url_changed.bind(this) + this.read(); + }, + cache: {}, + getters: {}, + setters: {}, + param: function(key) { + var base; + if (this.getters[key]) { + return (base = this.cache)[key] || (base[key] = this.getters[key](this._decodeURIComponent(this.params[key] || ''))); + } else { + return this._decodeURIComponent(this.params[key] || ''); + } + }, + write: function() { + var i, j, k, len, v; + for (i = j = 0, len = arguments.length; j < len; i = ++j) { + k = arguments[i]; + if (!(i % 2)) { + v = arguments[i + 1]; + this._write(k, v); + } + } + this._replaceState({}, this._location.pathname, this.to_path(this.view, this.params)); + this.url_changed(); + }, + _write: function(k, v) { + var value = this.setters[k] ? this.setters[k](v) : v; + value ? this.params[k] = this._encodeURIComponent(value) : delete this.params[k]; + }, + toggle: function(flag, state) { + this.write(flag, state != null ? (state ? 1 : void 0) : (!this.params[flag] ? 1 : void 0)); + }, + go: function(path) { + this._pushState({}, null, path); + this.url_changed(); + }, + read: function() { + var ref; + ref = this.split_path(this._location.hash), this.view = ref[0], this.params = ref[1]; + this._safe_params(); + }, + split_path: function(path) { + path = path.slice(2); + if (!path.length) { + return [this.root, {}]; + } + var list, params, view; + list = this.h.compact(path.split("/")); + view = this._existance(list.shift()); + params = this.h.fromPairs(this.h.chunk(list, 2)); + return [view, params]; + }, + _existance: function(view) { + if (this.h.includes(this.views, view)) { + return view; + } else { + return 'not_found'; + } + }, + _safe_params: function() { + return this.safe_params = this.h.fromPairs(this.h.reject(this.h.toPairs(this.params), function(pair) { + return /^_/.test(pair[0]); + })); + }, + to_path: function(view, params) { + var array; + if (view == null) { + view = this.view; + } + if (params == null) { + params = this.safe_params; + } + array = this.h.flatten(this.h.toPairs(params)); + return '#/' + view + '/' + array.join('/'); + }, + url_changed: function() { + this.cache = {}; + this.read(); + this.render(); + } + +};