@brightspace-ui/labs 2.38.2 → 2.40.0

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 CHANGED
@@ -79,7 +79,7 @@
79
79
  "@rollup/plugin-dynamic-import-vars": "^2",
80
80
  "@rollup/plugin-node-resolve": "^16",
81
81
  "@rollup/plugin-replace": "^6",
82
- "@web/dev-server": "^0.3",
82
+ "@web/dev-server": "^0.4",
83
83
  "@web/rollup-plugin-html": "^2",
84
84
  "eslint": "^9",
85
85
  "eslint-config-brightspace": "^2",
@@ -104,15 +104,14 @@
104
104
  "@adobe/lit-mobx": "^2",
105
105
  "@brightspace-ui/core": "^3",
106
106
  "@brightspace-ui/intl": "^3",
107
- "@lit/context": "^1.1.3",
108
- "fuse.js": "^7.1.0",
107
+ "@lit/context": "^1",
108
+ "fuse.js": "^7",
109
109
  "lit": "^3",
110
- "lodash-es": "^4.17.21",
110
+ "lodash-es": "^4",
111
111
  "mobx": "^5",
112
- "page": "^1",
113
112
  "parse-srt": "^1.0.0-alpha",
114
113
  "resize-observer-polyfill": "^1",
115
- "webvtt-parser": "^2.1.2"
114
+ "webvtt-parser": "^2"
116
115
  },
117
- "version": "2.38.2"
116
+ "version": "2.40.0"
118
117
  }
@@ -10,7 +10,7 @@ import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
10
10
  import { styleMap } from 'lit/directives/style-map.js';
11
11
 
12
12
  const mediaQueryList = window.matchMedia('(max-width: 615px)');
13
- const immersiveNavTextSpacingFlag = getFlag('GAUD-8465-immersive-nav-text-spacing', false);
13
+ const immersiveNavTextSpacingFlag = getFlag('GAUD-8465-immersive-nav-text-spacing', true);
14
14
 
