@internetarchive/ia-item-navigator 0.0.0-a10 → 0.0.0-a16

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.
Files changed (54) hide show
  1. package/README.md +29 -19
  2. package/demo/app-root.ts +37 -31
  3. package/demo/index.html +1 -0
  4. package/dist/demo/app-root.d.ts +11 -15
  5. package/dist/demo/app-root.js +26 -26
  6. package/dist/demo/app-root.js.map +1 -1
  7. package/dist/src/interfaces/custom-theater-interface.d.ts +20 -0
  8. package/dist/src/interfaces/custom-theater-interface.js +2 -0
  9. package/dist/src/interfaces/custom-theater-interface.js.map +1 -0
  10. package/dist/src/interfaces/event-interfaces.d.ts +11 -11
  11. package/dist/src/interfaces/event-interfaces.js.map +1 -1
  12. package/dist/src/interfaces/menu-interfaces.d.ts +6 -7
  13. package/dist/src/interfaces/menu-interfaces.js.map +1 -1
  14. package/dist/src/interfaces/nav-controller-interface.d.ts +11 -6
  15. package/dist/src/interfaces/nav-controller-interface.js.map +1 -1
  16. package/dist/src/item-inspector/item-inspector.d.ts +0 -47
  17. package/dist/src/item-inspector/item-inspector.js +253 -271
  18. package/dist/src/item-inspector/item-inspector.js.map +1 -1
  19. package/dist/src/item-navigator.d.ts +41 -27
  20. package/dist/src/item-navigator.js +87 -84
  21. package/dist/src/item-navigator.js.map +1 -1
  22. package/dist/src/no-theater-available.d.ts +9 -0
  23. package/dist/src/no-theater-available.js +79 -0
  24. package/dist/src/no-theater-available.js.map +1 -0
  25. package/dist/test/book-nav-stub.d.ts +22 -0
  26. package/dist/test/book-nav-stub.js +49 -0
  27. package/dist/test/book-nav-stub.js.map +1 -0
  28. package/dist/test/ia-item-navigator.test.d.ts +1 -0
  29. package/dist/test/ia-item-navigator.test.js +279 -131
  30. package/dist/test/ia-item-navigator.test.js.map +1 -1
  31. package/dist/test/ia-stub.d.ts +22 -0
  32. package/dist/test/ia-stub.js +34 -3
  33. package/dist/test/ia-stub.js.map +1 -1
  34. package/dist/test/no-theater-available.test.d.ts +1 -0
  35. package/dist/test/no-theater-available.test.js +27 -0
  36. package/dist/test/no-theater-available.test.js.map +1 -0
  37. package/package.json +4 -3
  38. package/src/interfaces/custom-theater-interface.ts +28 -0
  39. package/src/interfaces/event-interfaces.ts +15 -11
  40. package/src/interfaces/menu-interfaces.ts +9 -10
  41. package/src/item-navigator.ts +124 -114
  42. package/src/no-theater-available.ts +85 -0
  43. package/test/book-nav-stub.ts +47 -0
  44. package/test/ia-item-navigator.test.ts +365 -156
  45. package/test/ia-stub.ts +78 -2
  46. package/test/no-theater-available.test.ts +32 -0
  47. package/demo/demo-book-manifest.json +0 -1163
  48. package/src/interfaces/nav-controller-interface.ts +0 -18
  49. package/src/item-inspector/files-by-type/files-by-type-provider.ts +0 -43
  50. package/src/item-inspector/files-by-type/ia-files-by-type.ts +0 -100
  51. package/src/item-inspector/item-inspector.ts +0 -296
  52. package/src/item-inspector/share-provider.ts +0 -51
  53. package/src/item-inspector/visual-mod-provider.ts +0 -65
  54. package/src/item-navigator-js.js +0 -372
