@readium/navigator 2.10.3 → 2.11.1

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 (94) hide show
  1. package/dist/audio/AudioNavigator.js +1 -1
  2. package/dist/audio/AudioPoolManager.js +1 -1
  3. package/dist/audio/engine/WebAudioEngine.js +1 -1
  4. package/dist/divina/DivinaNavigator.js +1 -0
  5. package/dist/divina/DivinaPageManager.js +1 -0
  6. package/dist/divina/DivinaPagedPresenter.js +1 -0
  7. package/dist/divina/DivinaPeripherals.js +1 -0
  8. package/dist/divina/DivinaScrolledPresenter.js +1 -0
  9. package/dist/divina/DivinaSpreader.js +1 -0
  10. package/dist/divina/DivinaVariantSelector.js +1 -0
  11. package/dist/divina/preferences/DivinaDefaults.js +1 -0
  12. package/dist/divina/preferences/DivinaPreferences.js +1 -0
  13. package/dist/divina/preferences/DivinaPreferencesEditor.js +1 -0
  14. package/dist/divina/preferences/DivinaSettings.js +1 -0
  15. package/dist/divina/protection/DivinaNavigatorProtector.js +1 -0
  16. package/dist/epub/EpubNavigator.js +1 -1
  17. package/dist/epub/frame/FrameBlobBuilder.js +3 -1
  18. package/dist/epub/frame/FrameComms.js +1 -1
  19. package/dist/epub/frame/FrameManager.js +1 -1
  20. package/dist/epub/frame/FramePoolManager.js +1 -1
  21. package/dist/epub/fxl/FXLFrameManager.js +1 -1
  22. package/dist/epub/fxl/FXLFramePoolManager.js +1 -1
  23. package/dist/epub/fxl/FXLPeripherals.js +2 -2
  24. package/dist/helpers/serialize.js +1 -0
  25. package/dist/index.js +1 -1
  26. package/dist/peripherals/KeyboardConditionBridge.js +1 -1
  27. package/dist/peripherals/KeyboardPeripherals.js +1 -1
  28. package/dist/webpub/WebPubFrameManager.js +1 -1
  29. package/dist/webpub/WebPubFramePoolManager.js +1 -1
  30. package/dist/webpub/WebPubNavigator.js +1 -1
  31. package/package.json +5 -5
  32. package/src/audio/AudioNavigator.ts +107 -5
  33. package/src/audio/AudioPoolManager.ts +14 -8
  34. package/src/audio/engine/AudioEngine.ts +34 -1
  35. package/src/audio/engine/WebAudioEngine.ts +48 -3
  36. package/src/divina/DivinaNavigator.ts +704 -0
  37. package/src/divina/DivinaPageManager.ts +322 -0
  38. package/src/divina/DivinaPagedPresenter.ts +508 -0
  39. package/src/divina/DivinaPeripherals.ts +630 -0
  40. package/src/divina/DivinaScrolledPresenter.ts +516 -0
  41. package/src/divina/DivinaSpreader.ts +202 -0
  42. package/src/divina/DivinaVariantSelector.ts +77 -0
  43. package/src/divina/index.ts +8 -0
  44. package/src/divina/preferences/DivinaDefaults.ts +37 -0
  45. package/src/divina/preferences/DivinaPreferences.ts +77 -0
  46. package/src/divina/preferences/DivinaPreferencesEditor.ts +96 -0
  47. package/src/divina/preferences/DivinaSettings.ts +38 -0
  48. package/src/divina/preferences/index.ts +4 -0
  49. package/src/divina/protection/DivinaNavigatorProtector.ts +44 -0
  50. package/src/epub/EpubNavigator.ts +73 -7
  51. package/src/epub/frame/FrameBlobBuilder.ts +144 -39
  52. package/src/epub/frame/FrameComms.ts +42 -7
  53. package/src/epub/frame/FrameManager.ts +27 -16
  54. package/src/epub/frame/FramePoolManager.ts +106 -48
  55. package/src/epub/fxl/FXLFrameManager.ts +99 -34
  56. package/src/epub/fxl/FXLFramePoolManager.ts +98 -53
  57. package/src/epub/fxl/FXLPeripherals.ts +22 -1
  58. package/src/helpers/serialize.ts +9 -0
  59. package/src/index.ts +1 -0
  60. package/src/peripherals/KeyboardConditionBridge.ts +15 -5
  61. package/src/peripherals/KeyboardPeripherals.ts +13 -7
  62. package/src/webpub/WebPubFrameManager.ts +27 -16
  63. package/src/webpub/WebPubFramePoolManager.ts +5 -2
  64. package/src/webpub/WebPubNavigator.ts +44 -0
  65. package/types/src/audio/AudioNavigator.d.ts +29 -0
  66. package/types/src/audio/engine/AudioEngine.d.ts +27 -1
  67. package/types/src/audio/engine/WebAudioEngine.d.ts +14 -2
  68. package/types/src/divina/DivinaNavigator.d.ts +119 -0
  69. package/types/src/divina/DivinaPageManager.d.ts +66 -0
  70. package/types/src/divina/DivinaPagedPresenter.d.ts +122 -0
  71. package/types/src/divina/DivinaPeripherals.d.ts +121 -0
  72. package/types/src/divina/DivinaScrolledPresenter.d.ts +125 -0
  73. package/types/src/divina/DivinaSpreader.d.ts +65 -0
  74. package/types/src/divina/DivinaVariantSelector.d.ts +30 -0
  75. package/types/src/divina/index.d.ts +8 -0
  76. package/types/src/divina/preferences/DivinaDefaults.d.ts +18 -0
  77. package/types/src/divina/preferences/DivinaPreferences.d.ts +33 -0
  78. package/types/src/divina/preferences/DivinaPreferencesEditor.d.ts +20 -0
  79. package/types/src/divina/preferences/DivinaSettings.d.ts +26 -0
  80. package/types/src/divina/preferences/index.d.ts +4 -0
  81. package/types/src/divina/protection/DivinaNavigatorProtector.d.ts +14 -0
  82. package/types/src/epub/EpubNavigator.d.ts +7 -1
  83. package/types/src/epub/frame/FrameBlobBuilder.d.ts +19 -3
  84. package/types/src/epub/frame/FrameComms.d.ts +8 -1
  85. package/types/src/epub/frame/FrameManager.d.ts +3 -0
  86. package/types/src/epub/frame/FramePoolManager.d.ts +5 -1
  87. package/types/src/epub/fxl/FXLFrameManager.d.ts +7 -0
  88. package/types/src/epub/fxl/FXLFramePoolManager.d.ts +8 -2
  89. package/types/src/epub/fxl/FXLPeripherals.d.ts +3 -0
  90. package/types/src/helpers/serialize.d.ts +1 -0
  91. package/types/src/index.d.ts +1 -0
  92. package/types/src/peripherals/KeyboardPeripherals.d.ts +1 -0
  93. package/types/src/webpub/WebPubFrameManager.d.ts +3 -0
  94. package/types/src/webpub/WebPubNavigator.d.ts +2 -0