15
15
  class NavigationImmersive extends LitElement {
16
16
 
@@ -0,0 +1,1284 @@
1
+ /**
2
+ * @license
3
+ * (The MIT License)
4
+ *
5
+ * Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+ *
9
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
+ */
13
+ /**
14
+ * NOTE: this code was copied from https://github.com/visionmedia/page.js and modified to use a patch
15
+ * version 1.9.0 of "path-to-regexp".
16
+ *
17
+ * Process:
18
+ * 1. Clone the https://github.com/visionmedia/page.js repo
19
+ * 2. Update package.json to use "path-to-regexp": "^1"
20
+ * 3. Run npm install
21
+ * 4. Run make clean && make
22
+ * 5. Copy the contents of page.mjs into this file
23
+ */
24
+ var isarray = Array.isArray || function (arr) {
25
+ return Object.prototype.toString.call(arr) == '[object Array]';
26
+ };
27
+
28
+ /**
29
+ * Expose `pathToRegexp`.
30
+ */
31
+ var pathToRegexp_1 = pathToRegexp;
32
+ var parse_1 = parse;
33
+ var compile_1 = compile;
34
+ var tokensToFunction_1 = tokensToFunction;
35
+ var tokensToRegExp_1 = tokensToRegExp;
36
+
37
+ /**
38
+ * The main path matching regexp utility.
39
+ *
40
+ * @type {RegExp}
41
+ */
42
+ var PATH_REGEXP = new RegExp([
43
+ // Match escaped characters that would otherwise appear in future matches.
44
+ // This allows the user to escape special characters that won't transform.
45
+ '(\\\\.)',
46
+ // Match Express-style parameters and un-named parameters with a prefix
47
+ // and optional suffixes. Matches appear as:
48
+ //
49
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
50
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
51
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
52
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
53
+ ].join('|'), 'g');
54
+
55
+ /**
56
+ * Parse a string for the raw tokens.
57
+ *
58
+ * @param {string} str
59
+ * @param {Object=} options
60
+ * @return {!Array}
61
+ */
62
+ function parse (str, options) {
63
+ var tokens = [];
64
+ var key = 0;
65
+ var index = 0;
66
+ var path = '';
67
+ var defaultDelimiter = options && options.delimiter || '/';
68
+ var res;
69
+
70
+ while ((res = PATH_REGEXP.exec(str)) != null) {
71
+ var m = res[0];
72
+ var escaped = res[1];
73
+ var offset = res.index;
74
+ path += str.slice(index, offset);
75
+ index = offset + m.length;
76
+
77
+ // Ignore already escaped sequences.
78
+ if (escaped) {
79
+ path += escaped[1];
80
+ continue
81
+ }
82
+
83
+ var next = str[index];
84
+ var prefix = res[2];
85
+ var name = res[3];
86
+ var capture = res[4];
87
+ var group = res[5];
88
+ var modifier = res[6];
89
+ var asterisk = res[7];
90
+
91
+ // Push the current path onto the tokens.
92
+ if (path) {
93
+ tokens.push(path);
94
+ path = '';
95
+ }
96
+
97
+ var partial = prefix != null && next != null && next !== prefix;
98
+ var repeat = modifier === '+' || modifier === '*';
99
+ var optional = modifier === '?' || modifier === '*';
100
+ var delimiter = prefix || defaultDelimiter;
101
+ var pattern = capture || group;
102
+ var prevText = prefix || (typeof tokens[tokens.length - 1] === 'string' ? tokens[tokens.length - 1] : '');
103
+
104
+ tokens.push({
105
+ name: name || key++,
106
+ prefix: prefix || '',
107
+ delimiter: delimiter,
108
+ optional: optional,
109
+ repeat: repeat,
110
+ partial: partial,
111
+ asterisk: !!asterisk,
112
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : restrictBacktrack(delimiter, prevText))
113
+ });
114
+ }
115
+
116
+ // Match any characters still remaining.
117
+ if (index < str.length) {
118
+ path += str.substr(index);
119
+ }
120
+
121
+ // If the path exists, push it onto the end.
122
+ if (path) {
123
+ tokens.push(path);
124
+ }
125
+
126
+ return tokens
127
+ }
128
+
129
+ function restrictBacktrack(delimiter, prevText) {
130
+ if (!prevText || prevText.indexOf(delimiter) > -1) {
131
+ return '[^' + escapeString(delimiter) + ']+?'
132
+ }
133
+
134
+ return escapeString(prevText) + '|(?:(?!' + escapeString(prevText) + ')[^' + escapeString(delimiter) + '])+?'
135
+ }
136
+
137
+ /**
138
+ * Compile a string to a template function for the path.
139
+ *
140
+ * @param {string} str
141
+ * @param {Object=} options
142
+ * @return {!function(Object=, Object=)}
143
+ */
144
+ function compile (str, options) {
145
+ return tokensToFunction(parse(str, options), options)
146
+ }
147
+
148
+ /**
149
+ * Prettier encoding of URI path segments.
150
+ *
151
+ * @param {string}
152
+ * @return {string}
153
+ */
154
+ function encodeURIComponentPretty (str) {
155
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
156
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
157
+ })
158
+ }
159
+
160
+ /**
161
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
162
+ *
163
+ * @param {string}
164
+ * @return {string}
165
+ */
166
+ function encodeAsterisk (str) {
167
+ return encodeURI(str).replace(/[?#]/g, function (c) {
168
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
169
+ })
170
+ }
171
+
172
+ /**
173
+ * Expose a method for transforming tokens into the path function.
174
+ */
175
+ function tokensToFunction (tokens, options) {
176
+ // Compile all the tokens into regexps.
177
+ var matches = new Array(tokens.length);
178
+
179
+ // Compile all the patterns before compilation.
180
+ for (var i = 0; i < tokens.length; i++) {
181
+ if (typeof tokens[i] === 'object') {
182
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));
183
+ }
184
+ }
185
+
186
+ return function (obj, opts) {
187
+ var path = '';
188
+ var data = obj || {};
189
+ var options = opts || {};
190
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
191
+
192
+ for (var i = 0; i < tokens.length; i++) {
193
+ var token = tokens[i];
194
+
195
+ if (typeof token === 'string') {
196
+ path += token;
197
+
198
+ continue
199
+ }
200
+
201
+ var value = data[token.name];
202
+ var segment;
203
+
204
+ if (value == null) {
205
+ if (token.optional) {
206
+ // Prepend partial segment prefixes.
207
+ if (token.partial) {
208
+ path += token.prefix;
209
+ }
210
+
211
+ continue
212
+ } else {
213
+ throw new TypeError('Expected "' + token.name + '" to be defined')
214
+ }
215
+ }
216
+
217
+ if (isarray(value)) {
218
+ if (!token.repeat) {
219
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
220
+ }
221
+
222
+ if (value.length === 0) {
223
+ if (token.optional) {
224
+ continue
225
+ } else {
226
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
227
+ }
228
+ }
229
+
230
+ for (var j = 0; j < value.length; j++) {
231
+ segment = encode(value[j]);
232
+
233
+ if (!matches[i].test(segment)) {
234
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
235
+ }
236
+
237
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
238
+ }
239
+
240
+ continue
241
+ }
242
+
243
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
244
+
245
+ if (!matches[i].test(segment)) {
246
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
247
+ }
248
+
249
+ path += token.prefix + segment;
250
+ }
251
+
252
+ return path
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Escape a regular expression string.
258
+ *
259
+ * @param {string} str
260
+ * @return {string}
261
+ */
262
+ function escapeString (str) {
263
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
264
+ }
265
+
266
+ /**
267
+ * Escape the capturing group by escaping special characters and meaning.
268
+ *
269
+ * @param {string} group
270
+ * @return {string}
271
+ */
272
+ function escapeGroup (group) {
273
+ return group.replace(/([=!:$\/()])/g, '\\$1')
274
+ }
275
+
276
+ /**
277
+ * Attach the keys as a property of the regexp.
278
+ *
279
+ * @param {!RegExp} re
280
+ * @param {Array} keys
281
+ * @return {!RegExp}
282
+ */
283
+ function attachKeys (re, keys) {
284
+ re.keys = keys;
285
+ return re
286
+ }
287
+
288
+ /**
289
+ * Get the flags for a regexp from the options.
290
+ *
291
+ * @param {Object} options
292
+ * @return {string}
293
+ */
294
+ function flags (options) {
295
+ return options && options.sensitive ? '' : 'i'
296
+ }
297
+
298
+ /**
299
+ * Pull out keys from a regexp.
300
+ *
301
+ * @param {!RegExp} path
302
+ * @param {!Array} keys
303
+ * @return {!RegExp}
304
+ */
305
+ function regexpToRegexp (path, keys) {
306
+ // Use a negative lookahead to match only capturing groups.
307
+ var groups = path.source.match(/\((?!\?)/g);
308
+
309
+ if (groups) {
310
+ for (var i = 0; i < groups.length; i++) {
311
+ keys.push({
312
+ name: i,
313
+ prefix: null,
314
+ delimiter: null,
315
+ optional: false,
316
+ repeat: false,
317
+ partial: false,
318
+ asterisk: false,
319
+ pattern: null
320
+ });
321
+ }
322
+ }
323
+
324
+ return attachKeys(path, keys)
325
+ }
326
+
327
+ /**
328
+ * Transform an array into a regexp.
329
+ *
330
+ * @param {!Array} path
331
+ * @param {Array} keys
332
+ * @param {!Object} options
333
+ * @return {!RegExp}
334
+ */
335
+ function arrayToRegexp (path, keys, options) {
336
+ var parts = [];
337
+
338
+ for (var i = 0; i < path.length; i++) {
339
+ parts.push(pathToRegexp(path[i], keys, options).source);
340
+ }
341
+
342
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
343
+
344
+ return attachKeys(regexp, keys)
345
+ }
346
+
347
+ /**
348
+ * Create a path regexp from string input.
349
+ *
350
+ * @param {string} path
351
+ * @param {!Array} keys
352
+ * @param {!Object} options
353
+ * @return {!RegExp}
354
+ */
355
+ function stringToRegexp (path, keys, options) {
356
+ return tokensToRegExp(parse(path, options), keys, options)
357
+ }
358
+
359
+ /**
360
+ * Expose a function for taking tokens and returning a RegExp.
361
+ *
362
+ * @param {!Array} tokens
363
+ * @param {(Array|Object)=} keys
364
+ * @param {Object=} options
365
+ * @return {!RegExp}
366
+ */
367
+ function tokensToRegExp (tokens, keys, options) {
368
+ if (!isarray(keys)) {
369
+ options = /** @type {!Object} */ (keys || options);
370
+ keys = [];
371
+ }
372
+
373
+ options = options || {};
374
+
375
+ var strict = options.strict;
376
+ var end = options.end !== false;
377
+ var route = '';
378
+
379
+ // Iterate over the tokens and create our regexp string.
380
+ for (var i = 0; i < tokens.length; i++) {
381
+ var token = tokens[i];
382
+
383
+ if (typeof token === 'string') {
384
+ route += escapeString(token);
385
+ } else {
386
+ var prefix = escapeString(token.prefix);
387
+ var capture = '(?:' + token.pattern + ')';
388
+
389
+ keys.push(token);
390
+
391
+ if (token.repeat) {
392
+ capture += '(?:' + prefix + capture + ')*';
393
+ }
394
+
395
+ if (token.optional) {
396
+ if (!token.partial) {
397
+ capture = '(?:' + prefix + '(' + capture + '))?';
398
+ } else {
399
+ capture = prefix + '(' + capture + ')?';
400
+ }
401
+ } else {
402
+ capture = prefix + '(' + capture + ')';
403
+ }
404
+
405
+ route += capture;
406
+ }
407
+ }
408
+
409
+ var delimiter = escapeString(options.delimiter || '/');
410
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
411
+
412
+ // In non-strict mode we allow a slash at the end of match. If the path to
413
+ // match already ends with a slash, we remove it for consistency. The slash
414
+ // is valid at the end of a path match, not in the middle. This is important
415
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
416
+ if (!strict) {
417
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
418
+ }
419
+
420
+ if (end) {
421
+ route += '$';
422
+ } else {
423
+ // In non-ending mode, we need the capturing groups to match as much as
424
+ // possible by using a positive lookahead to the end or next path segment.
425
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
426
+ }
427
+
428
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
429
+ }
430
+
431
+ /**
432
+ * Normalize the given path string, returning a regular expression.
433
+ *
434
+ * An empty array can be passed in for the keys, which will hold the
435
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
436
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
437
+ *
438
+ * @param {(string|RegExp|Array)} path
439
+ * @param {(Array|Object)=} keys
440
+ * @param {Object=} options
441
+ * @return {!RegExp}
442
+ */
443
+ function pathToRegexp (path, keys, options) {
444
+ if (!isarray(keys)) {
445
+ options = /** @type {!Object} */ (keys || options);
446
+ keys = [];
447
+ }
448
+
449
+ options = options || {};
450
+
451
+ if (path instanceof RegExp) {
452
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
453
+ }
454
+
455
+ if (isarray(path)) {
456
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
457
+ }
458
+
459
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
460
+ }
461
+
462
+ pathToRegexp_1.parse = parse_1;
463
+ pathToRegexp_1.compile = compile_1;
464
+ pathToRegexp_1.tokensToFunction = tokensToFunction_1;
465
+ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
466
+
467
+ /**
468
+ * Module dependencies.
469
+ */
470
+
471
+
472
+
473
+ /**
474
+ * Short-cuts for global-object checks
475
+ */
476
+
477
+ var hasDocument = ('undefined' !== typeof document);
478
+ var hasWindow = ('undefined' !== typeof window);
479
+ var hasHistory = ('undefined' !== typeof history);
480
+ var hasProcess = typeof process !== 'undefined';
481
+
482
+ /**
483
+ * Detect click event
484
+ */
485
+ var clickEvent = hasDocument && document.ontouchstart ? 'touchstart' : 'click';
486
+
487
+ /**
488
+ * To work properly with the URL
489
+ * history.location generated polyfill in https://github.com/devote/HTML5-History-API
490
+ */
491
+
492
+ var isLocation = hasWindow && !!(window.history.location || window.location);
493
+
494
+ /**
495
+ * The page instance
496
+ * @api private
497
+ */
498
+ function Page() {
499
+ // public things
500
+ this.callbacks = [];
501
+ this.exits = [];
502
+ this.current = '';
503
+ this.len = 0;
504
+
505
+ // private things
506
+ this._decodeURLComponents = true;
507
+ this._base = '';
508
+ this._strict = false;
509
+ this._running = false;
510
+ this._hashbang = false;
511
+
512
+ // bound functions
513
+ this.clickHandler = this.clickHandler.bind(this);
514
+ this._onpopstate = this._onpopstate.bind(this);
515
+ }
516
+
517
+ /**
518
+ * Configure the instance of page. This can be called multiple times.
519
+ *
520
+ * @param {Object} options
521
+ * @api public
522
+ */
523
+
524
+ Page.prototype.configure = function(options) {
525
+ var opts = options || {};
526
+
527
+ this._window = opts.window || (hasWindow && window);
528
+ this._decodeURLComponents = opts.decodeURLComponents !== false;
529
+ this._popstate = opts.popstate !== false && hasWindow;
530
+ this._click = opts.click !== false && hasDocument;
531
+ this._hashbang = !!opts.hashbang;
532
+
533
+ var _window = this._window;
534
+ if(this._popstate) {
535
+ _window.addEventListener('popstate', this._onpopstate, false);
536
+ } else if(hasWindow) {
537
+ _window.removeEventListener('popstate', this._onpopstate, false);
538
+ }
539
+
540
+ if (this._click) {
541
+ _window.document.addEventListener(clickEvent, this.clickHandler, false);
542
+ } else if(hasDocument) {
543
+ _window.document.removeEventListener(clickEvent, this.clickHandler, false);
544
+ }
545
+
546
+ if(this._hashbang && hasWindow && !hasHistory) {
547
+ _window.addEventListener('hashchange', this._onpopstate, false);
548
+ } else if(hasWindow) {
549
+ _window.removeEventListener('hashchange', this._onpopstate, false);
550
+ }
551
+ };
552
+
553
+ /**
554
+ * Get or set basepath to `path`.
555
+ *
556
+ * @param {string} path
557
+ * @api public
558
+ */
559
+
560
+ Page.prototype.base = function(path) {
561
+ if (0 === arguments.length) return this._base;
562
+ this._base = path;
563
+ };
564
+
565
+ /**
566
+ * Gets the `base`, which depends on whether we are using History or
567
+ * hashbang routing.
568
+
569
+ * @api private
570
+ */
571
+ Page.prototype._getBase = function() {
572
+ var base = this._base;
573
+ if(!!base) return base;
574
+ var loc = hasWindow && this._window && this._window.location;
575
+
576
+ if(hasWindow && this._hashbang && loc && loc.protocol === 'file:') {
577
+ base = loc.pathname;
578
+ }
579
+
580
+ return base;
581
+ };
582
+
583
+ /**
584
+ * Get or set strict path matching to `enable`
585
+ *
586
+ * @param {boolean} enable
587
+ * @api public
588
+ */
589
+
590
+ Page.prototype.strict = function(enable) {
591
+ if (0 === arguments.length) return this._strict;
592
+ this._strict = enable;
593
+ };
594
+
595
+
596
+ /**
597
+ * Bind with the given `options`.
598
+ *
599
+ * Options:
600
+ *
601
+ * - `click` bind to click events [true]
602
+ * - `popstate` bind to popstate [true]
603
+ * - `dispatch` perform initial dispatch [true]
604
+ *
605
+ * @param {Object} options
606
+ * @api public
607
+ */
608
+
609
+ Page.prototype.start = function(options) {
610
+ var opts = options || {};
611
+ this.configure(opts);
612
+
613
+ if (false === opts.dispatch) return;
614
+ this._running = true;
615
+
616
+ var url;
617
+ if(isLocation) {
618
+ var window = this._window;
619
+ var loc = window.location;
620
+
621
+ if(this._hashbang && ~loc.hash.indexOf('#!')) {
622
+ url = loc.hash.substr(2) + loc.search;
623
+ } else if (this._hashbang) {
624
+ url = loc.search + loc.hash;
625
+ } else {
626
+ url = loc.pathname + loc.search + loc.hash;
627
+ }
628
+ }
629
+
630
+ this.replace(url, null, true, opts.dispatch);
631
+ };
632
+
633
+ /**
634
+ * Unbind click and popstate event handlers.
635
+ *
636
+ * @api public
637
+ */
638
+
639
+ Page.prototype.stop = function() {
640
+ if (!this._running) return;
641
+ this.current = '';
642
+ this.len = 0;
643
+ this._running = false;
644
+
645
+ var window = this._window;
646
+ this._click && window.document.removeEventListener(clickEvent, this.clickHandler, false);
647
+ hasWindow && window.removeEventListener('popstate', this._onpopstate, false);
648
+ hasWindow && window.removeEventListener('hashchange', this._onpopstate, false);
649
+ };
650
+
651
+ /**
652
+ * Show `path` with optional `state` object.
653
+ *
654
+ * @param {string} path
655
+ * @param {Object=} state
656
+ * @param {boolean=} dispatch
657
+ * @param {boolean=} push
658
+ * @return {!Context}
659
+ * @api public
660
+ */
661
+
662
+ Page.prototype.show = function(path, state, dispatch, push) {
663
+ var ctx = new Context(path, state, this),
664
+ prev = this.prevContext;
665
+ this.prevContext = ctx;
666
+ this.current = ctx.path;
667
+ if (false !== dispatch) this.dispatch(ctx, prev);
668
+ if (false !== ctx.handled && false !== push) ctx.pushState();
669
+ return ctx;
670
+ };
671
+
672
+ /**
673
+ * Goes back in the history
674
+ * Back should always let the current route push state and then go back.
675
+ *
676
+ * @param {string} path - fallback path to go back if no more history exists, if undefined defaults to page.base
677
+ * @param {Object=} state
678
+ * @api public
679
+ */
680
+
681
+ Page.prototype.back = function(path, state) {
682
+ var page = this;
683
+ if (this.len > 0) {
684
+ var window = this._window;
685
+ // this may need more testing to see if all browsers
686
+ // wait for the next tick to go back in history
687
+ hasHistory && window.history.back();
688
+ this.len--;
689
+ } else if (path) {
690
+ setTimeout(function() {
691
+ page.show(path, state);
692
+ });
693
+ } else {
694
+ setTimeout(function() {
695
+ page.show(page._getBase(), state);
696
+ });
697
+ }
698
+ };
699
+
700
+ /**
701
+ * Register route to redirect from one path to other
702
+ * or just redirect to another route
703
+ *
704
+ * @param {string} from - if param 'to' is undefined redirects to 'from'
705
+ * @param {string=} to
706
+ * @api public
707
+ */
708
+ Page.prototype.redirect = function(from, to) {
709
+ var inst = this;
710
+
711
+ // Define route from a path to another
712
+ if ('string' === typeof from && 'string' === typeof to) {
713
+ page.call(this, from, function(e) {
714
+ setTimeout(function() {
715
+ inst.replace(/** @type {!string} */ (to));
716
+ }, 0);
717
+ });
718
+ }
719
+
720
+ // Wait for the push state and replace it with another
721
+ if ('string' === typeof from && 'undefined' === typeof to) {
722
+ setTimeout(function() {
723
+ inst.replace(from);
724
+ }, 0);
725
+ }
726
+ };
727
+
728
+ /**
729
+ * Replace `path` with optional `state` object.
730
+ *
731
+ * @param {string} path
732
+ * @param {Object=} state
733
+ * @param {boolean=} init
734
+ * @param {boolean=} dispatch
735
+ * @return {!Context}
736
+ * @api public
737
+ */
738
+
739
+
740
+ Page.prototype.replace = function(path, state, init, dispatch) {
741
+ var ctx = new Context(path, state, this),
742
+ prev = this.prevContext;
743
+ this.prevContext = ctx;
744
+ this.current = ctx.path;
745
+ ctx.init = init;
746
+ ctx.save(); // save before dispatching, which may redirect
747
+ if (false !== dispatch) this.dispatch(ctx, prev);
748
+ return ctx;
749
+ };
750
+
751
+ /**
752
+ * Dispatch the given `ctx`.
753
+ *
754
+ * @param {Context} ctx
755
+ * @api private
756
+ */
757
+
758
+ Page.prototype.dispatch = function(ctx, prev) {
759
+ var i = 0, j = 0, page = this;
760
+
761
+ function nextExit() {
762
+ var fn = page.exits[j++];
763
+ if (!fn) return nextEnter();
764
+ fn(prev, nextExit);
765
+ }
766
+
767
+ function nextEnter() {
768
+ var fn = page.callbacks[i++];
769
+
770
+ if (ctx.path !== page.current) {
771
+ ctx.handled = false;
772
+ return;
773
+ }
774
+ if (!fn) return unhandled.call(page, ctx);
775
+ fn(ctx, nextEnter);
776
+ }
777
+
778
+ if (prev) {
779
+ nextExit();
780
+ } else {
781
+ nextEnter();
782
+ }
783
+ };
784
+
785
+ /**
786
+ * Register an exit route on `path` with
787
+ * callback `fn()`, which will be called
788
+ * on the previous context when a new
789
+ * page is visited.
790
+ */
791
+ Page.prototype.exit = function(path, fn) {
792
+ if (typeof path === 'function') {
793
+ return this.exit('*', path);
794
+ }
795
+
796
+ var route = new Route(path, null, this);
797
+ for (var i = 1; i < arguments.length; ++i) {
798
+ this.exits.push(route.middleware(arguments[i]));
799
+ }
800
+ };
801
+
802
+ /**
803
+ * Handle "click" events.
804
+ */
805
+
806
+ /* jshint +W054 */
807
+ Page.prototype.clickHandler = function(e) {
808
+ if (1 !== this._which(e)) return;
809
+
810
+ if (e.metaKey || e.ctrlKey || e.shiftKey) return;
811
+ if (e.defaultPrevented) return;
812
+
813
+ // ensure link
814
+ // use shadow dom when available if not, fall back to composedPath()
815
+ // for browsers that only have shady
816
+ var el = e.target;
817
+ var eventPath = e.path || (e.composedPath ? e.composedPath() : null);
818
+
819
+ if(eventPath) {
820
+ for (var i = 0; i < eventPath.length; i++) {
821
+ if (!eventPath[i].nodeName) continue;
822
+ if (eventPath[i].nodeName.toUpperCase() !== 'A') continue;
823
+ if (!eventPath[i].href) continue;
824
+
825
+ el = eventPath[i];
826
+ break;
827
+ }
828
+ }
829
+
830
+ // continue ensure link
831
+ // el.nodeName for svg links are 'a' instead of 'A'
832
+ while (el && 'A' !== el.nodeName.toUpperCase()) el = el.parentNode;
833
+ if (!el || 'A' !== el.nodeName.toUpperCase()) return;
834
+
835
+ // check if link is inside an svg
836
+ // in this case, both href and target are always inside an object
837
+ var svg = (typeof el.href === 'object') && el.href.constructor.name === 'SVGAnimatedString';
838
+
839
+ // Ignore if tag has
840
+ // 1. "download" attribute
841
+ // 2. rel="external" attribute
842
+ if (el.hasAttribute('download') || el.getAttribute('rel') === 'external') return;
843
+
844
+ // ensure non-hash for the same path
845
+ var link = el.getAttribute('href');
846
+ if(!this._hashbang && this._samePath(el) && (el.hash || '#' === link)) return;
847
+
848
+ // Check for mailto: in the href
849
+ if (link && link.indexOf('mailto:') > -1) return;
850
+
851
+ // check target
852
+ // svg target is an object and its desired value is in .baseVal property
853
+ if (svg ? el.target.baseVal : el.target) return;
854
+
855
+ // x-origin
856
+ // note: svg links that are not relative don't call click events (and skip page.js)
857
+ // consequently, all svg links tested inside page.js are relative and in the same origin
858
+ if (!svg && !this.sameOrigin(el.href)) return;
859
+
860
+ // rebuild path
861
+ // There aren't .pathname and .search properties in svg links, so we use href
862
+ // Also, svg href is an object and its desired value is in .baseVal property
863
+ var path = svg ? el.href.baseVal : (el.pathname + el.search + (el.hash || ''));
864
+
865
+ path = path[0] !== '/' ? '/' + path : path;
866
+
867
+ // strip leading "/[drive letter]:" on NW.js on Windows
868
+ if (hasProcess && path.match(/^\/[a-zA-Z]:\//)) {
869
+ path = path.replace(/^\/[a-zA-Z]:\//, '/');
870
+ }
871
+
872
+ // same page
873
+ var orig = path;
874
+ var pageBase = this._getBase();
875
+
876
+ if (path.indexOf(pageBase) === 0) {
877
+ path = path.substr(pageBase.length);
878
+ }
879
+
880
+ if (this._hashbang) path = path.replace('#!', '');
881
+
882
+ if (pageBase && orig === path && (!isLocation || this._window.location.protocol !== 'file:')) {
883
+ return;
884
+ }
885
+
886
+ e.preventDefault();
887
+ this.show(orig);
888
+ };
889
+
890
+ /**
891
+ * Handle "populate" events.
892
+ * @api private
893
+ */
894
+
895
+ Page.prototype._onpopstate = (function () {
896
+ var loaded = false;
897
+ if ( ! hasWindow ) {
898
+ return function () {};
899
+ }
900
+ if (hasDocument && document.readyState === 'complete') {
901
+ loaded = true;
902
+ } else {
903
+ window.addEventListener('load', function() {
904
+ setTimeout(function() {
905
+ loaded = true;
906
+ }, 0);
907
+ });
908
+ }
909
+ return function onpopstate(e) {
910
+ if (!loaded) return;
911
+ var page = this;
912
+ if (e.state) {
913
+ var path = e.state.path;
914
+ page.replace(path, e.state);
915
+ } else if (isLocation) {
916
+ var loc = page._window.location;
917
+ page.show(loc.pathname + loc.search + loc.hash, undefined, undefined, false);
918
+ }
919
+ };
920
+ })();
921
+
922
+ /**
923
+ * Event button.
924
+ */
925
+ Page.prototype._which = function(e) {
926
+ e = e || (hasWindow && this._window.event);
927
+ return null == e.which ? e.button : e.which;
928
+ };
929
+
930
+ /**
931
+ * Convert to a URL object
932
+ * @api private
933
+ */
934
+ Page.prototype._toURL = function(href) {
935
+ var window = this._window;
936
+ if(typeof URL === 'function' && isLocation) {
937
+ return new URL(href, window.location.toString());
938
+ } else if (hasDocument) {
939
+ var anc = window.document.createElement('a');
940
+ anc.href = href;
941
+ return anc;
942
+ }
943
+ };
944
+
945
+ /**
946
+ * Check if `href` is the same origin.
947
+ * @param {string} href
948
+ * @api public
949
+ */
950
+ Page.prototype.sameOrigin = function(href) {
951
+ if(!href || !isLocation) return false;
952
+
953
+ var url = this._toURL(href);
954
+ var window = this._window;
955
+
956
+ var loc = window.location;
957
+
958
+ /*
959
+ When the port is the default http port 80 for http, or 443 for
960
+ https, internet explorer 11 returns an empty string for loc.port,
961
+ so we need to compare loc.port with an empty string if url.port
962
+ is the default port 80 or 443.
963
+ Also the comparition with `port` is changed from `===` to `==` because
964
+ `port` can be a string sometimes. This only applies to ie11.
965
+ */
966
+ return loc.protocol === url.protocol &&
967
+ loc.hostname === url.hostname &&
968
+ (loc.port === url.port || loc.port === '' && (url.port == 80 || url.port == 443)); // jshint ignore:line
969
+ };
970
+
971
+ /**
972
+ * @api private
973
+ */
974
+ Page.prototype._samePath = function(url) {
975
+ if(!isLocation) return false;
976
+ var window = this._window;
977
+ var loc = window.location;
978
+ return url.pathname === loc.pathname &&
979
+ url.search === loc.search;
980
+ };
981
+
982
+ /**
983
+ * Remove URL encoding from the given `str`.
984
+ * Accommodates whitespace in both x-www-form-urlencoded
985
+ * and regular percent-encoded form.
986
+ *
987
+ * @param {string} val - URL component to decode
988
+ * @api private
989
+ */
990
+ Page.prototype._decodeURLEncodedURIComponent = function(val) {
991
+ if (typeof val !== 'string') { return val; }
992
+ return this._decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, ' ')) : val;
993
+ };
994
+
995
+ /**
996
+ * Create a new `page` instance and function
997
+ */
998
+ function createPage() {
999
+ var pageInstance = new Page();
1000
+
1001
+ function pageFn(/* args */) {
1002
+ return page.apply(pageInstance, arguments);
1003
+ }
1004
+
1005
+ // Copy all of the things over. In 2.0 maybe we use setPrototypeOf
1006
+ pageFn.callbacks = pageInstance.callbacks;
1007
+ pageFn.exits = pageInstance.exits;
1008
+ pageFn.base = pageInstance.base.bind(pageInstance);
1009
+ pageFn.strict = pageInstance.strict.bind(pageInstance);
1010
+ pageFn.start = pageInstance.start.bind(pageInstance);
1011
+ pageFn.stop = pageInstance.stop.bind(pageInstance);
1012
+ pageFn.show = pageInstance.show.bind(pageInstance);
1013
+ pageFn.back = pageInstance.back.bind(pageInstance);
1014
+ pageFn.redirect = pageInstance.redirect.bind(pageInstance);
1015
+ pageFn.replace = pageInstance.replace.bind(pageInstance);
1016
+ pageFn.dispatch = pageInstance.dispatch.bind(pageInstance);
1017
+ pageFn.exit = pageInstance.exit.bind(pageInstance);
1018
+ pageFn.configure = pageInstance.configure.bind(pageInstance);
1019
+ pageFn.sameOrigin = pageInstance.sameOrigin.bind(pageInstance);
1020
+ pageFn.clickHandler = pageInstance.clickHandler.bind(pageInstance);
1021
+
1022
+ pageFn.create = createPage;
1023
+
1024
+ Object.defineProperty(pageFn, 'len', {
1025
+ get: function(){
1026
+ return pageInstance.len;
1027
+ },
1028
+ set: function(val) {
1029
+ pageInstance.len = val;
1030
+ }
1031
+ });
1032
+
1033
+ Object.defineProperty(pageFn, 'current', {
1034
+ get: function(){
1035
+ return pageInstance.current;
1036
+ },
1037
+ set: function(val) {
1038
+ pageInstance.current = val;
1039
+ }
1040
+ });
1041
+
1042
+ // In 2.0 these can be named exports
1043
+ pageFn.Context = Context;
1044
+ pageFn.Route = Route;
1045
+
1046
+ return pageFn;
1047
+ }
1048
+
1049
+ /**
1050
+ * Register `path` with callback `fn()`,
1051
+ * or route `path`, or redirection,
1052
+ * or `page.start()`.
1053
+ *
1054
+ * page(fn);
1055
+ * page('*', fn);
1056
+ * page('/user/:id', load, user);
1057
+ * page('/user/' + user.id, { some: 'thing' });
1058
+ * page('/user/' + user.id);
1059
+ * page('/from', '/to')
1060
+ * page();
1061
+ *
1062
+ * @param {string|!Function|!Object} path
1063
+ * @param {Function=} fn
1064
+ * @api public
1065
+ */
1066
+
1067
+ function page(path, fn) {
1068
+ // <callback>
1069
+ if ('function' === typeof path) {
1070
+ return page.call(this, '*', path);
1071
+ }
1072
+
1073
+ // route <path> to <callback ...>
1074
+ if ('function' === typeof fn) {
1075
+ var route = new Route(/** @type {string} */ (path), null, this);
1076
+ for (var i = 1; i < arguments.length; ++i) {
1077
+ this.callbacks.push(route.middleware(arguments[i]));
1078
+ }
1079
+ // show <path> with [state]
1080
+ } else if ('string' === typeof path) {
1081
+ this['string' === typeof fn ? 'redirect' : 'show'](path, fn);
1082
+ // start [options]
1083
+ } else {
1084
+ this.start(path);
1085
+ }
1086
+ }
1087
+
1088
+ /**
1089
+ * Unhandled `ctx`. When it's not the initial
1090
+ * popstate then redirect. If you wish to handle
1091
+ * 404s on your own use `page('*', callback)`.
1092
+ *
1093
+ * @param {Context} ctx
1094
+ * @api private
1095
+ */
1096
+ function unhandled(ctx) {
1097
+ if (ctx.handled) return;
1098
+ var current;
1099
+ var page = this;
1100
+ var window = page._window;
1101
+
1102
+ if (page._hashbang) {
1103
+ current = isLocation && this._getBase() + window.location.hash.replace('#!', '');
1104
+ } else {
1105
+ current = isLocation && window.location.pathname + window.location.search;
1106
+ }
1107
+
1108
+ if (current === ctx.canonicalPath) return;
1109
+ page.stop();
1110
+ ctx.handled = false;
1111
+ isLocation && (window.location.href = ctx.canonicalPath);
1112
+ }
1113
+
1114
+ /**
1115
+ * Escapes RegExp characters in the given string.
1116
+ *
1117
+ * @param {string} s
1118
+ * @api private
1119
+ */
1120
+ function escapeRegExp(s) {
1121
+ return s.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1');
1122
+ }
1123
+
1124
+ /**
1125
+ * Initialize a new "request" `Context`
1126
+ * with the given `path` and optional initial `state`.
1127
+ *
1128
+ * @constructor
1129
+ * @param {string} path
1130
+ * @param {Object=} state
1131
+ * @api public
1132
+ */
1133
+
1134
+ function Context(path, state, pageInstance) {
1135
+ var _page = this.page = pageInstance || page;
1136
+ var window = _page._window;
1137
+ var hashbang = _page._hashbang;
1138
+
1139
+ var pageBase = _page._getBase();
1140
+ if ('/' === path[0] && 0 !== path.indexOf(pageBase)) path = pageBase + (hashbang ? '#!' : '') + path;
1141
+ var i = path.indexOf('?');
1142
+
1143
+ this.canonicalPath = path;
1144
+ var re = new RegExp('^' + escapeRegExp(pageBase));
1145
+ this.path = path.replace(re, '') || '/';
1146
+ if (hashbang) this.path = this.path.replace('#!', '') || '/';
1147
+
1148
+ this.title = (hasDocument && window.document.title);
1149
+ this.state = state || {};
1150
+ this.state.path = path;
1151
+ this.querystring = ~i ? _page._decodeURLEncodedURIComponent(path.slice(i + 1)) : '';
1152
+ this.pathname = _page._decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path);
1153
+ this.params = {};
1154
+
1155
+ // fragment
1156
+ this.hash = '';
1157
+ if (!hashbang) {
1158
+ if (!~this.path.indexOf('#')) return;
1159
+ var parts = this.path.split('#');
1160
+ this.path = this.pathname = parts[0];
1161
+ this.hash = _page._decodeURLEncodedURIComponent(parts[1]) || '';
1162
+ this.querystring = this.querystring.split('#')[0];
1163
+ }
1164
+ }
1165
+
1166
+ /**
1167
+ * Push state.
1168
+ *
1169
+ * @api private
1170
+ */
1171
+
1172
+ Context.prototype.pushState = function() {
1173
+ var page = this.page;
1174
+ var window = page._window;
1175
+ var hashbang = page._hashbang;
1176
+
1177
+ page.len++;
1178
+ if (hasHistory) {
1179
+ window.history.pushState(this.state, this.title,
1180
+ hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
1181
+ }
1182
+ };
1183
+
1184
+ /**
1185
+ * Save the context state.
1186
+ *
1187
+ * @api public
1188
+ */
1189
+
1190
+ Context.prototype.save = function() {
1191
+ var page = this.page;
1192
+ if (hasHistory) {
1193
+ page._window.history.replaceState(this.state, this.title,
1194
+ page._hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
1195
+ }
1196
+ };
1197
+
1198
+ /**
1199
+ * Initialize `Route` with the given HTTP `path`,
1200
+ * and an array of `callbacks` and `options`.
1201
+ *
1202
+ * Options:
1203
+ *
1204
+ * - `sensitive` enable case-sensitive routes
1205
+ * - `strict` enable strict matching for trailing slashes
1206
+ *
1207
+ * @constructor
1208
+ * @param {string} path
1209
+ * @param {Object=} options
1210
+ * @api private
1211
+ */
1212
+
1213
+ function Route(path, options, page) {
1214
+ var _page = this.page = page || globalPage;
1215
+ var opts = options || {};
1216
+ opts.strict = opts.strict || _page._strict;
1217
+ this.path = (path === '*') ? '(.*)' : path;
1218
+ this.method = 'GET';
1219
+ this.regexp = pathToRegexp_1(this.path, this.keys = [], opts);
1220
+ }
1221
+
1222
+ /**
1223
+ * Return route middleware with
1224
+ * the given callback `fn()`.
1225
+ *
1226
+ * @param {Function} fn
1227
+ * @return {Function}
1228
+ * @api public
1229
+ */
1230
+
1231
+ Route.prototype.middleware = function(fn) {
1232
+ var self = this;
1233
+ return function(ctx, next) {
1234
+ if (self.match(ctx.path, ctx.params)) {
1235
+ ctx.routePath = self.path;
1236
+ return fn(ctx, next);
1237
+ }
1238
+ next();
1239
+ };
1240
+ };
1241
+
1242
+ /**
1243
+ * Check if this route matches `path`, if so
1244
+ * populate `params`.
1245
+ *
1246
+ * @param {string} path
1247
+ * @param {Object} params
1248
+ * @return {boolean}
1249
+ * @api private
1250
+ */
1251
+
1252
+ Route.prototype.match = function(path, params) {
1253
+ var keys = this.keys,
1254
+ qsIndex = path.indexOf('?'),
1255
+ pathname = ~qsIndex ? path.slice(0, qsIndex) : path,
1256
+ m = this.regexp.exec(decodeURIComponent(pathname));
1257
+
1258
+ if (!m) return false;
1259
+
1260
+ delete params[0];
1261
+
1262
+ for (var i = 1, len = m.length; i < len; ++i) {
1263
+ var key = keys[i - 1];
1264
+ var val = this.page._decodeURLEncodedURIComponent(m[i]);
1265
+ if (val !== undefined || !(hasOwnProperty.call(params, key.name))) {
1266
+ params[key.name] = val;
1267
+ }
1268
+ }
1269
+
1270
+ return true;
1271
+ };
1272
+
1273
+
1274
+ /**
1275
+ * Module exports.
1276
+ */
1277
+
1278
+ var globalPage = createPage();
1279
+ var page_js = globalPage;
1280
+ var default_1 = globalPage;
1281
+
1282
+ page_js.default = default_1;
1283
+
1284
+ export default page_js;
@@ -1,4 +1,4 @@
1
- import page from 'page';
1
+ import page from './page.js';
2
2
 
3
3
  let activePage = page;
4
4
  let _lastOptions = {};