@@ -1,4 +1,35 @@
1
- "use strict";
2
- // const parsed = JSON.parse(raw);
3
- // export default parsed;
1
+ import { html } from 'lit-html';
2
+ export class ItemStub {
3
+ constructor() {
4
+ this.rawResponse = '';
5
+ this.created = 1;
6
+ this.d1 = 'hello';
7
+ this.d2 = 'boop';
8
+ this.dir = 'whee';
9
+ this.files = [];
10
+ this.files_count = 0;
11
+ this.item_last_updated = 2020;
12
+ this.item_size = 111;
13
+ this.metadata = { identifier: 'foo' };
14
+ this.server = 'foo-server';
15
+ this.uniq = 2;
16
+ this.workable_servers = ['abc'];
17
+ }
18
+ }
19
+ export const shortcut = {
20
+ id: 'fullscreen',
21
+ icon: html `<i class="fas fullscreen-test"></i>`,
22
+ };
23
+ export const menuProvider = {
24
+ ...shortcut,
25
+ label: 'foo',
26
+ menuDetails: html `<div>foo</div>`,
27
+ selected: true,
28
+ followable: false,
29
+ href: 'https://archive.foo',
30
+ item: new ItemStub(),
31
+ baseHost: 'https://archive.foo',
32
+ subPrefix: 'bar',
33
+ updated: () => { },
34
+ };
4
35
  //# sourceMappingURL=ia-stub.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ia-stub.js","sourceRoot":"","sources":["../../test/ia-stub.ts"],"names":[],"mappings":";AAAA,kCAAkC;AAElC,yBAAyB","sourcesContent":["// const parsed = JSON.parse(raw);\n\n// export default parsed;\n"]}
