@readium/navigator 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/Navigator.js +1 -0
  2. package/dist/_virtual/index.js +1 -0
  3. package/dist/_virtual/preload-helper.js +1 -0
  4. package/dist/audio/AudioNavigator.js +1 -0
  5. package/dist/audio/AudioPoolManager.js +1 -0
  6. package/dist/audio/engine/PreservePitchProcessor.js +215 -0
  7. package/dist/audio/engine/PreservePitchWorklet.js +1 -0
  8. package/dist/audio/engine/WebAudioEngine.js +1 -0
  9. package/dist/audio/preferences/AudioDefaults.js +1 -0
  10. package/dist/audio/preferences/AudioPreferences.js +1 -0
  11. package/dist/audio/preferences/AudioPreferencesEditor.js +1 -0
  12. package/dist/audio/preferences/AudioSettings.js +1 -0
  13. package/dist/audio/protection/AudioNavigatorProtector.js +1 -0
  14. package/dist/css/Properties.js +1 -0
  15. package/dist/dom/_readium_cssSelectorGenerator.js +1 -0
  16. package/dist/dom/_readium_executionCleanup.js +14 -0
  17. package/dist/dom/_readium_executionPrevention.js +66 -0
  18. package/dist/dom/_readium_webpubExecution.js +5 -0
  19. package/dist/epub/EpubNavigator.js +1 -0
  20. package/dist/epub/css/Properties.js +1 -0
  21. package/dist/epub/css/ReadiumCSS.js +1 -0
  22. package/dist/epub/frame/FrameBlobBuilder.js +1 -0
  23. package/dist/epub/frame/FrameComms.js +1 -0
  24. package/dist/epub/frame/FrameManager.js +1 -0
  25. package/dist/epub/frame/FramePoolManager.js +1 -0
  26. package/dist/epub/fxl/FXLCoordinator.js +1 -0
  27. package/dist/epub/fxl/FXLFrameManager.js +1 -0
  28. package/dist/epub/fxl/FXLFramePoolManager.js +1 -0
  29. package/dist/epub/fxl/FXLPeripherals.js +4 -0
  30. package/dist/epub/fxl/FXLPeripheralsDebug.js +1 -0
  31. package/dist/epub/fxl/FXLSpreader.js +1 -0
  32. package/dist/epub/preferences/EpubDefaults.js +1 -0
  33. package/dist/epub/preferences/EpubPreferences.js +1 -0
  34. package/dist/epub/preferences/EpubPreferencesEditor.js +1 -0
  35. package/dist/epub/preferences/EpubSettings.js +1 -0
  36. package/dist/helpers/dimensions.js +1 -0
  37. package/dist/helpers/dist/sML.js +1 -0
  38. package/dist/helpers/lineLength.js +1 -0
  39. package/dist/helpers/minify.js +1 -0
  40. package/dist/helpers/scriptMode.js +1 -0
  41. package/dist/index.js +1 -10990
  42. package/dist/injection/Injector.js +1 -0
  43. package/dist/injection/epubInjectables.js +1 -0
  44. package/dist/injection/webpubInjectables.js +1 -0
  45. package/dist/{ReadiumCSS-after-D7unrNI9.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/ReadiumCSS-after.css.js} +2 -5
  46. package/dist/{ReadiumCSS-before-DwBLxUVH.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/ReadiumCSS-before.css.js} +2 -5
  47. package/dist/{ReadiumCSS-default-AIAk8uwU.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/ReadiumCSS-default.css.js} +2 -5
  48. package/dist/{ReadiumCSS-ebpaj_fonts_patch-Dt2XliTg.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/ReadiumCSS-ebpaj_fonts_patch.css.js} +2 -5
  49. package/dist/{ReadiumCSS-after-XUKPAxfT.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-horizontal/ReadiumCSS-after.css.js} +2 -5
  50. package/dist/{ReadiumCSS-before-8FMq19-x.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-horizontal/ReadiumCSS-before.css.js} +2 -5
  51. package/dist/{ReadiumCSS-default-N65xNiIp.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-horizontal/ReadiumCSS-default.css.js} +2 -5
  52. package/dist/{ReadiumCSS-after-ClF4TBzj.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-vertical/ReadiumCSS-after.css.js} +2 -5
  53. package/dist/{ReadiumCSS-before-BNTwR8Qm.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-vertical/ReadiumCSS-before.css.js} +2 -5
  54. package/dist/{ReadiumCSS-default-BesyZHRU.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/cjk-vertical/ReadiumCSS-default.css.js} +2 -5
  55. package/dist/{ReadiumCSS-after-d5mC4cme.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/rtl/ReadiumCSS-after.css.js} +2 -5
  56. package/dist/{ReadiumCSS-before-CG-KmDa3.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/rtl/ReadiumCSS-before.css.js} +2 -5
  57. package/dist/{ReadiumCSS-default-BhdLiyWp.js → node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/rtl/ReadiumCSS-default.css.js} +2 -5
  58. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/dist/webPub/ReadiumCSS-webPub.css.js +274 -0
  59. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/vars/colors.json.js +1 -0
  60. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/vars/experiments.json.js +1 -0
  61. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/vars/fontStacks.json.js +1 -0
  62. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/vars/i18n.json.js +1 -0
  63. package/dist/node_modules/.pnpm/@readium_css@2.0.5/node_modules/@readium/css/css/vars/settings.json.js +1 -0
  64. package/dist/node_modules/.pnpm/path-browserify@1.0.1/node_modules/path-browserify/index.js +1 -0
  65. package/dist/peripherals/KeyboardConditionBridge.js +1 -0
  66. package/dist/peripherals/KeyboardPeripherals.js +1 -0
  67. package/dist/preferences/Preference.js +1 -0
  68. package/dist/preferences/Types.js +1 -0
  69. package/dist/preferences/guards.js +1 -0
  70. package/dist/protection/AutomationDetector.js +1 -0
  71. package/dist/protection/ContextMenuProtector.js +1 -0
  72. package/dist/protection/CopyProtector.js +1 -0
  73. package/dist/protection/DevToolsDetector.js +1 -0
  74. package/dist/protection/DragAndDropProtector.js +1 -0
  75. package/dist/protection/IframeEmbeddingDetector.js +1 -0
  76. package/dist/protection/NavigatorProtector.js +1 -0
  77. package/dist/protection/PrintProtector.js +15 -0
  78. package/dist/protection/utils/WorkerConsole.js +12 -0
  79. package/dist/protection/utils/console.js +1 -0
  80. package/dist/protection/utils/match.js +1 -0
  81. package/dist/protection/utils/platform.js +1 -0
  82. package/dist/webpub/WebPubBlobBuilder.js +2 -0
  83. package/dist/webpub/WebPubFrameManager.js +1 -0
  84. package/dist/webpub/WebPubFramePoolManager.js +1 -0
  85. package/dist/webpub/WebPubNavigator.js +1 -0
  86. package/dist/webpub/css/Properties.js +1 -0
  87. package/dist/webpub/css/WebPubCSS.js +1 -0
  88. package/dist/webpub/preferences/WebPubDefaults.js +1 -0
  89. package/dist/webpub/preferences/WebPubPreferences.js +1 -0
  90. package/dist/webpub/preferences/WebPubPreferencesEditor.js +1 -0
  91. package/dist/webpub/preferences/WebPubSettings.js +1 -0
  92. package/package.json +11 -9
  93. package/src/Navigator.ts +4 -1
  94. package/src/audio/AudioNavigator.ts +8 -8
  95. package/src/decorations/index.ts +24 -127
  96. package/src/epub/EpubNavigator.ts +149 -20
  97. package/src/epub/frame/FrameManager.ts +8 -3
  98. package/src/epub/frame/FramePoolManager.ts +5 -2
  99. package/src/epub/fxl/FXLCoordinator.ts +1 -1
  100. package/src/epub/fxl/FXLFrameManager.ts +1 -1
  101. package/src/epub/preferences/EpubDefaults.ts +1 -1
  102. package/src/epub/preferences/EpubSettings.ts +1 -1
  103. package/src/protection/DevToolsDetector.ts +1 -1
  104. package/src/webpub/WebPubFrameManager.ts +9 -3
  105. package/src/webpub/WebPubFramePoolManager.ts +5 -2
  106. package/src/webpub/WebPubNavigator.ts +100 -19
  107. package/src/webpub/preferences/WebPubDefaults.ts +1 -1
  108. package/src/webpub/preferences/WebPubSettings.ts +1 -1
  109. package/types/src/Navigator.d.ts +3 -1
  110. package/types/src/decorations/index.d.ts +5 -59
  111. package/types/src/epub/EpubNavigator.d.ts +13 -3
  112. package/types/src/epub/frame/FrameManager.d.ts +2 -1
  113. package/types/src/epub/frame/FramePoolManager.d.ts +2 -1
  114. package/types/src/epub/fxl/FXLFramePoolManager.d.ts +1 -1
  115. package/types/src/webpub/WebPubFrameManager.d.ts +2 -1
  116. package/types/src/webpub/WebPubFramePoolManager.d.ts +2 -1
  117. package/types/src/webpub/WebPubNavigator.d.ts +12 -3
  118. package/dist/ar-DyHX_uy2.js +0 -7
  119. package/dist/da-Dct0PS3E.js +0 -7
  120. package/dist/fr-C5HEel98.js +0 -7
  121. package/dist/index.umd.cjs +0 -5615
  122. package/dist/it-DFOBoXGy.js +0 -7
  123. package/dist/pt_PT-Di3sVjze.js +0 -7
  124. package/dist/sv-BfzAFsVN.js +0 -7
