UNPKG

5.16 kBJavaScriptView Raw
1
2export const RouteConfig = {
3 prefix: '',
4 hasTrailingSlash: false,
5};
6
7export const Route = {
8
9 Config: RouteConfig,
10
11 _routes: {}, // object of arrays, key = URI, value = array of callbacks
12 _groupData: null,
13
14 modifyURI(uri) {
15 if (uri.lastIndexOf('/') === uri.length - 1 && !this.Config.hasTrailingSlash) {
16 uri = uri.substr(0, uri.length - 1);
17 }
18 if (uri === '' && this.Config.prefix === '') {
19 return '/';
20 }
21 return this.Config.prefix + uri;
22 },
23
24 getCurrentURI() {
25 const pref = this.Config.prefix;
26 let path = window.location.pathname;
27 if (path.indexOf(pref) === 0) {
28 path = path.substr(pref.length);
29 }
30 return path;
31 },
32
33 /**
34 * Check if current URL is attached to route (1st param)
35 * or if second optional param passed - checks against haystack_url not current URL
36 * @param uri
37 * @param haystack_url
38 * @returns {boolean}
39 */
40 is(uri, haystack_url = window.location.pathname) {
41 uri = this.modifyURI(uri);
42 const original_segments = haystack_url.split('/');
43 const route_segments = uri.split('/');
44 const original_length = original_segments.length;
45 const route_length = route_segments.length;
46 if (original_length !== route_length) {
47 return false;
48 }
49 for (let i = 1; i < original_length; i++) {
50 if (route_segments[i].indexOf('{') === -1 && route_segments[i] !== original_segments[i]) {
51 return false;
52 }
53 }
54 return true;
55 },
56
57 /**
58 * Get route named params, for example if URL is /page/{id}, then will return { id: id from url }
59 * @param uri
60 * @returns {Object}
61 */
62 getNamedParams(uri) {
63 const original_segments = window.location.pathname.split('/');
64 const route_segments = uri.split('/');
65 const route_length = route_segments.length;
66 const params = {};
67 for (let i = 1; i < route_length; i++) {
68 if (route_segments[i].indexOf('{') !== -1) {
69 let name = route_segments[i].substr(1, route_segments[i].length-2);
70 params[name] = original_segments[i];
71 }
72 }
73 return params;
74 },
75
76 /**
77 * Match URI with route, return defined route or false if coulnd't match URI with route
78 * Example:
79 * Defined route: users/{id}
80 * URI: users/42
81 * Will return users/{id}
82 * @param uri
83 * @returns {*|boolean}
84 */
85 matchURIWithRoute(uri) {
86 for (let route in this._routes) {
87 if (this.is(route, uri)) {
88 return route;
89 }
90 }
91 return false;
92 },
93
94 isDefined(uri) {
95 uri = this.modifyURI(uri);
96 return this._routes[uri] !== undefined;
97 },
98
99 /**
100 * Define new route
101 *
102 * @param {string} uri
103 * @param {callback|Function} callback
104 */
105 on(uri, callback) {
106 if (this._groupData !== null) {
107 if (this._groupData.prefix !== undefined) {
108 uri = this._groupData.prefix + uri;
109 }
110 }
111 uri = this.modifyURI(uri);
112
113 if (this._routes[uri] === undefined) {
114 this._routes[uri] = [];
115 }
116 this._routes[uri].push(callback);
117 },
118
119 /**
120 * Can be used to add prefix to all routes defined in the callback
121 *
122 * Route.group('/users', () => {
123 * Route.on('/edit/{id}', UsersEditPage);
124 * Route.on('/delete/{id}', UsersDeletePage);
125 * });
126 *
127 * @param prefix
128 * @param callback
129 */
130 group(prefix, callback) {
131 this._groupData = {prefix};
132 callback();
133 this._groupData = null;
134 },
135
136 getAllRouteNames() {
137 return Object.keys(this._routes);
138 },
139
140 getRouteCallbacks(uri) {
141 if (this._routes[uri] !== undefined) {
142 return this._routes[uri];
143 }
144 return false;
145 },
146
147 /**
148 * Call closure/controller attached to route
149 * @param uri
150 * @returns {boolean}
151 */
152 run(uri) {
153 uri = this.modifyURI(uri);
154 //console.log('trying to call route', uri);
155 const callbacks = this.getRouteCallbacks(uri);
156 if (callbacks === false) {
157 console.error('Route "' + uri + '" is not defined.');
158 return false;
159 }
160
161 const namedParams = this.getNamedParams(uri);
162
163 callbacks.forEach(cb => {
164 cb(namedParams)
165 });
166
167 return true;
168 },
169
170 /**
171 * Changes the browser URL without a refresh to a new URL and calls callbacks if that route is defined
172 * @param uri
173 * @returns {boolean}
174 */
175 to(uri) {
176 uri = this.modifyURI(uri);
177 history.pushState(null, null, uri);
178 const route = Route.matchURIWithRoute(uri);
179 const event = new CustomEvent('onRouteChange', {detail: uri});
180 event.route = route;
181 document.dispatchEvent(event);
182
183 if (route) {
184 const callbacks = this.getRouteCallbacks(route);
185 if (callbacks !== false) {
186 const namedParams = this.getNamedParams(uri);
187 callbacks.forEach(cb => {
188 cb(namedParams)
189 });
190 }
191 }
192 }
193
194};
195
196document.addEventListener('DOMContentLoaded', function() {
197 const curURI = Route.getCurrentURI();
198 const route = Route.matchURIWithRoute(curURI);
199 if (route) {
200 Route.run(route);
201 }
202}, false);