1
+ {"version":3,"file":"ia-stub.js","sourceRoot":"","sources":["../../test/ia-stub.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAMhC,MAAM,OAAO,QAAQ;IACnB;QACE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,EAAE,UAAU,EAAE,KAAK,EAAc,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;CA+BF;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,IAAI,CAAA,qCAAqC;CACvB,CAAC;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,GAAG,QAAQ;IACX,KAAK,EAAE,KAAK;IACZ,WAAW,EAAE,IAAI,CAAA,gBAAgB;IACjC,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,KAAK;IACjB,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE,IAAI,QAAQ,EAAE;IACpB,QAAQ,EAAE,qBAAqB;IAC/B,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;CACO,CAAC","sourcesContent":["/* eslint-disable camelcase */\nimport {\n MetadataResponse,\n Metadata,\n File,\n Review,\n SpeechMusicASREntry,\n} from '@internetarchive/search-service';\nimport { html } from 'lit-html';\nimport {\n MenuShortcutInterface,\n MenuProviderInterface,\n} from '../src/interfaces/menu-interfaces';\n\nexport class ItemStub implements MetadataResponse {\n constructor() {\n this.rawResponse = '';\n this.created = 1;\n this.d1 = 'hello';\n this.d2 = 'boop';\n this.dir = 'whee';\n this.files = [];\n this.files_count = 0;\n this.item_last_updated = 2020;\n this.item_size = 111;\n this.metadata = { identifier: 'foo' } as Metadata;\n this.server = 'foo-server';\n this.uniq = 2;\n this.workable_servers = ['abc'];\n }\n\n rawResponse: any;\n\n created: number;\n\n d1: string;\n\n d2: string;\n\n dir: string;\n\n files: File[];\n\n files_count: number;\n\n item_last_updated: number;\n\n item_size: number;\n\n metadata: Metadata;\n\n server: string;\n\n uniq: number;\n\n workable_servers: string[];\n\n speech_vs_music_asr?: SpeechMusicASREntry[] | undefined;\n\n reviews?: Review[] | undefined;\n}\n\nexport const shortcut = {\n id: 'fullscreen',\n icon: html`<i class=\"fas fullscreen-test\"></i>`,\n} as MenuShortcutInterface;\n\nexport const menuProvider = {\n ...shortcut,\n label: 'foo',\n menuDetails: html`<div>foo</div>`,\n selected: true,\n followable: false,\n href: 'https://archive.foo',\n item: new ItemStub(),\n baseHost: 'https://archive.foo',\n subPrefix: 'bar',\n updated: () => {},\n} as MenuProviderInterface;\n"]}
@@ -0,0 +1 @@
1
+ import '../src/no-theater-available';
@@ -0,0 +1,27 @@
1
+ import { html, fixture, expect } from '@open-wc/testing';
2
+ import '../src/no-theater-available';
3
+ describe('IANoTheaterAvailable', () => {
4
+ it('Fires `loadingStateUpdated` on identifier change', async () => {
5
+ const el = await fixture(html `<ia-no-theater-available
6
+ .identifier=${`foo`}
7
+ ></ia-no-theater-available>`);
8
+ let eventFired = false;
9
+ el.addEventListener('loadingStateUpdated', () => {
10
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
+ eventFired = true;
12
+ });
13
+ expect(eventFired).to.be.false;
14
+ el.identifier = 'bar';
15
+ await el.updateComplete;
16
+ expect(eventFired).to.be.true;
17
+ });
18
+ it('Has link to item download page', async () => {
19
+ var _a, _b;
20
+ const el = await fixture(html `<ia-no-theater-available
21
+ .identifier=${`foo`}
22
+ ></ia-no-theater-available>`);
23
+ expect(el.downloadUrl).to.equal('/download/foo');
24
+ expect((_b = (_a = el === null || el === void 0 ? void 0 : el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('a')) === null || _b === void 0 ? void 0 : _b.href).to.contain(el.downloadUrl);
25
+ });
26
+ });
27
+ //# sourceMappingURL=no-theater-available.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-theater-available.test.js","sourceRoot":"","sources":["../../test/no-theater-available.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,6BAA6B,CAAC;AAErC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,EAAE,GAAG,MAAM,OAAO,CACtB,IAAI,CAAA;sBACY,KAAK;kCACO,CAC7B,CAAC;QACF,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,EAAE,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC9C,6DAA6D;YAC7D,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAE/B,EAAE,CAAC,UAAU,GAAG,KAAK,CAAC;QACtB,MAAM,EAAE,CAAC,cAAc,CAAC;QACxB,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;;QAC9C,MAAM,EAAE,GAAG,MAAM,OAAO,CACtB,IAAI,CAAA;sBACY,KAAK;kCACO,CAC7B,CAAC;QACF,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,CAAC,MAAA,MAAA,EAAE,aAAF,EAAE,uBAAF,EAAE,CAAE,UAAU,0CAAE,aAAa,CAAC,GAAG,CAAC,0CAAE,IAAI,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { html, fixture, expect } from '@open-wc/testing';\nimport { IANoTheaterAvailable } from '../src/no-theater-available';\nimport '../src/no-theater-available';\n\ndescribe('IANoTheaterAvailable', () => {\n it('Fires `loadingStateUpdated` on identifier change', async () => {\n const el = await fixture<IANoTheaterAvailable>(\n html`<ia-no-theater-available\n .identifier=${`foo`}\n ></ia-no-theater-available>`\n );\n let eventFired = false;\n el.addEventListener('loadingStateUpdated', () => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n eventFired = true;\n });\n expect(eventFired).to.be.false;\n\n el.identifier = 'bar';\n await el.updateComplete;\n expect(eventFired).to.be.true;\n });\n it('Has link to item download page', async () => {\n const el = await fixture<IANoTheaterAvailable>(\n html`<ia-no-theater-available\n .identifier=${`foo`}\n ></ia-no-theater-available>`\n );\n expect(el.downloadUrl).to.equal('/download/foo');\n expect(el?.shadowRoot?.querySelector('a')?.href).to.contain(el.downloadUrl);\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/ia-item-navigator",
3
- "version": "0.0.0-a10",
3
+ "version": "0.0.0-a16",
4
4
  "description": "Internet Archive's Item Navigator, visually eplore an item's contents.",
5
5
  "author": "Internet Archive",
6
6
  "license": "AGPL-3.0-only",
@@ -21,7 +21,7 @@
21
21
  "test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\""
22
22
  },
23
23
  "dependencies": {
24
- "@internetarchive/ia-menu-slider": "^1.1.0",
24
+ "@internetarchive/ia-menu-slider": "^1.1.1",
25
25
  "@internetarchive/ia-sharing-options": "^0.1.3-alpha2",
26
26
  "@internetarchive/icon-ellipses": "^1.1.3",
27
27
  "@internetarchive/icon-share": "^1.1.3",
@@ -78,7 +78,8 @@
78
78
  "js": "never",
79
79
  "ts": "never"
80
80
  }
81
- ]
81
+ ],
82
+ "import/no-duplicates": "off"
82
83
  }
83
84
  },