@@ -0,0 +1,15 @@
1
+ class i{constructor(t={}){this.styleElement=null,this.beforePrintHandler=null,this.onPrintAttempt=t.onPrintAttempt,t.disable&&this.setupPrintProtection(t.watermark)}setupPrintProtection(t){const e=document.createElement("style");e.textContent=`
2
+ @media print {
3
+ body * {
4
+ display: none !important;
5
+ }
6
+ body::after {
7
+ content: "${t||"Printing has been disabled"}";
8
+ font-size: 200%;
9
+ display: block;
10
+ text-align: center;
11
+ margin-top: 50vh;
12
+ transform: translateY(-50%);
13
+ }
14
+ }
15
+ `,document.head.appendChild(e),this.styleElement=e,this.beforePrintHandler=n=>(n.preventDefault(),this.onPrintAttempt?.(),!1),window.addEventListener("beforeprint",this.beforePrintHandler)}destroy(){this.beforePrintHandler&&(window.removeEventListener("beforeprint",this.beforePrintHandler),this.beforePrintHandler=null),this.styleElement?.parentNode&&(this.styleElement.parentNode.removeChild(this.styleElement),this.styleElement=null)}}export{i as PrintProtector};
@@ -0,0 +1,12 @@
1
+ let n=0;function l(){return++n}const d=`
2
+ onmessage = function(event) {
3
+ var action = event.data;
4
+ var startTime = performance.now()
5
+
6
+ console[action.type](...action.payload);
7
+ postMessage({
8
+ id: action.id,
9
+ time: performance.now() - startTime
10
+ })
11
+ }
12
+ `,r=class r{constructor(s,i){this.callbacks=new Map,this.worker=s,this.blobUrl=i,this.worker.onmessage=t=>{const e=t.data,a=e.id,o=this.callbacks.get(e.id);o&&(o({time:e.time}),this.callbacks.delete(a))},this.log=(...t)=>this.send("log",...t),this.table=(...t)=>this.send("table",...t),this.clear=(...t)=>this.send("clear",...t)}async send(s,...i){const t=l();return new Promise((e,a)=>{this.callbacks.set(t,e),this.worker.postMessage({id:t,type:s,payload:i}),setTimeout(()=>{a(new Error("timeout")),this.callbacks.delete(t)},2e3)})}destroy(){this.worker.terminate(),URL.revokeObjectURL(this.blobUrl)}};r.workerScript=d;let c=r;export{c as WorkerConsole};
@@ -0,0 +1 @@
1
+ function o(e){return typeof window<"u"&&console?console[e]:(...n)=>{}}const t=o("log"),c=o("table"),l=o("clear");export{l as clear,t as log,c as table};
@@ -0,0 +1 @@
1
+ function u(r){return r.excludes.some(e=>e())?!1:r.includes.some(e=>e())}export{u as match};
@@ -0,0 +1 @@
1
+ async function r(){if(typeof navigator<"u"&&navigator.brave&&navigator.brave.isBrave)try{return await Promise.race([navigator.brave.isBrave(),new Promise(e=>setTimeout(()=>e(!1),1e3))])}catch{return!0}return!1}export{r as isBrave};
@@ -0,0 +1,2 @@
1
+ class a{constructor(t,i,e,r){this.injector=null,this.pub=t,this.item=e,this.burl=e.toURL(i)||"",this.cssProperties=r.cssProperties,this.injector=r.injector??null}async build(){if(!this.item.mediaType.isHTML)throw new Error(`Unsupported media type for WebPub: ${this.item.mediaType.string}`);return await this.buildHtmlFrame()}async buildHtmlFrame(){const t=await this.pub.get(this.item).readAsString();if(!t)throw new Error(`Failed reading item ${this.item.href}`);const i=new DOMParser().parseFromString(t,this.item.mediaType.string),e=i.querySelector("parsererror");if(e){const r=e.querySelector("div");throw new Error(`Failed parsing item ${this.item.href}: ${r?.textContent||e.textContent}`)}return this.injector&&await this.injector.injectForDocument(i,this.item),this.finalizeDOM(i,this.burl,this.item.mediaType,t,this.cssProperties)}setProperties(t,i){for(const e in t){const r=t[e];r&&i.documentElement.style.setProperty(e,r)}}finalizeDOM(t,i,e,r,o){if(!t)return"";if(o&&this.setProperties(o,t),t.body.querySelectorAll("img").forEach(n=>{n.setAttribute("fetchpriority","high")}),i!==void 0){const n=t.createElement("base");n.href=i,n.dataset.readium="true",t.head.firstChild.before(n)}let s;return e.string==="application/xhtml+xml"?s=new XMLSerializer().serializeToString(t):s=this.serializeAsHTML(t,r||""),URL.createObjectURL(new Blob([s],{type:e.isHTML?e.string:"application/xhtml+xml"}))}serializeAsHTML(t,i){const e=i.match(/<!DOCTYPE[^>]*>/i),r=e?e[0]+`
2
+ `:"";let s=t.documentElement.outerHTML;return r+s}}export{a as WebPubBlobBuilder};
@@ -0,0 +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"../helpers/dist/sML.js";import{KeyboardConditionBridge as m}from"../peripherals/KeyboardConditionBridge.js";class y{constructor(t,i={},r=[],e=[]){this.timelineFragmentIds=e,this.hidden=!0,this.destroyed=!1,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=[...r]}async load(t=[]){return new Promise((i,r)=>{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{r(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 m(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)}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,r=>{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,r)=>{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};
@@ -0,0 +1 @@
1
+ import{WebPubBlobBuilder as w}from"./WebPubBlobBuilder.js";import{WebPubFrameManager as y}from"./WebPubFrameManager.js";class L{constructor(t,o,s,n={},r=[],i){this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.pendingUpdates=new Map,this.injector=null,this.container=t,this.currentCssProperties=o,this.injector=s,this.contentProtectionConfig=n,this.keyboardPeripheralsConfig=[...r],this.getFragmentIds=i??(()=>[])}async destroy(){let t=this.inprogress.values(),o=t.next();const s=[];for(;o.value;)s.push(o.value),o=t.next();s.length>0&&await Promise.allSettled(s),this.inprogress.clear();let n=this.pool.values(),r=n.next();for(;r.value;)await r.value.destroy(),r=n.next();this.pool.clear(),this.blobs.forEach(i=>{this.injector?.releaseBlobUrl?.(i),URL.revokeObjectURL(i)}),this.blobs.clear(),this.injector?.dispose(),this.container.childNodes.forEach(i=>{(i.nodeType===Node.ELEMENT_NODE||i.nodeType===Node.TEXT_NODE)&&i.remove()})}async update(t,o,s){const n=t.readingOrder.items;let r=n.findIndex(f=>f.href===o.href);if(r<0)throw Error(`Locator not found in reading order: ${o.href}`);const i=n[r].href;this.inprogress.has(i)&&await this.inprogress.get(i);const c=new Promise(async(f,u)=>{const g=[],d=[];t.readingOrder.items.forEach((e,h)=>{h!==r&&h!==r-1&&h!==r+1&&(g.includes(e.href)||g.push(e.href)),h===r&&(d.includes(e.href)||d.push(e.href))}),g.forEach(async e=>{d.includes(e)||this.pool.has(e)&&(await this.pool.get(e)?.destroy(),this.pool.delete(e))}),this.currentBaseURL!==void 0&&t.baseURL!==this.currentBaseURL&&(this.blobs.forEach(e=>{this.injector?.releaseBlobUrl?.(e),URL.revokeObjectURL(e)}),this.blobs.clear()),this.currentBaseURL=t.baseURL;const b=async e=>{if(this.pendingUpdates.has(e)&&this.pendingUpdates.get(e)?.inPool===!1){const l=this.blobs.get(e);l&&(this.injector?.releaseBlobUrl?.(l),URL.revokeObjectURL(l),this.blobs.delete(e),this.pendingUpdates.delete(e))}if(this.pool.has(e)){const l=this.pool.get(e);if(!this.blobs.has(e))await l.destroy(),this.pool.delete(e),this.pendingUpdates.delete(e);else{await l.load(s);return}}const h=t.readingOrder.findWithHref(e);if(!h)return;if(!this.blobs.has(e)){const m=await new w(t,this.currentBaseURL||"",h,{cssProperties:this.currentCssProperties,injector:this.injector}).build();this.blobs.set(e,m)}const p=new y(this.blobs.get(e),this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.getFragmentIds(e));e!==i&&await p.hide(),this.container.appendChild(p.iframe),await p.load(s),this.pool.set(e,p)};try{await Promise.all(d.map(e=>b(e)))}catch(e){u(e)}const a=this.pool.get(i);if(a?.source!==this._currentFrame?.source&&(await this._currentFrame?.hide(),a&&await a.load(s),a&&await a.show(o.locations.progression),this._currentFrame=a,a)){const e=this.container.ownerDocument.activeElement;e&&e.tagName==="IFRAME"&&e!==a.iframe&&a.iframe.focus({preventScroll:!0})}f()});this.inprogress.set(i,c),await c,this.inprogress.delete(i)}setCSSProperties(t){if(!((s,n)=>{const r=Object.keys(s),i=Object.keys(n);if(r.length!==i.length)return!1;for(const c of r)if(s[c]!==n[c])return!1;return!0})(this.currentCssProperties||{},t)){this.currentCssProperties=t,this.pool.forEach(s=>{s.setCSSProperties(t)});for(const s of this.blobs.keys())this.pendingUpdates.set(s,{inPool:this.pool.has(s)})}}get currentFrames(){return[this._currentFrame]}get currentBounds(){const t={x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0,toJSON(){return this}};return this.currentFrames.forEach(o=>{if(!o)return;const s=o.realSize;t.x=Math.min(t.x,s.x),t.y=Math.min(t.y,s.y),t.width+=s.width,t.height=Math.max(t.height,s.height),t.top=Math.min(t.top,s.top),t.right=Math.min(t.right,s.right),t.bottom=Math.min(t.bottom,s.bottom),t.left=Math.min(t.left,s.left)}),t}}export{L as WebPubFramePoolManager};
@@ -0,0 +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 C}from"./WebPubFramePoolManager.js";import{WebPubModules as x}from"@readium/navigator-html-injectables";import{p as g}from"../_virtual/index.js";import{getScriptMode as E}from"../helpers/scriptMode.js";import{WebPubCSS as O}from"./css/WebPubCSS.js";import{WebUserProperties as A,WebRSProperties as I}from"./css/Properties.js";import{WebPubPreferences as W}from"./preferences/WebPubPreferences.js";import{WebPubDefaults as H}from"./preferences/WebPubDefaults.js";import{WebPubSettings as _}from"./preferences/WebPubSettings.js";import{WebPubPreferencesEditor as v}from"./preferences/WebPubPreferencesEditor.js";import{Injector as M}from"../injection/Injector.js";import{createReadiumWebPubRules as T}from"../injection/webpubInjectables.js";import{NavigatorProtector as F,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as b}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as N,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as w}from"../peripherals/KeyboardPeripherals.js";import{supportsDecorationStyle as R,decorationsEqual as V,resolveDecorationForWire as m}from"@readium/decorator";const z=d=>({frameLoaded:d.frameLoaded||(()=>{}),positionChanged:d.positionChanged||(()=>{}),timelineItemChanged:d.timelineItemChanged||(()=>{}),tap:d.tap||(()=>!1),click:d.click||(()=>!1),zoom:d.zoom||(()=>{}),scroll:d.scroll||(()=>{}),customEvent:d.customEvent||(()=>{}),handleLocator:d.handleLocator||(()=>!1),textSelected:d.textSelected||(()=>{}),contentProtection:d.contentProtection||(()=>{}),contextMenu:d.contextMenu||(()=>{}),peripheral:d.peripheral||(()=>{})});class j extends D{constructor(e,t,r,i=void 0,s={preferences:{},defaults:{}}){super(),this.currentIndex=0,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=z(r),this._preferences=new W(s.preferences),this._defaults=new H(s.defaults),this._settings=new _(this._preferences,this._defaults,this.hasDisplayTransformability),this._css=new O({rsProperties:new I({experiments:this._settings.experiments||null}),userProperties:new A({zoom:this._settings.zoom})});const n=T(t.readingOrder.items),h=s.injectables||{rules:[],allowedDomains:[]};if(this._injector=new M({rules:[...n,...h.rules],allowedDomains:h.allowedDomains}),this._contentProtection=s.contentProtection||{},this._decoratorConfig=s.decoratorConfig||{},this._keyboardPeripherals=this.mergeKeyboardPeripherals(this._contentProtection,s.keyboardPeripherals||[]),(this._contentProtection.disableContextMenu||this._contentProtection.checkAutomation||this._contentProtection.checkIFrameEmbedding||this._contentProtection.monitorDevTools||this._contentProtection.protectPrinting?.disable)&&(this._navigatorProtector=new F(this._contentProtection),this._suspiciousActivityListener=a=>{const{type:o,...c}=a.detail;o==="context_menu"?this.listeners.contextMenu(c):this.listeners.contentProtection(o,c)},window.addEventListener(b,this._suspiciousActivityListener)),this._keyboardPeripherals.length>0&&(this._keyboardPeripheralsManager=new N({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=a=>{const o=a.detail;this.listeners.peripheral(o)},window.addEventListener(w,this._keyboardPeripheralListener)),i&&typeof i.copyWithLocations=="function"){this.currentLocation=i;const a=this.pub.readingOrder.findIndexWithHref(i.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 C(this.container,e,this._injector,this._contentProtection,this._keyboardPeripherals,t=>this.pub.timeline.segmentsForHref(t).flatMap(r=>r.references).map(r=>{const i=r.indexOf("#");return i>=0?r.slice(i+1):""}).filter(Boolean)),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[r,i]of Object.entries(e.rsProperties.toCSSProperties()))t[r]=i;for(const[r,i]of Object.entries(e.userProperties.toCSSProperties()))t[r]=i;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 r=p.deserialize(t);if(!r)break;this.currentLocation=new p({href:this.currentLocation.href,type:this.currentLocation.type,title:this.currentLocation.title,locations:r?.locations,text:r?.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 i=t;if(i.interactiveElement){const a=new DOMParser().parseFromString(i.interactiveElement,"text/html").body.children[0];if(a.nodeType===a.ELEMENT_NODE&&a.nodeName==="A"&&a.hasAttribute("href")){const o=a.attributes.getNamedItem("href")?.value;if(o.startsWith("#"))this.go(this.currentLocation.copyWithLocations({fragments:[o.substring(1)]}),!1,()=>{});else if(o.startsWith("mailto:")||o.startsWith("tel:"))this.listeners.handleLocator(new u({href:o}).locator);else try{let c;if(o.startsWith("http://")||o.startsWith("https://"))c=o;else if(this.currentLocation.href.startsWith("http://")||this.currentLocation.href.startsWith("https://")){const f=new URL(this.currentLocation.href);c=new URL(o,f).href}else c=g.join(g.dirname(this.currentLocation.href),o);const l=this.pub.readingOrder.findWithHref(c);l?this.goLink(l,!1,()=>{}):(console.warn(`Internal link not found in readingOrder: ${c}`),this.listeners.handleLocator(new u({href:o}).locator))}catch(c){console.warn(`Couldn't resolve internal link for ${o}: ${c}`),this.listeners.handleLocator(new u({href:o}).locator)}}else console.log("Clicked on",a)}else if(e==="click"?this.listeners.click(i):this.listeners.tap(i))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 s=t;this.listeners.contentProtection(s.type,s);break;case"context_menu":this.listeners.contextMenu(t);break;case"keyboard_peripherals":const n=t,h={...n,interactiveElement:void 0};n.interactiveElement&&(h.interactiveElement=new DOMParser().parseFromString(n.interactiveElement,"text/html").body.children[0]),this.listeners.peripheral(h);break;case"log":console.log(this.framePool.currentFrames[0]?.source?.split("/")[3],...t);break;default:this.listeners.customEvent(e,t);break}}determineModules(){const e=x.slice(),t=E(this.pub.metadata);return t==="cjk-vertical"||t==="mongolian-vertical"?e.map(r=>r==="webpub_snapper"?"cjk_vertical_snapper":r):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()}supportsDecorationStyle(e){return R(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,r)=>{if(!t.has(e))return;t.delete(e);const i=[...t].some(n=>n.onDecorationActivated);this._decorationActivationState.has(r)&&!i&&(this._decorationActivationState.delete(r),this._sendDecorationActivatable(r,!1));const s=[...t].some(n=>n.onDecorationPointerEnter||n.onDecorationPointerLeave);this._decorationHoverState.has(r)&&!s&&(this._decorationHoverState.delete(r),this._sendDecorationHoverable(r,!1))})}_sendDecorationActivatable(e,t){const r=this.framePool?.currentFrames[0];r?.msg&&r.msg.send("decoration_activatable",{group:e,activatable:t})}_sendDecorationHoverable(e,t){const r=this.framePool?.currentFrames[0];r?.msg&&r.msg.send("decoration_hoverable",{group:e,hoverable:t})}applyDecorations(e,t){const r=this._decorations.get(t)??[],i=new Map(r.map(l=>[l.id,l])),s=new Map(e.map(l=>[l.id,l])),n=[],h=[],a=[];for(const[l,f]of i)s.has(l)?V(f,s.get(l))||a.push(s.get(l)):n.push(l);for(const[l,f]of s)i.has(l)||h.push(f);this._decorations.set(t,e),this._sendDecorationOps(t,n,h,a,r);const o=this._decorationActivationState.get(t);o!==void 0&&this._sendDecorationActivatable(t,o);const c=this._decorationHoverState.get(t);c!==void 0&&this._sendDecorationHoverable(t,c)}_sendDecorationOps(e,t,r,i,s){const n=this.framePool?.currentFrames[0];if(!n?.msg)return;const h=this.currentLocation.href,a=new Map(s.map(o=>[o.id,o]));for(const o of t){const c=a.get(o);!c||c.locator.href!==h||n.msg.send("decorate",{group:e,action:"remove",decoration:{id:o}})}for(const o of r)o.locator.href===h&&n.msg.send("decorate",{group:e,action:"add",decoration:m(o,this._decoratorConfig.decorationTemplates)});for(const o of i)o.locator.href===h&&n.msg.send("decorate",{group:e,action:"update",decoration:m(o,this._decoratorConfig.decorationTemplates)})}_reapplyDecorationsToCurrentFrame(){const e=this.framePool?.currentFrames[0];if(!e?.msg)return;const t=this.currentLocation.href;for(const[r,i]of this._decorations){const s=i.filter(n=>n.locator.href===t);if(s.length!==0){e.msg.send("decorate",{group:r,action:"clear"});for(const n of s)e.msg.send("decorate",{group:r,action:"add",decoration:m(n,this._decoratorConfig.decorationTemplates)})}}for(const[r,i]of this._decorationActivationState)e.msg.send("decoration_activatable",{group:r,activatable:i});for(const[r,i]of this._decorationHoverState)e.msg.send("decoration_hoverable",{group:r,hoverable:i})}_handleDecorationActivated(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return!1;const r=(this._decorations.get(e.group)??[]).find(n=>n.id===e.decorationId);if(!r)return!1;const i={decoration:r,group:e.group,rect:e.rect,point:e.point};let s=!1;for(const n of t)n.onDecorationActivated?.(i)&&(s=!0);return s}_handleDecorationPointerEnter(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const r=(this._decorations.get(e.group)??[]).find(s=>s.id===e.decorationId);if(!r)return;this._decorationHoveredDecorations.set(e.group,r);const i={decoration:r,group:e.group,rect:e.rect,point:e.point};for(const s of t)s.onDecorationPointerEnter?.(i)}_handleDecorationPointerLeave(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const r=(this._decorations.get(e.group)??[]).find(s=>s.id===e.decorationId)??this._decorationHoveredDecorations.get(e.group);if(this._decorationHoveredDecorations.delete(e.group),!r)return;const i={decoration:r,group:e.group,rect:e.rect,point:e.point};for(const s of t)s.onDecorationPointerLeave?.(i)}async changeResource(e){if(e===0)return!1;const t=this.pub.readingOrder.findIndexWithHref(this.currentLocation.href),r=Math.max(0,Math.min(this.pub.readingOrder.items.length-1,t+e));return r===t?!1:(this.currentIndex=r,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 r=t.fragmentId?this.currentLocation.copyWithLocations({fragments:[`#${t.fragmentId}`]}):this.currentLocation;this._notifyTimelineChange(r),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(r=>{this._isNavigating=!1,t(r)})}goForward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this.changeResource(1).then(r=>{this._isNavigating=!1,t(r)})}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(){return this.pub.timeline}async loadLocator(e,t){let r=!1,i=y(e.locations);if(e.text?.highlight?r=await new Promise((a,o)=>{this.framePool.currentFrames[0].msg.send("go_text",i?[e.text?.serialize(),i]:e.text?.serialize(),c=>a(c))}):i&&(r=await new Promise((a,o)=>{this.framePool.currentFrames[0].msg.send("go_text",["",i],c=>a(c))})),r){t(r);return}const s=S(e.locations);if(s&&(r=await new Promise((a,o)=>{this.framePool.currentFrames[0].msg.send("go_id",s,c=>a(c))})),r){t(r);return}const n=e?.locations?.progression;n&&n>0?r=await new Promise((a,o)=>{this.framePool.currentFrames[0].msg.send("go_progression",n,c=>a(c))}):r=!0,t(r)}go(e,t,r){const i=e.href.split("#")[0];if(!this.pub.readingOrder.findWithHref(i))return r(this.listeners.handleLocator(e));const n=this.pub.readingOrder.findIndexWithHref(i);if(n>=0&&(this.currentIndex=n),this._isNavigating){r(!1);return}this._isNavigating=!0,this.currentLocation=this.createCurrentLocator(),this.apply().then(()=>this.loadLocator(e,h=>{this._isNavigating=!1,r(h)})).then(()=>{this.attachListener()})}goLink(e,t,r){return this.go(e.locator,t,r)}createCurrentLocator(){const t=this.pub.readingOrder.items[this.currentIndex];if(!t)throw new Error("No current resource available");const i=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:i,position:this.currentIndex+1})})}_notifyTimelineChange(e){const t=this.timeline.locate(e);t!==this._currentTimelineItem&&(this._currentTimelineItem=t,this.listeners.timelineItemChanged(t))}}const ae=j;export{ae as ExperimentalWebPubNavigator,j as WebPubNavigator};
@@ -0,0 +1 @@
1
+ import{experiments as l}from"../../preferences/Types.js";import{Properties as e}from"../../css/Properties.js";class a extends e{constructor(t){super(),this.a11yNormalize=t.a11yNormalize??null,this.bodyHyphens=t.bodyHyphens??null,this.fontFamily=t.fontFamily??null,this.fontWeight=t.fontWeight??null,this.iOSPatch=t.iOSPatch??null,this.iPadOSPatch=t.iPadOSPatch??null,this.letterSpacing=t.letterSpacing??null,this.ligatures=t.ligatures??null,this.lineHeight=t.lineHeight??null,this.noRuby=t.noRuby??null,this.paraIndent=t.paraIndent??null,this.paraSpacing=t.paraSpacing??null,this.textAlign=t.textAlign??null,this.wordSpacing=t.wordSpacing??null,this.zoom=t.zoom??null}toCSSProperties(){const t={};return this.a11yNormalize&&(t["--USER__a11yNormalize"]=this.toFlag("a11y")),this.bodyHyphens&&(t["--USER__bodyHyphens"]=this.bodyHyphens),this.fontFamily&&(t["--USER__fontFamily"]=this.fontFamily),this.fontWeight!=null&&(t["--USER__fontWeight"]=this.toUnitless(this.fontWeight)),this.iOSPatch&&(t["--USER__iOSPatch"]=this.toFlag("iOSPatch")),this.iPadOSPatch&&(t["--USER__iPadOSPatch"]=this.toFlag("iPadOSPatch")),this.letterSpacing!=null&&(t["--USER__letterSpacing"]=this.toRem(this.letterSpacing)),this.ligatures&&(t["--USER__ligatures"]=this.ligatures),this.lineHeight!=null&&(t["--USER__lineHeight"]=this.toUnitless(this.lineHeight)),this.noRuby&&(t["--USER__noRuby"]=this.toFlag("noRuby")),this.paraIndent!=null&&(t["--USER__paraIndent"]=this.toRem(this.paraIndent)),this.paraSpacing!=null&&(t["--USER__paraSpacing"]=this.toRem(this.paraSpacing)),this.textAlign&&(t["--USER__textAlign"]=this.textAlign),this.wordSpacing!=null&&(t["--USER__wordSpacing"]=this.toRem(this.wordSpacing)),this.zoom!==null&&(t["--USER__zoom"]=this.toPercentage(this.zoom,!0)),t}}class o extends e{constructor(t){super(),this.experiments=t.experiments??null}toCSSProperties(){const t={};return this.experiments&&this.experiments.forEach(i=>{t["--RS__"+i]=l[i].value}),t}}export{o as WebRSProperties,a as WebUserProperties};
@@ -0,0 +1 @@
1
+ import{WebUserProperties as o}from"./Properties.js";class i{constructor(e){this.rsProperties=e.rsProperties,this.userProperties=e.userProperties}update(e){e.experiments&&(this.rsProperties.experiments=e.experiments);const r={a11yNormalize:e.textNormalization,bodyHyphens:typeof e.hyphens!="boolean"?null:e.hyphens?"auto":"none",fontFamily:e.fontFamily,fontWeight:e.fontWeight,iOSPatch:e.iOSPatch,iPadOSPatch:e.iPadOSPatch,letterSpacing:e.letterSpacing,ligatures:typeof e.ligatures!="boolean"?null:e.ligatures?"common-ligatures":"none",lineHeight:e.lineHeight,noRuby:e.noRuby,paraIndent:e.paragraphIndent,paraSpacing:e.paragraphSpacing,textAlign:e.textAlign,wordSpacing:e.wordSpacing,zoom:e.zoom};this.userProperties=new o(r)}}export{i as WebPubCSS};
@@ -0,0 +1 @@
1
+ import{fontWeightRangeConfig as r,zoomRangeConfig as o,TextAlignment as h}from"../../preferences/Types.js";import{ensureString as l,ensureValueInRange as a,ensureBoolean as t,ensureNonNegative as n,ensureEnumValue as g,ensureExperiment as s}from"../../preferences/guards.js";import{sMLWithRequest as e}from"../../helpers/dist/sML.js";class c{constructor(i){this.fontFamily=l(i.fontFamily)||null,this.fontWeight=a(i.fontWeight,r.range)||null,this.hyphens=t(i.hyphens)??null,this.iOSPatch=i.iOSPatch===!1?!1:(e.OS.iOS||e.OS.iPadOS)&&e.iOSRequest==="mobile",this.iPadOSPatch=i.iPadOSPatch===!1?!1:e.OS.iPadOS&&e.iOSRequest==="desktop",this.letterSpacing=n(i.letterSpacing)||null,this.ligatures=t(i.ligatures)??null,this.lineHeight=n(i.lineHeight)||null,this.noRuby=t(i.noRuby)??!1,this.paragraphIndent=n(i.paragraphIndent)??null,this.paragraphSpacing=n(i.paragraphSpacing)??null,this.textAlign=g(i.textAlign,h)||null,this.textNormalization=t(i.textNormalization)??!1,this.wordSpacing=n(i.wordSpacing)||null,this.zoom=a(i.zoom,o.range)||1,this.experiments=s(i.experiments)??null}}export{c as WebPubDefaults};
@@ -0,0 +1 @@
1
+ import{fontWeightRangeConfig as s,zoomRangeConfig as r,TextAlignment as l}from"../../preferences/Types.js";import{ensureString as e,ensureValueInRange as h,ensureBoolean as a,ensureNonNegative as n,ensureEnumValue as u}from"../../preferences/guards.js";class g{constructor(t={}){this.fontFamily=e(t.fontFamily),this.fontWeight=h(t.fontWeight,s.range),this.hyphens=a(t.hyphens),this.iOSPatch=a(t.iOSPatch),this.iPadOSPatch=a(t.iPadOSPatch),this.letterSpacing=n(t.letterSpacing),this.ligatures=a(t.ligatures),this.lineHeight=n(t.lineHeight),this.noRuby=a(t.noRuby),this.paragraphIndent=n(t.paragraphIndent),this.paragraphSpacing=n(t.paragraphSpacing),this.textAlign=u(t.textAlign,l),this.textNormalization=a(t.textNormalization),this.wordSpacing=n(t.wordSpacing),this.zoom=h(t.zoom,r.range)}static serialize(t){const{...i}=t;return JSON.stringify(i)}static deserialize(t){try{const i=JSON.parse(t);return new g(i)}catch(i){return console.error("Failed to deserialize preferences:",i),null}}merging(t){const i={...this};for(const o of Object.keys(t))t[o]!==void 0&&(i[o]=t[o]);return new g(i)}}export{g as WebPubPreferences};
@@ -0,0 +1 @@
1
+ import{Feature as c}from"@readium/shared";import{WebPubPreferences as o}from"./WebPubPreferences.js";import{Preference as d,RangePreference as t,BooleanPreference as i,EnumPreference as m}from"../../preferences/Preference.js";import{fontWeightRangeConfig as a,letterSpacingRangeConfig as s,lineHeightRangeConfig as r,paragraphIndentRangeConfig as l,paragraphSpacingRangeConfig as f,TextAlignment as p,wordSpacingRangeConfig as g,zoomRangeConfig as h}from"../../preferences/Types.js";class b{constructor(e,n,u){this.preferences=e,this.settings=n,this.metadata=u}clear(){this.preferences=new o({})}updatePreference(e,n){this.preferences[e]=n}get isDisplayTransformable(){return this.metadata?.accessibility?.feature?.some(e=>e.value===c.DISPLAY_TRANSFORMABILITY.value)??!1}get fontFamily(){return new d({initialValue:this.preferences.fontFamily,effectiveValue:this.settings.fontFamily||null,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("fontFamily",e??null)}})}get fontWeight(){return new t({initialValue:this.preferences.fontWeight,effectiveValue:this.settings.fontWeight||400,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("fontWeight",e??null)},supportedRange:a.range,step:a.step})}get hyphens(){return new i({initialValue:this.preferences.hyphens,effectiveValue:this.settings.hyphens||!1,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("hyphens",e??null)}})}get iOSPatch(){return new i({initialValue:this.preferences.iOSPatch,effectiveValue:this.settings.iOSPatch||!1,isEffective:!0,onChange:e=>{this.updatePreference("iOSPatch",e??null)}})}get iPadOSPatch(){return new i({initialValue:this.preferences.iPadOSPatch,effectiveValue:this.settings.iPadOSPatch||!1,isEffective:!0,onChange:e=>{this.updatePreference("iPadOSPatch",e??null)}})}get letterSpacing(){return new t({initialValue:this.preferences.letterSpacing,effectiveValue:this.settings.letterSpacing||0,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("letterSpacing",e??null)},supportedRange:s.range,step:s.step})}get ligatures(){return new i({initialValue:this.preferences.ligatures,effectiveValue:this.settings.ligatures||!0,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("ligatures",e??null)}})}get lineHeight(){return new t({initialValue:this.preferences.lineHeight,effectiveValue:this.settings.lineHeight,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("lineHeight",e??null)},supportedRange:r.range,step:r.step})}get noRuby(){return new i({initialValue:this.preferences.noRuby,effectiveValue:this.settings.noRuby||!1,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("noRuby",e??null)}})}get paragraphIndent(){return new t({initialValue:this.preferences.paragraphIndent,effectiveValue:this.settings.paragraphIndent||0,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("paragraphIndent",e??null)},supportedRange:l.range,step:l.step})}get paragraphSpacing(){return new t({initialValue:this.preferences.paragraphSpacing,effectiveValue:this.settings.paragraphSpacing||0,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("paragraphSpacing",e??null)},supportedRange:f.range,step:f.step})}get textAlign(){return new m({initialValue:this.preferences.textAlign,effectiveValue:this.settings.textAlign||p.start,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("textAlign",e??null)},supportedValues:Object.values(p)})}get textNormalization(){return new i({initialValue:this.preferences.textNormalization,effectiveValue:this.settings.textNormalization||!1,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("textNormalization",e??null)}})}get wordSpacing(){return new t({initialValue:this.preferences.wordSpacing,effectiveValue:this.settings.wordSpacing||0,isEffective:this.isDisplayTransformable,onChange:e=>{this.updatePreference("wordSpacing",e??null)},supportedRange:g.range,step:g.step})}get zoom(){return new t({initialValue:this.preferences.zoom,effectiveValue:this.settings.zoom||1,isEffective:CSS.supports("zoom","1")??!1,onChange:e=>{this.updatePreference("zoom",e??null)},supportedRange:h.range,step:h.step})}}export{b as WebPubPreferencesEditor};
@@ -0,0 +1 @@
1
+ import{sMLWithRequest as a}from"../../helpers/dist/sML.js";class o{constructor(i,t,h){this.fontFamily=null,this.fontWeight=null,this.hyphens=null,this.iOSPatch=null,this.iPadOSPatch=null,this.letterSpacing=null,this.ligatures=null,this.lineHeight=null,this.noRuby=null,this.paragraphIndent=null,this.paragraphSpacing=null,this.textAlign=null,this.textNormalization=null,this.wordSpacing=null,h&&(this.fontFamily=i.fontFamily||t.fontFamily||null,this.fontWeight=i.fontWeight!==void 0?i.fontWeight:t.fontWeight!==void 0?t.fontWeight:null,this.hyphens=typeof i.hyphens=="boolean"?i.hyphens:t.hyphens??null,this.iOSPatch=i.iOSPatch===!1?!1:i.iOSPatch===!0?(a.OS.iOS||a.OS.iPadOS)&&a.iOSRequest==="mobile":t.iOSPatch,this.iPadOSPatch=i.iPadOSPatch===!1?!1:i.iPadOSPatch===!0?a.OS.iPadOS&&a.iOSRequest==="desktop":t.iPadOSPatch,this.letterSpacing=i.letterSpacing!==void 0?i.letterSpacing:t.letterSpacing!==void 0?t.letterSpacing:null,this.ligatures=typeof i.ligatures=="boolean"?i.ligatures:t.ligatures??null,this.lineHeight=i.lineHeight!==void 0?i.lineHeight:t.lineHeight!==void 0?t.lineHeight:null,this.noRuby=typeof i.noRuby=="boolean"?i.noRuby:t.noRuby??null,this.paragraphIndent=i.paragraphIndent!==void 0?i.paragraphIndent:t.paragraphIndent!==void 0?t.paragraphIndent:null,this.paragraphSpacing=i.paragraphSpacing!==void 0?i.paragraphSpacing:t.paragraphSpacing!==void 0?t.paragraphSpacing:null,this.textAlign=i.textAlign||t.textAlign||null,this.textNormalization=typeof i.textNormalization=="boolean"?i.textNormalization:t.textNormalization??null,this.wordSpacing=i.wordSpacing!==void 0?i.wordSpacing:t.wordSpacing!==void 0?t.wordSpacing:null),this.zoom=i.zoom!==void 0?i.zoom:t.zoom!==void 0?t.zoom:null,this.experiments=t.experiments||null}}export{o as WebPubSettings};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/navigator",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "type": "module",
5
5
  "description": "Next generation SDK for publications in Web Apps",
