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

Sign up to get free protection for your applications and to get access to all the features.
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);