@@ -1 +1 @@
1
- import{Loader as h}from"@readium/navigator-html-injectables";import{ReadingProgression as a,Page as n}from"@readium/shared";import{FrameComms as c}from"../frame/FrameComms.js";import{KeyboardConditionBridge as d}from"../../peripherals/KeyboardConditionBridge.js";class u{constructor(t,e,s,r={},i=[],o=[]){this.pendingUnwatchSelectors=[],this.currModules=[],this.cachedPage=void 0,this.peripherals=t,this.debugHref=s,this.contentProtectionConfig={...r},this.keyboardPeripheralsConfig=[...i],this.resizeWatchSelectors=[...o],this.frame=document.createElement("iframe"),this.frame.sandbox.value="allow-same-origin allow-scripts",this.frame.classList.add("readium-navigator-iframe"),this.frame.classList.add("blank"),this.frame.scrolling="no",this.frame.style.visibility="hidden",this.frame.style.setProperty("aria-hidden","true"),this.frame.style.display="none",this.frame.style.position="absolute",this.frame.style.pointerEvents="none",this.frame.style.transformOrigin="0 0",this.frame.style.transform="scale(1)",this.frame.style.background="#fff",this.frame.style.touchAction="none",this.frame.dataset.originalHref=s,this.source="about:blank",this.wrapper=document.createElement("div"),this.wrapper.style.position="relative",this.wrapper.style.float=this.wrapper.style.cssFloat=e===a.rtl?"right":"left",this.wrapper.appendChild(this.frame)}async load(t,e){return this.source===e&&this.loadPromise&&[...this.currModules].sort().join("|")===[...t].sort().join("|")?this.loadPromise:(this.loaded&&this.source!==e&&this.window.stop(),this.source=e,this.loadPromise=new Promise((s,r)=>{if(this.loader&&this.loaded){const i=this.frame.contentWindow;if([...this.currModules].sort().join("|")===[...t].sort().join("|")){try{s(i),this.loadPromise=void 0}catch{}return}this.comms?.halt(),this.loader.destroy(),this.loader=new h(i,t),this.currModules=t,this.comms=void 0;try{s(i),this.loadPromise=void 0}catch{}return}this.frame.addEventListener("load",()=>{const i=this.frame.contentWindow;this.loader=new h(i,t),this.currModules=t,this.peripherals.observe(this.wrapper),this.peripherals.observe(i);try{s(i)}catch{}},{once:!0}),this.frame.addEventListener("error",i=>{try{r(i.error),this.loadPromise=void 0}catch{}},{once:!0}),this.frame.style.removeProperty("display"),this.frame.contentWindow.location.replace(this.source)}),this.loadPromise)}loadPageSize(){const t=this.frame.contentWindow,e=t.document.head.querySelector("meta[name=viewport]");if(e){const s=/(\w+) *= *([^\s,]+)/g;let r,i=0,o=0;for(;r=s.exec(e.content);)r[1]==="width"?i=Number.parseFloat(r[2]):r[1]==="height"&&(o=Number.parseFloat(r[2]));if(i>0&&o>0)return{width:i,height:o}}return{width:t.document.body.scrollWidth,height:t.document.body.scrollHeight}}update(t){if(!this.loaded)return;const e=this.loadPageSize();this.frame.style.height=`${e.height}px`,this.frame.style.width=`${e.width}px`;const s=Math.min(this.wrapper.clientWidth/e.width,this.wrapper.clientHeight/e.height);this.frame.style.transform=`scale(${s})`;const r=this.frame.getBoundingClientRect(),i=this.wrapper.clientHeight-r.height;if(this.frame.style.top=`${i/2}px`,t===n.left){const o=this.wrapper.clientWidth-r.width;this.frame.style.left=`${o}px`}else if(t===n.center){const o=this.wrapper.clientWidth-r.width;this.frame.style.left=`${o/2}px`}else this.frame.style.left="0px";this.frame.style.removeProperty("visibility"),this.frame.style.removeProperty("aria-hidden"),this.frame.style.removeProperty("pointer-events"),this.frame.classList.remove("blank"),this.frame.classList.add("loaded")}async destroy(){this.conditionBridge?.destroy(),await this.unfocus(),this.loader?.destroy(),this.wrapper.remove()}async unload(){if(this.loaded)return this.deselect(),this.frame.style.visibility="hidden",this.frame.style.setProperty("aria-hidden","true"),this.frame.style.pointerEvents="none",this.frame.classList.add("blank"),this.frame.classList.remove("loaded"),this.comms?.halt(),this.loader?.destroy(),this.comms=void 0,this.frame.blur(),new Promise((t,e)=>{this.frame.addEventListener("load",()=>{try{this.showPromise=void 0,t()}catch{}},{once:!0}),this.frame.addEventListener("error",s=>{try{this.showPromise=void 0,e(s.error)}catch{}},{once:!0}),this.source="about:blank",this.frame.contentWindow.location.replace("about:blank"),this.frame.style.display="none"})}deselect(){this.frame.contentWindow?.getSelection()?.removeAllRanges()}async unfocus(){if(this.frame.parentElement)return this.comms===void 0?void 0:(this.frame.blur(),new Promise((t,e)=>{this.comms?.send("unfocus",void 0,s=>{this.comms?.halt(),this.showPromise=void 0,t()})}));this.comms?.halt()}applyContentProtection(){this.comms||this.comms.resume(),this.comms.send("peripherals_protection",this.contentProtectionConfig),this.keyboardPeripheralsConfig&&this.keyboardPeripheralsConfig.length>0&&(this.conditionBridge?.destroy(),this.conditionBridge=new d(this.keyboardPeripheralsConfig,t=>{t.length>0&&this.comms.send("keyboard_peripherals",t)}),this.conditionBridge.setup()),this.contentProtectionConfig.protectPrinting?.disable&&this.comms.send("print_protection",this.contentProtectionConfig.protectPrinting),this.resizeWatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"watch",selector:t})}),this.pendingUnwatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"unwatch",selector:t})}),this.pendingUnwatchSelectors=[]}addResizeTarget(t){this.resizeWatchSelectors.includes(t)||this.resizeWatchSelectors.push(t),this.pendingUnwatchSelectors=this.pendingUnwatchSelectors.filter(e=>e!==t),this.comms?.ready&&this.comms.send("decoration_resize",{action:"watch",selector:t})}removeResizeTarget(t){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(e=>e!==t),this.comms?.ready?this.comms.send("decoration_resize",{action:"unwatch",selector:t}):this.pendingUnwatchSelectors.includes(t)||this.pendingUnwatchSelectors.push(t)}async show(t){if(!this.frame.parentElement){console.warn("Trying to show frame that is not attached to the DOM");return}if(!this.loaded){this.showPromise=void 0;return}return this.showPromise?(this.cachedPage!==t&&(this.update(t),this.cachedPage=t),this.showPromise):(this.cachedPage=t,this.comms?this.comms.resume():this.comms=new c(this.frame.contentWindow,this.source),this.showPromise=new Promise((e,s)=>{this.comms.send("focus",void 0,r=>{this.update(this.cachedPage),this.applyContentProtection(),e()})}),this.showPromise)}async activate(){return new Promise((t,e)=>{if(!this.comms)return t();this.comms?.send("activate",void 0,()=>{t()})})}get element(){return this.wrapper}get iframe(){return this.frame}get realSize(){return this.frame.getBoundingClientRect()}get loaded(){return this.frame.contentWindow&&this.frame.contentWindow.location.href!=="about:blank"}set width(t){const e=`${t}%`;this.wrapper.style.width!==e&&(this.wrapper.style.width=e)}set height(t){const e=`${t}px`;this.wrapper.style.height!==e&&(this.wrapper.style.height=e)}get window(){if(!this.frame.contentWindow)throw Error("Trying to use frame window when it doesn't exist");return this.frame.contentWindow}get atLeft(){return this.window.scrollX<5}get atRight(){return this.window.scrollX>this.window.document.scrollingElement.scrollWidth-this.window.innerWidth-5}get msg(){return this.comms}get ldr(){return this.loader}}export{u as FXLFrameManager};
1
+ import{Loader as n}from"@readium/navigator-html-injectables";import{ReadingProgression as c,Page as h}from"@readium/shared";import{FrameComms as d}from"../frame/FrameComms.js";import{isTypedOMSupported as a}from"./FXLPeripherals.js";import{KeyboardConditionBridge as l}from"../../peripherals/KeyboardConditionBridge.js";import{createSerializer as m}from"../../helpers/serialize.js";class v{constructor(t,e,s,r={},i=[],o=[]){this.frameIsAppended=!1,this.pendingUnwatchSelectors=[],this.currModules=[],this.viewportSize=void 0,this.serialize=m(),this.cachedPage=void 0,this.peripherals=t,this.debugHref=s,this.contentProtectionConfig={...r},this.keyboardPeripheralsConfig=[...i],this.resizeWatchSelectors=[...o],this.frame=document.createElement("iframe"),this.frame.sandbox.value="allow-same-origin allow-scripts",this.frame.classList.add("readium-navigator-iframe"),this.frame.classList.add("blank"),this.frame.scrolling="no",this.frame.style.visibility="hidden",this.frame.ariaHidden="true",this.frame.style.display="none",this.frame.style.position="absolute",this.frame.style.pointerEvents="none",this.frame.style.transformOrigin="0 0",this.frame.style.transform="scale(1)",this.frame.style.background="#fff",this.frame.style.touchAction="none",this.frame.dataset.originalHref=s,this.source="about:blank",this.wrapper=document.createElement("div"),this.wrapper.style.position="relative",this.wrapper.style.contain="strict",this.wrapper.style.float=this.wrapper.style.cssFloat=e===c.rtl?"right":"left"}async load(t,e){return this.serialize(()=>this.loadNow(t,e))}async loadNow(t,e){return this.frameIsAppended||(this.wrapper.appendChild(this.frame),this.frameIsAppended=!0),this.source===e&&this.loadPromise&&[...this.currModules].sort().join("|")===[...t].sort().join("|")?this.loadPromise:(this.loaded&&this.source!==e&&this.window.stop(),this.source=e,this.loadPromise=new Promise((s,r)=>{if(this.loader&&this.loaded){const i=this.frame.contentWindow;if([...this.currModules].sort().join("|")===[...t].sort().join("|")){try{s(i),this.loadPromise=void 0}catch{}return}this.comms?.halt(),this.loader.destroy(),this.loader=new n(i,t),this.currModules=t,this.comms=void 0;try{s(i),this.loadPromise=void 0}catch{}return}this.frame.addEventListener("load",()=>{const i=this.frame.contentWindow;this.loader=new n(i,t),this.currModules=t,this.peripherals.observe(this.wrapper),this.peripherals.observe(i);try{s(i)}catch{}},{once:!0}),this.frame.addEventListener("error",i=>{try{r(i.error),this.loadPromise=void 0}catch{}},{once:!0}),this.frame.style.removeProperty("display"),this.frame.contentWindow.location.replace(this.source)}),this.loadPromise)}loadPageSize(){if(this.viewportSize)return this.viewportSize;const t=this.frame.contentWindow,e=t.document.head.querySelector("meta[name=viewport]");if(e){const s=/(\w+) *= *([^\s,]+)/g;let r,i=0,o=0;for(;r=s.exec(e.content);)r[1]==="width"?i=Number.parseFloat(r[2]):r[1]==="height"&&(o=Number.parseFloat(r[2]));if(i>0&&o>0)return this.viewportSize={width:i,height:o},this.viewportSize}return{width:t.document.body.scrollWidth,height:t.document.body.scrollHeight}}update(t){if(!this.loaded)return;const e=this.loadPageSize(),s=Math.min(this.wrapper.clientWidth/e.width,this.wrapper.clientHeight/e.height);a()?(this.frame.attributeStyleMap.set("width",CSS.px(e.width)),this.frame.attributeStyleMap.set("height",CSS.px(e.height)),this.frame.attributeStyleMap.set("transform",new CSSTransformValue([new CSSScale(s,s)]))):(this.frame.style.height=`${e.height}px`,this.frame.style.width=`${e.width}px`,this.frame.style.transform=`scale(${s})`);const r=this.frame.getBoundingClientRect(),i=this.wrapper.clientHeight-r.height;if(a())if(this.frame.attributeStyleMap.set("top",CSS.px(i/2)),t===h.left){const o=this.wrapper.clientWidth-r.width;this.frame.attributeStyleMap.set("left",CSS.px(o))}else if(t===h.center){const o=this.wrapper.clientWidth-r.width;this.frame.attributeStyleMap.set("left",CSS.px(o/2))}else this.frame.attributeStyleMap.set("left",CSS.px(0));else if(this.frame.style.top=`${i/2}px`,t===h.left){const o=this.wrapper.clientWidth-r.width;this.frame.style.left=`${o}px`}else if(t===h.center){const o=this.wrapper.clientWidth-r.width;this.frame.style.left=`${o/2}px`}else this.frame.style.left="0px";this.frame.style.removeProperty("visibility"),this.frame.ariaHidden=null,this.frame.style.removeProperty("pointer-events"),this.frame.classList.remove("blank"),this.frame.classList.add("loaded")}async destroy(){return this.serialize(async()=>{this.conditionBridge?.destroy(),await this.unfocusNow(),this.loader?.destroy(),this.wrapper.remove()})}async unload(){return this.serialize(()=>this.unloadNow())}async unloadNow(){if(this.loaded)return this.deselect(),this.frame.style.visibility="hidden",this.frame.ariaHidden="true",this.frame.style.pointerEvents="none",this.frame.classList.add("blank"),this.frame.classList.remove("loaded"),this.comms?.halt(),this.loader?.destroy(),this.comms=void 0,this.frame.blur(),new Promise((t,e)=>{this.frame.addEventListener("load",()=>{try{this.showPromise=void 0,t()}catch{}},{once:!0}),this.frame.addEventListener("error",s=>{try{this.showPromise=void 0,e(s.error)}catch{}},{once:!0}),this.source="about:blank",this.frame.contentWindow.location.replace("about:blank"),this.frame.style.display="none",this.frame.style.width="0px",this.frame.style.height="0px"})}deselect(){this.frame.contentWindow?.getSelection()?.removeAllRanges()}async unfocus(){return this.serialize(()=>this.unfocusNow())}async unfocusNow(){if(this.frame.parentElement)return this.comms===void 0||!this.comms.ready?void 0:(this.frame.blur(),new Promise((t,e)=>{this.comms?.send("unfocus",void 0,s=>{this.comms?.halt(),this.showPromise=void 0,t()})}));this.comms?.halt()}applyContentProtection(){this.comms||this.comms.resume(),this.comms.send("peripherals_protection",this.contentProtectionConfig),this.keyboardPeripheralsConfig&&this.keyboardPeripheralsConfig.length>0&&(this.conditionBridge?.destroy(),this.conditionBridge=new l(this.keyboardPeripheralsConfig,t=>{t.length>0&&this.comms.send("keyboard_peripherals",t)}),this.conditionBridge.setup()),this.contentProtectionConfig.protectPrinting?.disable&&this.comms.send("print_protection",this.contentProtectionConfig.protectPrinting),this.resizeWatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"watch",selector:t})}),this.pendingUnwatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"unwatch",selector:t})}),this.pendingUnwatchSelectors=[]}addResizeTarget(t){this.resizeWatchSelectors.includes(t)||this.resizeWatchSelectors.push(t),this.pendingUnwatchSelectors=this.pendingUnwatchSelectors.filter(e=>e!==t),this.comms?.ready&&this.comms.send("decoration_resize",{action:"watch",selector:t})}removeResizeTarget(t){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(e=>e!==t),this.comms?.ready?this.comms.send("decoration_resize",{action:"unwatch",selector:t}):this.pendingUnwatchSelectors.includes(t)||this.pendingUnwatchSelectors.push(t)}async show(t){return this.serialize(()=>this.showNow(t))}async showNow(t){if(!this.frame.parentElement){console.warn("Trying to show frame that is not attached to the DOM");return}if(!this.loaded){this.showPromise=void 0;return}return this.showPromise?(this.cachedPage!==t&&(this.update(t),this.cachedPage=t),this.showPromise):(this.cachedPage=t,this.comms?this.comms.resume():this.comms=new d(this.frame.contentWindow,this.source),this.showPromise=new Promise((e,s)=>{this.comms.send("focus",void 0,r=>{this.update(this.cachedPage),this.applyContentProtection(),e()})}),this.showPromise)}async activate(){return this.serialize(()=>new Promise((t,e)=>{if(!this.comms?.ready)return t();this.comms?.send("activate",void 0,()=>{t()})}))}get element(){return this.wrapper}get iframe(){return this.frame}get realSize(){return this.frame.getBoundingClientRect()}get loaded(){return this.frame.contentWindow&&this.frame.contentWindow.location.href!=="about:blank"}set width(t){if(a()){const e=this.wrapper.attributeStyleMap.get("width");if(e instanceof CSSUnitValue&&e.unit==="percent"&&e.value===t)return;this.wrapper.attributeStyleMap.set("width",CSS.percent(t))}else{const e=`${t}%`;if(this.wrapper.style.width===e)return;this.wrapper.style.width=e}}set height(t){if(a()){const e=this.wrapper.attributeStyleMap.get("height");if(e instanceof CSSUnitValue&&e.unit==="px"&&e.value===t)return;this.wrapper.attributeStyleMap.set("height",CSS.px(t))}else{const e=`${t}px`;if(this.wrapper.style.height===e)return;this.wrapper.style.height=e}}get window(){if(!this.frame.contentWindow)throw Error("Trying to use frame window when it doesn't exist");return this.frame.contentWindow}get atLeft(){return this.window.scrollX<5}get atRight(){return this.window.scrollX>this.window.document.scrollingElement.scrollWidth-this.window.innerWidth-5}get msg(){return this.comms}get ldr(){return this.loader}}export{v as FXLFrameManager};
@@ -1 +1 @@
1
- import{ReadingProgression as w,Page as u}from"@readium/shared";import k from"../frame/FrameBlobBuilder.js";import{FXLFrameManager as M}from"./FXLFrameManager.js";import{FXLPeripherals as x}from"./FXLPeripherals.js";import{Spread as y,FXLSpreader as B,Orientation as T}from"./FXLSpreader.js";const O=8,v=5,U=300,A=15e3,D=250,I=150,z=500;class X{constructor(e,t,s,a,n,r,l=[]){if(this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.delayedShow=new Map,this.delayedTimeout=new Map,this.previousFrames=[],this.injector=null,this.width=0,this.height=0,this.transform="",this.currentSlide=0,this.spread=!0,this.orientationInternal=-1,this.container=e,this.positions=t,this.pub=s,this.injector=a??null,this.contentProtectionConfig=n||{},this.keyboardPeripheralsConfig=r||[],this.resizeWatchSelectors=[...l],this.spreadPresentation=s.metadata.otherMetadata?.spread||y.auto,this.pub.metadata.effectiveReadingProgression!==w.rtl&&this.pub.metadata.effectiveReadingProgression!==w.ltr)throw Error("Unsupported reading progression for EPUB");this.spreader=new B(this.pub),this.containerHeightCached=e.clientHeight,this.bookElement=document.createElement("div"),this.bookElement.ariaLabel="Book",this.bookElement.tabIndex=-1,this.updateBookStyle(!0),this.spineElement=document.createElement("div"),this.spineElement.ariaLabel="Spine",this.bookElement.appendChild(this.spineElement),this.container.appendChild(this.bookElement),this.updateSpineStyle(!0),this.peripherals=new x(this),this.pub.readingOrder.items.forEach(h=>{const d=new M(this.peripherals,this.pub.metadata.effectiveReadingProgression,h.href,this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.resizeWatchSelectors);this.spineElement.appendChild(d.element),this.pool.set(h.href,d),d.width=100/this.length*(h.properties?.otherProperties.orientation===T.landscape||h.properties?.otherProperties.addBlank?this.perPage:1),d.height=this.height})}set listener(e){this._listener=e}get listener(){return this._listener}get doNotDisturb(){return this.peripherals.pan.touchID>0}resizeHandler(e=!0,t=!0){this.currentSlide+this.perPage>this.length&&(this.currentSlide=this.length<=this.perPage?0:this.length-1),this.containerHeightCached=this.container.clientHeight,this.orientationInternal=-1,this.updateSpineStyle(!0),e&&(this.currentSlide=this.reAlign(),this.slideToCurrent(!t,t)),clearTimeout(this.resizeTimeout),this.resizeTimeout=window.setTimeout(()=>{this.pool.forEach((s,a)=>{let n=this.pub.readingOrder.items.findIndex(h=>h.href===a);const r=this.pub.readingOrder.items[n];if(s.width=100/this.length*(r.properties?.otherProperties.orientation===T.landscape||r.properties?.otherProperties.addBlank?this.perPage:1),s.height=this.height,!s.loaded)return;const l=this.spreader.findByLink(r);s.update(this.spreadPosition(l,r))})},D)}updateDimensions(){this.width=this.bookElement.clientWidth,this.height=this.bookElement.clientHeight}get rtl(){return this.pub.metadata.effectiveReadingProgression===w.rtl}get single(){return!this.spread||this.portrait}get perPage(){return this.spread&&!this.portrait?2:1}get threshold(){return 50}get portrait(){return this.spreadPresentation===y.none?!0:(this.orientationInternal===-1&&(this.orientationInternal=this.containerHeightCached>this.container.clientWidth?1:0),this.orientationInternal===1)}updateSpineStyle(e,t=!0){let s="0";this.updateDimensions(),this.perPage>1&&(s=`${this.width/2}px`);const a={transition:e?`all ${t?I:z}ms ease-out`:"all 0ms ease-out",marginRight:this.rtl?s:"0",marginLeft:this.rtl?"0":s,width:`${this.width/this.perPage*this.length}px`,transform:this.transform,contain:"content"};Object.assign(this.spineElement.style,a)}updateBookStyle(e=!1){if(e){const t={overflow:"hidden",direction:this.pub.metadata.effectiveReadingProgression,cursor:"",height:"100%",width:"100%",position:"relative",outline:"none",transition:this.peripherals?.dragState?"none":"transform .15s ease-in-out",touchAction:"none"};Object.assign(this.bookElement.style,t)}this.bookElement.style.transform=`scale(${this.peripherals?.scale||1})`+(this.peripherals?` translate3d(${this.peripherals.pan.translateX}px, ${this.peripherals.pan.translateY}px, 0px)`:"")}goTo(e){if(this.slength<=this.perPage)return;e=this.reAlign(e);const t=this.currentSlide;this.currentSlide=Math.min(Math.max(e,0),this.length-1),t!==this.currentSlide&&this.slideToCurrent(!1)}onChange(){this.peripherals.scale=1,this.updateBookStyle()}get offset(){return(this.rtl?1:-1)*this.currentSlide*(this.width/this.perPage)}get length(){if(this.single)return this.slength;const e=this.slength+this.nLandscape;return this.shift&&e%2===0?e+1:e}get slength(){return this.pub.readingOrder.items.length||0}get shift(){return this.spreader.shift}get nLandscape(){return this.spreader.nLandscape}setPerPage(e){e===null?this.spread=!0:e===1?this.spread=!1:this.spread=!0,requestAnimationFrame(()=>this.resizeHandler(!0))}slideToCurrent(e,t=!0){if(this.updateDimensions(),e)requestAnimationFrame(()=>{requestAnimationFrame(()=>{const s=`translate3d(${this.offset}px, 0, 0)`;this.spineElement.style.transform!==s&&(this.transform=s,this.updateSpineStyle(!0,t),this.deselect())})});else{const s=`translate3d(${this.offset}px, 0, 0)`;if(this.spineElement.style.transform===s)return;this.transform=s,this.updateSpineStyle(!1),this.deselect()}}bounce(e=!1){requestAnimationFrame(()=>{this.transform=`translate3d(${this.offset+50*(e?1:-1)}px, 0, 0)`,this.updateSpineStyle(!0,!0),setTimeout(()=>{this.transform=`translate3d(${this.offset}px, 0, 0)`,this.updateSpineStyle(!0,!0)},100)})}next(e=1){if(this.slength<=this.perPage)return!1;const t=this.currentSlide;return this.currentSlide=Math.min(this.currentSlide+e,this.length-1),this.perPage>1&&this.currentSlide%2&&this.currentSlide--,this.currentSlide===t&&(this.currentSlide+1,this.length),t!==this.currentSlide?(this.slideToCurrent(!0),this.onChange(),!0):(this.bounce(this.rtl),!1)}prev(e=1){if(this.slength<=this.perPage)return!1;const t=this.currentSlide;return this.currentSlide=Math.max(this.currentSlide-e,0),this.perPage>1&&this.currentSlide%2&&this.currentSlide++,t!==this.currentSlide?(this.slideToCurrent(!0),this.onChange(),!0):(this.bounce(!this.rtl),!1)}get ownerWindow(){return this.container.ownerDocument.defaultView||window}async destroy(){let e=this.inprogress.values(),t=e.next();const s=[];for(;t.value;)s.push(t.value),t=e.next();s.length>0&&await Promise.allSettled(s),this.inprogress.clear();let a=this.pool.values(),n=a.next();for(;n.value;)await n.value.destroy(),n=a.next();this.pool.clear(),this.blobs.forEach(r=>URL.revokeObjectURL(r)),this.injector?.dispose(),this.container.childNodes.forEach(r=>{(r.nodeType===Node.ELEMENT_NODE||r.nodeType===Node.TEXT_NODE)&&r.remove()})}makeSpread(e){return this.perPage<2?[this.pub.readingOrder.items[e]]:this.spreader.currentSpread(e,this.perPage)}reAlign(e=this.currentSlide){return e%2&&!this.single&&e++,e}spreadPosition(e,t){return this.perPage<2?u.center:e.length<2?u.center:t.href===e[0].href?this.rtl?u.right:u.left:this.rtl?u.left:u.right}async waitForItem(e){if(this.inprogress.has(e)&&await this.inprogress.get(e),this.delayedShow.has(e)){const t=this.delayedTimeout.get(e);t>0?clearTimeout(t):await this.delayedShow.get(e),this.delayedTimeout.set(e,0),this.delayedShow.delete(e)}}async cancelShowing(e){if(this.delayedShow.has(e)){const t=this.delayedTimeout.get(e);t>0&&clearTimeout(t),this.delayedShow.delete(e)}}async update(e,t,s,a=!1){let n=this.pub.readingOrder.items.findIndex(h=>h.href===t.href);if(n<0)throw Error("Href not found in reading order");this.currentSlide!==n&&(this.currentSlide=this.reAlign(n),this.slideToCurrent(!0));const r=this.makeSpread(this.currentSlide);this.perPage>1&&n++;for(const h of r)await this.waitForItem(h.href);const l=new Promise(async(h,d)=>{const f=[],g=[];this.positions.forEach((i,o)=>{(o>n+O||o<n-O)&&(f.includes(i.href)||f.push(i.href)),o<n+v&&o>n-v&&(g.includes(i.href)||g.push(i.href))}),f.forEach(async i=>{g.includes(i)||this.pool.has(i)&&(this.cancelShowing(i),await this.pool.get(i)?.unload())}),this.currentBaseURL!==void 0&&e.baseURL!==this.currentBaseURL&&(this.blobs.forEach(i=>URL.revokeObjectURL(i)),this.blobs.clear()),this.currentBaseURL=e.baseURL;const L=async i=>{const o=e.readingOrder.findIndexWithHref(i),p=e.readingOrder.items[o];if(p){if(!this.blobs.has(i)){const S=await new k(e,this.currentBaseURL||"",p,{injector:this.injector}).build(!0);this.blobs.set(i,S)}this.delayedShow.has(i)||this.delayedShow.set(i,new Promise((b,S)=>{let P=!1;const R=window.setTimeout(async()=>{this.delayedTimeout.set(i,0);const F=this.makeSpread(this.reAlign(o)),C=this.spreadPosition(F,p),E=this.pool.get(i);await E.load(s,this.blobs.get(i)),this.peripherals.isScaled||await E.show(C),this.delayedShow.delete(i),P=!0,b()},U);setTimeout(()=>{!P&&this.delayedShow.has(i)&&S(`Offscreen load timeout: ${i}`)},A),this.delayedTimeout.set(i,R)}))}};try{await Promise.all(g.map(i=>L(i)))}catch(i){d(i)}const c=[];for(const i of r){const o=this.pool.get(i.href),p=this.blobs.get(i.href);p&&(this.cancelShowing(i.href),await o.load(s,p),await o.show(this.spreadPosition(r,i)),this.previousFrames.push(o),await o.activate(),c.push(o))}for(;this.previousFrames.length>0;){const i=this.previousFrames.shift();i&&!c.includes(i)&&await i.unfocus()}this.previousFrames=c;const m=this.container.ownerDocument.activeElement;m&&m.tagName==="IFRAME"&&!c.some(i=>i.iframe===m)&&c[0]?.iframe.focus({preventScroll:!0}),h()});for(const h of r)this.inprogress.set(h.href,l);await l;for(const h of r)this.inprogress.delete(h.href)}addResizeTarget(e){this.resizeWatchSelectors.includes(e)||this.resizeWatchSelectors.push(e),this.pool.forEach(t=>t.addResizeTarget(e))}removeResizeTarget(e){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(t=>t!==e),this.pool.forEach(t=>t.removeResizeTarget(e))}get currentFrames(){if(this.perPage<2){const t=this.pub.readingOrder.items[this.currentSlide];return[this.pool.get(t.href)]}return this.spreader.currentSpread(this.currentSlide,this.perPage).map(t=>this.pool.get(t.href))}get currentBounds(){const e={x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0,toJSON(){return this}};return this.currentFrames.forEach(t=>{if(!t)return;const s=t.realSize;e.x=Math.min(e.x,s.x),e.y=Math.min(e.y,s.y),e.width+=s.width,e.height=Math.max(e.height,s.height),e.top=Math.min(e.top,s.top),e.right=Math.min(e.right,s.right),e.bottom=Math.min(e.bottom,s.bottom),e.left=Math.min(e.left,s.left)}),e}get viewport(){const e={readingOrder:[],progressions:new Map,positions:null};return(this.perPage<2?[this.pub.readingOrder.items[this.currentSlide]]:this.spreader.currentSpread(this.currentSlide,this.perPage)).forEach(s=>{e.readingOrder.push(s.href),e.progressions.set(s.href,{start:0,end:1})}),e.positions=this.getCurrentNumbers(),e}getCurrentNumbers(){if(this.perPage<2)return[this.pub.readingOrder.items[this.currentSlide].properties?.otherProperties.number];const e=this.spreader.currentSpread(this.currentSlide,this.perPage);return e.length>1?[e[0].properties?.otherProperties.number,e[e.length-1].properties?.otherProperties.number]:[e[0].properties?.otherProperties.number]}deselect(){this.currentFrames?.forEach(e=>e?.deselect())}}export{X as FXLFramePoolManager};
1
+ import{ReadingProgression as b,Page as g}from"@readium/shared";import A from"../frame/FrameBlobBuilder.js";import{FXLFrameManager as I}from"./FXLFrameManager.js";import{FXLPeripherals as D,isTypedOMSupported as P}from"./FXLPeripherals.js";import{Spread as E,FXLSpreader as B,Orientation as T}from"./FXLSpreader.js";const C=8,k=5,U=300,_=15e3,z=250,M=150,v=500;class X{constructor(e,t,s,h,r,n,l,a=[],f){if(this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.delayedShow=new Map,this.delayedTimeout=new Map,this.previousFrames=[],this.injector=null,this.width=0,this.height=0,this.currentSlide=0,this.spread=!0,this.orientationInternal=-1,this.bookScale=null,this.bookTranslate=null,this.bookTransform=null,this.container=e,this.positions=t,this.pub=s,this.injector=r??null,this.contentProtectionConfig=n||{},this.keyboardPeripheralsConfig=l||[],this.resizeWatchSelectors=[...a],this.upgradeInsecureRequests=f??"always",this.spreadPresentation=s.metadata.otherMetadata?.spread||E.auto,this.pub.metadata.effectiveReadingProgression!==b.rtl&&this.pub.metadata.effectiveReadingProgression!==b.ltr)throw Error("Unsupported reading progression for fixed-layout EPUB");this.spreader=new B(this.pub),this.containerHeightCached=e.clientHeight,this.bookElement=document.createElement("div"),this.bookElement.ariaLabel="Book",this.bookElement.tabIndex=-1,this.updateBookStyle(!0),this.spineElement=document.createElement("div"),this.spineElement.ariaLabel="Spine",this.bookElement.appendChild(this.spineElement),this.container.appendChild(this.bookElement),this.updateSpineStyle(!0),this.peripherals=new D(this);const d=document.createDocumentFragment();this.pub.readingOrder.items.forEach(p=>{const u=new I(this.peripherals,this.pub.metadata.effectiveReadingProgression,p.href,this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.resizeWatchSelectors);this.pool.set(p.href,u),u.width=100/this.length*(p.properties?.otherProperties.orientation===T.landscape||p.properties?.otherProperties.addBlank?this.perPage:1),u.height=this.height,d.appendChild(u.wrapper)}),this.spineElement.appendChild(d)}set listener(e){this._listener=e}get listener(){return this._listener}get doNotDisturb(){return this.peripherals.pan.touchID>0}resizeHandler(e=!0,t=!0){this.currentSlide+this.perPage>this.length&&(this.currentSlide=this.length<=this.perPage?0:this.length-1),this.containerHeightCached=this.container.clientHeight,this.orientationInternal=-1,this.updateSpineStyle(!0),e&&(this.currentSlide=this.reAlign(),this.slideToCurrent(!t,t)),clearTimeout(this.resizeTimeout),this.resizeTimeout=window.setTimeout(()=>{const s=100/this.length,h=new Map(this.pub.readingOrder.items.map(r=>[r.href,r]));this.pool.forEach((r,n)=>{const l=h.get(n);l&&requestAnimationFrame(()=>{if(r.width=s*(l.properties?.otherProperties.orientation===T.landscape||l.properties?.otherProperties.addBlank?this.perPage:1),r.height=this.height,!r.loaded)return;const a=this.spreader.findByLink(l);r.update(this.spreadPosition(a,l))})})},z)}updateDimensions(){this.width=this.bookElement.clientWidth,this.height=this.bookElement.clientHeight}get rtl(){return this.pub.metadata.effectiveReadingProgression===b.rtl}get single(){return!this.spread||this.portrait}get perPage(){return this.spread&&!this.portrait?2:1}get threshold(){return 50}get portrait(){return this.spreadPresentation===E.none?!0:(this.orientationInternal===-1&&(this.orientationInternal=this.containerHeightCached>this.container.clientWidth?1:0),this.orientationInternal===1)}updateSpineStyle(e,t=!0){let s=0;if(this.updateDimensions(),this.perPage>1&&(s=this.width/2),P())this.spineElement.attributeStyleMap.set("transition",new CSSUnparsedValue([e?`all ${t?M:v}ms ease-out`:"all 0ms ease-out"])),this.spineElement.attributeStyleMap.set("margin-right",CSS.px(this.rtl?s:0)),this.spineElement.attributeStyleMap.set("margin-left",CSS.px(this.rtl?0:s)),this.spineElement.attributeStyleMap.set("width",CSS.px(this.width/this.perPage*this.length)),this.transform?this.spineElement.attributeStyleMap.set("transform",new CSSTransformValue([new CSSTranslate(CSS.px(this.transform||0),CSS.px(0),CSS.px(0))])):this.spineElement.attributeStyleMap.delete("transform"),this.spineElement.attributeStyleMap.set("contain",new CSSUnparsedValue(["content"]));else{const h={transition:e?`all ${t?M:v}ms ease-out`:"all 0ms ease-out",marginRight:this.rtl?`${s}px`:"0",marginLeft:this.rtl?"0":`${s}px`,width:`${this.width/this.perPage*this.length}px`,transform:this.transform?`translate3d(${this.transform}px, 0px, 0px)`:"",contain:"content"};Object.assign(this.spineElement.style,h)}}updateBookStyle(e=!1){if(e){const r={overflow:"hidden",direction:this.pub.metadata.effectiveReadingProgression,cursor:"",height:"100%",width:"100%",position:"relative",outline:"none",transition:this.peripherals?.dragState?"none":"transform .15s ease-in-out",touchAction:"none"};Object.assign(this.bookElement.style,r)}const t=this.peripherals?.scale||1,s=this.peripherals?.pan.translateX||0,h=this.peripherals?.pan.translateY||0;P()?(this.bookTransform||(this.bookScale=new CSSScale(1,1),this.bookTranslate=new CSSTranslate(CSS.px(0),CSS.px(0),CSS.px(0)),this.bookTransform=new CSSTransformValue([this.bookScale,this.bookTranslate])),this.bookScale.x.value=t,this.bookScale.y.value=t,this.bookTranslate.x.value=s,this.bookTranslate.y.value=h,this.bookElement.attributeStyleMap.set("transform",this.bookTransform)):this.bookElement.style.transform=`scale(${t}) translate3d(${s}px, ${h}px, 0px)`}goTo(e){if(this.slength<=this.perPage)return;e=this.reAlign(e);const t=this.currentSlide;this.currentSlide=Math.min(Math.max(e,0),this.length-1),t!==this.currentSlide&&this.slideToCurrent(!1)}onChange(){this.peripherals.scale=1,this.updateBookStyle()}get offset(){return(this.rtl?1:-1)*this.currentSlide*(this.width/this.perPage)}get length(){if(this.single)return this.slength;const e=this.slength+this.nLandscape;return this.shift&&e%2===0?e+1:e}get slength(){return this.pub.readingOrder.items.length||0}get shift(){return this.spreader.shift}get nLandscape(){return this.spreader.nLandscape}setPerPage(e){e===null?this.spread=!0:e===1?this.spread=!1:this.spread=!0,requestAnimationFrame(()=>this.resizeHandler(!0))}slideToCurrent(e,t=!0){this.updateDimensions(),e?requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.transform=this.offset,this.updateSpineStyle(!0,t),this.deselect()})}):(this.transform=this.offset,this.updateSpineStyle(!1),this.deselect())}bounce(e=!1){requestAnimationFrame(()=>{this.transform=this.offset+50*(e?1:-1),this.updateSpineStyle(!0,!0),setTimeout(()=>{this.transform=this.offset,this.updateSpineStyle(!0,!0)},100)})}next(e=1){if(this.slength<=this.perPage)return!1;const t=this.currentSlide;return this.currentSlide=Math.min(this.currentSlide+e,this.length-1),this.perPage>1&&this.currentSlide%2&&this.currentSlide--,this.currentSlide===t&&(this.currentSlide+1,this.length),t!==this.currentSlide?(this.slideToCurrent(!0),this.onChange(),!0):(this.bounce(this.rtl),!1)}prev(e=1){if(this.slength<=this.perPage)return!1;const t=this.currentSlide;return this.currentSlide=Math.max(this.currentSlide-e,0),this.perPage>1&&this.currentSlide%2&&this.currentSlide++,t!==this.currentSlide?(this.slideToCurrent(!0),this.onChange(),!0):(this.bounce(!this.rtl),!1)}get ownerWindow(){return this.container.ownerDocument.defaultView||window}async destroy(){let e=this.inprogress.values(),t=e.next();const s=[];for(;t.value;)s.push(t.value),t=e.next();s.length>0&&await Promise.allSettled(s),this.inprogress.clear();let h=this.pool.values(),r=h.next();for(;r.value;)await r.value.destroy(),r=h.next();this.pool.clear(),this.blobs.forEach(n=>n.reset()),this.blobs.clear(),this.injector?.dispose(),this.container.childNodes.forEach(n=>{(n.nodeType===Node.ELEMENT_NODE||n.nodeType===Node.TEXT_NODE)&&n.remove()})}makeSpread(e){return this.perPage<2?[this.pub.readingOrder.items[e]]:this.spreader.currentSpread(e,this.perPage)}reAlign(e=this.currentSlide){return e%2&&!this.single&&e++,e}spreadPosition(e,t){return this.perPage<2?g.center:e.length<2?g.center:t.href===e[0].href?this.rtl?g.right:g.left:this.rtl?g.left:g.right}async waitForItem(e){if(this.inprogress.has(e)&&await this.inprogress.get(e),this.delayedShow.has(e)){const t=this.delayedTimeout.get(e);t>0?clearTimeout(t):await this.delayedShow.get(e),this.delayedTimeout.set(e,0),this.delayedShow.delete(e)}}async cancelShowing(e){if(this.delayedShow.has(e)){const t=this.delayedTimeout.get(e);t>0&&clearTimeout(t),this.delayedShow.delete(e)}}async update(e,t,s,h=!1){let r=this.pub.readingOrder.items.findIndex(a=>a.href===t.href);if(r<0)throw Error("Href not found in reading order");this.currentSlide!==r&&(this.currentSlide=this.reAlign(r),this.slideToCurrent(!0));const n=this.makeSpread(this.currentSlide);this.perPage>1&&r++;for(const a of n)await this.waitForItem(a.href);const l=new Promise(async(a,f)=>{const d=[],p=[];this.positions.forEach((i,o)=>{(o>r+C||o<r-C)&&(d.includes(i.href)||d.push(i.href)),o<r+k&&o>r-k&&(p.includes(i.href)||p.push(i.href))}),d.forEach(async i=>{p.includes(i)||this.pool.has(i)&&(this.cancelShowing(i),await this.pool.get(i)?.unload(),this.blobs.get(i)?.reset())}),this.currentBaseURL!==void 0&&e.baseURL!==this.currentBaseURL&&(this.blobs.forEach(i=>i.reset()),this.blobs.clear()),this.currentBaseURL=e.baseURL;const u=async i=>{const o=e.readingOrder.findIndexWithHref(i),c=e.readingOrder.items[o];c&&(this.blobs.has(i)||this.blobs.set(i,new A(e,this.currentBaseURL||"",c,{injector:this.injector,upgradeInsecureRequests:this.upgradeInsecureRequests})),this.delayedShow.has(i)||this.delayedShow.set(i,new Promise((x,F)=>{let w=!1;const O=window.setTimeout(async()=>{this.delayedTimeout.set(i,0);const R=this.makeSpread(this.reAlign(o)),L=this.spreadPosition(R,c),y=this.pool.get(i);await y.load(s,await this.blobs.get(i).build(!0)),this.peripherals.isScaled||await y.show(L),this.delayedShow.delete(i),w=!0,x()},U);setTimeout(()=>{!w&&this.delayedShow.has(i)&&F(`Offscreen load timeout: ${i}`)},_),this.delayedTimeout.set(i,O)})))};try{await Promise.all(p.map(i=>u(i)))}catch(i){f(i)}const m=[];for(const i of n){const o=this.pool.get(i.href),c=this.blobs.get(i.href);c&&(this.cancelShowing(i.href),await o.load(s,await c.build(!0)),await o.show(this.spreadPosition(n,i)),this.previousFrames.push(o),await o.activate(),m.push(o))}for(;this.previousFrames.length>0;){const i=this.previousFrames.shift();i&&!m.includes(i)&&await i.unfocus()}this.previousFrames=m;const S=this.container.ownerDocument.activeElement;S&&S.tagName==="IFRAME"&&!m.some(i=>i.iframe===S)&&m[0]?.iframe.focus({preventScroll:!0}),a()});for(const a of n)this.inprogress.set(a.href,l);try{await l}finally{for(const a of n)this.inprogress.delete(a.href)}}addResizeTarget(e){this.resizeWatchSelectors.includes(e)||this.resizeWatchSelectors.push(e),this.pool.forEach(t=>t.addResizeTarget(e))}removeResizeTarget(e){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(t=>t!==e),this.pool.forEach(t=>t.removeResizeTarget(e))}get currentFrames(){if(this.perPage<2){const t=this.pub.readingOrder.items[this.currentSlide];return[this.pool.get(t.href)]}return this.spreader.currentSpread(this.currentSlide,this.perPage).map(t=>this.pool.get(t.href))}get currentBounds(){const e={x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0,toJSON(){return this}};return this.currentFrames.forEach(t=>{if(!t)return;const s=t.realSize;e.x=Math.min(e.x,s.x),e.y=Math.min(e.y,s.y),e.width+=s.width,e.height=Math.max(e.height,s.height),e.top=Math.min(e.top,s.top),e.right=Math.min(e.right,s.right),e.bottom=Math.min(e.bottom,s.bottom),e.left=Math.min(e.left,s.left)}),e}get viewport(){const e={readingOrder:[],progressions:new Map,positions:null};return(this.perPage<2?[this.pub.readingOrder.items[this.currentSlide]]:this.spreader.currentSpread(this.currentSlide,this.perPage)).forEach(s=>{e.readingOrder.push(s.href),e.progressions.set(s.href,{start:0,end:1})}),e.positions=this.getCurrentNumbers(),e}getCurrentNumbers(){if(this.perPage<2)return[this.pub.readingOrder.items[this.currentSlide].properties?.otherProperties.number];const e=this.spreader.currentSpread(this.currentSlide,this.perPage);return e.length>1?[e[0].properties?.otherProperties.number,e[e.length-1].properties?.otherProperties.number]:[e[0].properties?.otherProperties.number]}deselect(){this.currentFrames?.forEach(e=>e?.deselect())}}export{X as FXLFramePoolManager};
@@ -1,4 +1,4 @@
1
- import{FXLCoordinator as X}from"./FXLCoordinator.js";import{FXLPeripheralsDebug as f}from"./FXLPeripheralsDebug.js";const g=6,l=1.02,p=50;class v{constructor(t,e=!1){this.dragState=0,this.minimumMoved=!1,this.pan={startX:0,endX:0,startY:0,overscrollX:0,overscrollY:0,letItGo:!1,preventClick:!1,translateX:0,translateY:0,touchID:0},this.pinch={startDistance:0,startScale:0,target:{X:0,Y:0},touchN:0,startTranslate:{X:0,Y:0}},this._scale=1,this.scaleDebouncer=0,this.frameBounds=null,this.debugger=null,this.btouchstartHandler=this.touchstartHandler.bind(this),this.btouchendHandler=this.touchendHandler.bind(this),this.btouchmoveHandler=this.touchmoveHandler.bind(this),this.bdblclickHandler=this.dblclickHandler.bind(this),this.bmousedownHandler=this.mousedownHandler.bind(this),this.bmouseupHandler=this.mouseupHandler.bind(this),this.bmousemoveHandler=this.mousemoveHandler.bind(this),this.moveFrame=0,this.manager=t,this.coordinator=new X,this.attachEvents(),e&&(this.debugger=new f)}get scale(){return this._scale}set scale(t){isNaN(t)&&(t=1),window.clearTimeout(this.scaleDebouncer),this.scaleDebouncer=window.setTimeout(()=>{this.dragState===0&&this.scale<l&&(this.pan.translateX=0,this.pan.translateY=0,this.clearPan(),this.manager.updateBookStyle()),this.manager.listener("zoom",t)},100),this._scale=t}attachEvents(){this.observe(this.manager.spineElement),this.pan={startX:0,startY:0,endX:0,overscrollX:0,overscrollY:0,letItGo:!1,preventClick:!1,translateX:0,translateY:0,touchID:0},this.pinch={startDistance:0,startScale:0,target:{X:0,Y:0},startTranslate:{X:0,Y:0},touchN:0}}clearPan(){this.pan.letItGo=!1,this.pan.touchID=0,this.pan.endX=0,this.pan.overscrollX=0,this.pan.overscrollY=0}clearPinch(){this.pinch={startDistance:0,startScale:this.pinch.startScale,target:{X:0,Y:0},touchN:0,startTranslate:{X:0,Y:0}}}observe(t){t.addEventListener("touchstart",this.btouchstartHandler),t.addEventListener("touchend",this.btouchendHandler),t.addEventListener("touchmove",this.btouchmoveHandler,{passive:!0}),t.addEventListener("dblclick",this.bdblclickHandler,{passive:!0}),t.addEventListener("mousedown",this.bmousedownHandler),t.addEventListener("mouseup",this.bmouseupHandler),t.addEventListener("mousemove",this.bmousemoveHandler)}clickHandler(t){}touchstartHandler(t){if(["TEXTAREA","OPTION","INPUT","SELECT"].indexOf(t.target.nodeName)!==-1)return;switch(t.stopPropagation(),this.frameBounds=this.manager.currentBounds,this.coordinator.refreshOuterPixels(this.frameBounds),t.touches.length){case 3:return;case 2:{t.preventDefault(),this.pinch.startDistance=this.coordinator.getTouchDistance(t);const r=this.startTouch(t);this.pan.startX=r.X,this.pan.startY=r.Y,this.dragState=2,this.manager.updateBookStyle(!0),this.isScaled?(this.pinch.target.X-=this.pan.translateX*(this.pinch.startScale/this.scale),this.pinch.target.Y-=this.pan.translateY*(this.pinch.startScale/this.scale),this.pinch.target={X:0,Y:0},this.pinch.startScale=1/this.scale):(this.pinch.target={X:0,Y:0},this.pinch.startScale=this.scale),this.pinch.startTranslate={X:this.pan.translateX,Y:this.pan.translateY},this.debugger?.show&&(this.debugger.DOM.touch2.style.display="",this.debugger.DOM.center.style.display="",this.debugger.DOM.pinchTarget.style.display="");return}case 1:this.pan.touchID=t.touches[0].identifier,this.debugger?.show&&(this.debugger.DOM.touch1.style.display="");default:this.dragState<1&&(this.dragState=1),this.manager.updateBookStyle(!0)}this.manager.updateSpineStyle(!1);const h=this.startTouch(t);this.pan.startX=h.X,this.pan.startY=h.Y}startTouch(t){const e=this.coordinator.getTouchCenter(t)||this.coordinator.getBibiEventCoord(t);return{X:e.X-this.manager.width/2-this.pan.translateX*this.scale+this.manager.width/2,Y:e.Y-this.manager.height/2-this.pan.translateY*this.scale+this.manager.height/2}}touchendHandler(t){if(t.stopPropagation(),!t.touches||t.touches.length===0)this.pan.endX&&!this.isScaled?(this.pinch.touchN&&(this.pan.endX=this.pan.startX),this.updateAfterDrag()):!this.pinch.touchN&&Math.abs(this.pan.overscrollX)>p&&Math.abs(this.pan.overscrollY)<p/2&&(this.pan.startX=0,this.pan.endX=-this.pan.overscrollX,this.updateAfterDrag()),this.dragState=0,this.minimumMoved=!1,this.clearPinch(),this.debugger?.show&&(this.debugger.DOM.center.style.display="none",this.debugger.DOM.touch1.style.display="none",this.debugger.DOM.touch2.style.display="none");else if(t.touches.length===1){this.dragState=1,t.touches[0].identifier!==this.pan.touchID&&(this.pan.touchID=t.touches[0].identifier),this.debugger?.show&&(this.debugger.DOM.center.style.display="none",this.debugger.DOM.touch2.style.display="none",this.debugger.DOM.pinchTarget.style.display="none");const e=this.startTouch(t);this.pan.startX=e.X,this.pan.startY=e.Y}window.setTimeout(()=>{this.manager.updateBookStyle(!0),this.dragState===0&&(this.scale<l&&(this.pan.translateX=0,this.pan.translateY=0),this.clearPan()),this.manager.updateBookStyle(!0)},50)}touchmoveHandler(t){t.stopPropagation();const e=this.coordinator.getBibiEventCoord(t);Math.abs(this.pan.startY-e.Y)+Math.abs(this.pan.startX-e.X)>5&&(this.minimumMoved||(this.manager.deselect(),this.minimumMoved=!0),this.dragState<1&&(this.dragState=1));const h=this.coordinator?.getTouchDistance(t);let r=!1;const c=this.scale;if(this.dragState===2&&h){if(this.pinch.touchN++,this.pinch.touchN<4)return;let a=h/this.pinch.startDistance*this.scale;a>=g&&(a=g),a<=l&&(a=1),this.scale=a,this.pinch.startDistance=h,r=!0}if(this.pan.letItGo===!1&&(this.pan.letItGo=Math.abs(this.pan.startY-e.Y)<Math.abs(this.pan.startX-e.X)),this.debugger?.show&&(this.debugger.DOM.touch1.style.top=`${e.Y-10}px`,this.debugger.DOM.touch1.style.left=`${e.X-10}px`,this.debugger.DOM.touch1.innerText=`${e.X.toFixed(2)},${e.Y.toFixed(2)}`),this.dragState>0&&this.isScaled||this.dragState>1){if(this.dragState===1){const s={X:e.X-this.manager.width/2,Y:e.Y-this.manager.height/2};this.pan.translateX=(s.X-(this.pan.startX-this.manager.width/2))*1/this.scale,this.pan.translateY=(s.Y-(this.pan.startY-this.manager.height/2))*1/this.scale}else if(this.dragState===2){const s=this.coordinator.getTouchCenter(t);if(this.debugger?.show){this.debugger.DOM.center.style.top=`${s.Y-5}px`,this.debugger.DOM.center.style.left=`${s.X-5}px`,this.debugger.DOM.center.innerText=`${s.X.toFixed(2)},${s.Y.toFixed(2)}`;const o=this.coordinator.getBibiEventCoord(t,1);this.debugger.DOM.touch2.style.top=`${o.Y-10}px`,this.debugger.DOM.touch2.style.left=`${o.X-10}px`,this.debugger.DOM.touch2.innerText=`${o.X.toFixed(2)},${o.Y.toFixed(2)}`}s.X-=this.manager.width/2,s.Y-=this.manager.height/2;let n=-s.X/c;n+=s.X/this.scale,this.pinch.target.X+=n,s.X+=this.pinch.target.X*this.scale/this.pinch.startScale;let d=-s.Y/c;d+=s.Y/this.scale,this.pinch.target.Y+=d,s.Y+=this.pinch.target.Y*this.scale/this.pinch.startScale;let u=(s.X-(this.pan.startX-this.manager.width/2))*1/this.scale,m=(s.Y-(this.pan.startY-this.manager.height/2))*1/this.scale;this.pan.translateX=u,this.pan.translateY=m,this.debugger?.show&&(this.debugger.DOM.pinchTarget.style.left=`${this.pinch.target.X*this.scale/this.pinch.startScale-5+this.manager.width/2}px`,this.debugger.DOM.pinchTarget.style.top=`${this.pinch.target.Y*this.scale/this.pinch.startScale-5+this.manager.height/2}px`,this.debugger.DOM.pinchTarget.innerText=`${(this.pinch.target.X*this.scale/this.pinch.startScale).toFixed(2)},${(this.pinch.target.Y*this.scale/this.pinch.startScale).toFixed(2)}`)}const a=this.frameBounds.width/6,i=this.frameBounds.height/6;this.pan.translateX<-a&&(this.pan.overscrollX=-(a+this.pan.translateX),this.pan.translateX=-a),this.pan.translateY<-i&&(this.pan.overscrollY=-(i+this.pan.translateY),this.pan.translateY=-i),this.pan.translateX>a&&(this.pan.overscrollX=a-this.pan.translateX,this.pan.translateX=a),this.pan.translateY>i&&(this.pan.overscrollY=i-this.pan.translateY,this.pan.translateY=i),r=!0,this.debugger?.show&&(this.debugger.DOM.stats.innerText=`TX: ${this.pan.translateX.toFixed(2)}
1
+ import{FXLCoordinator as f}from"./FXLCoordinator.js";import{FXLPeripheralsDebug as X}from"./FXLPeripheralsDebug.js";const p=6,d=1.02,u=50,b=()=>typeof window.CSSTransformValue<"u";class T{constructor(t,e=!1){this.dragState=0,this.minimumMoved=!1,this.pan={startX:0,endX:0,startY:0,overscrollX:0,overscrollY:0,letItGo:!1,preventClick:!1,translateX:0,translateY:0,touchID:0},this.pinch={startDistance:0,startScale:0,target:{X:0,Y:0},touchN:0,startTranslate:{X:0,Y:0}},this._scale=1,this.scaleDebouncer=0,this.frameBounds=null,this.debugger=null,this.btouchstartHandler=this.touchstartHandler.bind(this),this.btouchendHandler=this.touchendHandler.bind(this),this.btouchmoveHandler=this.touchmoveHandler.bind(this),this.bdblclickHandler=this.dblclickHandler.bind(this),this.bmousedownHandler=this.mousedownHandler.bind(this),this.bmouseupHandler=this.mouseupHandler.bind(this),this.bmousemoveHandler=this.mousemoveHandler.bind(this),this.moveFrame=0,this.dragTranslate=null,this.dragTransform=null,this.manager=t,this.coordinator=new f,this.attachEvents(),e&&(this.debugger=new X)}get scale(){return this._scale}set scale(t){isNaN(t)&&(t=1),window.clearTimeout(this.scaleDebouncer),this.scaleDebouncer=window.setTimeout(()=>{this.dragState===0&&this.scale<d&&(this.pan.translateX=0,this.pan.translateY=0,this.clearPan(),this.manager.updateBookStyle()),this.manager.listener("zoom",t)},100),this._scale=t}attachEvents(){this.observe(this.manager.spineElement),this.pan={startX:0,startY:0,endX:0,overscrollX:0,overscrollY:0,letItGo:!1,preventClick:!1,translateX:0,translateY:0,touchID:0},this.pinch={startDistance:0,startScale:0,target:{X:0,Y:0},startTranslate:{X:0,Y:0},touchN:0}}clearPan(){this.pan.letItGo=!1,this.pan.touchID=0,this.pan.endX=0,this.pan.overscrollX=0,this.pan.overscrollY=0}clearPinch(){this.pinch={startDistance:0,startScale:this.pinch.startScale,target:{X:0,Y:0},touchN:0,startTranslate:{X:0,Y:0}}}observe(t){t.addEventListener("touchstart",this.btouchstartHandler),t.addEventListener("touchend",this.btouchendHandler),t.addEventListener("touchmove",this.btouchmoveHandler,{passive:!0}),t.addEventListener("dblclick",this.bdblclickHandler,{passive:!0}),t.addEventListener("mousedown",this.bmousedownHandler),t.addEventListener("mouseup",this.bmouseupHandler),t.addEventListener("mousemove",this.bmousemoveHandler)}clickHandler(t){}touchstartHandler(t){if(["TEXTAREA","OPTION","INPUT","SELECT"].indexOf(t.target.nodeName)!==-1)return;switch(t.stopPropagation(),this.frameBounds=this.manager.currentBounds,this.coordinator.refreshOuterPixels(this.frameBounds),t.touches.length){case 3:return;case 2:{t.preventDefault(),this.pinch.startDistance=this.coordinator.getTouchDistance(t);const r=this.startTouch(t);this.pan.startX=r.X,this.pan.startY=r.Y,this.dragState=2,this.manager.updateBookStyle(!0),this.isScaled?(this.pinch.target.X-=this.pan.translateX*(this.pinch.startScale/this.scale),this.pinch.target.Y-=this.pan.translateY*(this.pinch.startScale/this.scale),this.pinch.target={X:0,Y:0},this.pinch.startScale=1/this.scale):(this.pinch.target={X:0,Y:0},this.pinch.startScale=this.scale),this.pinch.startTranslate={X:this.pan.translateX,Y:this.pan.translateY},this.debugger?.show&&(this.debugger.DOM.touch2.style.display="",this.debugger.DOM.center.style.display="",this.debugger.DOM.pinchTarget.style.display="");return}case 1:this.pan.touchID=t.touches[0].identifier,this.debugger?.show&&(this.debugger.DOM.touch1.style.display="");default:this.dragState<1&&(this.dragState=1),this.manager.updateBookStyle(!0)}this.manager.updateSpineStyle(!1);const h=this.startTouch(t);this.pan.startX=h.X,this.pan.startY=h.Y}startTouch(t){const e=this.coordinator.getTouchCenter(t)||this.coordinator.getBibiEventCoord(t);return{X:e.X-this.manager.width/2-this.pan.translateX*this.scale+this.manager.width/2,Y:e.Y-this.manager.height/2-this.pan.translateY*this.scale+this.manager.height/2}}touchendHandler(t){if(t.stopPropagation(),!t.touches||t.touches.length===0)this.pan.endX&&!this.isScaled?(this.pinch.touchN&&(this.pan.endX=this.pan.startX),this.updateAfterDrag()):!this.pinch.touchN&&Math.abs(this.pan.overscrollX)>u&&Math.abs(this.pan.overscrollY)<u/2&&(this.pan.startX=0,this.pan.endX=-this.pan.overscrollX,this.updateAfterDrag()),this.dragState=0,this.minimumMoved=!1,this.clearPinch(),this.debugger?.show&&(this.debugger.DOM.center.style.display="none",this.debugger.DOM.touch1.style.display="none",this.debugger.DOM.touch2.style.display="none");else if(t.touches.length===1){this.dragState=1,t.touches[0].identifier!==this.pan.touchID&&(this.pan.touchID=t.touches[0].identifier),this.debugger?.show&&(this.debugger.DOM.center.style.display="none",this.debugger.DOM.touch2.style.display="none",this.debugger.DOM.pinchTarget.style.display="none");const e=this.startTouch(t);this.pan.startX=e.X,this.pan.startY=e.Y}window.setTimeout(()=>{this.manager.updateBookStyle(!0),this.dragState===0&&(this.scale<d&&(this.pan.translateX=0,this.pan.translateY=0),this.clearPan()),this.manager.updateBookStyle(!0)},50)}touchmoveHandler(t){t.stopPropagation();const e=this.coordinator.getBibiEventCoord(t);Math.abs(this.pan.startY-e.Y)+Math.abs(this.pan.startX-e.X)>5&&(this.minimumMoved||(this.manager.deselect(),this.minimumMoved=!0),this.dragState<1&&(this.dragState=1));const h=this.coordinator?.getTouchDistance(t);let r=!1;const g=this.scale;if(this.dragState===2&&h){if(this.pinch.touchN++,this.pinch.touchN<4)return;let a=h/this.pinch.startDistance*this.scale;a>=p&&(a=p),a<=d&&(a=1),this.scale=a,this.pinch.startDistance=h,r=!0}if(this.pan.letItGo===!1&&(this.pan.letItGo=Math.abs(this.pan.startY-e.Y)<Math.abs(this.pan.startX-e.X)),this.debugger?.show&&(this.debugger.DOM.touch1.style.top=`${e.Y-10}px`,this.debugger.DOM.touch1.style.left=`${e.X-10}px`,this.debugger.DOM.touch1.innerText=`${e.X.toFixed(2)},${e.Y.toFixed(2)}`),this.dragState>0&&this.isScaled||this.dragState>1){if(this.dragState===1){const s={X:e.X-this.manager.width/2,Y:e.Y-this.manager.height/2};this.pan.translateX=(s.X-(this.pan.startX-this.manager.width/2))*1/this.scale,this.pan.translateY=(s.Y-(this.pan.startY-this.manager.height/2))*1/this.scale}else if(this.dragState===2){const s=this.coordinator.getTouchCenter(t);if(this.debugger?.show){this.debugger.DOM.center.style.top=`${s.Y-5}px`,this.debugger.DOM.center.style.left=`${s.X-5}px`,this.debugger.DOM.center.innerText=`${s.X.toFixed(2)},${s.Y.toFixed(2)}`;const c=this.coordinator.getBibiEventCoord(t,1);this.debugger.DOM.touch2.style.top=`${c.Y-10}px`,this.debugger.DOM.touch2.style.left=`${c.X-10}px`,this.debugger.DOM.touch2.innerText=`${c.X.toFixed(2)},${c.Y.toFixed(2)}`}s.X-=this.manager.width/2,s.Y-=this.manager.height/2;let o=-s.X/g;o+=s.X/this.scale,this.pinch.target.X+=o,s.X+=this.pinch.target.X*this.scale/this.pinch.startScale;let n=-s.Y/g;n+=s.Y/this.scale,this.pinch.target.Y+=n,s.Y+=this.pinch.target.Y*this.scale/this.pinch.startScale;let l=(s.X-(this.pan.startX-this.manager.width/2))*1/this.scale,m=(s.Y-(this.pan.startY-this.manager.height/2))*1/this.scale;this.pan.translateX=l,this.pan.translateY=m,this.debugger?.show&&(this.debugger.DOM.pinchTarget.style.left=`${this.pinch.target.X*this.scale/this.pinch.startScale-5+this.manager.width/2}px`,this.debugger.DOM.pinchTarget.style.top=`${this.pinch.target.Y*this.scale/this.pinch.startScale-5+this.manager.height/2}px`,this.debugger.DOM.pinchTarget.innerText=`${(this.pinch.target.X*this.scale/this.pinch.startScale).toFixed(2)},${(this.pinch.target.Y*this.scale/this.pinch.startScale).toFixed(2)}`)}const a=this.frameBounds.width/6,i=this.frameBounds.height/6;this.pan.translateX<-a&&(this.pan.overscrollX=-(a+this.pan.translateX),this.pan.translateX=-a),this.pan.translateY<-i&&(this.pan.overscrollY=-(i+this.pan.translateY),this.pan.translateY=-i),this.pan.translateX>a&&(this.pan.overscrollX=a-this.pan.translateX,this.pan.translateX=a),this.pan.translateY>i&&(this.pan.overscrollY=i-this.pan.translateY,this.pan.translateY=i),r=!0,this.debugger?.show&&(this.debugger.DOM.stats.innerText=`TX: ${this.pan.translateX.toFixed(2)}
2
2
  TY: ${this.pan.translateY.toFixed(2)}
3
3
  Zoom: ${this.scale.toFixed(2)}
4
- Overscroll: ${this.pan.overscrollX.toFixed(2)},${this.pan.overscrollY.toFixed(2)}`)}if(r){this.manager.updateBookStyle();return}if(this.dragState>0&&this.pan.letItGo){this.pan.endX=e.X;const i=this.manager.currentSlide*(this.manager.width/this.manager.perPage),s=this.pan.endX-this.pan.startX,n=this.manager.rtl?i+s:i-s;cancelAnimationFrame(this.moveFrame),this.moveFrame=requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.manager.spineElement.style.transform=`translate3d(${(this.manager.rtl?1:-1)*n}px, 0, 0)`})})}}dblclickHandler(t){clearTimeout(this.dtimer),this.pdblclick=!0,this.dtimer=window.setTimeout(()=>this.pdblclick=!1,200),!this.disableDblClick&&this.isScaled&&(this.scale=1)}get isScaled(){return this.scale>1}addTouch(t){t.touches=[{pageX:t.pageX,pageY:t.pageY}]}mousedownHandler(t){this.isScaled&&(this.addTouch(t),this.touchstartHandler(t))}mouseupHandler(t){this.isScaled&&this.touchendHandler(t)}mousemoveHandler(t){this.isScaled&&t.buttons>0&&(t.preventDefault(),this.addTouch(t),this.touchmoveHandler(t))}updateAfterDrag(){const t=(this.manager.rtl?-1:1)*(this.pan.endX-this.pan.startX),e=Math.abs(t);t>0&&e>this.manager.threshold&&this.manager.slength>this.manager.perPage?this.manager.listener("no_less",void 0):t<0&&e>this.manager.threshold&&this.manager.slength>this.manager.perPage&&this.manager.listener("no_more",void 0),this.manager.slideToCurrent(!0,!0)}}export{v as FXLPeripherals};
4
+ Overscroll: ${this.pan.overscrollX.toFixed(2)},${this.pan.overscrollY.toFixed(2)}`)}if(r){this.manager.updateBookStyle();return}if(this.dragState>0&&this.pan.letItGo){this.pan.endX=e.X;const i=this.manager.currentSlide*(this.manager.width/this.manager.perPage),s=this.pan.endX-this.pan.startX,o=this.manager.rtl?i+s:i-s,n=window.devicePixelRatio||1,l=Math.round((this.manager.rtl?1:-1)*o*n)/n;cancelAnimationFrame(this.moveFrame),this.moveFrame=requestAnimationFrame(()=>{requestAnimationFrame(()=>{b()?(this.dragTransform||(this.dragTranslate=new CSSTranslate(CSS.px(0),CSS.px(0),CSS.px(0)),this.dragTransform=new CSSTransformValue([this.dragTranslate])),this.dragTranslate.x.value=l,this.manager.spineElement.attributeStyleMap.set("transform",this.dragTransform)):this.manager.spineElement.style.transform=`translate3d(${l}px, 0, 0)`})})}}dblclickHandler(t){clearTimeout(this.dtimer),this.pdblclick=!0,this.dtimer=window.setTimeout(()=>this.pdblclick=!1,200),!this.disableDblClick&&this.isScaled&&(this.scale=1)}get isScaled(){return this.scale>1}addTouch(t){t.touches=[{pageX:t.pageX,pageY:t.pageY}]}mousedownHandler(t){this.isScaled&&(this.addTouch(t),this.touchstartHandler(t))}mouseupHandler(t){this.isScaled&&this.touchendHandler(t)}mousemoveHandler(t){this.isScaled&&t.buttons>0&&(t.preventDefault(),this.addTouch(t),this.touchmoveHandler(t))}updateAfterDrag(){const t=(this.manager.rtl?-1:1)*(this.pan.endX-this.pan.startX),e=Math.abs(t);t>0&&e>this.manager.threshold&&this.manager.slength>this.manager.perPage?this.manager.listener("no_less",void 0):t<0&&e>this.manager.threshold&&this.manager.slength>this.manager.perPage&&this.manager.listener("no_more",void 0),this.manager.slideToCurrent(!0,!0)}}export{T as FXLPeripherals,b as isTypedOMSupported};
@@ -0,0 +1 @@
1
+ function n(){let e=Promise.resolve();return t=>{const r=e.then(t);return e=r.catch(()=>{}),r}}export{n as createSerializer};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{MediaNavigator as o,Navigator as t,VisualNavigator as n}from"./Navigator.js";import{BUILTIN_DECORATION_TYPES as i,DecorationLayout as f,DecorationStyleType as p,DecorationWidth as g,decorationsEqual as m,resolveDecorationForWire as u,supportsDecorationStyle as x}from"@readium/decorator";import{ExperimentalWebPubNavigator as l,WebPubNavigator as b}from"./webpub/WebPubNavigator.js";import{WebPubBlobBuilder as c}from"./webpub/WebPubBlobBuilder.js";import{WebPubFrameManager as R}from"./webpub/WebPubFrameManager.js";import{WebPubFramePoolManager as C}from"./webpub/WebPubFramePoolManager.js";import{WebPubDefaults as W}from"./webpub/preferences/WebPubDefaults.js";import{WebPubPreferencesEditor as h}from"./webpub/preferences/WebPubPreferencesEditor.js";import{WebPubPreferences as L}from"./webpub/preferences/WebPubPreferences.js";import{WebPubSettings as D}from"./webpub/preferences/WebPubSettings.js";import{WebRSProperties as T,WebUserProperties as A}from"./webpub/css/Properties.js";import{WebPubCSS as y}from"./webpub/css/WebPubCSS.js";import{EpubNavigator as O}from"./epub/EpubNavigator.js";import{FrameComms as V}from"./epub/frame/FrameComms.js";import{FrameManager as q}from"./epub/frame/FrameManager.js";import{FramePoolManager as U}from"./epub/frame/FramePoolManager.js";import{FXLCoordinator as H,HorizontalThird as _,VerticalThird as j}from"./epub/fxl/FXLCoordinator.js";import{FXLFrameManager as G}from"./epub/fxl/FXLFrameManager.js";import{FXLFramePoolManager as K}from"./epub/fxl/FXLFramePoolManager.js";import{FXLPeripherals as Z}from"./epub/fxl/FXLPeripherals.js";import{FXLSpreader as ee,Orientation as re,Spread as oe}from"./epub/fxl/FXLSpreader.js";import{EpubDefaults as ne}from"./epub/preferences/EpubDefaults.js";import{EpubPreferencesEditor as ie}from"./epub/preferences/EpubPreferencesEditor.js";import{EpubPreferences as pe}from"./epub/preferences/EpubPreferences.js";import{EpubSettings as me}from"./epub/preferences/EpubSettings.js";import{RSProperties as xe,UserProperties as se}from"./epub/css/Properties.js";import{ReadiumCSS as be}from"./epub/css/ReadiumCSS.js";import{WebAudioEngine as ce}from"./audio/engine/WebAudioEngine.js";import{AudioPreferences as Re}from"./audio/preferences/AudioPreferences.js";import{AudioDefaults as Ce}from"./audio/preferences/AudioDefaults.js";import{AudioSettings as We}from"./audio/preferences/AudioSettings.js";import{AudioPreferencesEditor as he}from"./audio/preferences/AudioPreferencesEditor.js";import{AudioNavigator as Le}from"./audio/AudioNavigator.js";import{LineLengths as De}from"./helpers/lineLength.js";import{getScriptMode as Te}from"./helpers/scriptMode.js";import{BooleanPreference as Ie,EnumPreference as ye,Preference as Be,RangePreference as Oe}from"./preferences/Preference.js";import{TextAlignment as Ve,experiments as ke,filterRangeConfig as qe,fontSizeRangeConfig as ze,fontWeightRangeConfig as Ue,fontWidthRangeConfig as we,i18n as He,letterSpacingRangeConfig as _e,lineHeightRangeConfig as je,lineLengthRangeConfig as Ye,paragraphIndentRangeConfig as Ge,paragraphSpacingRangeConfig as Je,playbackRateRangeConfig as Ke,settings as Qe,skipIntervalRangeConfig as Ze,volumeRangeConfig as $e,wordSpacingRangeConfig as er,zoomRangeConfig as rr}from"./preferences/Types.js";import{ensureBoolean as tr,ensureEnumValue as nr,ensureExperiment as ar,ensureFilter as ir,ensureLessThanOrEqual as fr,ensureMoreThanOrEqual as pr,ensureNonNegative as gr,ensureString as mr,ensureValueInRange as ur,withFallback as xr}from"./preferences/guards.js";import{Properties as lr}from"./css/Properties.js";import{Injector as Pr}from"./injection/Injector.js";export{Ce as AudioDefaults,Le as AudioNavigator,Re as AudioPreferences,he as AudioPreferencesEditor,We as AudioSettings,i as BUILTIN_DECORATION_TYPES,Ie as BooleanPreference,f as DecorationLayout,p as DecorationStyleType,g as DecorationWidth,ye as EnumPreference,ne as EpubDefaults,O as EpubNavigator,pe as EpubPreferences,ie as EpubPreferencesEditor,me as EpubSettings,l as ExperimentalWebPubNavigator,H as FXLCoordinator,G as FXLFrameManager,K as FXLFramePoolManager,Z as FXLPeripherals,ee as FXLSpreader,V as FrameComms,q as FrameManager,U as FramePoolManager,_ as HorizontalThird,Pr as Injector,De as LineLengths,o as MediaNavigator,t as Navigator,re as Orientation,Be as Preference,lr as Properties,xe as RSProperties,Oe as RangePreference,be as ReadiumCSS,oe as Spread,Ve as TextAlignment,se as UserProperties,j as VerticalThird,n as VisualNavigator,ce as WebAudioEngine,c as WebPubBlobBuilder,y as WebPubCSS,W as WebPubDefaults,R as WebPubFrameManager,C as WebPubFramePoolManager,b as WebPubNavigator,L as WebPubPreferences,h as WebPubPreferencesEditor,D as WebPubSettings,T as WebRSProperties,A as WebUserProperties,m as decorationsEqual,tr as ensureBoolean,nr as ensureEnumValue,ar as ensureExperiment,ir as ensureFilter,fr as ensureLessThanOrEqual,pr as ensureMoreThanOrEqual,gr as ensureNonNegative,mr as ensureString,ur as ensureValueInRange,ke as experiments,qe as filterRangeConfig,ze as fontSizeRangeConfig,Ue as fontWeightRangeConfig,we as fontWidthRangeConfig,Te as getScriptMode,He as i18n,_e as letterSpacingRangeConfig,je as lineHeightRangeConfig,Ye as lineLengthRangeConfig,Ge as paragraphIndentRangeConfig,Je as paragraphSpacingRangeConfig,Ke as playbackRateRangeConfig,u as resolveDecorationForWire,Qe as settings,Ze as skipIntervalRangeConfig,x as supportsDecorationStyle,$e as volumeRangeConfig,xr as withFallback,er as wordSpacingRangeConfig,rr as zoomRangeConfig};
1
+ import{MediaNavigator as o,Navigator as t,VisualNavigator as a}from"./Navigator.js";import{BUILTIN_DECORATION_TYPES as i,DecorationLayout as p,DecorationStyleType as f,DecorationWidth as g,decorationsEqual as m,resolveDecorationForWire as x,supportsDecorationStyle as s}from"@readium/decorator";import{ExperimentalWebPubNavigator as l,WebPubNavigator as P}from"./webpub/WebPubNavigator.js";import{WebPubBlobBuilder as d}from"./webpub/WebPubBlobBuilder.js";import{WebPubFrameManager as S}from"./webpub/WebPubFrameManager.js";import{WebPubFramePoolManager as D}from"./webpub/WebPubFramePoolManager.js";import{WebPubDefaults as R}from"./webpub/preferences/WebPubDefaults.js";import{WebPubPreferencesEditor as W}from"./webpub/preferences/WebPubPreferencesEditor.js";import{WebPubPreferences as F}from"./webpub/preferences/WebPubPreferences.js";import{WebPubSettings as L}from"./webpub/preferences/WebPubSettings.js";import{WebRSProperties as T,WebUserProperties as I}from"./webpub/css/Properties.js";import{WebPubCSS as O}from"./webpub/css/WebPubCSS.js";import{EpubNavigator as B}from"./epub/EpubNavigator.js";import{FrameComms as X}from"./epub/frame/FrameComms.js";import{FrameManager as H}from"./epub/frame/FrameManager.js";import{FramePoolManager as q}from"./epub/frame/FramePoolManager.js";import{FXLCoordinator as U,HorizontalThird as w,VerticalThird as G}from"./epub/fxl/FXLCoordinator.js";import{FXLFrameManager as Q}from"./epub/fxl/FXLFrameManager.js";import{FXLFramePoolManager as J}from"./epub/fxl/FXLFramePoolManager.js";import{FXLPeripherals as Z,isTypedOMSupported as $}from"./epub/fxl/FXLPeripherals.js";import{FXLSpreader as re,Orientation as oe,Spread as te}from"./epub/fxl/FXLSpreader.js";import{EpubDefaults as ne}from"./epub/preferences/EpubDefaults.js";import{EpubPreferencesEditor as pe}from"./epub/preferences/EpubPreferencesEditor.js";import{EpubPreferences as ge}from"./epub/preferences/EpubPreferences.js";import{EpubSettings as xe}from"./epub/preferences/EpubSettings.js";import{RSProperties as ue,UserProperties as le}from"./epub/css/Properties.js";import{ReadiumCSS as be}from"./epub/css/ReadiumCSS.js";import{DivinaNavigator as ce}from"./divina/DivinaNavigator.js";import{DivinaPage as ve,DivinaSpreader as De}from"./divina/DivinaSpreader.js";import{DivinaPageManager as Re,placeholderSVG as Ce}from"./divina/DivinaPageManager.js";import{DivinaPagedPresenter as he}from"./divina/DivinaPagedPresenter.js";import{DivinaScrolledPresenter as Me}from"./divina/DivinaScrolledPresenter.js";import{DivinaPeripherals as Ne}from"./divina/DivinaPeripherals.js";import{DivinaQuality as Ie,MOBILE_MAX_HEIGHT as Ae,MOBILE_MAX_WIDTH as Oe,gatherVariants as ye,selectVariant as Be}from"./divina/DivinaVariantSelector.js";import{DivinaDefaults as Xe}from"./divina/preferences/DivinaDefaults.js";import{DivinaPreferences as He,stripWidthRangeConfig as ke}from"./divina/preferences/DivinaPreferences.js";import{DivinaPreferencesEditor as ze}from"./divina/preferences/DivinaPreferencesEditor.js";import{DivinaSettings as we}from"./divina/preferences/DivinaSettings.js";import{WebAudioEngine as je}from"./audio/engine/WebAudioEngine.js";import{AudioPreferences as Ye}from"./audio/preferences/AudioPreferences.js";import{AudioDefaults as Ke}from"./audio/preferences/AudioDefaults.js";import{AudioSettings as $e}from"./audio/preferences/AudioSettings.js";import{AudioPreferencesEditor as rr}from"./audio/preferences/AudioPreferencesEditor.js";import{AudioNavigator as tr}from"./audio/AudioNavigator.js";import{LineLengths as nr}from"./helpers/lineLength.js";import{getScriptMode as pr}from"./helpers/scriptMode.js";import{BooleanPreference as gr,EnumPreference as mr,Preference as xr,RangePreference as sr}from"./preferences/Preference.js";import{TextAlignment as lr,experiments as Pr,filterRangeConfig as br,fontSizeRangeConfig as dr,fontWeightRangeConfig as cr,fontWidthRangeConfig as Sr,i18n as vr,letterSpacingRangeConfig as Dr,lineHeightRangeConfig as Er,lineLengthRangeConfig as Rr,paragraphIndentRangeConfig as Cr,paragraphSpacingRangeConfig as Wr,playbackRateRangeConfig as hr,settings as Fr,skipIntervalRangeConfig as Mr,volumeRangeConfig as Lr,wordSpacingRangeConfig as Nr,zoomRangeConfig as Tr}from"./preferences/Types.js";import{ensureBoolean as Ar,ensureEnumValue as Or,ensureExperiment as yr,ensureFilter as Br,ensureLessThanOrEqual as Vr,ensureMoreThanOrEqual as Xr,ensureNonNegative as _r,ensureString as Hr,ensureValueInRange as kr,withFallback as qr}from"./preferences/guards.js";import{Properties as Ur}from"./css/Properties.js";import{Injector as Gr}from"./injection/Injector.js";export{Ke as AudioDefaults,tr as AudioNavigator,Ye as AudioPreferences,rr as AudioPreferencesEditor,$e as AudioSettings,i as BUILTIN_DECORATION_TYPES,gr as BooleanPreference,p as DecorationLayout,f as DecorationStyleType,g as DecorationWidth,Xe as DivinaDefaults,ce as DivinaNavigator,ve as DivinaPage,Re as DivinaPageManager,he as DivinaPagedPresenter,Ne as DivinaPeripherals,He as DivinaPreferences,ze as DivinaPreferencesEditor,Ie as DivinaQuality,Me as DivinaScrolledPresenter,we as DivinaSettings,De as DivinaSpreader,mr as EnumPreference,ne as EpubDefaults,B as EpubNavigator,ge as EpubPreferences,pe as EpubPreferencesEditor,xe as EpubSettings,l as ExperimentalWebPubNavigator,U as FXLCoordinator,Q as FXLFrameManager,J as FXLFramePoolManager,Z as FXLPeripherals,re as FXLSpreader,X as FrameComms,H as FrameManager,q as FramePoolManager,w as HorizontalThird,Gr as Injector,nr as LineLengths,Ae as MOBILE_MAX_HEIGHT,Oe as MOBILE_MAX_WIDTH,o as MediaNavigator,t as Navigator,oe as Orientation,xr as Preference,Ur as Properties,ue as RSProperties,sr as RangePreference,be as ReadiumCSS,te as Spread,lr as TextAlignment,le as UserProperties,G as VerticalThird,a as VisualNavigator,je as WebAudioEngine,d as WebPubBlobBuilder,O as WebPubCSS,R as WebPubDefaults,S as WebPubFrameManager,D as WebPubFramePoolManager,P as WebPubNavigator,F as WebPubPreferences,W as WebPubPreferencesEditor,L as WebPubSettings,T as WebRSProperties,I as WebUserProperties,m as decorationsEqual,Ar as ensureBoolean,Or as ensureEnumValue,yr as ensureExperiment,Br as ensureFilter,Vr as ensureLessThanOrEqual,Xr as ensureMoreThanOrEqual,_r as ensureNonNegative,Hr as ensureString,kr as ensureValueInRange,Pr as experiments,br as filterRangeConfig,dr as fontSizeRangeConfig,cr as fontWeightRangeConfig,Sr as fontWidthRangeConfig,ye as gatherVariants,pr as getScriptMode,vr as i18n,$ as isTypedOMSupported,Dr as letterSpacingRangeConfig,Er as lineHeightRangeConfig,Rr as lineLengthRangeConfig,Cr as paragraphIndentRangeConfig,Wr as paragraphSpacingRangeConfig,Ce as placeholderSVG,hr as playbackRateRangeConfig,x as resolveDecorationForWire,Be as selectVariant,Fr as settings,Mr as skipIntervalRangeConfig,ke as stripWidthRangeConfig,s as supportsDecorationStyle,Lr as volumeRangeConfig,qr as withFallback,Nr as wordSpacingRangeConfig,Tr as zoomRangeConfig};
@@ -1 +1 @@
1
- class u{constructor(i,s){this.config=i,this.onUpdate=s,this.unsubs=[],this.conditionValues=new Map}setup(){let i=!0;this.config.forEach(s=>s.keyCombos.forEach(t=>{if(t.condition){const n=t.condition.subscribe(o=>{this.conditionValues.set(t,o),i||this.onUpdate(this.buildSerializable())});this.unsubs.push(n)}})),i=!1,this.onUpdate(this.buildSerializable())}buildSerializable(){return this.config.map(i=>({...i,keyCombos:i.keyCombos.filter(s=>!s.condition||this.conditionValues.get(s)===!0).map(({condition:s,...t})=>t)})).filter(i=>i.keyCombos.length>0)}destroy(){this.unsubs.forEach(i=>i()),this.unsubs=[],this.conditionValues.clear()}}export{u as KeyboardConditionBridge};
1
+ class c{constructor(i,s){this.config=i,this.onUpdate=s,this.unsubs=[],this.conditionValues=new Map}setup(){let i=!0;const s=new Map;this.config.forEach(o=>o.keyCombos.forEach(t=>{if(t.condition){const n=s.get(t.condition)??[];n.push(t),s.set(t.condition,n)}})),s.forEach((o,t)=>{const n=t.subscribe(e=>{o.forEach(a=>this.conditionValues.set(a,e)),i||this.onUpdate(this.buildSerializable())});this.unsubs.push(n)}),i=!1,this.onUpdate(this.buildSerializable())}buildSerializable(){return this.config.map(i=>({...i,keyCombos:i.keyCombos.filter(s=>!s.condition||this.conditionValues.get(s)===!0).map(({condition:s,...o})=>o)})).filter(i=>i.keyCombos.length>0)}destroy(){this.unsubs.forEach(i=>i()),this.unsubs=[],this.conditionValues.clear()}}export{c as KeyboardConditionBridge};
@@ -1 +1 @@
1
- import{KeyCombinationManager as d}from"@readium/navigator-html-injectables";const o="readium:navigator:keyboardPeripheral";class s{constructor(e={}){this.keyManager=new d,this.setupKeyboardPeripherals(e.keyboardPeripherals||[])}setupKeyboardPeripherals(e){if(e.length>0){const n=t=>{const r=new CustomEvent(o,{detail:t});window.dispatchEvent(r)};this.keydownHandler=this.keyManager.createUnifiedHandler("",e,n),this.keydownHandler&&document.addEventListener("keydown",this.keydownHandler,!0)}window.addEventListener("unload",()=>this.destroy())}destroy(){this.keydownHandler&&(document.removeEventListener("keydown",this.keydownHandler,!0),this.keydownHandler=void 0)}}export{s as KeyboardPeripherals,o as NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT};
1
+ import{KeyCombinationManager as i}from"@readium/navigator-html-injectables";const r="readium:navigator:keyboardPeripheral";class o{constructor(e={}){this.keyManager=new i,this.pagehideHandler=t=>{t.persisted||this.destroy()},this.setupKeyboardPeripherals(e.keyboardPeripherals||[])}setupKeyboardPeripherals(e){if(e.length>0){const t=n=>{const d=new CustomEvent(r,{detail:n});window.dispatchEvent(d)};this.keydownHandler=this.keyManager.createUnifiedHandler("",e,t),this.keydownHandler&&document.addEventListener("keydown",this.keydownHandler,!0)}window.addEventListener("pagehide",this.pagehideHandler)}destroy(){this.keydownHandler&&(document.removeEventListener("keydown",this.keydownHandler,!0),this.keydownHandler=void 0),window.removeEventListener("pagehide",this.pagehideHandler)}}export{o as KeyboardPeripherals,r as NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT};
@@ -1 +1 @@
1
- import{Loader as o}from"@readium/navigator-html-injectables";import{FrameComms as n}from"../epub/frame/FrameComms.js";import{sML as h}from"@readium/helpers";import{KeyboardConditionBridge as a}from"../peripherals/KeyboardConditionBridge.js";class y{constructor(t,i={},s=[],e=[],r=[]){this.timelineFragmentIds=e,this.hidden=!0,this.destroyed=!1,this.pendingUnwatchSelectors=[],this.currModules=[],this.frame=document.createElement("iframe"),this.frame.classList.add("readium-navigator-iframe"),this.frame.style.visibility="hidden",this.frame.style.setProperty("aria-hidden","true"),this.frame.style.opacity="0",this.frame.style.position="absolute",this.frame.style.pointerEvents="none",this.frame.style.transition="visibility 0s, opacity 0.1s linear",this.frame.style.backgroundColor="#FFFFFF",this.source=t,this.contentProtectionConfig={...i},this.keyboardPeripheralsConfig=[...s],this.resizeWatchSelectors=[...r]}async load(t=[]){return new Promise((i,s)=>{if(this.loader){const e=this.frame.contentWindow;if([...this.currModules].sort().join("|")===[...t].sort().join("|")){try{i(e)}catch{}return}this.comms?.halt(),this.loader.destroy(),this.loader=new o(e,t),this.currModules=t,this.comms=void 0;try{i(e)}catch{}return}this.frame.onload=()=>{const e=this.frame.contentWindow;this.loader=new o(e,t),this.currModules=t;try{i(e)}catch{}},this.frame.onerror=e=>{try{s(e)}catch{}},this.frame.contentWindow.location.replace(this.source)})}applyContentProtection(){this.comms||this.comms.resume(),this.comms.send("peripherals_protection",this.contentProtectionConfig),this.keyboardPeripheralsConfig&&this.keyboardPeripheralsConfig.length>0&&(this.conditionBridge?.destroy(),this.conditionBridge=new a(this.keyboardPeripheralsConfig,t=>{t.length>0&&this.comms.send("keyboard_peripherals",t)}),this.conditionBridge.setup()),this.contentProtectionConfig.monitorScrollingExperimental&&this.comms.send("scroll_protection",{}),this.contentProtectionConfig.protectPrinting?.disable&&this.comms.send("print_protection",this.contentProtectionConfig.protectPrinting),this.resizeWatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"watch",selector:t})}),this.pendingUnwatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"unwatch",selector:t})}),this.pendingUnwatchSelectors=[]}addResizeTarget(t){this.resizeWatchSelectors.includes(t)||this.resizeWatchSelectors.push(t),this.pendingUnwatchSelectors=this.pendingUnwatchSelectors.filter(i=>i!==t),this.comms?.ready&&this.comms.send("decoration_resize",{action:"watch",selector:t})}removeResizeTarget(t){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(i=>i!==t),this.comms?.ready?this.comms.send("decoration_resize",{action:"unwatch",selector:t}):this.pendingUnwatchSelectors.includes(t)||this.pendingUnwatchSelectors.push(t)}async destroy(){this.conditionBridge?.destroy(),await this.hide(),this.loader?.destroy(),this.frame.remove(),this.destroyed=!0}async hide(){if(!this.destroyed){if(this.frame.style.visibility="hidden",this.frame.style.setProperty("aria-hidden","true"),this.frame.style.opacity="0",this.frame.style.pointerEvents="none",this.hidden=!0,this.frame.parentElement)return this.comms===void 0||!this.comms.ready?void 0:new Promise((t,i)=>{this.comms?.send("unfocus",void 0,s=>{this.comms?.halt(),t()})});this.comms?.halt()}}async show(t){if(this.destroyed)throw Error("Trying to show frame when it doesn't exist");if(!this.frame.parentElement)throw Error("Trying to show frame that is not attached to the DOM");return this.comms?this.comms.resume():this.comms=new n(this.frame.contentWindow,this.source),new Promise((i,s)=>{this.comms?.send("activate",void 0,()=>{this.comms?.send("focus",void 0,()=>{this.applyContentProtection(),this.timelineFragmentIds.length>0&&this.comms?.send("timeline_entries",this.timelineFragmentIds);const e=()=>{this.frame.style.removeProperty("visibility"),this.frame.style.removeProperty("aria-hidden"),this.frame.style.removeProperty("opacity"),this.frame.style.removeProperty("pointer-events"),this.hidden=!1,h.UA.WebKit&&this.comms?.send("force_webkit_recalc",void 0),i()};t!==void 0?this.comms?.send("go_progression",t,e):e()})})})}setCSSProperties(t){this.destroyed||!this.frame.contentWindow||(this.hidden&&(this.comms?this.comms?.resume():this.comms=new n(this.frame.contentWindow,this.source)),this.comms?.send("update_properties",t),this.hidden&&this.comms?.halt())}get iframe(){if(this.destroyed)throw Error("Trying to use frame when it doesn't exist");return this.frame}get realSize(){if(this.destroyed)throw Error("Trying to use frame client rect when it doesn't exist");return this.frame.getBoundingClientRect()}get window(){if(this.destroyed||!this.frame.contentWindow)throw Error("Trying to use frame window when it doesn't exist");return this.frame.contentWindow}get msg(){return this.comms}get ldr(){return this.loader}}export{y as WebPubFrameManager};
1
+ import{Loader as o}from"@readium/navigator-html-injectables";import{FrameComms as n}from"../epub/frame/FrameComms.js";import{sML as h}from"@readium/helpers";import{KeyboardConditionBridge as a}from"../peripherals/KeyboardConditionBridge.js";import{createSerializer as c}from"../helpers/serialize.js";class w{constructor(t,i={},s=[],e=[],r=[]){this.timelineFragmentIds=e,this.hidden=!0,this.destroyed=!1,this.pendingUnwatchSelectors=[],this.currModules=[],this.serialize=c(),this.frame=document.createElement("iframe"),this.frame.classList.add("readium-navigator-iframe"),this.frame.style.visibility="hidden",this.frame.ariaHidden="true",this.frame.style.opacity="0",this.frame.style.position="absolute",this.frame.style.pointerEvents="none",this.frame.style.transition="visibility 0s, opacity 0.1s linear",this.frame.style.backgroundColor="#FFFFFF",this.source=t,this.contentProtectionConfig={...i},this.keyboardPeripheralsConfig=[...s],this.resizeWatchSelectors=[...r]}async load(t=[]){return this.serialize(()=>new Promise((i,s)=>{if(this.loader){const e=this.frame.contentWindow;if([...this.currModules].sort().join("|")===[...t].sort().join("|")){try{i(e)}catch{}return}this.comms?.halt(),this.loader.destroy(),this.loader=new o(e,t),this.currModules=t,this.comms=void 0;try{i(e)}catch{}return}this.frame.onload=()=>{const e=this.frame.contentWindow;this.loader=new o(e,t),this.currModules=t;try{i(e)}catch{}},this.frame.onerror=e=>{try{s(e)}catch{}},this.frame.contentWindow.location.replace(this.source)}))}applyContentProtection(){this.comms||this.comms.resume(),this.comms.send("peripherals_protection",this.contentProtectionConfig),this.keyboardPeripheralsConfig&&this.keyboardPeripheralsConfig.length>0&&(this.conditionBridge?.destroy(),this.conditionBridge=new a(this.keyboardPeripheralsConfig,t=>{t.length>0&&this.comms.send("keyboard_peripherals",t)}),this.conditionBridge.setup()),this.contentProtectionConfig.monitorScrollingExperimental&&this.comms.send("scroll_protection",{}),this.contentProtectionConfig.protectPrinting?.disable&&this.comms.send("print_protection",this.contentProtectionConfig.protectPrinting),this.resizeWatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"watch",selector:t})}),this.pendingUnwatchSelectors.forEach(t=>{this.comms.send("decoration_resize",{action:"unwatch",selector:t})}),this.pendingUnwatchSelectors=[]}addResizeTarget(t){this.resizeWatchSelectors.includes(t)||this.resizeWatchSelectors.push(t),this.pendingUnwatchSelectors=this.pendingUnwatchSelectors.filter(i=>i!==t),this.comms?.ready&&this.comms.send("decoration_resize",{action:"watch",selector:t})}removeResizeTarget(t){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(i=>i!==t),this.comms?.ready?this.comms.send("decoration_resize",{action:"unwatch",selector:t}):this.pendingUnwatchSelectors.includes(t)||this.pendingUnwatchSelectors.push(t)}async destroy(){return this.serialize(async()=>{this.conditionBridge?.destroy(),await this.hideNow(),this.loader?.destroy(),this.frame.remove(),this.destroyed=!0})}async hide(){return this.serialize(()=>this.hideNow())}async hideNow(){if(!this.destroyed){if(this.frame.style.visibility="hidden",this.frame.ariaHidden="true",this.frame.style.opacity="0",this.frame.style.pointerEvents="none",this.hidden=!0,this.frame.parentElement)return this.comms===void 0||!this.comms.ready?void 0:new Promise((t,i)=>{this.comms?.send("unfocus",void 0,s=>{this.comms?.halt(),t()})});this.comms?.halt()}}async show(t){return this.serialize(()=>this.showNow(t))}async showNow(t){if(this.destroyed)throw Error("Trying to show frame when it doesn't exist");if(!this.frame.parentElement)throw Error("Trying to show frame that is not attached to the DOM");return this.comms?this.comms.resume():this.comms=new n(this.frame.contentWindow,this.source),new Promise((i,s)=>{this.comms?.send("activate",void 0,()=>{this.comms?.send("focus",void 0,()=>{this.applyContentProtection(),this.timelineFragmentIds.length>0&&this.comms?.send("timeline_entries",this.timelineFragmentIds);const e=()=>{this.frame.style.removeProperty("visibility"),this.frame.ariaHidden=null,this.frame.style.removeProperty("opacity"),this.frame.style.removeProperty("pointer-events"),this.hidden=!1,h.UA.WebKit&&this.comms?.send("force_webkit_recalc",void 0),i()};t!==void 0?this.comms?.send("go_progression",t,e):e()})})})}setCSSProperties(t){this.destroyed||!this.frame.contentWindow||(this.hidden&&!this.comms&&(this.comms=new n(this.frame.contentWindow,this.source),this.comms.halt()),this.comms?.send("update_properties",t))}get iframe(){if(this.destroyed)throw Error("Trying to use frame when it doesn't exist");return this.frame}get realSize(){if(this.destroyed)throw Error("Trying to use frame client rect when it doesn't exist");return this.frame.getBoundingClientRect()}get window(){if(this.destroyed||!this.frame.contentWindow)throw Error("Trying to use frame window when it doesn't exist");return this.frame.contentWindow}get msg(){return this.comms}get ldr(){return this.loader}}export{w as WebPubFrameManager};
@@ -1 +1 @@
1
- import{WebPubBlobBuilder as w}from"./WebPubBlobBuilder.js";import{WebPubFrameManager as y}from"./WebPubFrameManager.js";class R{constructor(e,i,s,n={},o=[],r,h=[]){this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.pendingUpdates=new Map,this.injector=null,this.container=e,this.currentCssProperties=i,this.injector=s,this.contentProtectionConfig=n,this.keyboardPeripheralsConfig=[...o],this.getFragmentIds=r??(()=>[]),this.resizeWatchSelectors=[...h]}addResizeTarget(e){this.resizeWatchSelectors.includes(e)||this.resizeWatchSelectors.push(e),this.pool.forEach(i=>i.addResizeTarget(e))}removeResizeTarget(e){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(i=>i!==e),this.pool.forEach(i=>i.removeResizeTarget(e))}async destroy(){let e=this.inprogress.values(),i=e.next();const s=[];for(;i.value;)s.push(i.value),i=e.next();s.length>0&&await Promise.allSettled(s),this.inprogress.clear();let n=this.pool.values(),o=n.next();for(;o.value;)await o.value.destroy(),o=n.next();this.pool.clear(),this.blobs.forEach(r=>{this.injector?.releaseBlobUrl?.(r),URL.revokeObjectURL(r)}),this.blobs.clear(),this.injector?.dispose(),this.container.childNodes.forEach(r=>{(r.nodeType===Node.ELEMENT_NODE||r.nodeType===Node.TEXT_NODE)&&r.remove()})}async update(e,i,s){const n=e.readingOrder.items;let o=n.findIndex(f=>f.href===i.href);if(o<0)throw Error(`Locator not found in reading order: ${i.href}`);const r=n[o].href;this.inprogress.has(r)&&await this.inprogress.get(r);const h=new Promise(async(f,u)=>{const g=[],d=[];e.readingOrder.items.forEach((t,c)=>{c!==o&&c!==o-1&&c!==o+1&&(g.includes(t.href)||g.push(t.href)),c===o&&(d.includes(t.href)||d.push(t.href))}),g.forEach(async t=>{d.includes(t)||this.pool.has(t)&&(await this.pool.get(t)?.destroy(),this.pool.delete(t))}),this.currentBaseURL!==void 0&&e.baseURL!==this.currentBaseURL&&(this.blobs.forEach(t=>{this.injector?.releaseBlobUrl?.(t),URL.revokeObjectURL(t)}),this.blobs.clear()),this.currentBaseURL=e.baseURL;const b=async t=>{if(this.pendingUpdates.has(t)&&this.pendingUpdates.get(t)?.inPool===!1){const l=this.blobs.get(t);l&&(this.injector?.releaseBlobUrl?.(l),URL.revokeObjectURL(l),this.blobs.delete(t),this.pendingUpdates.delete(t))}if(this.pool.has(t)){const l=this.pool.get(t);if(!this.blobs.has(t))await l.destroy(),this.pool.delete(t),this.pendingUpdates.delete(t);else{await l.load(s);return}}const c=e.readingOrder.findWithHref(t);if(!c)return;if(!this.blobs.has(t)){const m=await new w(e,this.currentBaseURL||"",c,{cssProperties:this.currentCssProperties,injector:this.injector}).build();this.blobs.set(t,m)}const p=new y(this.blobs.get(t),this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.getFragmentIds(t),this.resizeWatchSelectors);t!==r&&await p.hide(),this.container.appendChild(p.iframe),await p.load(s),this.pool.set(t,p)};try{await Promise.all(d.map(t=>b(t)))}catch(t){u(t)}const a=this.pool.get(r);if(a?.source!==this._currentFrame?.source&&(await this._currentFrame?.hide(),a&&await a.load(s),a&&await a.show(i.locations.progression),this._currentFrame=a,a)){const t=this.container.ownerDocument.activeElement;t&&t.tagName==="IFRAME"&&t!==a.iframe&&a.iframe.focus({preventScroll:!0})}f()});this.inprogress.set(r,h),await h,this.inprogress.delete(r)}setCSSProperties(e){if(!((s,n)=>{const o=Object.keys(s),r=Object.keys(n);if(o.length!==r.length)return!1;for(const h of o)if(s[h]!==n[h])return!1;return!0})(this.currentCssProperties||{},e)){this.currentCssProperties=e,this.pool.forEach(s=>{s.setCSSProperties(e)});for(const s of this.blobs.keys())this.pendingUpdates.set(s,{inPool:this.pool.has(s)})}}get currentFrames(){return[this._currentFrame]}get currentBounds(){const e={x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0,toJSON(){return this}};return this.currentFrames.forEach(i=>{if(!i)return;const s=i.realSize;e.x=Math.min(e.x,s.x),e.y=Math.min(e.y,s.y),e.width+=s.width,e.height=Math.max(e.height,s.height),e.top=Math.min(e.top,s.top),e.right=Math.min(e.right,s.right),e.bottom=Math.min(e.bottom,s.bottom),e.left=Math.min(e.left,s.left)}),e}}export{R as WebPubFramePoolManager};
1
+ import{WebPubBlobBuilder as w}from"./WebPubBlobBuilder.js";import{WebPubFrameManager as y}from"./WebPubFrameManager.js";class R{constructor(e,i,s,n={},o=[],r,h=[]){this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.pendingUpdates=new Map,this.injector=null,this.container=e,this.currentCssProperties=i,this.injector=s,this.contentProtectionConfig=n,this.keyboardPeripheralsConfig=[...o],this.getFragmentIds=r??(()=>[]),this.resizeWatchSelectors=[...h]}addResizeTarget(e){this.resizeWatchSelectors.includes(e)||this.resizeWatchSelectors.push(e),this.pool.forEach(i=>i.addResizeTarget(e))}removeResizeTarget(e){this.resizeWatchSelectors=this.resizeWatchSelectors.filter(i=>i!==e),this.pool.forEach(i=>i.removeResizeTarget(e))}async destroy(){let e=this.inprogress.values(),i=e.next();const s=[];for(;i.value;)s.push(i.value),i=e.next();s.length>0&&await Promise.allSettled(s),this.inprogress.clear();let n=this.pool.values(),o=n.next();for(;o.value;)await o.value.destroy(),o=n.next();this.pool.clear(),this.blobs.forEach(r=>{this.injector?.releaseBlobUrl?.(r),URL.revokeObjectURL(r)}),this.blobs.clear(),this.injector?.dispose(),this.container.childNodes.forEach(r=>{(r.nodeType===Node.ELEMENT_NODE||r.nodeType===Node.TEXT_NODE)&&r.remove()})}async update(e,i,s){const n=e.readingOrder.items;let o=n.findIndex(f=>f.href===i.href);if(o<0)throw Error(`Locator not found in reading order: ${i.href}`);const r=n[o].href;this.inprogress.has(r)&&await this.inprogress.get(r);const h=new Promise(async(f,u)=>{const g=[],d=[];e.readingOrder.items.forEach((t,l)=>{l!==o&&l!==o-1&&l!==o+1&&(g.includes(t.href)||g.push(t.href)),l===o&&(d.includes(t.href)||d.push(t.href))}),g.forEach(async t=>{d.includes(t)||this.pool.has(t)&&(await this.pool.get(t)?.destroy(),this.pool.delete(t))}),this.currentBaseURL!==void 0&&e.baseURL!==this.currentBaseURL&&(this.blobs.forEach(t=>{this.injector?.releaseBlobUrl?.(t),URL.revokeObjectURL(t)}),this.blobs.clear()),this.currentBaseURL=e.baseURL;const b=async t=>{if(this.pendingUpdates.has(t)&&this.pendingUpdates.get(t)?.inPool===!1){const c=this.blobs.get(t);c&&(this.injector?.releaseBlobUrl?.(c),URL.revokeObjectURL(c),this.blobs.delete(t),this.pendingUpdates.delete(t))}if(this.pool.has(t)){const c=this.pool.get(t);if(!this.blobs.has(t))await c.destroy(),this.pool.delete(t),this.pendingUpdates.delete(t);else{await c.load(s);return}}const l=e.readingOrder.findWithHref(t);if(!l)return;if(!this.blobs.has(t)){const m=await new w(e,this.currentBaseURL||"",l,{cssProperties:this.currentCssProperties,injector:this.injector}).build();this.blobs.set(t,m)}const p=new y(this.blobs.get(t),this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.getFragmentIds(t),this.resizeWatchSelectors);t!==r&&await p.hide(),this.container.appendChild(p.iframe),await p.load(s),this.pool.set(t,p)};try{await Promise.all(d.map(t=>b(t)))}catch(t){u(t)}const a=this.pool.get(r);if(a?.source!==this._currentFrame?.source&&(await this._currentFrame?.hide(),a&&await a.load(s),a&&await a.show(i.locations.progression),this._currentFrame=a,a)){const t=this.container.ownerDocument.activeElement;t&&t.tagName==="IFRAME"&&t!==a.iframe&&a.iframe.focus({preventScroll:!0})}f()});this.inprogress.set(r,h);try{await h}finally{this.inprogress.delete(r)}}setCSSProperties(e){if(!((s,n)=>{const o=Object.keys(s),r=Object.keys(n);if(o.length!==r.length)return!1;for(const h of o)if(s[h]!==n[h])return!1;return!0})(this.currentCssProperties||{},e)){this.currentCssProperties=e,this.pool.forEach(s=>{s.setCSSProperties(e)});for(const s of this.blobs.keys())this.pendingUpdates.set(s,{inPool:this.pool.has(s)})}}get currentFrames(){return[this._currentFrame]}get currentBounds(){const e={x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0,toJSON(){return this}};return this.currentFrames.forEach(i=>{if(!i)return;const s=i.realSize;e.x=Math.min(e.x,s.x),e.y=Math.min(e.y,s.y),e.width+=s.width,e.height=Math.max(e.height,s.height),e.top=Math.min(e.top,s.top),e.right=Math.min(e.right,s.right),e.bottom=Math.min(e.bottom,s.bottom),e.left=Math.min(e.left,s.left)}),e}}export{R as WebPubFramePoolManager};
@@ -1 +1 @@
1
- import{Feature as L,Link as u,Locator as p,LocatorText as P,getCssSelector as y,getHtmlId as S,LocatorLocations as k}from"@readium/shared";import{VisualNavigator as D}from"../Navigator.js";import{WebPubFramePoolManager as x}from"./WebPubFramePoolManager.js";import{WebPubModules as C}from"@readium/navigator-html-injectables";import{p as g}from"../_virtual/index.js";import{getScriptMode as I}from"../helpers/scriptMode.js";import{WebPubCSS as E}from"./css/WebPubCSS.js";import{WebUserProperties as O,WebRSProperties as A}from"./css/Properties.js";import{WebPubPreferences as F}from"./preferences/WebPubPreferences.js";import{WebPubDefaults as T}from"./preferences/WebPubDefaults.js";import{WebPubSettings as _}from"./preferences/WebPubSettings.js";import{WebPubPreferencesEditor as v}from"./preferences/WebPubPreferencesEditor.js";import{Injector as W}from"../injection/Injector.js";import{createReadiumWebPubRules as R}from"../injection/webpubInjectables.js";import{NavigatorProtector as H,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as b}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as M,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as w}from"../peripherals/KeyboardPeripherals.js";import{supportsDecorationStyle as N,decorationsEqual as z,resolveDecorationForWire as m}from"@readium/decorator";const V=h=>({frameLoaded:h.frameLoaded||(()=>{}),positionChanged:h.positionChanged||(()=>{}),timelineItemChanged:h.timelineItemChanged||(()=>{}),tap:h.tap||(()=>!1),click:h.click||(()=>!1),zoom:h.zoom||(()=>{}),scroll:h.scroll||(()=>{}),customEvent:h.customEvent||(()=>{}),handleLocator:h.handleLocator||(()=>!1),textSelected:h.textSelected||(()=>{}),contentProtection:h.contentProtection||(()=>{}),contextMenu:h.contextMenu||(()=>{}),peripheral:h.peripheral||(()=>{})});function j(h,e){return h.length===e.length&&h.every((t,i)=>t===e[i])}class B extends D{constructor(e,t,i,r=void 0,o={preferences:{},defaults:{}}){super(),this.currentIndex=0,this._visibleFragmentIds=[],this._notifiedVisibleFragmentIds=[],this._preferencesEditor=null,this._injector=null,this._isNavigating=!1,this._navigatorProtector=null,this._keyboardPeripheralsManager=null,this._suspiciousActivityListener=null,this._keyboardPeripheralListener=null,this._decorations=new Map,this._decorationObservers=new Map,this._decorationHoveredDecorations=new Map,this._decorationActivationState=new Map,this._decorationHoverState=new Map,this._decorationActivationConsumed=!1,this.webViewport={readingOrder:[],progressions:new Map,positions:null},this.pub=t,this.container=e,this.listeners=V(i),this._preferences=new F(o.preferences),this._defaults=new T(o.defaults),this._settings=new _(this._preferences,this._defaults,this.hasDisplayTransformability),this._css=new E({rsProperties:new A({experiments:this._settings.experiments||null}),userProperties:new O({zoom:this._settings.zoom})});const n=R(t.readingOrder.items),l=o.injectables||{rules:[],allowedDomains:[]};if(this._injector=new W({rules:[...n,...l.rules],allowedDomains:l.allowedDomains}),this._contentProtection=o.contentProtection||{},this._decoratorConfig=o.decoratorConfig||{},this._decorationResizeSelectors=new Set(this._decoratorConfig.resizeWatchSelectors??[]),this._keyboardPeripherals=this.mergeKeyboardPeripherals(this._contentProtection,o.keyboardPeripherals||[]),(this._contentProtection.disableContextMenu||this._contentProtection.checkAutomation||this._contentProtection.checkIFrameEmbedding||this._contentProtection.monitorDevTools||this._contentProtection.protectPrinting?.disable)&&(this._navigatorProtector=new H(this._contentProtection),this._suspiciousActivityListener=a=>{const{type:s,...c}=a.detail;s==="context_menu"?this.listeners.contextMenu(c):this.listeners.contentProtection(s,c)},window.addEventListener(b,this._suspiciousActivityListener)),this._keyboardPeripherals.length>0&&(this._keyboardPeripheralsManager=new M({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=a=>{const s=a.detail;this.listeners.peripheral(s)},window.addEventListener(w,this._keyboardPeripheralListener)),r&&typeof r.copyWithLocations=="function"){this.currentLocation=r;const a=this.pub.readingOrder.findIndexWithHref(r.href);a>=0&&(this.currentIndex=a)}else this.currentLocation=this.createCurrentLocator()}async load(){await this.updateCSS(!1);const e=this.compileCSSProperties(this._css);this.framePool=new x(this.container,e,this._injector,this._contentProtection,this._keyboardPeripherals,t=>this.pub.timeline.segmentsForHref(t).flatMap(i=>i.references).map(i=>{const r=i.indexOf("#");return r>=0?i.slice(r+1):""}).filter(Boolean),[...this._decorationResizeSelectors]),await this.apply()}get settings(){return Object.freeze({...this._settings})}get preferencesEditor(){return this._preferencesEditor===null&&(this._preferencesEditor=new v(this._preferences,this.settings,this.pub.metadata)),this._preferencesEditor}async submitPreferences(e){this._preferences=this._preferences.merging(e),await this.applyPreferences()}async applyPreferences(){this._settings=new _(this._preferences,this._defaults,this.hasDisplayTransformability),this._preferencesEditor!==null&&(this._preferencesEditor=new v(this._preferences,this.settings,this.pub.metadata)),await this.updateCSS(!0)}async updateCSS(e){this._css.update(this._settings),e&&await this.commitCSS(this._css)}compileCSSProperties(e){const t={};for(const[i,r]of Object.entries(e.rsProperties.toCSSProperties()))t[i]=r;for(const[i,r]of Object.entries(e.userProperties.toCSSProperties()))t[i]=r;return t}async commitCSS(e){const t=this.compileCSSProperties(e);this.framePool.setCSSProperties(t)}get _cframes(){return this.framePool.currentFrames}get hasDisplayTransformability(){return this.pub.metadata?.accessibility?.feature?.some(e=>e.value===L.DISPLAY_TRANSFORMABILITY.value)??!1}eventListener(e,t){switch(e){case"_pong":this.listeners.frameLoaded(this.framePool.currentFrames[0].iframe.contentWindow),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),this._reapplyDecorationsToCurrentFrame();break;case"first_visible_locator":const i=p.deserialize(t);if(!i)break;this.currentLocation=new p({href:this.currentLocation.href,type:this.currentLocation.type,title:this.currentLocation.title,locations:i?.locations,text:i?.text}),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation);break;case"text_selected":{const a=t;a.locator=new p({href:this.currentLocation.href,type:this.currentLocation.type,text:new P({highlight:a.text})}),this.listeners.textSelected(a);break}case"decoration_activated":{this._handleDecorationActivated(t)&&(this._decorationActivationConsumed=!0);break}case"decoration_pointer_enter":this._handleDecorationPointerEnter(t);break;case"decoration_pointer_leave":this._handleDecorationPointerLeave(t);break;case"click":case"tap":if(this._decorationActivationConsumed){this._decorationActivationConsumed=!1;break}const r=t;if(r.interactiveElement){const a=new DOMParser().parseFromString(r.interactiveElement,"text/html").body.children[0];if(a.nodeType===a.ELEMENT_NODE&&a.nodeName==="A"&&a.hasAttribute("href")){const s=a.attributes.getNamedItem("href")?.value;if(s.startsWith("#"))this.go(this.currentLocation.copyWithLocations({fragments:[s.substring(1)]}),!1,()=>{});else if(s.startsWith("mailto:")||s.startsWith("tel:"))this.listeners.handleLocator(new u({href:s}).locator);else try{let c;if(s.startsWith("http://")||s.startsWith("https://"))c=s;else if(this.currentLocation.href.startsWith("http://")||this.currentLocation.href.startsWith("https://")){const f=new URL(this.currentLocation.href);c=new URL(s,f).href}else c=g.join(g.dirname(this.currentLocation.href),s);const d=this.pub.readingOrder.findWithHref(c);d?this.goLink(d,!1,()=>{}):(console.warn(`Internal link not found in readingOrder: ${c}`),this.listeners.handleLocator(new u({href:s}).locator))}catch(c){console.warn(`Couldn't resolve internal link for ${s}: ${c}`),this.listeners.handleLocator(new u({href:s}).locator)}}else console.log("Clicked on",a)}else if(e==="click"?this.listeners.click(r):this.listeners.tap(r))break;break;case"scroll":this.listeners.scroll(t);break;case"zoom":this.listeners.zoom(t);break;case"progress":this.syncLocation(t);break;case"content_protection":const o=t;this.listeners.contentProtection(o.type,o);break;case"context_menu":this.listeners.contextMenu(t);break;case"keyboard_peripherals":const n=t,l={...n,interactiveElement:void 0};n.interactiveElement&&(l.interactiveElement=new DOMParser().parseFromString(n.interactiveElement,"text/html").body.children[0]),this.listeners.peripheral(l);break;case"log":console.log(this.framePool.currentFrames[0]?.source?.split("/")[3],...t);break;default:this.listeners.customEvent(e,t);break}}determineModules(){const e=C.slice(),t=I(this.pub.metadata);return t==="cjk-vertical"||t==="mongolian-vertical"?e.map(i=>i==="webpub_snapper"?"cjk_vertical_snapper":i):e}attachListener(){this.framePool.currentFrames[0]?.msg&&(this.framePool.currentFrames[0].msg.listener=(e,t)=>{this.eventListener(e,t)}),this._reapplyDecorationsToCurrentFrame()}async apply(){if(await this.framePool.update(this.pub,this.currentLocation,this.determineModules()),this.attachListener(),this.pub.readingOrder.findIndexWithHref(this.currentLocation.href)<0)throw Error("Link for "+this.currentLocation.href+" not found!")}async destroy(){this._suspiciousActivityListener&&window.removeEventListener(b,this._suspiciousActivityListener),this._keyboardPeripheralListener&&window.removeEventListener(w,this._keyboardPeripheralListener),this._navigatorProtector?.destroy(),this._keyboardPeripheralsManager?.destroy(),await this.framePool?.destroy(),this._decorations.clear(),this._decorationObservers.clear(),this._decorationHoveredDecorations.clear(),this._decorationActivationState.clear(),this._decorationHoverState.clear(),this._decorationResizeSelectors.clear()}supportsDecorationStyle(e){return N(e,this._decoratorConfig.decorationTemplates)}registerDecorationObserver(e,t){this._decorationObservers.has(e)||this._decorationObservers.set(e,new Set),this._decorationObservers.get(e).add(t),t.onDecorationActivated&&(this._decorationActivationState.set(e,!0),this._sendDecorationActivatable(e,!0)),(t.onDecorationPointerEnter||t.onDecorationPointerLeave)&&(this._decorationHoverState.set(e,!0),this._sendDecorationHoverable(e,!0))}unregisterDecorationObserver(e){this._decorationObservers.forEach((t,i)=>{if(!t.has(e))return;t.delete(e);const r=[...t].some(n=>n.onDecorationActivated);this._decorationActivationState.has(i)&&!r&&(this._decorationActivationState.delete(i),this._sendDecorationActivatable(i,!1));const o=[...t].some(n=>n.onDecorationPointerEnter||n.onDecorationPointerLeave);this._decorationHoverState.has(i)&&!o&&(this._decorationHoverState.delete(i),this._sendDecorationHoverable(i,!1))})}_sendDecorationActivatable(e,t){const i=this.framePool?.currentFrames[0];i?.msg&&i.msg.send("decoration_activatable",{group:e,activatable:t})}_sendDecorationHoverable(e,t){const i=this.framePool?.currentFrames[0];i?.msg&&i.msg.send("decoration_hoverable",{group:e,hoverable:t})}addDecorationResizeTarget(e){this._decorationResizeSelectors.add(e),this.framePool?.addResizeTarget(e)}removeDecorationResizeTarget(e){this._decorationResizeSelectors.delete(e),this.framePool?.removeResizeTarget(e)}applyDecorations(e,t){const i=this._decorations.get(t)??[],r=new Map(i.map(d=>[d.id,d])),o=new Map(e.map(d=>[d.id,d])),n=[],l=[],a=[];for(const[d,f]of r)o.has(d)?z(f,o.get(d))||a.push(o.get(d)):n.push(d);for(const[d,f]of o)r.has(d)||l.push(f);this._decorations.set(t,e),this._sendDecorationOps(t,n,l,a,i);const s=this._decorationActivationState.get(t);s!==void 0&&this._sendDecorationActivatable(t,s);const c=this._decorationHoverState.get(t);c!==void 0&&this._sendDecorationHoverable(t,c)}_sendDecorationOps(e,t,i,r,o){const n=this.framePool?.currentFrames[0];if(!n?.msg)return;const l=this.currentLocation.href,a=new Map(o.map(s=>[s.id,s]));for(const s of t){const c=a.get(s);!c||c.locator.href!==l||n.msg.send("decorate",{group:e,action:"remove",decoration:{id:s}})}for(const s of i)s.locator.href===l&&n.msg.send("decorate",{group:e,action:"add",decoration:m(s,this._decoratorConfig.decorationTemplates)});for(const s of r)s.locator.href===l&&n.msg.send("decorate",{group:e,action:"update",decoration:m(s,this._decoratorConfig.decorationTemplates)})}_reapplyDecorationsToCurrentFrame(){const e=this.framePool?.currentFrames[0];if(!e?.msg)return;const t=this.currentLocation.href;for(const[i,r]of this._decorations){const o=r.filter(n=>n.locator.href===t);if(o.length!==0){e.msg.send("decorate",{group:i,action:"clear"});for(const n of o)e.msg.send("decorate",{group:i,action:"add",decoration:m(n,this._decoratorConfig.decorationTemplates)})}}for(const[i,r]of this._decorationActivationState)e.msg.send("decoration_activatable",{group:i,activatable:r});for(const[i,r]of this._decorationHoverState)e.msg.send("decoration_hoverable",{group:i,hoverable:r})}_handleDecorationActivated(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return!1;const i=(this._decorations.get(e.group)??[]).find(n=>n.id===e.decorationId);if(!i)return!1;const r={decoration:i,group:e.group,rect:e.rect,point:e.point};let o=!1;for(const n of t)n.onDecorationActivated?.(r)&&(o=!0);return o}_handleDecorationPointerEnter(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(o=>o.id===e.decorationId);if(!i)return;this._decorationHoveredDecorations.set(e.group,i);const r={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const o of t)o.onDecorationPointerEnter?.(r)}_handleDecorationPointerLeave(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(o=>o.id===e.decorationId)??this._decorationHoveredDecorations.get(e.group);if(this._decorationHoveredDecorations.delete(e.group),!i)return;const r={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const o of t)o.onDecorationPointerLeave?.(r)}async changeResource(e){if(e===0)return!1;const t=this.pub.readingOrder.findIndexWithHref(this.currentLocation.href),i=Math.max(0,Math.min(this.pub.readingOrder.items.length-1,t+e));return i===t?!1:(this.currentIndex=i,this.currentLocation=this.createCurrentLocator(),await this.apply(),!0)}updateViewport(e){this.webViewport.readingOrder=[],this.webViewport.progressions.clear(),this.webViewport.positions=null,this.currentLocation&&(this.webViewport.readingOrder.push(this.currentLocation.href),this.webViewport.progressions.set(this.currentLocation.href,e),this.currentLocation.locations?.position!==void 0&&(this.webViewport.positions=[this.currentLocation.locations.position]))}async syncLocation(e){const t=e;this.currentLocation&&(this.currentLocation=this.currentLocation.copyWithLocations({progression:t.start})),this.updateViewport(t),this.listeners.positionChanged(this.currentLocation);const i=t.fragmentId?this.currentLocation.copyWithLocations({fragments:[`#${t.fragmentId}`]}):this.currentLocation;this._visibleFragmentIds=t.visibleFragmentIds??[],this._notifyTimelineChange(i),await this.framePool.update(this.pub,this.currentLocation,this.determineModules())}goBackward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this.changeResource(-1).then(i=>{this._isNavigating=!1,t(i)})}goForward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this.changeResource(1).then(i=>{this._isNavigating=!1,t(i)})}get currentLocator(){return this.currentLocation}get viewport(){return this.webViewport}get isScrollStart(){const e=this.viewport.readingOrder[0];return this.viewport.progressions.get(e)?.start===0}get isScrollEnd(){const e=this.viewport.readingOrder[this.viewport.readingOrder.length-1];return this.viewport.progressions.get(e)?.end===1}get canGoBackward(){const e=this.pub.readingOrder.items[0]?.href;return!(this.viewport.progressions.has(e)&&this.viewport.progressions.get(e)?.start===0)}get canGoForward(){const e=this.pub.readingOrder.items[this.pub.readingOrder.items.length-1]?.href;return!(this.viewport.progressions.has(e)&&this.viewport.progressions.get(e)?.end===1)}get readingProgression(){return this.pub.metadata.effectiveReadingProgression}get publication(){return this.pub}get timeline(){const e=this.pub.timeline;return this._wrappedTimeline||(this._wrappedTimeline=new Proxy(e,{get:(t,i)=>{if(i!=="navigableFrom"){const r=Reflect.get(t,i,t);return typeof r=="function"?r.bind(t):r}return r=>{const o=this._visibleFragmentIds;let n=(o.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${o[0]}`]})):void 0)??r;const l=(o.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${o[o.length-1]}`]})):void 0)??r;if(this.isScrollStart){const c=t.ancestors(n).find(d=>d.references.includes(this.currentLocation.href));c&&(n=c)}const a=t.navigableFrom(n).previous,s=t.navigableFrom(l).next;return{previous:a,next:s}}}})),this._wrappedTimeline}async loadLocator(e,t){let i=!1,r=y(e.locations);if(e.text?.highlight?i=await new Promise((a,s)=>{this.framePool.currentFrames[0].msg.send("go_text",r?[e.text?.serialize(),r]:e.text?.serialize(),c=>a(c))}):r&&(i=await new Promise((a,s)=>{this.framePool.currentFrames[0].msg.send("go_text",["",r],c=>a(c))})),i){t(i);return}const o=S(e.locations);if(o&&(i=await new Promise((a,s)=>{this.framePool.currentFrames[0].msg.send("go_id",o,c=>a(c))})),i){t(i);return}const n=e?.locations?.progression;n&&n>0?i=await new Promise((a,s)=>{this.framePool.currentFrames[0].msg.send("go_progression",n,c=>a(c))}):i=!0,t(i)}go(e,t,i){const r=e.href.split("#")[0];if(!this.pub.readingOrder.findWithHref(r))return i(this.listeners.handleLocator(e));const n=this.pub.readingOrder.findIndexWithHref(r);if(n>=0&&(this.currentIndex=n),this._isNavigating){i(!1);return}this._isNavigating=!0,this.currentLocation=this.createCurrentLocator(),this.apply().then(()=>this.loadLocator(e,l=>{this._isNavigating=!1,i(l)})).then(()=>{this.attachListener()})}goLink(e,t,i){return this.go(e.locator,t,i)}createCurrentLocator(){const t=this.pub.readingOrder.items[this.currentIndex];if(!t)throw new Error("No current resource available");const r=this.currentLocation&&this.currentLocation.href===t.href&&this.currentLocation.locations.progression?this.currentLocation.locations.progression:0;return this.pub.manifest.locatorFromLink(t)||new p({href:t.href,type:t.type||"text/html",locations:new k({fragments:[],progression:r,position:this.currentIndex+1})})}_notifyTimelineChange(e){const t=this.timeline.locate(e),i=!j(this._visibleFragmentIds,this._notifiedVisibleFragmentIds);(t!==this._currentTimelineItem||i)&&(this._currentTimelineItem=t,this._notifiedVisibleFragmentIds=this._visibleFragmentIds,this.listeners.timelineItemChanged(t))}}const ce=B;export{ce as ExperimentalWebPubNavigator,B as WebPubNavigator};
1
+ import{Feature as w,Link as u,Locator as f,LocatorText as P,getCssSelector as y,getHtmlId as S,LocatorLocations as k}from"@readium/shared";import{VisualNavigator as x}from"../Navigator.js";import{WebPubFramePoolManager as D}from"./WebPubFramePoolManager.js";import{WebPubModules as C}from"@readium/navigator-html-injectables";import{p as g}from"../_virtual/index.js";import{getScriptMode as I}from"../helpers/scriptMode.js";import{WebPubCSS as O}from"./css/WebPubCSS.js";import{WebUserProperties as E,WebRSProperties as F}from"./css/Properties.js";import{WebPubPreferences as A}from"./preferences/WebPubPreferences.js";import{WebPubDefaults as T}from"./preferences/WebPubDefaults.js";import{WebPubSettings as _}from"./preferences/WebPubSettings.js";import{WebPubPreferencesEditor as v}from"./preferences/WebPubPreferencesEditor.js";import{Injector as W}from"../injection/Injector.js";import{createReadiumWebPubRules as M}from"../injection/webpubInjectables.js";import{NavigatorProtector as R,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as b}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as H,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as L}from"../peripherals/KeyboardPeripherals.js";import{supportsDecorationStyle as N,decorationsEqual as z,resolveDecorationForWire as m}from"@readium/decorator";const V=h=>({frameLoaded:h.frameLoaded||(()=>{}),positionChanged:h.positionChanged||(()=>{}),timelineItemChanged:h.timelineItemChanged||(()=>{}),tap:h.tap||(()=>!1),click:h.click||(()=>!1),zoom:h.zoom||(()=>{}),scroll:h.scroll||(()=>{}),customEvent:h.customEvent||(()=>{}),handleLocator:h.handleLocator||(()=>!1),textSelected:h.textSelected||(()=>{}),contentProtection:h.contentProtection||(()=>{}),contextMenu:h.contextMenu||(()=>{}),peripheral:h.peripheral||(()=>{})});function j(h,e){return h.length===e.length&&h.every((t,i)=>t===e[i])}class B extends x{constructor(e,t,i,r=void 0,o={preferences:{},defaults:{}}){super(),this.currentIndex=0,this._destroyed=!1,this._visibleFragmentIds=[],this._notifiedVisibleFragmentIds=[],this._preferencesEditor=null,this._injector=null,this._isNavigating=!1,this._navigatorProtector=null,this._keyboardPeripheralsManager=null,this._suspiciousActivityListener=null,this._keyboardPeripheralListener=null,this._decorations=new Map,this._decorationObservers=new Map,this._decorationHoveredDecorations=new Map,this._decorationActivationState=new Map,this._decorationHoverState=new Map,this._decorationActivationConsumed=!1,this.webViewport={readingOrder:[],progressions:new Map,positions:null},this.pub=t,this.container=e,this.listeners=V(i),this._preferences=new A(o.preferences),this._defaults=new T(o.defaults),this._settings=new _(this._preferences,this._defaults,this.hasDisplayTransformability),this._css=new O({rsProperties:new F({experiments:this._settings.experiments||null}),userProperties:new E({zoom:this._settings.zoom})});const s=M(t.readingOrder.items),l=o.injectables||{rules:[],allowedDomains:[]};if(this._injector=new W({rules:[...s,...l.rules],allowedDomains:l.allowedDomains}),this._contentProtection=o.contentProtection||{},this._decoratorConfig=o.decoratorConfig||{},this._decorationResizeSelectors=new Set(this._decoratorConfig.resizeWatchSelectors??[]),this._keyboardPeripherals=this.mergeKeyboardPeripherals(this._contentProtection,o.keyboardPeripherals||[]),(this._contentProtection.disableContextMenu||this._contentProtection.checkAutomation||this._contentProtection.checkIFrameEmbedding||this._contentProtection.monitorDevTools||this._contentProtection.protectPrinting?.disable)&&(this._navigatorProtector=new R(this._contentProtection),this._suspiciousActivityListener=a=>{const{type:n,...c}=a.detail;n==="context_menu"?this.listeners.contextMenu(c):this.listeners.contentProtection(n,c)},window.addEventListener(b,this._suspiciousActivityListener)),this._keyboardPeripherals.length>0&&(this._keyboardPeripheralsManager=new H({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=a=>{const n=a.detail;this.listeners.peripheral(n)},window.addEventListener(L,this._keyboardPeripheralListener)),r&&typeof r.copyWithLocations=="function"){this.currentLocation=r;const a=this.pub.readingOrder.findIndexWithHref(r.href);a>=0&&(this.currentIndex=a)}else this.currentLocation=this.createCurrentLocator()}async load(){if(await this.updateCSS(!1),this._destroyed)return;const e=this.compileCSSProperties(this._css);this.framePool=new D(this.container,e,this._injector,this._contentProtection,this._keyboardPeripherals,t=>this.pub.timeline.segmentsForHref(t).flatMap(i=>i.references).map(i=>{const r=i.indexOf("#");return r>=0?i.slice(r+1):""}).filter(Boolean),[...this._decorationResizeSelectors]),!this._destroyed&&(this.currentLocation=this.completeLocator(this.currentLocation),await this.apply())}get settings(){return Object.freeze({...this._settings})}get preferencesEditor(){return this._preferencesEditor===null&&(this._preferencesEditor=new v(this._preferences,this.settings,this.pub.metadata)),this._preferencesEditor}async submitPreferences(e){this._preferences=this._preferences.merging(e),await this.applyPreferences()}async applyPreferences(){this._settings=new _(this._preferences,this._defaults,this.hasDisplayTransformability),this._preferencesEditor!==null&&(this._preferencesEditor=new v(this._preferences,this.settings,this.pub.metadata)),await this.updateCSS(!0)}async updateCSS(e){this._css.update(this._settings),e&&await this.commitCSS(this._css)}compileCSSProperties(e){const t={};for(const[i,r]of Object.entries(e.rsProperties.toCSSProperties()))t[i]=r;for(const[i,r]of Object.entries(e.userProperties.toCSSProperties()))t[i]=r;return t}async commitCSS(e){const t=this.compileCSSProperties(e);this.framePool.setCSSProperties(t)}get _cframes(){return this.framePool.currentFrames}get hasDisplayTransformability(){return this.pub.metadata?.accessibility?.feature?.some(e=>e.value===w.DISPLAY_TRANSFORMABILITY.value)??!1}eventListener(e,t){switch(e){case"_pong":this.listeners.frameLoaded(this.framePool.currentFrames[0].iframe.contentWindow),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),this._reapplyDecorationsToCurrentFrame();break;case"first_visible_locator":const i=f.deserialize(t);if(!i)break;this.currentLocation=new f({href:this.currentLocation.href,type:this.currentLocation.type,title:this.currentLocation.title,locations:i?.locations,text:i?.text}),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation);break;case"text_selected":{const a=t;a.locator=new f({href:this.currentLocation.href,type:this.currentLocation.type,text:new P({highlight:a.text})}),this.listeners.textSelected(a);break}case"decoration_activated":{this._handleDecorationActivated(t)&&(this._decorationActivationConsumed=!0);break}case"decoration_pointer_enter":this._handleDecorationPointerEnter(t);break;case"decoration_pointer_leave":this._handleDecorationPointerLeave(t);break;case"click":case"tap":if(this._decorationActivationConsumed){this._decorationActivationConsumed=!1;break}const r=t;if(r.interactiveElement){const a=new DOMParser().parseFromString(r.interactiveElement,"text/html").body.children[0];if(a.nodeType===a.ELEMENT_NODE&&a.nodeName==="A"&&a.hasAttribute("href")){const n=a.attributes.getNamedItem("href")?.value;if(n.startsWith("#"))this.go(this.currentLocation.copyWithLocations({fragments:[n.substring(1)]}),!1,()=>{});else if(n.startsWith("mailto:")||n.startsWith("tel:"))this.listeners.handleLocator(new u({href:n}).locator);else try{let c;if(n.startsWith("http://")||n.startsWith("https://"))c=n;else if(this.currentLocation.href.startsWith("http://")||this.currentLocation.href.startsWith("https://")){const p=new URL(this.currentLocation.href);c=new URL(n,p).href}else c=g.join(g.dirname(this.currentLocation.href),n);const d=this.pub.readingOrder.findWithHref(c);d?this.goLink(d,!1,()=>{}):(console.warn(`Internal link not found in readingOrder: ${c}`),this.listeners.handleLocator(new u({href:n}).locator))}catch(c){console.warn(`Couldn't resolve internal link for ${n}: ${c}`),this.listeners.handleLocator(new u({href:n}).locator)}}else console.log("Clicked on",a)}else if(e==="click"?this.listeners.click(r):this.listeners.tap(r))break;break;case"scroll":this.listeners.scroll(t);break;case"zoom":this.listeners.zoom(t);break;case"progress":this.syncLocation(t);break;case"content_protection":const o=t;this.listeners.contentProtection(o.type,o);break;case"context_menu":this.listeners.contextMenu(t);break;case"keyboard_peripherals":const s=t,l={...s,interactiveElement:void 0};s.interactiveElement&&(l.interactiveElement=new DOMParser().parseFromString(s.interactiveElement,"text/html").body.children[0]),this.listeners.peripheral(l);break;case"log":console.log(this.framePool.currentFrames[0]?.source?.split("/")[3],...t);break;default:this.listeners.customEvent(e,t);break}}determineModules(){const e=C.slice(),t=I(this.pub.metadata);return t==="cjk-vertical"||t==="mongolian-vertical"?e.map(i=>i==="webpub_snapper"?"cjk_vertical_snapper":i):e}attachListener(){this.framePool.currentFrames[0]?.msg&&(this.framePool.currentFrames[0].msg.listener=(e,t)=>{this.eventListener(e,t)}),this._reapplyDecorationsToCurrentFrame()}async apply(){if(await this.framePool.update(this.pub,this.currentLocation,this.determineModules()),this.attachListener(),this.pub.readingOrder.findIndexWithHref(this.currentLocation.href)<0)throw Error("Link for "+this.currentLocation.href+" not found!")}async destroy(){this._destroyed=!0,this._suspiciousActivityListener&&window.removeEventListener(b,this._suspiciousActivityListener),this._keyboardPeripheralListener&&window.removeEventListener(L,this._keyboardPeripheralListener),this._navigatorProtector?.destroy(),this._keyboardPeripheralsManager?.destroy(),await this.framePool?.destroy(),this._decorations.clear(),this._decorationObservers.clear(),this._decorationHoveredDecorations.clear(),this._decorationActivationState.clear(),this._decorationHoverState.clear(),this._decorationResizeSelectors.clear()}supportsDecorationStyle(e){return N(e,this._decoratorConfig.decorationTemplates)}registerDecorationObserver(e,t){this._decorationObservers.has(e)||this._decorationObservers.set(e,new Set),this._decorationObservers.get(e).add(t),t.onDecorationActivated&&(this._decorationActivationState.set(e,!0),this._sendDecorationActivatable(e,!0)),(t.onDecorationPointerEnter||t.onDecorationPointerLeave)&&(this._decorationHoverState.set(e,!0),this._sendDecorationHoverable(e,!0))}unregisterDecorationObserver(e){this._decorationObservers.forEach((t,i)=>{if(!t.has(e))return;t.delete(e);const r=[...t].some(s=>s.onDecorationActivated);this._decorationActivationState.has(i)&&!r&&(this._decorationActivationState.delete(i),this._sendDecorationActivatable(i,!1));const o=[...t].some(s=>s.onDecorationPointerEnter||s.onDecorationPointerLeave);this._decorationHoverState.has(i)&&!o&&(this._decorationHoverState.delete(i),this._sendDecorationHoverable(i,!1))})}_sendDecorationActivatable(e,t){const i=this.framePool?.currentFrames[0];i?.msg&&i.msg.send("decoration_activatable",{group:e,activatable:t})}_sendDecorationHoverable(e,t){const i=this.framePool?.currentFrames[0];i?.msg&&i.msg.send("decoration_hoverable",{group:e,hoverable:t})}addDecorationResizeTarget(e){this._decorationResizeSelectors.add(e),this.framePool?.addResizeTarget(e)}removeDecorationResizeTarget(e){this._decorationResizeSelectors.delete(e),this.framePool?.removeResizeTarget(e)}applyDecorations(e,t){const i=this._decorations.get(t)??[],r=new Map(i.map(d=>[d.id,d])),o=new Map(e.map(d=>[d.id,d])),s=[],l=[],a=[];for(const[d,p]of r)o.has(d)?z(p,o.get(d))||a.push(o.get(d)):s.push(d);for(const[d,p]of o)r.has(d)||l.push(p);this._decorations.set(t,e),this._sendDecorationOps(t,s,l,a,i);const n=this._decorationActivationState.get(t);n!==void 0&&this._sendDecorationActivatable(t,n);const c=this._decorationHoverState.get(t);c!==void 0&&this._sendDecorationHoverable(t,c)}_sendDecorationOps(e,t,i,r,o){const s=this.framePool?.currentFrames[0];if(!s?.msg)return;const l=this.currentLocation.href,a=new Map(o.map(n=>[n.id,n]));for(const n of t){const c=a.get(n);!c||c.locator.href!==l||s.msg.send("decorate",{group:e,action:"remove",decoration:{id:n}})}for(const n of i)n.locator.href===l&&s.msg.send("decorate",{group:e,action:"add",decoration:m(n,this._decoratorConfig.decorationTemplates)});for(const n of r)n.locator.href===l&&s.msg.send("decorate",{group:e,action:"update",decoration:m(n,this._decoratorConfig.decorationTemplates)})}_reapplyDecorationsToCurrentFrame(){const e=this.framePool?.currentFrames[0];if(!e?.msg)return;const t=this.currentLocation.href;for(const[i,r]of this._decorations){const o=r.filter(s=>s.locator.href===t);if(o.length!==0){e.msg.send("decorate",{group:i,action:"clear"});for(const s of o)e.msg.send("decorate",{group:i,action:"add",decoration:m(s,this._decoratorConfig.decorationTemplates)})}}for(const[i,r]of this._decorationActivationState)e.msg.send("decoration_activatable",{group:i,activatable:r});for(const[i,r]of this._decorationHoverState)e.msg.send("decoration_hoverable",{group:i,hoverable:r})}_handleDecorationActivated(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return!1;const i=(this._decorations.get(e.group)??[]).find(s=>s.id===e.decorationId);if(!i)return!1;const r={decoration:i,group:e.group,rect:e.rect,point:e.point};let o=!1;for(const s of t)s.onDecorationActivated?.(r)&&(o=!0);return o}_handleDecorationPointerEnter(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(o=>o.id===e.decorationId);if(!i)return;this._decorationHoveredDecorations.set(e.group,i);const r={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const o of t)o.onDecorationPointerEnter?.(r)}_handleDecorationPointerLeave(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(o=>o.id===e.decorationId)??this._decorationHoveredDecorations.get(e.group);if(this._decorationHoveredDecorations.delete(e.group),!i)return;const r={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const o of t)o.onDecorationPointerLeave?.(r)}async changeResource(e){if(e===0)return!1;const t=this.pub.readingOrder.findIndexWithHref(this.currentLocation.href),i=Math.max(0,Math.min(this.pub.readingOrder.items.length-1,t+e));return i===t?!1:(this.currentIndex=i,this.currentLocation=this.createCurrentLocator(),await this.apply(),!0)}updateViewport(e){this.webViewport.readingOrder=[],this.webViewport.progressions.clear(),this.webViewport.positions=null,this.currentLocation&&(this.webViewport.readingOrder.push(this.currentLocation.href),this.webViewport.progressions.set(this.currentLocation.href,e),this.currentLocation.locations?.position!==void 0&&(this.webViewport.positions=[this.currentLocation.locations.position]))}async syncLocation(e){const t=e;this.currentLocation&&(this.currentLocation=this.currentLocation.copyWithLocations({progression:t.start})),this.updateViewport(t),this.listeners.positionChanged(this.currentLocation);const i=t.fragmentId?this.currentLocation.copyWithLocations({fragments:[`#${t.fragmentId}`]}):this.currentLocation;this._visibleFragmentIds=t.visibleFragmentIds??[],this._notifyTimelineChange(i),await this.framePool.update(this.pub,this.currentLocation,this.determineModules())}goBackward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this.changeResource(-1).then(i=>{this._isNavigating=!1,t(i)})}goForward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this.changeResource(1).then(i=>{this._isNavigating=!1,t(i)})}get currentLocator(){return this.currentLocation}get viewport(){return this.webViewport}get isScrollStart(){const e=this.viewport.readingOrder[0];return this.viewport.progressions.get(e)?.start===0}get isScrollEnd(){const e=this.viewport.readingOrder[this.viewport.readingOrder.length-1];return this.viewport.progressions.get(e)?.end===1}get canGoBackward(){const e=this.pub.readingOrder.items[0]?.href;return!(this.viewport.progressions.has(e)&&this.viewport.progressions.get(e)?.start===0)}get canGoForward(){const e=this.pub.readingOrder.items[this.pub.readingOrder.items.length-1]?.href;return!(this.viewport.progressions.has(e)&&this.viewport.progressions.get(e)?.end===1)}get readingProgression(){return this.pub.metadata.effectiveReadingProgression}get publication(){return this.pub}get timeline(){const e=this.pub.timeline;return this._wrappedTimeline||(this._wrappedTimeline=new Proxy(e,{get:(t,i)=>{if(i!=="navigableFrom"){const r=Reflect.get(t,i,t);return typeof r=="function"?r.bind(t):r}return r=>{const o=this._visibleFragmentIds;let s=(o.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${o[0]}`]})):void 0)??r;const l=(o.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${o[o.length-1]}`]})):void 0)??r;if(this.isScrollStart){const c=t.ancestors(s).find(d=>d.references.includes(this.currentLocation.href));c&&(s=c)}const a=t.navigableFrom(s).previous,n=t.navigableFrom(l).next;return{previous:a,next:n}}}})),this._wrappedTimeline}async loadLocator(e,t){let i=!1,r=y(e.locations);if(e.text?.highlight?i=await new Promise((a,n)=>{this.framePool.currentFrames[0].msg.send("go_text",r?[e.text?.serialize(),r]:e.text?.serialize(),c=>a(c))}):r&&(i=await new Promise((a,n)=>{this.framePool.currentFrames[0].msg.send("go_text",["",r],c=>a(c))})),i){t(i);return}const o=S(e.locations);if(o&&(i=await new Promise((a,n)=>{this.framePool.currentFrames[0].msg.send("go_id",o,c=>a(c))})),i){t(i);return}const s=e?.locations?.progression;s&&s>0?i=await new Promise((a,n)=>{this.framePool.currentFrames[0].msg.send("go_progression",s,c=>a(c))}):i=!0,t(i)}completeLocator(e){if(!e.href){const t=this.pub.readingOrder.items;let i=!1;if(typeof e.locations.position=="number"){const r=t[e.locations.position-1];r&&(e=(this.pub.manifest.locatorFromLink(r)||new f({href:r.href,type:r.type||"text/html"})).copyWithLocations(e.locations),i=!0)}if(!i&&typeof e.locations?.totalProgression=="number"){const r=e.locations.totalProgression,o=Math.min(t.length-1,Math.max(0,Math.round(r*(t.length-1)))),s=t[o];s&&(e=(this.pub.manifest.locatorFromLink(s)||new f({href:s.href,type:s.type||"text/html"})).copyWithLocations(e.locations))}}return e}go(e,t,i){e=this.completeLocator(e);const r=e.href.split("#")[0];if(!this.pub.readingOrder.findWithHref(r))return i(this.listeners.handleLocator(e));const s=this.pub.readingOrder.findIndexWithHref(r);if(s>=0&&(this.currentIndex=s),this._isNavigating){i(!1);return}this._isNavigating=!0,this.currentLocation=this.createCurrentLocator(),this.apply().then(()=>this.loadLocator(e,l=>{this._isNavigating=!1,i(l)})).then(()=>{this.attachListener()})}goLink(e,t,i){return this.go(e.locator,t,i)}createCurrentLocator(){const t=this.pub.readingOrder.items[this.currentIndex];if(!t)throw new Error("No current resource available");const r=this.currentLocation&&this.currentLocation.href===t.href&&this.currentLocation.locations.progression?this.currentLocation.locations.progression:0;return this.pub.manifest.locatorFromLink(t)||new f({href:t.href,type:t.type||"text/html",locations:new k({fragments:[],progression:r,position:this.currentIndex+1})})}_notifyTimelineChange(e){const t=this.timeline.locate(e),i=!j(this._visibleFragmentIds,this._notifiedVisibleFragmentIds);(t!==this._currentTimelineItem||i)&&(this._currentTimelineItem=t,this._notifiedVisibleFragmentIds=this._visibleFragmentIds,this.listeners.timelineItemChanged(t))}}const ce=B;export{ce as ExperimentalWebPubNavigator,B as WebPubNavigator};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/navigator",
3
- "version": "2.10.3",
3
+ "version": "2.11.1",
4
4
  "type": "module",