6
6
  "author": "readium",
@@ -26,16 +26,15 @@
26
26
  "reader",
27
27
  "viewer"
28
28
  ],
29
- "main": "./dist/index.umd.cjs",
30
- "module": "./dist/index.js",
31
29
  "types": "./types/src/index.d.ts",
32
30
  "exports": {
33
31
  ".": {
32
+ "ts-toolkit-source": "./src/index.ts",
34
33
  "types": "./types/src/index.d.ts",
35
- "import": "./dist/index.js",
36
- "require": "./dist/index.umd.cjs"
34
+ "import": "./dist/index.js"
37
35
  }
38
36
  },
37
+ "sideEffects": false,
39
38
  "files": [
40
39
  "dist",
41
40
  "src",
@@ -49,17 +48,20 @@
49
48
  "build": "pnpm clean && node scripts/generate-css-selector.js && tsc && vite build",
50
49
  "generate:css-selector": "node scripts/generate-css-selector.js"
51
50
  },
51
+ "dependencies": {
52
+ "@readium/decorator": "workspace:*",
53
+ "@readium/helpers": "workspace:*",
54
+ "@readium/navigator-html-injectables": "workspace:*",
55
+ "@readium/shared": "workspace:*"
56
+ },
52
57
  "devDependencies": {
53
58
  "@readium/css": "^2.0.5",
54
- "@readium/navigator-html-injectables": "workspace:*",
55
- "@readium/shared": "workspace:*",
56
59
  "@types/path-browserify": "^1.0.3",
57
60
  "css-selector-generator": "^3.8.0",
58
61
  "path-browserify": "^1.0.1",
59
- "rimraf": "^6.1.2",
62
+ "rimraf": "^6.1.3",
60
63
  "tslib": "^2.8.1",
61
64
  "typescript": "^5.9.3",
62
- "typescript-plugin-css-modules": "^5.2.0",
63
65
  "vite": "^7.3.1"
64
66
  }
