@kubex/zinc 1.1.72 → 1.1.74
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/dist/custom-elements.json +671 -174
- package/dist/vscode.html-custom-data.json +31 -26
- package/dist/web-types.json +55 -45
- package/dist/zn.d.ts +72 -5
- package/dist/zn.min.js +269 -247
- package/docs/data/preview-frame-payload-tall.json +7 -0
- package/docs/pages/components/preview-frame-demo.njk +45 -2
- package/docs/pages/components/preview-frame.md +79 -0
- package/docs/pages/components/tabs.md +9 -2
- package/package.json +1 -2
- package/scripts/build.js +5 -5
- package/src/components/defined-label/defined-label.component.ts +10 -17
- package/src/components/defined-label/defined-label.test.ts +107 -1
- package/src/components/icon-picker/icon-picker.component.ts +51 -20
- package/src/components/icon-picker/icon-picker.scss +71 -0
- package/src/components/page/page.component.ts +71 -6
- package/src/components/page/page.test.ts +247 -0
- package/src/components/preview-frame/preview-frame.component.ts +84 -8
- package/src/components/preview-frame/preview-frame.scss +7 -1
- package/src/components/preview-frame/preview-frame.test.ts +184 -0
- package/src/components/tabs/tabs-navigation.ts +197 -0
- package/src/components/tabs/tabs.component.ts +188 -56
- package/src/components/tabs/tabs.test.ts +128 -0
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
2
|
+
import {deepQuerySelectorAll} from "../../utilities/query";
|
|
3
|
+
import {
|
|
4
|
+
endVisitsToOtherLocations,
|
|
5
|
+
getHistoryTab,
|
|
6
|
+
isRestorableLocation,
|
|
7
|
+
locationScopedKey,
|
|
8
|
+
pushHistoryTab,
|
|
9
|
+
replaceHistoryTab,
|
|
10
|
+
TAB_STORE_PREFIX
|
|
11
|
+
} from './tabs-navigation';
|
|
12
|
+
import {HasSlotController} from "../../internal/slot";
|
|
13
|
+
import {ifDefined} from "lit/directives/if-defined.js";
|
|
14
|
+
import {md5} from "../../utilities/md5";
|
|
15
|
+
import {MutationController} from '@lit-labs/observers/mutation-controller.js';
|
|
16
|
+
import {property} from 'lit/decorators.js';
|
|
17
|
+
import {Store} from "../../internal/storage";
|
|
9
18
|
import ZincElement from '../../internal/zinc-element';
|
|
10
19
|
|
|
11
20
|
import styles from './tabs.scss';
|
|
@@ -34,25 +43,25 @@ const tabContainerSelector = 'zn-tabs, zn-page, zn-page-nav';
|
|
|
34
43
|
*/
|
|
35
44
|
export default class ZnTabs extends ZincElement {
|
|
36
45
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
37
|
-
@property({
|
|
38
|
-
@property({
|
|
39
|
-
@property({
|
|
40
|
-
@property({
|
|
41
|
-
@property({
|
|
42
|
-
@property({
|
|
43
|
-
@property({
|
|
44
|
-
@property({
|
|
45
|
-
@property({
|
|
46
|
-
@property({
|
|
47
|
-
@property({
|
|
46
|
+
@property({attribute: 'master-id', reflect: true}) masterId: string;
|
|
47
|
+
@property({attribute: 'default-uri', reflect: true}) defaultUri = '';
|
|
48
|
+
@property({attribute: 'active', reflect: true}) _current = '';
|
|
49
|
+
@property({attribute: 'split', type: Number, reflect: true}) _split: number;
|
|
50
|
+
@property({attribute: 'split-min', type: Number, reflect: true}) _splitMin = 60;
|
|
51
|
+
@property({attribute: 'split-min-secondary', type: Number, reflect: true}) _splitMinSecondary: number;
|
|
52
|
+
@property({attribute: 'split-max', type: Number, reflect: true}) _splitMax: number;
|
|
53
|
+
@property({attribute: 'primary-caption', reflect: true}) primaryCaption = 'Navigation';
|
|
54
|
+
@property({attribute: 'secondary-caption', reflect: true}) secondaryCaption = 'Content';
|
|
55
|
+
@property({attribute: 'no-prefetch', type: Boolean, reflect: true}) noPrefetch = false;
|
|
56
|
+
@property({attribute: 'no-cache', type: Boolean, reflect: true}) noCache = false;
|
|
48
57
|
// session storage if not local
|
|
49
|
-
@property({
|
|
50
|
-
@property({
|
|
51
|
-
@property({
|
|
52
|
-
@property({
|
|
53
|
-
@property({
|
|
54
|
-
@property({
|
|
55
|
-
@property({
|
|
58
|
+
@property({attribute: 'local-storage', type: Boolean, reflect: true}) localStorage: boolean;
|
|
59
|
+
@property({attribute: 'store-key'}) storeKey: string;
|
|
60
|
+
@property({attribute: 'store-ttl', type: Number, reflect: true}) storeTtl = 0;
|
|
61
|
+
@property({attribute: 'padded', type: Boolean, reflect: true}) padded = false;
|
|
62
|
+
@property({attribute: 'fetch-style', type: String, reflect: true}) fetchStyle = "";
|
|
63
|
+
@property({attribute: 'full-width', type: Boolean, reflect: true}) fullWidth = false;
|
|
64
|
+
@property({attribute: 'padded-right', type: Boolean, reflect: true}) paddedRight = false;
|
|
56
65
|
@property() monitor: string;
|
|
57
66
|
// Creating a header
|
|
58
67
|
@property() caption: string;
|
|
@@ -66,11 +75,12 @@ export default class ZnTabs extends ZincElement {
|
|
|
66
75
|
private _tabs: HTMLElement[] = [];
|
|
67
76
|
private _actions: HTMLElement[] = [];
|
|
68
77
|
private _knownUri: Map<string, string> = new Map<string, string>();
|
|
78
|
+
private _defaultTab = '';
|
|
69
79
|
private readonly hasSlotController = new HasSlotController(this, '[default]', 'bottom', 'right', 'left', 'top', 'actions');
|
|
70
80
|
|
|
71
81
|
private readonly _domObserver = new MutationController(this, {
|
|
72
82
|
target: null,
|
|
73
|
-
config: {
|
|
83
|
+
config: {childList: true, subtree: true},
|
|
74
84
|
callback: mutations => {
|
|
75
85
|
mutations.forEach(mutation => {
|
|
76
86
|
if (mutation.type !== 'childList') return;
|
|
@@ -89,17 +99,16 @@ export default class ZnTabs extends ZincElement {
|
|
|
89
99
|
|
|
90
100
|
private readonly _monitorObserver = new MutationController(this, {
|
|
91
101
|
target: null,
|
|
92
|
-
config: {
|
|
102
|
+
config: {childList: true, subtree: true},
|
|
93
103
|
callback: mutations => {
|
|
94
104
|
mutations.forEach(mutation => {
|
|
95
105
|
if (mutation.type !== 'childList') return;
|
|
96
106
|
mutation.addedNodes.forEach(node => {
|
|
97
107
|
if (node instanceof HTMLElement && node.id === this.monitor) {
|
|
98
108
|
this.reRegisterTabs();
|
|
99
|
-
const storedValue = this.
|
|
109
|
+
const storedValue = this.getStoredTab();
|
|
100
110
|
if (storedValue !== null) {
|
|
101
|
-
this.
|
|
102
|
-
this.setActiveTab(storedValue, false, false);
|
|
111
|
+
this.restoreStoredTab(storedValue);
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
});
|
|
@@ -133,7 +142,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
133
142
|
|
|
134
143
|
const defaultID = this.defaultUri ? this._uriToId(this.defaultUri) : '';
|
|
135
144
|
|
|
136
|
-
this._store = new Store(this.localStorage ? window.localStorage : window.sessionStorage,
|
|
145
|
+
this._store = new Store(this.localStorage ? window.localStorage : window.sessionStorage, TAB_STORE_PREFIX, this.storeTtl);
|
|
137
146
|
Array.from(this.children).forEach((element) => {
|
|
138
147
|
if (element.slot === '') {
|
|
139
148
|
this._panels.set(element.getAttribute('id') || defaultID, [element]);
|
|
@@ -142,6 +151,21 @@ export default class ZnTabs extends ZincElement {
|
|
|
142
151
|
|
|
143
152
|
this.observerDom();
|
|
144
153
|
this.monitorDom();
|
|
154
|
+
window.addEventListener('popstate', this.handlePopState, {passive: true});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
disconnectedCallback() {
|
|
158
|
+
super.disconnectedCallback();
|
|
159
|
+
window.removeEventListener('popstate', this.handlePopState);
|
|
160
|
+
|
|
161
|
+
// The container is torn down before the url it is being replaced by is
|
|
162
|
+
// pushed, so the check waits a task: by then a navigation has changed the
|
|
163
|
+
// location and this visit is over, while a re-render is back on screen.
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
if (!this.isConnected) {
|
|
166
|
+
endVisitsToOtherLocations();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
145
169
|
}
|
|
146
170
|
|
|
147
171
|
monitorDom() {
|
|
@@ -150,6 +174,116 @@ export default class ZnTabs extends ZincElement {
|
|
|
150
174
|
}
|
|
151
175
|
}
|
|
152
176
|
|
|
177
|
+
/** The key the active tab is persisted under. Null disables persistence. */
|
|
178
|
+
protected getTabStoreKey(): string | null {
|
|
179
|
+
return this.storeKey || null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
protected getStoredTab(): string | null {
|
|
183
|
+
const key = this.getTabStoreKey();
|
|
184
|
+
if (key === null || !this._store) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Local storage persists across fresh navigation and browser sessions.
|
|
189
|
+
if (this.localStorage) {
|
|
190
|
+
return this._store.get(key);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Nothing is remembered for a location that has been navigated away from:
|
|
194
|
+
// its stored tab went with the visit, and so did the tabs on its entries.
|
|
195
|
+
const stored = this._store.get(locationScopedKey(key));
|
|
196
|
+
if (stored === null) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// The history entry is authoritative where it survived; a reload wipes it,
|
|
201
|
+
// leaving the selection the location was last left on.
|
|
202
|
+
const fromHistory = getHistoryTab(key);
|
|
203
|
+
if (fromHistory !== null) {
|
|
204
|
+
return fromHistory;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return isRestorableLocation() ? stored : null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
protected storeActiveTab(tabName: string) {
|
|
211
|
+
const key = this.getTabStoreKey();
|
|
212
|
+
if (key === null || !this._store) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Uri tab ids are derived from the master id, so store the uri itself.
|
|
217
|
+
const value = this.getUriForTabId(tabName) ?? tabName;
|
|
218
|
+
this._store.set(this.localStorage ? key : locationScopedKey(key), value);
|
|
219
|
+
if (!this.localStorage) {
|
|
220
|
+
replaceHistoryTab(key, value);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
protected restoreStoredTab(stored: string) {
|
|
225
|
+
const uriTab = this._tabs.find(tab => tab.getAttribute('tab-uri') === stored);
|
|
226
|
+
if (uriTab) {
|
|
227
|
+
this.clickTab(uriTab, false);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this._prepareTab(stored);
|
|
232
|
+
this.setActiveTab(stored, true, false);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Activates the tab the container starts on, ignoring any stored selection. */
|
|
236
|
+
protected activateDefaultTab() {
|
|
237
|
+
if (!this._panels.has(this._defaultTab) && this._tabs.length > 0) {
|
|
238
|
+
const tabUri = this._tabs[0].getAttribute('tab-uri');
|
|
239
|
+
if (tabUri) {
|
|
240
|
+
this.clickTab(this._tabs[0], false);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.setActiveTab(this._defaultTab, true, false);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Back and forward move between recorded tabs.
|
|
249
|
+
private readonly handlePopState = () => {
|
|
250
|
+
const key = this.getTabStoreKey();
|
|
251
|
+
if (key === null) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Only entries that name a tab move the container. Entries that say nothing
|
|
256
|
+
// about it - the extra one the console pushes for every document load, one
|
|
257
|
+
// pushed before this container was on screen, one belonging to another page,
|
|
258
|
+
// one left by a visit that has ended - leave the open tab where it is.
|
|
259
|
+
// Overwriting it with the default tab would show the first tab on the way
|
|
260
|
+
// through, in place of the tab the entry being stepped onto stands for.
|
|
261
|
+
const tab = getHistoryTab(key);
|
|
262
|
+
if (tab === null) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
this.restoreStoredTab(tab);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
private pushTabHistory(tabName: string) {
|
|
270
|
+
const key = this.getTabStoreKey();
|
|
271
|
+
if (key === null || this.localStorage) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
pushHistoryTab(key, this.getUriForTabId(tabName) ?? tabName);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private getUriForTabId(tabId: string): string | null {
|
|
279
|
+
for (const [uri, id] of this._knownUri) {
|
|
280
|
+
if (id === tabId) {
|
|
281
|
+
return uri;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
153
287
|
_addPanel(panel: HTMLElement) {
|
|
154
288
|
if (this._panels.has(panel.getAttribute('id')!)) {
|
|
155
289
|
return;
|
|
@@ -176,29 +310,20 @@ export default class ZnTabs extends ZincElement {
|
|
|
176
310
|
super.firstUpdated(_changedProperties);
|
|
177
311
|
setTimeout(() => {
|
|
178
312
|
this._registerTabs();
|
|
313
|
+
this._defaultTab = this._current || '';
|
|
179
314
|
|
|
180
|
-
const storedValue = this.
|
|
315
|
+
const storedValue = this.getStoredTab();
|
|
181
316
|
if (storedValue !== null) {
|
|
182
|
-
this.
|
|
183
|
-
this.setActiveTab(storedValue, false, false);
|
|
317
|
+
this.restoreStoredTab(storedValue);
|
|
184
318
|
return;
|
|
185
319
|
}
|
|
186
320
|
|
|
187
|
-
|
|
188
|
-
if (!this._panels.has(defaultTab) && this._tabs.length > 0) {
|
|
189
|
-
const tabUri = this._tabs[0].getAttribute('tab-uri');
|
|
190
|
-
if (tabUri) {
|
|
191
|
-
this.clickTab(this._tabs[0], false);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this.setActiveTab(defaultTab, false, false);
|
|
321
|
+
this.activateDefaultTab();
|
|
197
322
|
}, 10);
|
|
198
323
|
|
|
199
324
|
this.addEventListener('zn-menu-select', () => {
|
|
200
325
|
setTimeout(this.reRegisterTabs, 200);
|
|
201
|
-
}, {
|
|
326
|
+
}, {passive: true});
|
|
202
327
|
}
|
|
203
328
|
|
|
204
329
|
switchTab(inc: number) {
|
|
@@ -215,7 +340,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
215
340
|
nextIndex = 0; // wrap around to the first tab
|
|
216
341
|
}
|
|
217
342
|
const nextTabId = Array.from(this._panels.keys())[nextIndex];
|
|
218
|
-
this.setActiveTab(nextTabId, true, false);
|
|
343
|
+
this.setActiveTab(nextTabId, true, false, null, true);
|
|
219
344
|
}
|
|
220
345
|
|
|
221
346
|
nextTab() {
|
|
@@ -277,7 +402,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
277
402
|
}
|
|
278
403
|
|
|
279
404
|
document.dispatchEvent(new CustomEvent('zn-new-element', {
|
|
280
|
-
detail: {
|
|
405
|
+
detail: {element: tabNode, source: tabEle}
|
|
281
406
|
}));
|
|
282
407
|
return tabNode;
|
|
283
408
|
}
|
|
@@ -288,9 +413,9 @@ export default class ZnTabs extends ZincElement {
|
|
|
288
413
|
if (target) {
|
|
289
414
|
if ('startViewTransition' in document) {
|
|
290
415
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
291
|
-
(document as any).startViewTransition(() => this.clickTab(target, event.altKey));
|
|
416
|
+
(document as any).startViewTransition(() => this.clickTab(target, event.altKey, true));
|
|
292
417
|
} else {
|
|
293
|
-
this.clickTab(target, event.altKey)
|
|
418
|
+
this.clickTab(target, event.altKey, true)
|
|
294
419
|
}
|
|
295
420
|
}
|
|
296
421
|
}
|
|
@@ -303,7 +428,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
303
428
|
}
|
|
304
429
|
}
|
|
305
430
|
|
|
306
|
-
clickTab(target: HTMLElement, refresh: boolean) {
|
|
431
|
+
clickTab(target: HTMLElement, refresh: boolean, pushHistory = false) {
|
|
307
432
|
const tabUri = target.getAttribute('tab-uri');
|
|
308
433
|
const wasCached = !!tabUri && this._panels.has(this._uriToId(tabUri));
|
|
309
434
|
this.fetchUriTab(target);
|
|
@@ -311,7 +436,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
311
436
|
if (target.hasAttribute('tab')) {
|
|
312
437
|
const forceRefresh = refresh || (this.noCache && wasCached);
|
|
313
438
|
setTimeout(() => {
|
|
314
|
-
this.setActiveTab(target.getAttribute('tab') || '', true, forceRefresh, this.getRefTab(target));
|
|
439
|
+
this.setActiveTab(target.getAttribute('tab') || '', true, forceRefresh, this.getRefTab(target), pushHistory);
|
|
315
440
|
}, 10);
|
|
316
441
|
}
|
|
317
442
|
}
|
|
@@ -331,7 +456,8 @@ export default class ZnTabs extends ZincElement {
|
|
|
331
456
|
return null;
|
|
332
457
|
}
|
|
333
458
|
|
|
334
|
-
setActiveTab(tabName: string, store: boolean, refresh: boolean, refTab: string | null = null) {
|
|
459
|
+
setActiveTab(tabName: string, store: boolean, refresh: boolean, refTab: string | null = null, pushHistory = false) {
|
|
460
|
+
const previous = this._current;
|
|
335
461
|
let hasActive = false;
|
|
336
462
|
this._tabs.forEach(tab => {
|
|
337
463
|
|
|
@@ -355,8 +481,14 @@ export default class ZnTabs extends ZincElement {
|
|
|
355
481
|
//Set on the element as a failsafe before TabPanel is loaded
|
|
356
482
|
//This must be done AFTER selectTab to avoid panel bugs
|
|
357
483
|
|
|
358
|
-
|
|
359
|
-
|
|
484
|
+
// The entry must be pushed before the tab is recorded, so the entry being
|
|
485
|
+
// left keeps the tab it was showing.
|
|
486
|
+
if (pushHistory && this._current === tabName && previous !== tabName) {
|
|
487
|
+
this.pushTabHistory(tabName);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (store) {
|
|
491
|
+
this.storeActiveTab(tabName);
|
|
360
492
|
}
|
|
361
493
|
}
|
|
362
494
|
|
|
@@ -402,7 +534,7 @@ export default class ZnTabs extends ZincElement {
|
|
|
402
534
|
gaid = this._activeTab.getAttribute('gaid')!;
|
|
403
535
|
}
|
|
404
536
|
document.dispatchEvent(new CustomEvent('zn-refresh-element', {
|
|
405
|
-
detail: {
|
|
537
|
+
detail: {element: element, uri: uri, gaid: gaid}
|
|
406
538
|
}));
|
|
407
539
|
}
|
|
408
540
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
2
|
import { aTimeout, expect, fixture, html } from '@open-wc/testing';
|
|
3
|
+
import { locationScopedKey } from './tabs-navigation';
|
|
3
4
|
import type ZnTabs from './tabs.component';
|
|
4
5
|
|
|
5
6
|
describe('<zn-tabs>', () => {
|
|
@@ -48,4 +49,131 @@ describe('<zn-tabs>', () => {
|
|
|
48
49
|
const selectedPagePanel = page.shadowRoot!.querySelector<HTMLElement>('#content > div[selected]')!;
|
|
49
50
|
expect(selectedPagePanel.id).to.equal('');
|
|
50
51
|
});
|
|
52
|
+
|
|
53
|
+
describe('selection persistence', () => {
|
|
54
|
+
const storeKey = 'tabs-navigation-test';
|
|
55
|
+
const originalHref = window.location.href;
|
|
56
|
+
let locationCount = 0;
|
|
57
|
+
|
|
58
|
+
const renderTabs = () => fixture<ZnTabs>(html`
|
|
59
|
+
<zn-tabs store-key=${storeKey} active="first">
|
|
60
|
+
<zn-navbar slot="top">
|
|
61
|
+
<li tab="first">First</li>
|
|
62
|
+
<li tab="second">Second</li>
|
|
63
|
+
</zn-navbar>
|
|
64
|
+
<div id="first">First panel</div>
|
|
65
|
+
<div id="second">Second panel</div>
|
|
66
|
+
</zn-tabs>
|
|
67
|
+
`);
|
|
68
|
+
|
|
69
|
+
// Each test runs on its own location so a stored selection, and whether that
|
|
70
|
+
// location may restore one, cannot leak between them.
|
|
71
|
+
const navigateTo = (name: string) => window.history.pushState({}, '', `?tabs-test=${name}`);
|
|
72
|
+
const returnWithHistory = () => window.dispatchEvent(new PopStateEvent('popstate'));
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
locationCount += 1;
|
|
76
|
+
navigateTo(`case-${locationCount}`);
|
|
77
|
+
sessionStorage.removeItem(`zntab:${storeKey}`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
afterEach(() => window.history.replaceState({}, '', originalHref));
|
|
81
|
+
|
|
82
|
+
it('restores the tab a location was left on when returning to it', async () => {
|
|
83
|
+
const el = await renderTabs();
|
|
84
|
+
await aTimeout(40);
|
|
85
|
+
el.querySelector('zn-navbar')!.querySelectorAll<HTMLElement>('li')[1].click();
|
|
86
|
+
await aTimeout(40);
|
|
87
|
+
expect(el.getAttribute('active')).to.equal('second');
|
|
88
|
+
el.remove();
|
|
89
|
+
|
|
90
|
+
returnWithHistory();
|
|
91
|
+
const restored = await renderTabs();
|
|
92
|
+
await aTimeout(40);
|
|
93
|
+
|
|
94
|
+
expect(restored.getAttribute('active')).to.equal('second');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('starts from the default tab when navigating to the location', async () => {
|
|
98
|
+
const first = await renderTabs();
|
|
99
|
+
await aTimeout(40);
|
|
100
|
+
first.querySelector('zn-navbar')!.querySelectorAll<HTMLElement>('li')[1].click();
|
|
101
|
+
await aTimeout(40);
|
|
102
|
+
first.remove();
|
|
103
|
+
|
|
104
|
+
// Leave and navigate back, rather than returning through history.
|
|
105
|
+
const stored = window.location.search;
|
|
106
|
+
navigateTo('elsewhere');
|
|
107
|
+
window.history.pushState({}, '', stored);
|
|
108
|
+
|
|
109
|
+
const el = await renderTabs();
|
|
110
|
+
await aTimeout(40);
|
|
111
|
+
|
|
112
|
+
expect(el.getAttribute('active')).to.equal('first');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('stores tab changes made outside the navigation', async () => {
|
|
116
|
+
const el = await renderTabs();
|
|
117
|
+
await aTimeout(40);
|
|
118
|
+
|
|
119
|
+
el.nextTab();
|
|
120
|
+
await aTimeout(40);
|
|
121
|
+
expect(el.getAttribute('active')).to.equal('second');
|
|
122
|
+
el.remove();
|
|
123
|
+
|
|
124
|
+
returnWithHistory();
|
|
125
|
+
const restored = await renderTabs();
|
|
126
|
+
await aTimeout(40);
|
|
127
|
+
|
|
128
|
+
expect(restored.getAttribute('active')).to.equal('second');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('steps back through each tab that was opened', async () => {
|
|
132
|
+
const el = await renderTabs();
|
|
133
|
+
await aTimeout(40);
|
|
134
|
+
const items = el.querySelector('zn-navbar')!.querySelectorAll<HTMLElement>('li');
|
|
135
|
+
|
|
136
|
+
items[1].click();
|
|
137
|
+
await aTimeout(40);
|
|
138
|
+
expect(el.getAttribute('active')).to.equal('second');
|
|
139
|
+
|
|
140
|
+
await new Promise<void>(resolve => {
|
|
141
|
+
window.addEventListener('popstate', () => resolve(), {once: true});
|
|
142
|
+
window.history.back();
|
|
143
|
+
});
|
|
144
|
+
await aTimeout(40);
|
|
145
|
+
|
|
146
|
+
expect(el.getAttribute('active')).to.equal('first');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('forgets the selection once the location is navigated away from', async () => {
|
|
150
|
+
const el = await renderTabs();
|
|
151
|
+
await aTimeout(40);
|
|
152
|
+
el.querySelector('zn-navbar')!.querySelectorAll<HTMLElement>('li')[1].click();
|
|
153
|
+
await aTimeout(40);
|
|
154
|
+
const stored = window.location.search;
|
|
155
|
+
el.remove();
|
|
156
|
+
|
|
157
|
+
navigateTo('departed');
|
|
158
|
+
await aTimeout(40);
|
|
159
|
+
expect(sessionStorage.getItem(`zntab:${storeKey}@${window.location.pathname}${stored}`)).to.equal(null);
|
|
160
|
+
|
|
161
|
+
window.history.replaceState({}, '', stored);
|
|
162
|
+
returnWithHistory();
|
|
163
|
+
const returned = await renderTabs();
|
|
164
|
+
await aTimeout(40);
|
|
165
|
+
|
|
166
|
+
expect(returned.getAttribute('active')).to.equal('first');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('keeps a session selection out of local storage', async () => {
|
|
170
|
+
const el = await renderTabs();
|
|
171
|
+
await aTimeout(40);
|
|
172
|
+
el.querySelector('zn-navbar')!.querySelectorAll<HTMLElement>('li')[1].click();
|
|
173
|
+
await aTimeout(40);
|
|
174
|
+
|
|
175
|
+
expect(localStorage.getItem(`zntab:${storeKey}`)).to.equal(null);
|
|
176
|
+
expect(sessionStorage.getItem(`zntab:${locationScopedKey(storeKey)}`)).to.contain('second');
|
|
177
|
+
});
|
|
178
|
+
});
|
|
51
179
|
});
|