5
5
  "description": "Next generation SDK for publications in Web Apps",
6
6
  "author": "readium",
@@ -44,10 +44,10 @@
44
44
  "node": ">=18"
45
45
  },
46
46
  "dependencies": {
47
- "@readium/decorator": "1.2.3",
48
- "@readium/navigator-html-injectables": "2.8.3",
49
- "@readium/shared": "2.5.1",
50
- "@readium/helpers": "1.1.0"
47
+ "@readium/decorator": "1.2.4",
48
+ "@readium/helpers": "1.1.1",
49
+ "@readium/navigator-html-injectables": "2.8.4",
50
+ "@readium/shared": "2.6.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@readium/css": "^2.0.5",
@@ -1,7 +1,7 @@
1
1
  import { Link, Locator, LocatorLocations, Publication, Timeline, TimelineItem, getTime as locatorTime } from "@readium/shared";
2
2
  import { MediaNavigator, IContentProtectionConfig, IKeyboardPeripheralsConfig, KeyboardPeripheralEventData } from "../Navigator.ts";
3
3
  import { Configurable } from "../preferences/Configurable.ts";
4
- import { WebAudioEngine, PlaybackState } from "./engine/index.ts";
4
+ import { WebAudioEngine, PlaybackState, AudioMseLoaderFactory } from "./engine/index.ts";
5
5
  import {
6
6
  AudioPreferences,
7
7
  AudioDefaults,
@@ -69,6 +69,26 @@ export interface AudioNavigatorConfiguration {
69
69
  defaults: IAudioDefaults;
70
70
  contentProtection?: IAudioContentProtectionConfig;
71
71
  keyboardPeripherals?: IKeyboardPeripheralsConfig;
72
+
73
+ /**
74
+ * Called with the persistent playback element before
75
+ * the first src is assigned, so the host can prepare it. Use for MSE/EME
76
+ * setups. When it returns a promise, loading of
77
+ * the initial track (and prefetching of adjacent ones) is deferred until
78
+ * the promise settles; a rejection is forwarded to the error listener and
79
+ * loading proceeds anyway.
80
+ */
81
+ mediaElementSetup?: (element: HTMLMediaElement) => void | Promise<void>;
82
+
83
+ /**
84
+ * When provided, media bytes reach the playback element through Media
85
+ * Source Extensions instead of direct `src` assignment: the engine
86
+ * creates one loader per track via this factory and the loader owns all
87
+ * fetching. Supply one for e.g. EME encrypted audio, since browsers have
88
+ * poor support for encrypted audio directly through `src`. The container
89
+ * handling (WebM, fMP4, …) is the loader implementation's concern.
90
+ */
91
+ mseLoaderFactory?: AudioMseLoaderFactory;
72
92
  }
73
93
 
74
94
  export class AudioNavigator extends MediaNavigator implements Configurable<AudioSettings, AudioPreferences> {
@@ -94,6 +114,8 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
94
114
  /** True while a track transition is in progress; suppresses spurious mid-navigation events. */
95
115
  private _isNavigating: boolean = false;
96
116
  private _isStalled: boolean = false;
117
+ /** Set by destroy(); stops the deferred initial load from touching a dead instance. */
118
+ private _destroyed: boolean = false;
97
119
  private _stalledWatchdog: ReturnType<typeof setInterval> | null = null;
98
120
  private _stalledCheckTime: number = 0;
99
121
 
@@ -131,9 +153,19 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
131
153
  }
132
154
 
133
155
  const initialHref = this.currentLocation.href.split("#")[0];
134
- const trackIndex = this.hrefToTrackIndex(initialHref);
156
+ let trackIndex = this.hrefToTrackIndex(initialHref);
135
157
  if (trackIndex === -1) {
136
- throw new Error(`AudioNavigator: initial href "${ initialHref }" not found in reading order`);
158
+ // Progression-only locators (e.g. restored from an OPDS progression)
159
+ // Resolve totalProgression against the
160
+ // cumulative track durations instead of failing outright.
161
+ const totalProgression = this.currentLocation.locations?.totalProgression;
162
+ if (totalProgression !== undefined) {
163
+ const resolved = this.locatorFromTotalProgression(totalProgression);
164
+ this.currentLocation = resolved.locator;
165
+ trackIndex = resolved.trackIndex;
166
+ } else {
167
+ throw new Error(`AudioNavigator: initial href "${ initialHref }" not found in reading order`);
168
+ }
137
169
  }
138
170
  const initialTime = locatorTime(this.currentLocation.locations) || 0;
139
171
 
@@ -145,7 +177,8 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
145
177
  } as PlaybackState,
146
178
  playWhenReady: false,
147
179
  index: trackIndex
148
- }
180
+ },
181
+ mseLoaderFactory: configuration.mseLoaderFactory,
149
182
  });