65
67
  }
package/src/Navigator.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Link, Locator, Publication, ReadingProgression } from "@readium/shared";
1
+ import { Link, Locator, Publication, ReadingProgression, Timeline } from "@readium/shared";
2
2
  import {
3
3
  ContentProtectionConfig,
4
4
  PrintProtectionConfig,
@@ -24,6 +24,7 @@ export type IKeyboardPeripheralsConfig = Array<Omit<KeyboardPeripheral, 'type'>
24
24
  export interface ProgressionRange {
25
25
  start: number;
26
26
  end: number;
27
+ fragmentId?: string; // DOM element ID of the currently active timeline anchor
27
28
  }
28
29
 
29
30
  export interface VisualNavigatorViewport {
@@ -42,6 +43,8 @@ export abstract class Navigator {
42
43
  abstract get publication(): Publication; // Publication rendered by this navigator.
43
44
  abstract get currentLocator(): Locator; // Current position (detailed) in the publication. Can be used to save a bookmark to the current position.
44
45
 
46
+ abstract get timeline(): Timeline;
47
+
45
48
  /**
46
49
  * Moves to the position in the publication corresponding to the given {Locator}.
47
50
  */
@@ -1,4 +1,4 @@
1
- import { Link, Locator, LocatorLocations, Publication, Timeline, TimelineItem } from "@readium/shared";
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
4
  import { WebAudioEngine, PlaybackState } from "./engine/index.ts";
@@ -135,7 +135,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
135
135
  if (trackIndex === -1) {
136
136
  throw new Error(`AudioNavigator: initial href "${ initialHref }" not found in reading order`);
137
137
  }
138
- const initialTime = this.currentLocation.locations?.time() || 0;
138
+ const initialTime = locatorTime(this.currentLocation.locations) || 0;
139
139
 
140
140
  const audioEngine = new WebAudioEngine({
141
141
  playback: {
@@ -529,7 +529,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
529
529
  locator = this.ensureLocatorLocations(locator);
530
530
  const href = locator.href.split("#")[0];
531
531
  const trackIndex = this.hrefToTrackIndex(href);
532
- const time = locator.locations?.time() || 0;
532
+ const startTime = locatorTime(locator.locations) || 0;
533
533
 
534
534
  if (trackIndex === -1) {
535
535
  cb(false);
@@ -547,7 +547,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
547
547
  this.pool.setCurrentAudio(trackIndex, direction);
548
548
  this.currentLocation = locator.copyWithLocations(locator.locations);
549
549
 
550
- await this.waitForLoadedAndSeeked(time, id);
550
+ await this.waitForLoadedAndSeeked(startTime, id);
551
551
  this._isNavigating = false;
552
552
 
553
553
  if (id !== this.navigationId) {
@@ -583,8 +583,8 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
583
583
  cb(false);
584
584
  return;
585
585
  }
586
- const time = link.locator.locations?.time() ?? 0;
587
- const locator = this.createLocator(trackIndex, time);
586
+ const startTime = locatorTime(link.locator.locations) ?? 0;
587
+ const locator = this.createLocator(trackIndex, startTime);
588
588
  await this.go(locator, _animated, cb);
589
589
  }
590
590
 
@@ -642,7 +642,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
642
642
 
643
643
  get isTrackStart(): boolean {
644
644
  return this.currentTrackIndex() === 0
645
- && (this.currentLocation.locations?.time() || 0) === 0;
645
+ && (locatorTime(this.currentLocation.locations) || 0) === 0;
646
646
  }
647
647
 
648
648
  get isTrackEnd(): boolean {
@@ -652,7 +652,7 @@ export class AudioNavigator extends MediaNavigator implements Configurable<Audio
652
652
  if (progression !== undefined) return progression >= 1;
653
653
  const link = this.pub.readingOrder.items[trackIndex];
654
654
  const duration = this.duration || link?.duration || 0;
655
- return duration > 0 && (this.currentLocation.locations?.time() ?? 0) >= duration;
655
+ return duration > 0 && (locatorTime(this.currentLocation.locations) ?? 0) >= duration;
656
656
  }
657
657
 
658
658
  get canGoBackward(): boolean {
@@ -1,128 +1,27 @@
1
- import type {
2
- Decoration as InjectableDecoration,
1
+ import type { Decoration, DecorationObserver } from "@readium/decorator";
2
+ import { DecorationStyleType } from "@readium/decorator";
3
+
4
+ export type {
5
+ Decoration,
6
+ DecorationStyle,
7
+ HTMLDecorationTemplate,
8
+ NamedDecorationStyle,
3
9
  BuiltinDecorationStyle,
4
- HTMLDecorationTemplate as WireHTMLDecorationTemplate,
5
- } from "@readium/navigator-html-injectables";
6
- import { DecorationStyleType } from "@readium/navigator-html-injectables";
7
-
8
- export type { BuiltinDecorationStyle };
9
- export { DecorationLayout, DecorationStyleType, DecorationWidth } from "@readium/navigator-html-injectables";
10
-
11
- /**
12
- * Navigator-level decoration template. `element` is a function called once per decoration to
13
- * generate the HTML string that the injectable will render. The result is resolved on the
14
- * navigator side (before postMessage) and sanitized by the injectable.
15
- */
16
- export interface HTMLDecorationTemplate extends Omit<WireHTMLDecorationTemplate, 'element'> {
17
- element: (decoration: Decoration) => string;
18
- }
19
-
20
- export type DecorationStyle = BuiltinDecorationStyle | HTMLDecorationTemplate;
21
-
22
- export interface Decoration extends Omit<InjectableDecoration, 'style'> {
23
- style: DecorationStyle;
24
- }
25
-
26
- /**
27
- * Resolves a navigator-level Decoration to a wire-safe plain object for postMessage.
28
- * For Template styles, calls `element(decoration)` and embeds the resulting HTML string.
29
- * For registered custom style IDs (found in `decorationTemplates`), resolves the template
30
- * and converts the style to a Template wire object.
31
- */
32
- export function resolveDecorationForWire(
33
- decoration: Decoration,
34
- decorationTemplates?: Record<string, HTMLDecorationTemplate>
35
- ): unknown {
36
- const { style } = decoration;
37
- if (style.type === DecorationStyleType.Template) {
38
- const tpl = style as HTMLDecorationTemplate;
39
- return { ...decoration, style: { ...tpl, element: tpl.element(decoration) } };
40
- }
41
- if (style.type && decorationTemplates?.[style.type]) {
42
- const tpl = decorationTemplates[style.type];
43
- return {
44
- ...decoration,
45
- style: {
46
- type: DecorationStyleType.Template,
47
- layout: tpl.layout,
48
- width: tpl.width,
49
- stylesheet: tpl.stylesheet,
50
- isActive: style.isActive,
51
- element: tpl.element(decoration),
52
- },
53
- };
54
- }
55
- return decoration;
56
- }
57
-
58
- export interface DecorationActivationEvent {
59
- decoration: Decoration;
60
- group: string;
61
- /** Bounding rect of the activated decoration in navigator container coordinates (CSS pixels). */
62
- rect?: { top: number; left: number; width: number; height: number };
63
- /** Tap/click point in navigator container coordinates (CSS pixels). */
64
- point?: { x: number; y: number };
65
- }
66
-
67
- export interface DecorationObserver {
68
- /**
69
- * Called when a user activates a decoration (click or tap).
70
- * Return true to indicate the event was handled — this suppresses normal tap/click navigation.
71
- */
72
- onDecorationActivated(event: DecorationActivationEvent): boolean;
73
- }
74
-
75
- function stylesEqual(a: DecorationStyle, b: DecorationStyle): boolean {
76
- if (a.type !== b.type) return false;
77
- if ((a.isActive ?? false) !== (b.isActive ?? false)) return false;
78
- if (a.type === DecorationStyleType.Template) {
79
- const ta = a as HTMLDecorationTemplate;
80
- const tb = b as HTMLDecorationTemplate;
81
- // element is a function — not comparable by value; excluded from equality
82
- return ta.layout === tb.layout &&
83
- ta.width === tb.width &&
84
- ta.stylesheet === tb.stylesheet;
85
- }
86
- const ba = a as BuiltinDecorationStyle;
87
- const bb = b as BuiltinDecorationStyle;
88
- return ba.tint === bb.tint &&
89
- ba.layout === bb.layout &&
90
- ba.width === bb.width &&
91
- (ba.enforceContrast ?? true) === (bb.enforceContrast ?? true);
92
- }
93
-
94
- function serializeLocations(loc: any): any {
95
- return typeof loc?.serialize === 'function' ? loc.serialize() : loc;
96
- }
97
-
98
- export function decorationsEqual(a: Decoration, b: Decoration): boolean {
99
- return (
100
- a.locator.href === b.locator.href &&
101
- JSON.stringify(serializeLocations(a.locator.locations)) === JSON.stringify(serializeLocations(b.locator.locations)) &&
102
- stylesEqual(a.style, b.style) &&
103
- JSON.stringify(a.extras ?? null) === JSON.stringify(b.extras ?? null)
104
- );
105
- }
106
-
107
- /** Configuration for decoration rendering. */
108
- export interface DecoratorConfig {
109
- /**
110
- * Named custom styles. Each key is a style type ID; the value is the template that
111
- * generates the HTML for decorations of that type. When a decoration's `style.type`
112
- * matches a key here, the navigator resolves the template and sends it to the
113
- * injectable as a Template-type decoration.
114
- */
115
- decorationTemplates?: Record<string, HTMLDecorationTemplate>;
116
- }
117
-
118
- const BUILTIN_DECORATION_TYPES = new Set<string>([
119
- DecorationStyleType.Highlight,
120
- DecorationStyleType.Underline,
121
- DecorationStyleType.Outline,
122
- DecorationStyleType.TextColor,
123
- DecorationStyleType.Mask,
124
- DecorationStyleType.Template,
125
- ]);
10
+ DecoratorConfig,
11
+ OnDecorationActivatedEvent,
12
+ OnDecorationPointerEnterEvent,
13
+ OnDecorationPointerLeaveEvent,
14
+ DecorationObserver,
15
+ } from "@readium/decorator";
16
+ export {
17
+ DecorationStyleType,
18
+ DecorationLayout,
19
+ DecorationWidth,
20
+ BUILTIN_DECORATION_TYPES,
21
+ resolveDecorationForWire,
22
+ decorationsEqual,
23
+ supportsDecorationStyle,
24
+ } from "@readium/decorator";
126
25
 
127
26
  export interface DecorableNavigator {
128
27
  /**
@@ -136,7 +35,7 @@ export interface DecorableNavigator {
136
35
  * Returns whether the given style type ID can be rendered by this navigator.
137
36
  * Returns true for all built-in types and any IDs registered in DecoratorConfig.
138
37
  */
139
- supportsDecorationStyle(styleTypeId: string): boolean;
38
+ supportsDecorationStyle(styleTypeId: DecorationStyleType | string): boolean;
140
39
 
141
40
  /** Registers an observer for activation events on the given group. */
142
41
  registerDecorationObserver(group: string, observer: DecorationObserver): void;
@@ -144,5 +43,3 @@ export interface DecorableNavigator {
144
43
  /** Unregisters a previously registered observer from all groups. */
145
44
  unregisterDecorationObserver(observer: DecorationObserver): void;
146
45
  }
147
-
148
- export { BUILTIN_DECORATION_TYPES };