84
85
  "prettier": {
@@ -0,0 +1,28 @@
1
+ import { LitElement } from 'lit-element';
2
+ import { MetadataResponse } from '@internetarchive/search-service';
3
+ import { ModalManager } from '@internetarchive/modal-manager';
4
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
5
+ import {
6
+ MenuProviderInterface,
7
+ MenuShortcutInterface,
8
+ } from './menu-interfaces';
9
+
10
+ export interface CustomTheaterInterface extends LitElement {
11
+ baseHost?: string;
12
+ itemMD?: MetadataResponse;
13
+ menuProviders?: MenuProviderInterface[];
14
+ menuShortcuts?: MenuShortcutInterface[];
15
+ sideMenuOpen: boolean;
16
+
17
+ signedIn?: boolean | null;
18
+
19
+ sharedObserver?: SharedResizeObserver;
20
+ modal?: ModalManager;
21
+
22
+ emitLoadingStatusUpdate: (loaded: boolean) => void;
23
+
24
+ addMenuShortcut: (menuId: string) => void;
25
+ removeMenuShortcut: (menuId: string) => void;
26
+ sortMenuShortcuts: () => void;
27
+ emitMenuShortcutsUpdated: () => void;
28
+ }
@@ -1,36 +1,40 @@
1
- import { IntMenuProvider, IntMenuShortcut } from './menu-interfaces';
1
+ import {
2
+ MenuProviderInterface,
3
+ MenuShortcutInterface,
4
+ MenuId,
5
+ } from './menu-interfaces';
2
6
 
3
7
  /** Toggles Menu && Sets open panel */
4
- export interface IntManageSideMenuEvent extends CustomEvent {
8
+ export interface ToggleSideMenuOpenEvent extends CustomEvent {
5
9
  type: 'updateSideMenu';
6
10
  detail: {
7
- menuId: string | undefined | '';
11
+ menuId: MenuId | undefined | '';
8
12
  action: 'open' | 'toggle' | '';
9
13
  };
10
14
  }
11
15
 
12
16
  /** Sets open panel */
13
- export interface IntSetOpenMenuEvent extends CustomEvent {
17
+ export interface ToggleSidePanelOpenEvent extends CustomEvent {
14
18
  type: 'menuTypeSelected';
15
19
  detail: {
16
- id: string /** name of menu to open */;
20
+ id: MenuId | '';
17
21
  };
18
22
  }
19
23
 
20
24
  /** Sets menu order that is displayed */
21
- export interface IntSetMenuContentsEvent extends CustomEvent {
25
+ export interface SetSideMenuContentsEvent extends CustomEvent {
22
26
  type: 'menuUpdated';
23
- detail: IntMenuProvider[];
27
+ detail: MenuProviderInterface[];
24
28
  }
25
29
 
26
30
  /** Sets menu shortcuts that is displayed */
27
- export interface IntSetMenuShortcutsEvent extends CustomEvent {
31
+ export interface SetSideMenuShortcutsEvent extends CustomEvent {
28
32
  type: 'menuUpdated';
29
- detail: IntMenuShortcut[];
33
+ detail: MenuShortcutInterface[];
30
34
  }
31
35
 
32
36
  /** Toggles fullscreen mode */
33
- export interface IntManageFullscreenEvent extends CustomEvent {
37
+ export interface ManageFullscreenEvent extends CustomEvent {
34
38
  type: 'ViewportInFullScreen';
35
39
  detail: {
36
40
  isFullScreen: boolean;
@@ -38,7 +42,7 @@ export interface IntManageFullscreenEvent extends CustomEvent {
38
42
  }
39
43
 
40
44
  /** Toggles loading view */
41
- export interface IntLoadingStateUpdatedEvent extends CustomEvent {
45
+ export interface loadingStateUpdatedEvent extends CustomEvent {
42
46
  type: 'loadingStateUpdated';
43
47
  detail: {
44
48
  loaded: boolean;
@@ -1,14 +1,13 @@
1
1
  import { TemplateResult } from 'lit-html';
2
2
  import { MetadataResponse } from '@internetarchive/search-service';
3
3
 
4
- export interface IntMenuShortcut {
4
+ export type MenuId = string;
5
+ export interface MenuShortcutInterface {
5
6
  icon: TemplateResult;
6
- id: string;
7
+ id: MenuId;
7
8
  }
8
9
 
9
- export interface IntMenuIconAndDetails extends IntMenuShortcut {
10
- icon: TemplateResult;
11
- id: string;
10
+ export interface MenuDetailsInterface extends MenuShortcutInterface {
12
11
  label: string;
13
12
  menuDetails?: TemplateResult;
14
13
  selected?: boolean;
@@ -16,13 +15,13 @@ export interface IntMenuIconAndDetails extends IntMenuShortcut {
16
15
  href?: string;
17
16
  }
18
17
 
19
- export interface IntProviderArgs {
18
+ export interface MenuProviderBaseConfigInterface {
20
19
  item: MetadataResponse;
21
20
  baseHost: string;
22
21
  subPrefix: string;
23
22
  updated?: any;
24
23
  }
25
- export interface IntMenuProvider
26
- extends IntProviderArgs,
27
- IntMenuIconAndDetails,
28
- IntMenuShortcut {}
24
+ export interface MenuProviderInterface
25
+ extends MenuProviderBaseConfigInterface,
26
+ MenuDetailsInterface,
27
+ MenuShortcutInterface {}
@@ -1,4 +1,3 @@
1
- /* eslint-disable import/no-duplicates */
2
1
  import {
3
2
  css,
4
3
  html,
@@ -8,33 +7,39 @@ import {
8
7
  state,
9
8
  query,
10
9
  PropertyValues,
10
+ CSSResult,
11
11
  } from 'lit-element';
12
12
  import { nothing, TemplateResult } from 'lit-html';
13
13
  import { MetadataResponse } from '@internetarchive/search-service';
14
14
  import {
15
15
  SharedResizeObserver,
16
- SharedResizeObserverInterface,
17
16
  SharedResizeObserverResizeHandlerInterface,
18
17
  } from '@internetarchive/shared-resize-observer';
19
- // @ts-ignore
20
- import { IAMenuSlider } from '@internetarchive/ia-menu-slider';
21
18
  import '@internetarchive/ia-menu-slider';
22
19
 
23
- import { ModalManagerInterface } from '@internetarchive/modal-manager';
20
+ import { ModalManager } from '@internetarchive/modal-manager';
24
21
  import '@internetarchive/icon-ellipses/icon-ellipses';
25
22
  import './loader';
26
23
 
27
24
  import {
28
- IntManageSideMenuEvent,
29
- IntSetOpenMenuEvent,
30
- IntSetMenuContentsEvent,
31
- IntSetMenuShortcutsEvent,
32
- IntLoadingStateUpdatedEvent,
33
- IntManageFullscreenEvent,
25
+ ToggleSideMenuOpenEvent,
26
+ ToggleSidePanelOpenEvent,
27
+ SetSideMenuContentsEvent,
28
+ SetSideMenuShortcutsEvent,
29
+ loadingStateUpdatedEvent,
30
+ ManageFullscreenEvent,
34
31
  } from './interfaces/event-interfaces';
35
32
 
36
- import { IntMenuProvider, IntMenuShortcut } from './interfaces/menu-interfaces';
37
-
33
+ import {
34
+ MenuProviderInterface,
35
+ MenuShortcutInterface,
36
+ MenuId,
37
+ } from './interfaces/menu-interfaces';
38
+ import './no-theater-available';
39
+
40
+ export enum ItemType {
41
+ BOOK = 'bookreader',
42
+ }
38
43
  @customElement('ia-item-navigator')
39
44
  export class ItemNavigator
40
45
  extends LitElement
@@ -48,9 +53,9 @@ export class ItemNavigator
48
53
  return value as MetadataResponse;
49
54
  },
50
55
  })
51
- item: MetadataResponse | undefined = undefined;
56
+ item?: MetadataResponse;
52
57
 
53
- @property({ type: String }) itemType = '';
58
+ @property({ type: String }) itemType?: ItemType;
54
59
 
55
60
  @property({ type: String }) baseHost = 'archive.org';
56
61
 
@@ -64,66 +69,44 @@ export class ItemNavigator
64
69
  })
65
70
  signedIn = false;
66
71
 
67
- @property({
68
- type: Array,
69
- hasChanged: (newVal: Array<object>, oldVal: Array<object>) => {
70
- if (newVal !== oldVal) {
71
- return true;
72
- }
73
- return false;
74
- },
75
- })
76
- @property({ type: Array })
77
- menuContents: IntMenuProvider[] = [];
72
+ @property({ type: Array }) menuContents: MenuProviderInterface[] = [];
78
73
 
79
- @property({ type: Array }) menuShortcuts: IntMenuShortcut[] = [];
74
+ @property({ type: Array }) menuShortcuts: MenuShortcutInterface[] = [];
80
75
 
81
- @property({ type: Boolean, reflect: true }) viewportInFullscreen = false;
76
+ @property({ type: Boolean, reflect: true, attribute: true })
77
+ viewportInFullscreen: boolean | null = null;
82
78
 
83
79
  @property({ type: Boolean }) menuOpened = false;
84
80
 
85
- @property({ type: String }) openMenu = '';
81
+ @property({ type: String }) openMenu?: MenuId;
86
82
 
87
- @property({ attribute: false }) modal?: ModalManagerInterface;
83
+ @property({ attribute: false }) modal?: ModalManager;
88
84
 
89
- @property({ attribute: false })
90
- sharedObserver?: SharedResizeObserverInterface;
85
+ @property({ attribute: false }) sharedObserver?: SharedResizeObserver;
91
86
 
92
- @property({ type: Boolean, reflect: true }) loaded: boolean = false;
87
+ @property({ type: Boolean, reflect: true, attribute: true }) loaded:
88
+ | true
89
+ | null = null;
93
90
 
94
91
  @state() openMenuState: 'overlay' | 'shift' = 'shift';
95
92
 
96
93
  @query('#frame') private frame!: HTMLDivElement;
97
94
 
98
- disconnectedCallback() {
99
- this.sharedObserver?.removeObserver({
100
- handler: this,
101
- target: this.frame,
102
- });
103
- }
104
-
105
- firstUpdated(pp: any): void {
106
- console.log('first updated item-nav', this.modal, pp);
107
- if (!this.modal) {
108
- this.createModal();
109
- }
95
+ @query('slot[name="theater-header"]') private headerSlot!: HTMLDivElement;
110
96
 
111
- this.startResizeObserver();
97
+ disconnectedCallback() {
98
+ this.removeResizeObserver();
112
99
  }
113
100
 
114
101
  updated(changed: PropertyValues) {
115
- if (changed.has('modal')) {
116
- if (!this.modal) {
117
- this.createModal();
118
- }
119
- }
120
102
  if (changed.has('sharedObserver')) {
121
- if (!this.sharedObserver) {
122
- this.startResizeObserver();
123
- }
103
+ const oldObserver = changed.get('sharedObserver') as SharedResizeObserver;
104
+ oldObserver?.removeObserver(this.resizeObserverConfig);
105
+ this.setResizeObserver();
124
106
  }
125
107
  }
126
108
 
109
+ /** Shared observer */
127
110
  handleResize(entry: ResizeObserverEntry): void {
128
111
  const { width } = entry.contentRect;
129
112
  if (width <= 600) {
@@ -133,52 +116,87 @@ export class ItemNavigator
133
116
  this.openMenuState = 'shift';
134
117
  }
135
118
 
136
- private startResizeObserver(): void {
137
- if (!this.sharedObserver) {
138
- this.sharedObserver = new SharedResizeObserver();
139
- }
140
- this.sharedObserver.addObserver({
119
+ private setResizeObserver(): void {
120
+ this.sharedObserver?.addObserver(this.resizeObserverConfig);
121
+ }
122
+
123
+ private removeResizeObserver(): void {
124
+ this.sharedObserver?.removeObserver(this.resizeObserverConfig);
125
+ }
126
+
127
+ get resizeObserverConfig(): {
128
+ handler: SharedResizeObserverResizeHandlerInterface;
129
+ target: Element;
130
+ } {
131
+ return {
141
132
  handler: this,
142
133
  target: this.frame,
143
- });
134
+ };
144
135
  }
136
+ /** End shared observer */
145
137
 
146
138
  get loaderTitle() {
147
139
  return this.viewportInFullscreen ? 'Internet Archive' : '';
148
140
  }
149
141
 
142
+ get readerHeightStyle(): string {
143
+ const calcFSHeight = `calc(100vh - ${this.headerSlot?.offsetHeight}px)`;
144
+ return this.viewportInFullscreen ? `height: ${calcFSHeight}` : '';
145
+ }
146
+
147
+ get loadingArea() {
148
+ return html`
149
+ <div class="loading-area">
150
+ <div class="loading-view">
151
+ <ia-itemnav-loader .title=${this.loaderTitle}></ia-itemnav-loader>
152
+ </div>
153
+ </div>
154
+ `;
155
+ }
156
+
150
157
  render(): TemplateResult {
151
158
  const displayReaderClass = this.loaded ? '' : 'hide';
159
+ console.log('render selectedMenuId', this.selectedMenuId);
160
+ console.log('render openMenu', this.openMenu);
152
161
  return html`
153
162
  <div id="frame" class=${`${this.menuClass}`}>
154
- <slot name="theater-header"></slot>
155
163
  <div class="menu-and-reader">
156
164
  ${this.shouldRenderMenu ? this.renderSideMenu : nothing}
157
- <div id="reader" class=${displayReaderClass}>
165
+ <slot name="theater-header"></slot>
166
+ <div
167
+ id="reader"
168
+ class=${displayReaderClass}
169
+ style=${this.readerHeightStyle}
170
+ >
158
171
  ${this.renderViewport}
159
172
  </div>
160
- ${!this.loaded
161
- ? html` <div class="loading-area">
162
- <div class="loading-view">
163
- <ia-itemnav-loader
164
- .title=${this.loaderTitle}
165
- ></ia-itemnav-loader>
166
- </div>
167
- </div>`
168
- : nothing}
173
+ ${!this.loaded ? this.loadingArea : nothing}
169
174
  </div>
170
175
  </div>
171
176
  `;
172
177
  }
173
178
 
174
- get BooksViewer(): TemplateResult {
179
+ get noTheaterView() {
180
+ return html`<ia-no-theater-available
181
+ .identifier=${this.item?.metadata?.identifier}
182
+ @loadingStateUpdated=${this.loadingStateUpdated}
183
+ ></ia-no-theater-available>`;
184
+ }
185
+
186
+ get theaterSlot() {
187
+ return html`
188
+ <slot name="theater-main" style=${this.readerHeightStyle}></slot>
189
+ `;
190
+ }
191
+
192
+ get booksViewer(): TemplateResult {
175
193
  const slotVisibility = !this.loaded ? 'opacity: 0;' : 'opacity: 1;';
176
194
 
177
195
  return html`
178
196
  <book-navigator
179
197
  .modal=${this.modal}
180
198
  .baseHost=${this.baseHost}
181
- .book=${this.item}
199
+ .itemMD=${this.item}
182
200
  ?signedIn=${this.signedIn}
183
201
  ?sideMenuOpen=${this.menuOpened}
184
202
  .sharedObserver=${this.sharedObserver}
@@ -189,7 +207,7 @@ export class ItemNavigator
189
207
  @menuShortcutsUpdated=${this.setMenuShortcuts}
190
208
  >
191
209
  <div slot="theater-main" style=${slotVisibility}>
192
- <slot name="theater-main"></slot>
210
+ ${this.theaterSlot}
193
211
  </div>
194
212
  </book-navigator>
195
213
  `;
@@ -199,35 +217,27 @@ export class ItemNavigator
199
217
  if (!this.item) {
200
218
  return nothing;
201
219
  }
202
- if (this.itemType === 'bookreader') {
203
- return this.BooksViewer;
220
+ if (this.itemType === ItemType.BOOK) {
221
+ return this.booksViewer;
204
222
  }
205
- return nothing;
223
+ return this.noTheaterView;
206
224
  }
207
225
 
208
- loadingStateUpdated(e: IntLoadingStateUpdatedEvent): void {
226
+ loadingStateUpdated(e: loadingStateUpdatedEvent): void {
209
227
  const { loaded } = e.detail;
210
- this.loaded = !!loaded;
211
- console.log('******loadingStateUpdated', e.detail);
212
- }
213
-
214
- /** Creates modal DOM & attaches to `<body>` */
215
- private createModal(): void {
216
- this.modal = document.createElement(
217
- 'modal-manager'
218
- ) as ModalManagerInterface;
219
- document.body.appendChild(this.modal);
228
+ this.loaded = loaded || null;
220
229
  }
221
- /* End Modal management */
222
230
 
223
231
  /** Fullscreen Management */
224
- manageViewportFullscreen(e: IntManageFullscreenEvent): void {
225
- this.viewportInFullscreen = !!e.detail.isFullScreen;
226
- this.dispatchEvent(
227
- new CustomEvent('ViewportInFullScreen', {
228
- detail: e.detail,
229
- }) as IntManageFullscreenEvent
230
- );
232
+ manageViewportFullscreen(e: ManageFullscreenEvent): void {
233
+ const fullscreenStatus = !!e.detail.isFullScreen;
234
+ this.viewportInFullscreen = !fullscreenStatus ? null : fullscreenStatus;
235
+
236
+ const event = new CustomEvent('fullscreenToggled', {
237
+ detail: e.detail,
238
+ }) as ManageFullscreenEvent;
239
+
240
+ this.dispatchEvent(event);
231
241
  }
232
242
  /** End Fullscreen Management */
233
243
 
@@ -244,22 +254,22 @@ export class ItemNavigator
244
254
  this.menuOpened = false;
245
255
  }
246
256
 
247
- setOpenMenu(e: IntSetOpenMenuEvent): void {
257
+ setOpenMenu(e: ToggleSidePanelOpenEvent): void {
248
258
  const { id } = e.detail;
249
- this.openMenu = id === this.openMenu ? '' : id;
259
+ this.openMenu = id !== this.openMenu ? id : undefined;
250
260
  }
251
261
 
252
- setMenuContents(e: IntSetMenuContentsEvent): void {
262
+ setMenuContents(e: SetSideMenuContentsEvent): void {
253
263
  const updatedContents = [...e.detail];
254
264
  this.menuContents = updatedContents;
255
265
  }
256
266
 
257
- setMenuShortcuts(e: IntSetMenuShortcutsEvent) {
267
+ setMenuShortcuts(e: SetSideMenuShortcutsEvent) {
258
268
  this.menuShortcuts = [...e.detail];
259
269
  }
260
270
 
261
271
  /** Toggles Side Menu & Sets viewable subpanel */
262
- manageSideMenuEvents(e: IntManageSideMenuEvent): void {
272
+ manageSideMenuEvents(e: ToggleSideMenuOpenEvent): void {
263
273
  const { menuId, action } = e.detail;
264
274
  if (!menuId) {
265
275
  return;
@@ -274,7 +284,6 @@ export class ItemNavigator
274
284
  }
275
285
 
276
286
  get menuToggleButton() {
277
- // <ia-icon icon="ellipses" style="width: var(--iconWidth); height: var(--iconHeight);"></ia-icon>
278
287
  return html`
279
288
  <button
280
289
  class="toggle-menu"
@@ -290,16 +299,19 @@ export class ItemNavigator
290
299
  `;
291
300
  }
292
301
 
302
+ get selectedMenuId(): MenuId | '' {
303
+ return this.openMenu || '';
304
+ }
305
+
293
306
  get renderSideMenu(): TemplateResult {
294
307
  const drawerState = this.menuOpened ? '' : 'hidden';
295
-
296
308
  return html`
297
309
  <nav>
298
310
  <div class="minimized">${this.shortcuts} ${this.menuToggleButton}</div>
299
311
  <div id="menu" class=${drawerState}>
300
312
  <ia-menu-slider
301
313
  .menus=${this.menuContents}
302
- .selectedMenu=${this.openMenu}
314
+ .selectedMenu=${this.selectedMenuId}
303
315
  @menuTypeSelected=${this.setOpenMenu}
304
316
  @menuSliderClosed=${this.closeMenu}
305
317
  manuallyHandleClose
@@ -312,7 +324,7 @@ export class ItemNavigator
312
324
  /** End Side menu */
313
325
 
314
326
  /** Menu Shortcuts */
315
- openShortcut(selectedMenuId = ''): void {
327
+ openShortcut(selectedMenuId: MenuId = ''): void {
316
328
  this.openMenu = selectedMenuId;
317
329
  this.menuOpened = true;
318
330
  }
@@ -340,7 +352,7 @@ export class ItemNavigator
340
352
  return `${drawerState} ${fullscreenState} ${this.openMenuState}`;
341
353
  }
342
354
 
343
- static get styles() {
355
+ static get styles(): CSSResult {
344
356
  const subnavWidth = css`var(--menuWidth, 320px)`;
345
357
  const transitionTiming = css`var(--animationTiming, 200ms)`;
346
358
  const transitionEffect = css`transform ${transitionTiming} ease-out`;
@@ -350,7 +362,6 @@ export class ItemNavigator
350
362
  return css`
351
363
  :host,
352
364
  #frame,
353
- #reader,
354
365
  .menu-and-reader {
355
366
  min-height: inherit;
356
367
  height: inherit;
@@ -359,6 +370,11 @@ export class ItemNavigator
359
370
  display: block;
360
371
  }
361
372
 
373
+ slot {
374
+ display: block;
375
+ overflow: hidden;
376
+ }
377
+
362
378
  #frame {
363
379
  background-color: ${theaterBg};
364
380
  color-scheme: dark;
@@ -373,11 +389,6 @@ export class ItemNavigator
373
389
  z-index: 9;
374
390
  }
375
391
 
376
- #frame.fullscreen,
377
- #frame.fullscreen #reader {
378
- height: 100vh;
379
- }
380
-
381
392
  .loading-area {
382
393
  position: absolute;
383
394
  top: 0;
@@ -494,6 +505,7 @@ export class ItemNavigator
494
505
  transition: ${transitionEffect};
495
506
  }
496
507
 
508
+ .open.shift slot[name='theater-header'],
497
509
  .open.shift #reader {
498
510
  width: calc(100% - var(--menuWidth));
499
511
  float: right;
@@ -502,5 +514,3 @@ export class ItemNavigator
502
514
  `;
503
515
  }
504
516
  }
505
-
506
- customElements.define('ia-menu-slider', IAMenuSlider);