150
183
 
151
184
  this.pool = new AudioPoolManager(audioEngine, publication, configuration.contentProtection);
@@ -188,6 +221,29 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
188
221
  this.setupEventListeners();
189
222
 
190
223
  this._isNavigating = true;
224
+
225
+ const startInitialLoad = () => this.startInitialLoad(trackIndex, initialTime);
226
+ if (configuration.mediaElementSetup) {
227
+ // Defer the initial load until the host has prepared the element
228
+ // (e.g. attached MediaKeys for EME) so no media data is fetched or
229
+ // decoded before protection is in place.
230
+ if (this._destroyed) return;
231
+ Promise.resolve()
232
+ .then(() => configuration.mediaElementSetup!(this.pool.audioEngine.getMediaElement()))
233
+ .catch((error) => { this.listeners.error(error, this.currentLocator); })
234
+ .then(startInitialLoad);
235
+ } else {
236
+ startInitialLoad();
237
+ }
238
+ }
239
+
240
+ /** Sets the initial track on the primary element and seeks to the starting position. */
241
+ private startInitialLoad(trackIndex: number, initialTime: number): void {
242
+ // The navigator may have been destroyed while an async
243
+ // mediaElementSetup was pending (React StrictMode does this in dev) —
244
+ // don't start loading media on the orphaned element.
245
+ if (this._destroyed) return;
246
+
191
247
  this.pool.setCurrentAudio(trackIndex, "forward");
192
248
 
193
249
  // applyPreferences() must come after setCurrentAudio() so that the src
@@ -289,6 +345,47 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
289
345
  return this.hrefToTrackIndex(this.currentLocation.href);
290
346
  }
