@trullock/page-manager 0.14.1 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +56 -62
- package/dist/main.js +0 -116
- package/tests/dist/index.html +0 -23
- package/tests/dist/main.js +0 -1525
- package/tests/dist/main.js.map +0 -1
- package/tests/dist/page1.htm +0 -6
- package/tests/dist/page2.htm +0 -4
- package/tests/dist/page3.htm +0 -5
- package/tests/dist/page4.htm +0 -4
- package/tests/dist/page404.htm +0 -3
- package/tests/dist/pageX.htm +0 -4
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -14,19 +14,18 @@ var goal = null;
|
|
|
14
14
|
var backData = {};
|
|
15
15
|
var options = {
|
|
16
16
|
fetchPath: route => '/pages/' + route.routeName + '.html',
|
|
17
|
-
fetchPageTemplate: route => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
17
|
+
fetchPageTemplate: async route => {
|
|
18
|
+
const response = await fetch(options.fetchPath(route));
|
|
19
|
+
const html = await response.text();
|
|
20
|
+
|
|
21
|
+
var $div = document.createElement('div');
|
|
22
|
+
$div.innerHTML = html;
|
|
23
|
+
const $template = $div.firstElementChild;
|
|
24
|
+
|
|
25
|
+
// TODO: why is this in here and not in the caller?
|
|
26
|
+
pageTemplateCache[route.pattern] = $template;
|
|
27
|
+
|
|
28
|
+
return $template;
|
|
30
29
|
},
|
|
31
30
|
pageInterrupt: route => null,
|
|
32
31
|
attachMarkup: $html => document.body.appendChild($html),
|
|
@@ -120,29 +119,30 @@ function hideLoading() {
|
|
|
120
119
|
return Promise.resolve(page.hide());
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
function loadPage(route, data) {
|
|
122
|
+
async function loadPage(route, data) {
|
|
124
123
|
|
|
125
124
|
var fetchPage = pageTemplateCache[route.pattern] ? Promise.resolve(pageTemplateCache[route.pattern]) : options.fetchPageTemplate(route);
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
var $html = $template.cloneNode(true);
|
|
129
|
-
options.prepareMarkup($html);
|
|
130
|
-
options.attachMarkup($html);
|
|
131
|
-
|
|
132
|
-
let page = new (route.pageClass)($html);
|
|
126
|
+
const $template = await fetchPage;
|
|
133
127
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
128
|
+
var $html = $template.cloneNode(true);
|
|
129
|
+
options.prepareMarkup($html);
|
|
130
|
+
options.attachMarkup($html);
|
|
131
|
+
|
|
132
|
+
let page = new (route.pageClass)($html);
|
|
133
|
+
|
|
134
|
+
await Promise.resolve(page.boot(data));
|
|
135
|
+
|
|
136
|
+
let cacheKey = route.pageClass.cacheMarkupBy == 'path' ? route.path : route.pattern;
|
|
137
|
+
pageCache[cacheKey] = {
|
|
138
|
+
$html,
|
|
139
|
+
page
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return page;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
function showPage(url, data, event) {
|
|
145
|
+
async function showPage(url, data, event) {
|
|
146
146
|
var route = router.parse(url);
|
|
147
147
|
if (route == null) {
|
|
148
148
|
console.error(`Can't find page: '${url}'`);
|
|
@@ -163,7 +163,7 @@ function showPage(url, data, event) {
|
|
|
163
163
|
};
|
|
164
164
|
data.event = event;
|
|
165
165
|
|
|
166
|
-
let interrupt = options.pageInterrupt(route);
|
|
166
|
+
let interrupt = await Promise.resolve(options.pageInterrupt(route));
|
|
167
167
|
if(interrupt)
|
|
168
168
|
{
|
|
169
169
|
goal = { url, data };
|
|
@@ -183,43 +183,40 @@ function showPage(url, data, event) {
|
|
|
183
183
|
// handle initial page
|
|
184
184
|
if (event.action == 'load')
|
|
185
185
|
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
return page;
|
|
202
|
-
});
|
|
186
|
+
const page = await getPage;
|
|
187
|
+
await doShow(page, data);
|
|
188
|
+
// clean initial load
|
|
189
|
+
if (stackPointer == -1) {
|
|
190
|
+
stack.push({ uid: 0, data, page });
|
|
191
|
+
stackPointer = 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// page refresh
|
|
195
|
+
else {
|
|
196
|
+
stack[stackPointer].page = page;
|
|
197
|
+
stack[stackPointer].data = data;
|
|
198
|
+
}
|
|
199
|
+
return page;
|
|
203
200
|
}
|
|
204
201
|
|
|
205
202
|
let currentState = stack[stackPointer];
|
|
206
203
|
|
|
207
204
|
if (currentState.data.route.path == route.path) {
|
|
208
205
|
handleHistoryAction(event, url, data, currentState.page);
|
|
209
|
-
|
|
206
|
+
const page = await getPage;
|
|
207
|
+
await doUpdate(page, data);
|
|
208
|
+
return page;
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
currentState.data.scrollY = window.scrollY;
|
|
213
212
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return doShow(page, data);
|
|
222
|
-
});
|
|
213
|
+
const results = await Promise.all([
|
|
214
|
+
currentState.page.hide(event),
|
|
215
|
+
getPage
|
|
216
|
+
]);
|
|
217
|
+
const page = results[1];
|
|
218
|
+
handleHistoryAction(event, url, data, page);
|
|
219
|
+
await doShow(page, data);
|
|
223
220
|
// .catch(e => {
|
|
224
221
|
// // TODO: what case is this?
|
|
225
222
|
// manuallyAdjustingHistory = () => manuallyAdjustingHistory = false;
|
|
@@ -228,6 +225,7 @@ function showPage(url, data, event) {
|
|
|
228
225
|
// else if (event.action == 'fwd')
|
|
229
226
|
// history.go(-1);
|
|
230
227
|
// });
|
|
228
|
+
return page
|
|
231
229
|
}
|
|
232
230
|
|
|
233
231
|
async function doShow(page, data) {
|
|
@@ -237,17 +235,13 @@ async function doShow(page, data) {
|
|
|
237
235
|
await Promise.resolve(page.show(data));
|
|
238
236
|
document.title = page.title;
|
|
239
237
|
await hideLoading();
|
|
240
|
-
return page;
|
|
241
238
|
}
|
|
242
239
|
|
|
243
|
-
|
|
244
240
|
async function doUpdate(page, data) {
|
|
245
241
|
|
|
246
242
|
await Promise.resolve(page.update(data));
|
|
247
243
|
document.title = page.title
|
|
248
|
-
// todo: hide() should be passed an event object
|
|
249
244
|
await hideLoading();
|
|
250
|
-
return page;
|
|
251
245
|
}
|
|
252
246
|
|
|
253
247
|
function handleHistoryAction(event, url, data, page) {
|
package/dist/main.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
|
|
3
|
-
* This devtool is neither made for production nor for readable output files.
|
|
4
|
-
* It uses "eval()" calls to create a separate source file in the browser devtools.
|
|
5
|
-
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
|
6
|
-
* or disable the default devtool with "devtool: false".
|
|
7
|
-
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
|
8
|
-
*/
|
|
9
|
-
/******/ (() => { // webpackBootstrap
|
|
10
|
-
/******/ "use strict";
|
|
11
|
-
/******/ var __webpack_modules__ = ({
|
|
12
|
-
|
|
13
|
-
/***/ "./node_modules/@trullock/router/src/index.js":
|
|
14
|
-
/*!****************************************************!*\
|
|
15
|
-
!*** ./node_modules/@trullock/router/src/index.js ***!
|
|
16
|
-
\****************************************************/
|
|
17
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
18
|
-
|
|
19
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _pattern_lexer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./pattern-lexer.js */ \"./node_modules/@trullock/router/src/pattern-lexer.js\");\n\r\n\r\nfunction isKind(val, kind) {\r\n\treturn '[object ' + kind + ']' === Object.prototype.toString.call(val);\r\n}\r\nfunction isRegExp(val) {\r\n\treturn isKind(val, 'RegExp');\r\n}\r\n\r\nfunction decodeQueryString(queryStr, shouldTypecast) {\r\n\tvar queryArr = (queryStr || '').replace('?', '').split('&'),\r\n\t\treg = /([^=]+)=(.+)/,\r\n\t\ti = -1,\r\n\t\tobj = {},\r\n\t\tequalIndex, cur, pValue, pName;\r\n\r\n\twhile ((cur = queryArr[++i])) {\r\n\t\tequalIndex = cur.indexOf('=');\r\n\t\tpName = cur.substring(0, equalIndex);\r\n\t\tpValue = decodeURIComponent(cur.substring(equalIndex + 1));\r\n\r\n\t\tif (pName in obj){\r\n\t\t\tif(isArray(obj[pName])){\r\n\t\t\t\tobj[pName].push(pValue);\r\n\t\t\t} else {\r\n\t\t\t\tobj[pName] = [obj[pName], pValue];\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tobj[pName] = pValue;\r\n\t }\r\n\t}\r\n\treturn obj;\r\n}\r\n\r\nfunction Route(name, pattern, pageClass, priority, router) {\r\n\tvar isRegexPattern = isRegExp(pattern);\r\n\tthis._name = name;\r\n\tthis._router = router;\r\n\tthis._pattern = pattern;\r\n\tthis._paramsIds = isRegexPattern ? null : router.patternLexer.getParamIds(pattern);\r\n\tthis._optionalParamsIds = isRegexPattern ? null : router.patternLexer.getOptionalParamsIds(pattern);\r\n\tthis._matchRegexp = isRegexPattern ? pattern : router.patternLexer.compilePattern(pattern, router.ignoreCase);\r\n\tthis._pageClass = pageClass;\r\n\tthis._priority = priority || 0;\r\n}\r\n\r\nRoute.prototype = {\r\n\r\n\tmatch: function (request) {\r\n\t\treturn this._matchRegexp.test(request);\r\n\t},\r\n\r\n\t_isValidParam: function (request, prop, values) {\r\n\t\tvar validationRule = this.rules[prop],\r\n\t\t\tval = values[prop],\r\n\t\t\tisValid = false,\r\n\t\t\tisQuery = (prop.indexOf('?') === 0);\r\n\r\n\t\tif (val == null && this._optionalParamsIds && arrayIndexOf(this._optionalParamsIds, prop) !== -1) {\r\n\t\t\tisValid = true;\r\n\t\t}\r\n\t\telse if (isRegExp(validationRule)) {\r\n\t\t\tif (isQuery)\r\n\t\t\t\tval = values[prop + '_']; //use raw string\r\n\r\n\t\t\tisValid = validationRule.test(val);\r\n\t\t}\r\n\t\telse if (isArray(validationRule)) {\r\n\t\t\tif (isQuery)\r\n\t\t\t\tval = values[prop + '_']; //use raw string\r\n\r\n\t\t\tisValid = this._isValidArrayRule(validationRule, val);\r\n\t\t}\r\n\t\telse if (isFunction(validationRule)) {\r\n\t\t\tisValid = validationRule(val, request, values);\r\n\t\t}\r\n\r\n\t\treturn isValid; //fail silently if validationRule is from an unsupported type\r\n\t},\r\n\r\n\t_isValidArrayRule: function (arr, val) {\r\n\t\tif (!this._router.ignoreCase) {\r\n\t\t\treturn arrayIndexOf(arr, val) !== -1;\r\n\t\t}\r\n\r\n\t\tif (typeof val === 'string') {\r\n\t\t\tval = val.toLowerCase();\r\n\t\t}\r\n\r\n\t\tvar n = arr.length,\r\n\t\t\titem,\r\n\t\t\tcompareVal;\r\n\r\n\t\twhile (n--) {\r\n\t\t\titem = arr[n];\r\n\t\t\tcompareVal = (typeof item === 'string') ? item.toLowerCase() : item;\r\n\t\t\tif (compareVal === val) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t},\r\n\r\n\t_getParamsObject: function (request) {\r\n\t\tvar shouldTypecast = this._router.shouldTypecast,\r\n\t\t\tvalues = this._router.patternLexer.getParamValues(request, this._matchRegexp, shouldTypecast),\r\n\t\t\to = {},\r\n\t\t\tn = values.length,\r\n\t\t\tparam, val;\r\n\t\twhile (n--) {\r\n\t\t\tval = values[n];\r\n\t\t\tif (this._paramsIds) {\r\n\t\t\t\tparam = this._paramsIds[n];\r\n\t\t\t\tif (param.indexOf('?') === 0 && val) {\r\n\t\t\t\t\tval = decodeQueryString(val, shouldTypecast);\r\n\t\t\t\t\t\r\n\t\t\t\t\tfor(var key in val){\r\n\t\t\t\t\t\tif(!o[key])\r\n\t\t\t\t\t\t\to[key] = val[key];\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\to['?' + key] = val[key];\r\n\t\t\t\t\t}\r\n\t\t\t\t\to[n] = val;\r\n\t\t\t\t} \r\n\t\t\t\telse \r\n\t\t\t\t\to[param] = val;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn o;\r\n\t},\r\n\r\n\tinterpolate: function (replacements) {\r\n\t\ttry {\r\n\t\t\tvar str = this._router.patternLexer.interpolate(this._pattern, replacements);\r\n\t\t\treturn str;\r\n\t\t}\r\n\t\tcatch(e) {\r\n\t\t\tthrow new Error(`Error interpolating route ${this._pattern} with values ${JSON.stringify(replacements)}\\n` + e);\r\n\t\t}\r\n\t},\r\n\r\n\ttoString: function () {\r\n\t\treturn '[Route pattern:\"' + this._pattern + '\", numListeners:' + this.matched.getNumListeners() + ']';\r\n\t}\r\n\r\n};\r\n\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (new class {\r\n\tconstructor() {\r\n\t\tthis.routes = [];\r\n\t\tthis.routesByName = {};\r\n\t\tthis.patternLexer = (0,_pattern_lexer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])();\r\n\t}\r\n\r\n\taddRoute (name, pattern, pageClass, priority) {\r\n\t\tpattern += pattern.endsWith('/') ? ':?query:' : '/:?query:';\r\n\t\tvar route = new Route(name, pattern, pageClass, priority, this);\r\n\r\n\t\tvar n = this.routes.length;\r\n\t\tdo\r\n\t\t{ \r\n\t\t\t--n; \r\n\t\t} while (this.routes[n] && route._priority <= this.routes[n]._priority);\r\n\t\tthis.routes.splice(n + 1, 0, route);\r\n\r\n\t\tthis.routesByName[name] = route;\r\n\t\tObject.defineProperty(this, name, { get: () => pattern });\r\n\r\n\t\treturn route;\r\n\t}\r\n\r\n\tinterpolate(name, data){\r\n\t\tif(!this.routesByName[name])\r\n\t\t\tthrow new Error(`Cannot find route by name ${name}`);\r\n\t\t\t\r\n\t\treturn this.routesByName[name].interpolate(data);\r\n\t}\r\n\r\n\tparse (request) {\r\n\t\tvar n = this.routes.length;\r\n\t\tvar route, hash, path;\r\n\r\n\t\tvar index = request.indexOf('#');\r\n\t\tif(index > -1)\r\n\t\t{\r\n\t\t\thash = request.substr(index + 1);\r\n\t\t\trequest = request.substr(0, index);\r\n\t\t}\r\n\r\n\t\tindex = request.indexOf('?');\r\n\t\tif(index > -1)\r\n\t\t\tpath = request.substr(0, index)\r\n\t\telse\r\n\t\t\tpath = request;\t\r\n\t\t\r\n\r\n\t\twhile (route = this.routes[--n]) {\r\n\t\t\tif (route.match(request)) {\r\n\t\t\t\tvar params = route._getParamsObject(request);\r\n\t\t\t\tparams.hash = hash;\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\tpath: path.toLowerCase(),\r\n\t\t\t\t\trouteName: route._name,\r\n\t\t\t\t\tpattern: route._pattern,\r\n\t\t\t\t\tpageClass: route._pageClass,\r\n\t\t\t\t\tparams: params\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn null;\r\n\t}\r\n\r\n\ttoString () {\r\n\t\treturn '[Router numRoutes:' + this.getNumRoutes() + ']';\r\n\t}\r\n}());\n\n//# sourceURL=webpack://@trullock/page-manager/./node_modules/@trullock/router/src/index.js?");
|
|
20
|
-
|
|
21
|
-
/***/ }),
|
|
22
|
-
|
|
23
|
-
/***/ "./node_modules/@trullock/router/src/pattern-lexer.js":
|
|
24
|
-
/*!************************************************************!*\
|
|
25
|
-
!*** ./node_modules/@trullock/router/src/pattern-lexer.js ***!
|
|
26
|
-
\************************************************************/
|
|
27
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
28
|
-
|
|
29
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\r\n\r\n\tvar\r\n\t\t//match chars that should be escaped on string regexp\r\n\t\tESCAPE_CHARS_REGEXP = /[\\\\.+*?\\^$\\[\\](){}\\/'#]/g,\r\n\r\n\t\t//trailing slashes (begin/end of string)\r\n\t\tLOOSE_SLASHES_REGEXP = /^\\/|\\/$/g,\r\n\t\tLEGACY_SLASHES_REGEXP = /\\/$/g,\r\n\r\n\t\t//params - everything between `{ }` or `: :`\r\n\t\tPARAMS_REGEXP = /(?:\\{|:)([^}:]+)(?:\\}|:)/g,\r\n\r\n\t\t//used to save params during compile (avoid escaping things that\r\n\t\t//shouldn't be escaped).\r\n\t\tTOKENS = {\r\n\t\t\t'OS': {\r\n\t\t\t\t//optional slashes\r\n\t\t\t\t//slash between `::` or `}:` or `\\w:` or `:{?` or `}{?` or `\\w{?`\r\n\t\t\t\trgx: /([:}]|\\w(?=\\/))\\/?(:|(?:\\{\\?))/g,\r\n\t\t\t\tsave: '$1{{id}}$2',\r\n\t\t\t\tres: '\\\\/?'\r\n\t\t\t},\r\n\t\t\t'RS': {\r\n\t\t\t\t//required slashes\r\n\t\t\t\t//used to insert slash between `:{` and `}{`\r\n\t\t\t\trgx: /([:}])\\/?(\\{)/g,\r\n\t\t\t\tsave: '$1{{id}}$2',\r\n\t\t\t\tres: '\\\\/'\r\n\t\t\t},\r\n\t\t\t'RQ': {\r\n\t\t\t\t//required query string - everything in between `{? }`\r\n\t\t\t\trgx: /\\{\\?([^}]+)\\}/g,\r\n\t\t\t\t//everything from `?` till `#` or end of string\r\n\t\t\t\tres: '\\\\?([^#]+)'\r\n\t\t\t},\r\n\t\t\t'OQ': {\r\n\t\t\t\t//optional query string - everything in between `:? :`\r\n\t\t\t\trgx: /:\\?([^:]+):/g,\r\n\t\t\t\t//everything from `?` till `#` or end of string\r\n\t\t\t\tres: '(?:\\\\?([^#]*))?'\r\n\t\t\t},\r\n\t\t\t'OR': {\r\n\t\t\t\t//optional rest - everything in between `: *:`\r\n\t\t\t\trgx: /:([^:]+)\\*:/g,\r\n\t\t\t\tres: '(.*)?' // optional group to avoid passing empty string as captured\r\n\t\t\t},\r\n\t\t\t'RR': {\r\n\t\t\t\t//rest param - everything in between `{ *}`\r\n\t\t\t\trgx: /\\{([^}]+)\\*\\}/g,\r\n\t\t\t\tres: '(.+)'\r\n\t\t\t},\r\n\t\t\t// required/optional params should come after rest segments\r\n\t\t\t'RP': {\r\n\t\t\t\t//required params - everything between `{ }`\r\n\t\t\t\trgx: /\\{([^}]+)\\}/g,\r\n\t\t\t\tres: '([^\\\\/?]+)'\r\n\t\t\t},\r\n\t\t\t'OP': {\r\n\t\t\t\t//optional params - everything between `: :`\r\n\t\t\t\trgx: /:([^:]+):/g,\r\n\t\t\t\tres: '([^\\\\/?]+)?\\/?'\r\n\t\t\t}\r\n\t\t},\r\n\r\n\t\tLOOSE_SLASH = 1,\r\n\t\tSTRICT_SLASH = 2,\r\n\t\tLEGACY_SLASH = 3,\r\n\r\n\t\t_slashMode = LOOSE_SLASH;\r\n\r\n\r\n\tfunction precompileTokens() {\r\n\t\tvar key, cur;\r\n\t\tfor (key in TOKENS) {\r\n\t\t\tif (TOKENS.hasOwnProperty(key)) {\r\n\t\t\t\tcur = TOKENS[key];\r\n\t\t\t\tcur.id = '__CR_' + key + '__';\r\n\t\t\t\tcur.save = ('save' in cur) ? cur.save.replace('{{id}}', cur.id) : cur.id;\r\n\t\t\t\tcur.rRestore = new RegExp(cur.id, 'g');\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tprecompileTokens();\r\n\r\n\r\n\tfunction captureVals(regex, pattern) {\r\n\t\tvar vals = [], match;\r\n\t\t// very important to reset lastIndex since RegExp can have \"g\" flag\r\n\t\t// and multiple runs might affect the result, specially if matching\r\n\t\t// same string multiple times on IE 7-8\r\n\t\tregex.lastIndex = 0;\r\n\t\twhile (match = regex.exec(pattern)) {\r\n\t\t\tvals.push(match[1]);\r\n\t\t}\r\n\t\treturn vals;\r\n\t}\r\n\r\n\tfunction getParamIds(pattern) {\r\n\t\treturn captureVals(PARAMS_REGEXP, pattern);\r\n\t}\r\n\r\n\tfunction getOptionalParamsIds(pattern) {\r\n\t\treturn captureVals(TOKENS.OP.rgx, pattern);\r\n\t}\r\n\r\n\tfunction compilePattern(pattern, ignoreCase) {\r\n\t\tpattern = pattern || '';\r\n\r\n\t\tif (pattern) {\r\n\t\t\tif (_slashMode === LOOSE_SLASH) {\r\n\t\t\t\tpattern = pattern.replace(LOOSE_SLASHES_REGEXP, '');\r\n\t\t\t}\r\n\t\t\telse if (_slashMode === LEGACY_SLASH) {\r\n\t\t\t\tpattern = pattern.replace(LEGACY_SLASHES_REGEXP, '');\r\n\t\t\t}\r\n\r\n\t\t\t//save tokens\r\n\t\t\tpattern = replaceTokens(pattern, 'rgx', 'save');\r\n\t\t\t//regexp escape\r\n\t\t\tpattern = pattern.replace(ESCAPE_CHARS_REGEXP, '\\\\$&');\r\n\t\t\t//restore tokens\r\n\t\t\tpattern = replaceTokens(pattern, 'rRestore', 'res');\r\n\r\n\t\t\tif (_slashMode === LOOSE_SLASH) {\r\n\t\t\t\tpattern = '\\\\/?' + pattern;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (_slashMode !== STRICT_SLASH) {\r\n\t\t\t//single slash is treated as empty and end slash is optional\r\n\t\t\tpattern += '\\\\/?';\r\n\t\t}\r\n\t\treturn new RegExp('^' + pattern + '$', ignoreCase ? 'i' : '');\r\n\t}\r\n\r\n\tfunction replaceTokens(pattern, regexpName, replaceName) {\r\n\t\tvar cur, key;\r\n\t\tfor (key in TOKENS) {\r\n\t\t\tif (TOKENS.hasOwnProperty(key)) {\r\n\t\t\t\tcur = TOKENS[key];\r\n\t\t\t\tpattern = pattern.replace(cur[regexpName], cur[replaceName]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn pattern;\r\n\t}\r\n\r\n\tfunction getParamValues(request, regexp, shouldTypecast) {\r\n\t\tvar vals = regexp.exec(request);\r\n\t\tif (vals) {\r\n\t\t\tvals.shift();\r\n\t\t\tif (shouldTypecast) {\r\n\t\t\t\tvals = typecastArrayValues(vals);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn vals;\r\n\t}\r\n\r\n\tfunction interpolate(pattern, replacements) {\r\n\t\t// default to an empty object because pattern might have just\r\n\t\t// optional arguments\r\n\t\treplacements = replacements || {};\r\n\t\tif (typeof pattern !== 'string') {\r\n\t\t\tthrow new Error('Route pattern should be a string.');\r\n\t\t}\r\n\t\t\r\n\t\tvar replaceFn = function (match, prop) {\r\n\t\t\tvar val;\r\n\t\t\tprop = (prop.substr(0, 1) === '?') ? prop.substr(1) : prop;\r\n\t\t\tif (replacements[prop] != null) {\r\n\t\t\t\tif (typeof replacements[prop] === 'object') {\r\n\t\t\t\t\tvar queryParts = [], rep;\r\n\t\t\t\t\tfor (var key in replacements[prop]) {\r\n\t\t\t\t\t\trep = replacements[prop][key];\r\n\t\t\t\t\t\tif (isArray(rep)) {\r\n\t\t\t\t\t\t\tfor (var k in rep) {\r\n\t\t\t\t\t\t\t\tif (key.slice(-2) == '[]') {\r\n\t\t\t\t\t\t\t\t\tqueryParts.push(encodeURIComponent(key.slice(0, -2)) + '[]=' + encodeURIComponent(rep[k]));\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tqueryParts.push(encodeURIComponent(key + '=' + rep[k]));\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tqueryParts.push(encodeURIComponent(key + '=' + rep));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tval = '?' + queryParts.join('&');\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// make sure value is a string see #gh-54\r\n\t\t\t\t\tval = String(replacements[prop]);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (match.indexOf('*') === -1 && val.indexOf('/') !== -1) {\r\n\t\t\t\t\tthrow new Error('Invalid value \"' + val + '\" for segment \"' + match + '\".');\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse if (match.indexOf('{') !== -1) {\r\n\t\t\t\tthrow new Error('The segment ' + match + ' is required.');\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tval = '';\r\n\t\t\t}\r\n\t\t\treturn val;\r\n\t\t};\r\n\r\n\t\tif (!TOKENS.OS.trail) {\r\n\t\t\tTOKENS.OS.trail = new RegExp('(?:' + TOKENS.OS.id + ')+$');\r\n\t\t}\r\n\r\n\t\treturn pattern\r\n\t\t\t.replace(TOKENS.OS.rgx, TOKENS.OS.save)\r\n\t\t\t.replace(PARAMS_REGEXP, replaceFn)\r\n\t\t\t.replace(TOKENS.OS.trail, '') // remove trailing\r\n\t\t\t.replace(TOKENS.OS.rRestore, '/'); // add slash between segments\r\n\t}\r\n\r\n\t//API\r\n\treturn {\r\n\t\tstrict: function () {\r\n\t\t\t_slashMode = STRICT_SLASH;\r\n\t\t},\r\n\t\tloose: function () {\r\n\t\t\t_slashMode = LOOSE_SLASH;\r\n\t\t},\r\n\t\tlegacy: function () {\r\n\t\t\t_slashMode = LEGACY_SLASH;\r\n\t\t},\r\n\t\tgetParamIds: getParamIds,\r\n\t\tgetOptionalParamsIds: getOptionalParamsIds,\r\n\t\tgetParamValues: getParamValues,\r\n\t\tcompilePattern: compilePattern,\r\n\t\tinterpolate: interpolate\r\n\t};\r\n\r\n}\n\n//# sourceURL=webpack://@trullock/page-manager/./node_modules/@trullock/router/src/pattern-lexer.js?");
|
|
30
|
-
|
|
31
|
-
/***/ }),
|
|
32
|
-
|
|
33
|
-
/***/ "./src/index.js":
|
|
34
|
-
/*!**********************!*\
|
|
35
|
-
!*** ./src/index.js ***!
|
|
36
|
-
\**********************/
|
|
37
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
38
|
-
|
|
39
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"back\": () => (/* binding */ back),\n/* harmony export */ \"getPath\": () => (/* binding */ getPath),\n/* harmony export */ \"init\": () => (/* binding */ init),\n/* harmony export */ \"navigate\": () => (/* binding */ navigate),\n/* harmony export */ \"pages\": () => (/* binding */ pages),\n/* harmony export */ \"printStack\": () => (/* binding */ printStack),\n/* harmony export */ \"purgeCache\": () => (/* binding */ purgeCache),\n/* harmony export */ \"registerPage\": () => (/* binding */ registerPage),\n/* harmony export */ \"removeHistory\": () => (/* binding */ removeHistory),\n/* harmony export */ \"replace\": () => (/* binding */ replace),\n/* harmony export */ \"show\": () => (/* binding */ show)\n/* harmony export */ });\n/* harmony import */ var _trullock_router__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @trullock/router */ \"./node_modules/@trullock/router/src/index.js\");\n/* harmony import */ var _pageshowerror_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./pageshowerror.js */ \"./src/pageshowerror.js\");\n\n\n\nvar pageHash = {},\n\tpageCache = {},\n\tpageTemplateCache = {},\n\tstack = [],\n\tstackPointer = -1;\n\nvar manuallyAdjustingHistory = false;\nvar handlingBeforeUnload = false;\nvar lastNavigationDirection = null;\n\nvar goal = null;\nvar backData = {};\nvar options = {\n\tfetchPath: route => '/pages/' + route.routeName + '.html',\n\tfetchPageTemplate: route => {\n\t\treturn fetch(options.fetchPath(route))\n\t\t\t.then(r => r.text())\n\t\t\t.then(html => {\n\t\t\t\tvar $div = document.createElement('div');\n\t\t\t\t$div.innerHTML = html;\n\t\t\t\t// Pages are assumed to have a single wrapping element\n\t\t\t\treturn $div.firstElementChild;\n\t\t\t})\n\t\t\t.then($template => {\n\t\t\t\tpageTemplateCache[route.pattern] = $template;\n\t\t\t\treturn $template;\n\t\t\t});\n\t},\n\tpageInterrupt: route => null,\n\tattachMarkup: $html => document.body.appendChild($html),\n\tprepareMarkup: $html => { },\n\tloadingPageName: 'loading',\n\terror404PageName: 'error-404',\n\tdefaultPageName: 'root',\n\tbeforeUnload: null\n}\n\nconst pages = pageHash;\n\nfunction registerPage(argA, argB, argC) {\n\n\tlet namedRoutes = null, \n\t\tpageClass = null;\n\n\tif(argC == undefined)\n\t{\n\t\tnamedRoutes = argA;\n\t\tpageClass = argB;\n\t} else {\n\t\tnamedRoutes = {\n\t\t\t[argA]: argB\n\t\t};\n\t\tpageClass = argC;\n\t}\n\t\n\n\tfor (const [name, route] of Object.entries(namedRoutes)) {\n\t\t_trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].addRoute(name, route, pageClass);\n\n\t\tpageHash[name] = {\n\t\t\turl: route,\n\t\t\tpageClass: pageClass\n\t\t}\n\t}\n\n\treturn pageClass;\n}\n\nfunction getPath(name, values) {\n\tlet url = _trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].interpolate(name, values);\n\tif (values?.hash)\n\t\turl += '#' + values.hash;\n\treturn url;\n}\n\n// TODO: 404 and error too?\nfunction initLoading()\n{\n\tvar page = pageHash[options.loadingPageName];\n\tvar route = _trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].parse(page.url);\n\treturn loadPage(route, {});\n}\n\nfunction showLoading() {\n\tvar page = pageHash[options.loadingPageName];\n\tvar route = _trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].parse(page.url);\n\tvar data = {\n\t\troute: route,\n\t\tscrollY: window.scrollY,\n\t\tevent: {\n\t\t\taction: 'replace'\n\t\t}\n\t};\n\n\tvar page = pageCache[page.url].page;\n\n\treturn page.show(data);\n}\n\nfunction loadPage(route, data) {\n\n\tvar fetchPage = pageTemplateCache[route.pattern] ? Promise.resolve(pageTemplateCache[route.pattern]) : options.fetchPageTemplate(route);\n\n\treturn fetchPage.then($template => {\n\t\tvar $html = $template.cloneNode(true);\n\t\toptions.prepareMarkup($html);\n\t\toptions.attachMarkup($html);\n\t\tpageCache[route.path] = {\n\t\t\t$html,\n\t\t\tpage: new (route.pageClass)($html)\n\t\t}\n\n\t\tvar page = pageCache[route.path].page;\n\t\t\n\t\tlet booted = new Promise(resolve => resolve(page.boot(data)));\n\t\treturn booted.then(() => page);\n\t});\n}\n\nfunction showPage(url, data, event) {\n\tvar route = _trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].parse(url);\n\tif (route == null) {\n\t\tconsole.error(`Can't find page: '${url}'`);\n\t\tlet page404 = pageHash[options.error404PageName];\n\t\tif(!page404)\n\t\t\treturn Promise.reject(new _pageshowerror_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]('/', `Can't find page: '${url}'. Also can't find 404 page: '${options.error404PageName}'`, {}, 'replace'));\n\n\t\treturn Promise.reject(new _pageshowerror_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"](page404.url, `Can't find page: '${url}'`, {}, 'replace'));\n\t}\n\n\tdata = data || {};\n\tfor (let key in route.params)\n\t\tdata[key] = route.params[key];\n\n\tdata.route = {\n\t\turl: url,\n\t\tpath: route.path,\n\t\trouteName: route.routeName,\n\t\tparams: route.params\n\t};\n\tdata.event = event;\n\n\tlet interrupt = options.pageInterrupt(route);\n\tif(interrupt)\n\t{\n\t\tgoal = { url, data };\n\t\treturn showPage(interrupt.url, null, event);\n\t}\n\t\n\tvar getPage = showLoading().then(() => {\n\t\tif (pageCache[route.path])\n\t\t\treturn pageCache[route.path].page;\n\n\t\treturn loadPage(route, data)\n\t});\n\n\t// handle initial page\n\tif (event.action == 'load')\n\t{\n\t\treturn getPage\n\t\t\t\t\t.then(page => doShow(page, data))\n\t\t\t\t\t.then(page => {\n\t\t\t\t\t\t// clean initial load\n\t\t\t\t\t\tif(stackPointer == -1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstack.push({ uid: 0, data, page });\n\t\t\t\t\t\t\tstackPointer = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// page refresh\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstack[stackPointer].page = page;\n\t\t\t\t\t\t\tstack[stackPointer].data = data;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn page;\n\t\t\t\t\t});\n\t}\n\n\tlet currentState = stack[stackPointer];\n\n\tif (currentState.data.route.path == route.path) {\n\t\thandleHistoryAction(event, url, data, currentState.page);\n\t\treturn getPage.then(page => doUpdate(page, data));\n\t}\n\n\tcurrentState.data.scrollY = window.scrollY;\n\n\treturn Promise.all([\n\t\t\tcurrentState.page.hide(event),\n\t\t\tgetPage\n\t\t])\n\t\t\t.then(results => results[1])\n\t\t\t.then(page => {\n\t\t\t\thandleHistoryAction(event, url, data, page);\n\t\t\t\treturn doShow(page, data);\n\t\t\t});\n\t\t\t// .catch(e => {\n\t\t\t// \t// TODO: what case is this?\n\t\t\t// \tmanuallyAdjustingHistory = () => manuallyAdjustingHistory = false;\n\t\t\t// \tif (event.action == 'back')\n\t\t\t// \t\thistory.go(1);\n\t\t\t// \telse if (event.action == 'fwd')\n\t\t\t// \t\thistory.go(-1);\n\t\t\t// });\n}\n\nfunction doShow(page, data) {\n\n\twindow.scroll(0, 0);\n\n\treturn page.show(data)\n\t\t\t.then(() => document.title = page.title)\n\t\t\t// todo: hide() should be passed an event object\n\t\t\t.then(() => pageCache[pageHash[options.loadingPageName].url].page.hide())\n\t\t\t// return page\n\t\t\t.then(() => page);\n}\n\n\nfunction doUpdate(page, data) {\n\n\treturn page.update(data)\n\t\t\t.then(() => document.title = page.title)\n\t\t\t// todo: hide() should be passed an event object\n\t\t\t.then(() => pageCache[pageHash[options.loadingPageName].url].page.hide())\n\t\t\t// return page\n\t\t\t.then(() => page);\n}\n\nfunction handleHistoryAction(event, url, data, page) {\n\tif (event.action == 'push') {\n\t\tlet newUid = stack[stackPointer].uid + 1;\n\n\t\twindow.history.pushState({ uid: newUid }, null, url);\n\t\t\n\t\t// remove future\n\t\tstack.splice(stackPointer + 1, stack.length - stackPointer);\n\n\t\tstack.push({ uid: newUid, data, page });\n\t\tstackPointer++;\n\t}\n\telse if (event.action == 'replace') {\n\t\t// TODO: this case may be buggy\n\n\t\tlet currentUid = stack[stackPointer].uid;\n\t\twindow.history.replaceState({ uid: currentUid }, null, url);\n\t\t\n\t\tstack.pop();\n\t\tstack.push({ uid: currentUid, data, page });\n\t}\n\telse if(event.action == 'back')\n\t{\n\t\tstackPointer -= event.distance;\n\t}\n\telse if (event.action == 'fwd')\n\t{\n\t\tstackPointer += event.distance;\n\t}\t\n}\n\nfunction doNavigate(url, data) {\n\n\tif (url === 'goal') {\n\t\turl = goal ? goal.url : data?.fallback || getPath(options.defaultPageName);\n\t\tdata = goal?.data || {}\n\t\tgoal = null;\n\t}\n\n\treturn showPage(url, data, { action: 'push', distance: 0 });\n}\n\nfunction storageAvailable() {\n\treturn false;\n try {\n var x = '__storage_test__';\n window.sessionStorage.setItem(x, x);\n window.sessionStorage.removeItem(x);\n return true;\n }\n catch(e) {\n return false;\n }\n}\n\nasync function init(opts) {\n\n\tObject.assign(options, opts);\n\n\tif(storageAvailable())\n\t{\n\t\tlet storedStack = window.sessionStorage.getItem(\"stack\");\n\t\tif(storedStack)\n\t\t{\n\t\t\tstoredStack = JSON.parse(storedStack);\n\t\t\tstack = storedStack.stack;\n\t\t\tstackPointer = storedStack.stackPointer;\n\t\t\twindow.sessionStorage.removeItem(\"stack\");\n\t\t}\n\t}\n\n\t// handle pages whose markup is already loaded in the page\n\tfor (var key in pageHash) {\n\t\tif (pageHash[key].pageClass.existingDomSelector) {\n\t\t\tlet $html = document.querySelector(pageHash[key].pageClass.existingDomSelector)\n\t\t\tif(!$html)\n\t\t\t{\n\t\t\t\tconsole.error(`Unable to find DOM element '${pageHash[key].pageClass.existingDomSelector}' for page '${key}'`)\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// TODO: this is inefficient for non parameterised routes. There will always be HTML in memory and then copied for the page once loaded\n\t\t\tpageTemplateCache[_trullock_router__WEBPACK_IMPORTED_MODULE_0__[\"default\"].routesByName[key]._pattern] = $html;\n\t\t\t$html.parentElement.removeChild($html);\t\n\t\t}\n\t}\n\n\tawait initLoading();\n\t\n\t// set initial page\n\tshowPage(window.location.pathname + window.location.search + window.location.hash, null, { action: 'load', distance: 0 }).catch(e => {\n\t\tconsole.error(e);\n\t\t\n\t\tif (e instanceof _pageshowerror_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"])\n\t\t{\n\t\t\treturn showPage(e.url, e.data, { action: stackPointer == -1 ? 'load' : e.action || 'show' }).then(page => {\n\t\t\t\tif(e.action == 'replace')\n\t\t\t\t\thandleHistoryAction({ action: e.action }, e.url, e.data, page);\n\t\t\t\treturn page;\n\t\t\t});\n\t\t\t\n\t\t}\n\t});\n\n\tfunction handlePopstate(context, direction, distance) {\n\n\t\tif (manuallyAdjustingHistory) {\n\t\t\tmanuallyAdjustingHistory(context, { action: direction, distance });\n\t\t\treturn;\n\t\t}\n\n\t\tif (direction == 'back')\n\t\t\tObject.assign(context.data, backData);\n\t\tbackData = {};\n\n\t\tshowPage(context.data.route.url, context.data, { action: direction, distance }).catch(e => {\n\t\t\tconsole.error(e);\n\t\t\tif (e instanceof _pageshowerror_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"])\n\t\t\t\treturn showPage(e.url, e.data, { action: e.action || 'show' });\n\t\t}).then(page => {\n\t\t\t// set page as it can be missing in the case of refreshes\n\t\t\tcontext.page = page;\n\t\t})\n\t}\n\n\tfunction handleBeforeUnloadPart1() {\n\t\t// if we're ignoring beforeUnload this navigation\n\t\tif (handlingBeforeUnload === 'ignore') {\n\t\t\thandlingBeforeUnload = false;\n\t\t\treturn false;\n\t\t}\n\n\t\t// if we have a before-unload confirm to show\n\t\tif (stack[stackPointer].page.beforeUnload && options.beforeUnload && handlingBeforeUnload === false) {\n\t\t\tvar interrupt = stack[stackPointer].page.beforeUnload();\n\t\t\tif (interrupt) {\n\t\t\t\thandlingBeforeUnload = 'step1';\n\n\t\t\t\t// do this in a new thread, you cant call history actions from inside a history-aciton-handler\n\t\t\t\twindow.setTimeout(() => {\n\t\t\t\t\t// undo the navigation so the URL remains correct whilst we show the confirm dialog\n\t\t\t\t\tif (lastNavigationDirection == 'fwd')\n\t\t\t\t\t\thistory.back();\n\t\t\t\t\telse if (lastNavigationDirection == 'back')\n\t\t\t\t\t\thistory.forward();\n\t\t\t\t}, 1);\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// we've finished beforeUnloading\n\t\tif (handlingBeforeUnload === 'step2')\n\t\t\thandlingBeforeUnload = false;\n\n\t\treturn false;\n\t}\n\n\tfunction handleBeforeUnloadPart2() {\n\t\tif (handlingBeforeUnload !== 'step1')\n\t\t\treturn false;\n\n\t\t// do the beforeUnload action, then...\n\t\toptions.beforeUnload(stack[stackPointer].page.beforeUnload()).then(result => {\n\n\t\t\t// if the user confirmed, redo the original action\n\t\t\tif (result) {\n\n\t\t\t\thandlingBeforeUnload = 'step2';\n\n\t\t\t\tif (lastNavigationDirection == 'fwd')\n\t\t\t\t\thistory.forward();\n\t\t\t\telse if (lastNavigationDirection == 'back')\n\t\t\t\t\thistory.back();\n\t\t\t} else {\n\t\t\t\thandlingBeforeUnload = false;\n\t\t\t}\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t// listen for browser navigations\n\twindow.addEventListener(\"popstate\", e => {\n\t\tvar interrupted = handleBeforeUnloadPart2();\n\t\tif (interrupted)\n\t\t\treturn;\n\n\t\tlet newUid = e.state?.uid || 0;\n\t\tlet previousUid = stack[stackPointer].uid;\n\n\t\tlastNavigationDirection = newUid > previousUid ? 'fwd' : 'back';\n\t\tlet distance = Math.abs(newUid - previousUid);\n\n\t\tvar interrupted = handleBeforeUnloadPart1();\n\t\tif (interrupted)\n\t\t\treturn;\n\n\t\tvar context = findContext(newUid);\n\t\thandlePopstate(context, lastNavigationDirection, distance);\n\t});\n\n\tif(storageAvailable())\n\t{\n\t\twindow.addEventListener(\"beforeunload\", () => {\n\n\t\t\tlet stackToSerialize = stack.map(s => ({\n\t\t\t\tuid: s.uid,\n\t\t\t\tdata: s.data\n\t\t\t}));\n\t\t\tlet stackToStore = {\n\t\t\t\tstack: stackToSerialize,\n\t\t\t\tstackPointer\n\t\t\t}\n\t\t\twindow.sessionStorage.setItem('stack', JSON.stringify(stackToStore));\n\t\t});\n\t}\n}\n\nfunction findContext(uid){\n\tfor (var i = 0; i < stack.length; i++) {\n\t\tif (stack[i].uid == uid)\n\t\t\treturn stack[i];\n\t}\n\treturn null;\n}\n\nfunction expandOnlyHash(url)\n{\n\tif(url.startsWith('#'))\n\t{\n\t\tlet currentState = stack[stackPointer];\n\t\tlet currentUrl = currentState.data.route.url;\n\t\tlet hashIndex = currentUrl.indexOf('#');\n\t\tif(hashIndex > -1)\n\t\t\treturn currentUrl.substr(0, hashIndex);\n\t\treturn currentUrl + url;\n\t}\n\n\treturn url;\n}\n\nfunction navigate(url, data, checkBeforeUnload) {\n\n\turl = expandOnlyHash(url);\n\n\tif (checkBeforeUnload === true && stack[stackPointer].page.beforeUnload && options.beforeUnload) {\n\n\t\tvar interrupt = stack[stackPointer].page.beforeUnload();\n\t\tif (interrupt !== false) {\n\t\t\toptions.beforeUnload(interrupt).then(result => {\n\t\t\t\tif (result)\n\t\t\t\t\tdoNavigate(url, data);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t}\n\n\tdoNavigate(url, data);\n}\n\nfunction replace(url, data) {\n\turl = expandOnlyHash(url);\n\treturn showPage(url, data, { action: 'replace', distance: 0 });\n}\n\nfunction show(url, data) {\n\treturn showPage(url, data, { action: 'show', distance: 0 });\n}\n\nfunction back(data, checkBeforeUnload) {\n\tbackData = data || {};\n\thandlingBeforeUnload = checkBeforeUnload === false ? 'ignore' : false;\n\thistory.go(-1);\n}\n\nfunction printStack() {\n\tconsole.log(\"Stack length: \" + stack.length);\n\tconsole.log(\"Stack pointer: \" + stackPointer);\n\tfor(var i = 0; i < stack.length; i++)\n\t\tconsole.log(stack[i]);\n}\n\nfunction removeHistory(predicate)\n{\n\tlet statesToKeep = [];\n\tfor (var i = 0; i < stack.length; i++)\n\t{\n\t\tif (!predicate(stack[i], i))\n\t\t\tstatesToKeep.push(stack[i]);\n\t}\n\n\t// TODO: ensure we always have at least 1 state to keep - must/can this always be the current page?\n\n\tif (statesToKeep.length == stack.length)\n\t\treturn Promise.resolve();\n\n\n\treturn new Promise((resolve, reject) => {\n\n\n\t\tlet backsToDo = stackPointer - 1;\n\t\tlet currentUid = -1;\n\n\t\t// TODO: handle stack pointer not being at the tail when this process starts\n\n\t\tmanuallyAdjustingHistory = _ => {\n\t\t\t// rewind to the first history position\n\t\t\tif(backsToDo > 0)\n\t\t\t{\n\t\t\t\twindow.setTimeout(() => {\n\t\t\t\t\tbacksToDo--;\n\t\t\t\t\thistory.back();\n\t\t\t\t}, 1);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// reset the stack\n\t\t\tstack = [];\n\n\t\t\tfor (var k = 0; k < statesToKeep.length; k++) {\n\t\t\t\tlet currentState = statesToKeep[k];\n\t\t\t\tcurrentState.uid = ++currentUid;\n\n\t\t\t\tif (k == 0)\n\t\t\t\t\twindow.history.replaceState({ uid: currentState.uid }, null, currentState.data.route.url);\n\t\t\t\telse\n\t\t\t\t\twindow.history.pushState({ uid: currentState.uid }, null, currentState.data.route.url);\n\t\t\t\t\n\t\t\t\t\t// TODO: this doesnt seem to work when k=0\n\t\t\t\tdocument.title = currentState.page.title;\n\n\t\t\t\tstack.push(currentState);\n\t\t\t}\n\n\t\t\tstackPointer = stack.length - 1;\n\n\t\t\tmanuallyAdjustingHistory = false;\n\t\t};\n\n\t\thistory.back();\n\t});\n}\n\nfunction purgeCache() {\n\tfor (const path in pageCache)\n\t{\n\t\tpageCache[path].page.destroy && pageCache[path].page.destroy();\n\t\tif (!pageCache[path].page.constructor.existingDomSelector)\n\t\t{\n\t\t\tpageCache[path].$html.remove();\n\t\t\tdelete pageCache[path];\n\t\t}\n\t}\n}\n\n//# sourceURL=webpack://@trullock/page-manager/./src/index.js?");
|
|
40
|
-
|
|
41
|
-
/***/ }),
|
|
42
|
-
|
|
43
|
-
/***/ "./src/pageshowerror.js":
|
|
44
|
-
/*!******************************!*\
|
|
45
|
-
!*** ./src/pageshowerror.js ***!
|
|
46
|
-
\******************************/
|
|
47
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
48
|
-
|
|
49
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ PageShowError)\n/* harmony export */ });\nclass PageShowError extends Error {\r\n\tconstructor(url, message, data, action) {\r\n\t\tsuper(message || 'Error showing requested page')\r\n\r\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\r\n\t\tif (Error.captureStackTrace)\r\n\t\t\tError.captureStackTrace(this, PageShowError)\r\n\r\n\t\tthis.name = 'PageShowError'\r\n\t\tthis.url = url;\r\n\t\tthis.data = data;\r\n\t\tthis.action = action;\r\n\t}\r\n}\n\n//# sourceURL=webpack://@trullock/page-manager/./src/pageshowerror.js?");
|
|
50
|
-
|
|
51
|
-
/***/ })
|
|
52
|
-
|
|
53
|
-
/******/ });
|
|
54
|
-
/************************************************************************/
|
|
55
|
-
/******/ // The module cache
|
|
56
|
-
/******/ var __webpack_module_cache__ = {};
|
|
57
|
-
/******/
|
|
58
|
-
/******/ // The require function
|
|
59
|
-
/******/ function __webpack_require__(moduleId) {
|
|
60
|
-
/******/ // Check if module is in cache
|
|
61
|
-
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
62
|
-
/******/ if (cachedModule !== undefined) {
|
|
63
|
-
/******/ return cachedModule.exports;
|
|
64
|
-
/******/ }
|
|
65
|
-
/******/ // Create a new module (and put it into the cache)
|
|
66
|
-
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
67
|
-
/******/ // no module.id needed
|
|
68
|
-
/******/ // no module.loaded needed
|
|
69
|
-
/******/ exports: {}
|
|
70
|
-
/******/ };
|
|
71
|
-
/******/
|
|
72
|
-
/******/ // Execute the module function
|
|
73
|
-
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
74
|
-
/******/
|
|
75
|
-
/******/ // Return the exports of the module
|
|
76
|
-
/******/ return module.exports;
|
|
77
|
-
/******/ }
|
|
78
|
-
/******/
|
|
79
|
-
/************************************************************************/
|
|
80
|
-
/******/ /* webpack/runtime/define property getters */
|
|
81
|
-
/******/ (() => {
|
|
82
|
-
/******/ // define getter functions for harmony exports
|
|
83
|
-
/******/ __webpack_require__.d = (exports, definition) => {
|
|
84
|
-
/******/ for(var key in definition) {
|
|
85
|
-
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
86
|
-
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
87
|
-
/******/ }
|
|
88
|
-
/******/ }
|
|
89
|
-
/******/ };
|
|
90
|
-
/******/ })();
|
|
91
|
-
/******/
|
|
92
|
-
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
93
|
-
/******/ (() => {
|
|
94
|
-
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
95
|
-
/******/ })();
|
|
96
|
-
/******/
|
|
97
|
-
/******/ /* webpack/runtime/make namespace object */
|
|
98
|
-
/******/ (() => {
|
|
99
|
-
/******/ // define __esModule on exports
|
|
100
|
-
/******/ __webpack_require__.r = (exports) => {
|
|
101
|
-
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
102
|
-
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
103
|
-
/******/ }
|
|
104
|
-
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
105
|
-
/******/ };
|
|
106
|
-
/******/ })();
|
|
107
|
-
/******/
|
|
108
|
-
/************************************************************************/
|
|
109
|
-
/******/
|
|
110
|
-
/******/ // startup
|
|
111
|
-
/******/ // Load entry module and return exports
|
|
112
|
-
/******/ // This entry module can't be inlined because the eval devtool is used.
|
|
113
|
-
/******/ var __webpack_exports__ = __webpack_require__("./src/index.js");
|
|
114
|
-
/******/
|
|
115
|
-
/******/ })()
|
|
116
|
-
;
|
package/tests/dist/index.html
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<html>
|
|
2
|
-
<head>
|
|
3
|
-
<script defer src="/main.js"></script></head>
|
|
4
|
-
<body style="height: 100%;">
|
|
5
|
-
<div style="position: fixed; top: 0; background-color: white;">
|
|
6
|
-
<a href="/page1">Page 1</a>
|
|
7
|
-
<a href="/page2">Page 2</a>
|
|
8
|
-
<a href="/page3">Page 3</a>
|
|
9
|
-
<a href="/page4">Page 4</a>
|
|
10
|
-
<a href="/page/A">Page A</a>
|
|
11
|
-
<a href="/page/B">Page B</a>
|
|
12
|
-
<a href="/404">404</a>
|
|
13
|
-
<a href="/dont-exist">I dont exist</a>
|
|
14
|
-
<a href="/show-fail">I fail to show</a>
|
|
15
|
-
</div>
|
|
16
|
-
<div id="page-loading">
|
|
17
|
-
Loading
|
|
18
|
-
</div>
|
|
19
|
-
<div>
|
|
20
|
-
<button class="btnStack">Print stack</button>
|
|
21
|
-
</div>
|
|
22
|
-
</body>
|
|
23
|
-
</html>
|