291
347
 
348
+ /**
349
+ * Builds a locator for an overall publication progression (0–1) by walking
350
+ * the cumulative track durations. Falls back to the start of the first
351
+ * track when the reading order carries no duration metadata.
352
+ */
353
+ private locatorFromTotalProgression(totalProgression: number): { locator: Locator, trackIndex: number } {
354
+ const items = this.pub.readingOrder.items;
355
+ const durations = items.map(link => link.duration ?? 0);
356
+ const totalDuration = durations.reduce((sum, d) => sum + d, 0);
357
+
358
+ let trackIndex = 0;
359
+ let time = 0;
360
+ if (totalDuration > 0) {
361
+ let remaining = Math.min(Math.max(totalProgression, 0), 1) * totalDuration;
362
+ for (let i = 0; i < durations.length; i++) {
363
+ trackIndex = i;
364
+ if (remaining <= durations[i] || i === durations.length - 1) {
365
+ time = remaining;
366
+ break;
367
+ }
368
+ remaining -= durations[i];
369
+ }
370
+ }
371
+
372
+ const link = items[trackIndex];
373
+ return {
374
+ trackIndex,
375
+ locator: new Locator({
376
+ href: link.href,
377
+ type: link.type || "", // Should have a mimetype
378
+ title: link.title,
379
+ locations: new LocatorLocations({
380
+ position: trackIndex + 1,
381
+ progression: durations[trackIndex] > 0 ? time / durations[trackIndex] : 0,
382
+ totalProgression: Math.min(Math.max(totalProgression, 0), 1),
383
+ fragments: [`t=${ time }`]
384
+ })
385
+ })
386
+ };
387
+ }
388
+
292
389
  get currentLocator(): Locator {
293
390
  return this.currentLocation;
294
391
  }
@@ -384,7 +481,11 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
384
481
  fragments: [`t=${this.duration}`]
385
482
  }));
386
483
  this.listeners.trackEnded(this.currentLocator);
387
- if (!this.canGoForward) return;
484
+ if (!this.canGoForward) {
485
+ // Set final progress in audiobook
486
+ this.listeners.positionChanged(this.currentLocator);
487
+ return;
488
+ }
388
489
  await this.nextTrack();
389
490
  if (this._settings.autoPlay) this.play();
390
491
  });
@@ -698,6 +799,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
698
799
  }
699
800
 
700
801
  destroy(): void {
802
+ this._destroyed = true;
701
803
  this.stopPositionPolling();
702
804
  this._stopStalledWatchdog();
703
805
  this.destroyMediaSession();