@readium/navigator 2.9.1 → 2.10.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.
- package/dist/epub/EpubNavigator.js +1 -1
- package/dist/epub/frame/FrameManager.js +1 -1
- package/dist/epub/frame/FramePoolManager.js +1 -1
- package/dist/epub/fxl/FXLFrameManager.js +1 -1
- package/dist/epub/fxl/FXLFramePoolManager.js +1 -1
- package/dist/webpub/WebPubFrameManager.js +1 -1
- package/dist/webpub/WebPubFramePoolManager.js +1 -1
- package/dist/webpub/WebPubNavigator.js +1 -1
- package/package.json +5 -5
- package/src/decorations/index.ts +10 -0
- package/src/epub/EpubNavigator.ts +22 -2
- package/src/epub/frame/FrameManager.ts +31 -1
- package/src/epub/frame/FramePoolManager.ts +18 -2
- package/src/epub/fxl/FXLFrameManager.ts +31 -1
- package/src/epub/fxl/FXLFramePoolManager.ts +14 -1
- package/src/webpub/WebPubFrameManager.ts +31 -1
- package/src/webpub/WebPubFramePoolManager.ts +18 -2
- package/src/webpub/WebPubNavigator.ts +20 -1
- package/types/src/decorations/index.d.ts +8 -0
- package/types/src/epub/EpubNavigator.d.ts +3 -0
- package/types/src/epub/frame/FrameManager.d.ts +5 -1
- package/types/src/epub/frame/FramePoolManager.d.ts +4 -1
- package/types/src/epub/fxl/FXLFrameManager.d.ts +5 -1
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +4 -1
- package/types/src/webpub/WebPubFrameManager.d.ts +5 -1
- package/types/src/webpub/WebPubFramePoolManager.d.ts +4 -1
- package/types/src/webpub/WebPubNavigator.d.ts +3 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Layout as d,Profile as E,Link as _,ReadingProgression as g,Locator as v,LocatorText as D,getCssSelector as O,getHtmlId as I}from"@readium/shared";import{VisualNavigator as F}from"../Navigator.js";import{FramePoolManager as A}from"./frame/FramePoolManager.js";import{FXLFramePoolManager as M}from"./fxl/FXLFramePoolManager.js";import{ModuleLibrary as T,FXLModules as H,ReflowableModules as R}from"@readium/navigator-html-injectables";import{p as y}from"../_virtual/index.js";import{FrameManager as V}from"./frame/FrameManager.js";import{EpubPreferences as N}from"./preferences/EpubPreferences.js";import{EpubDefaults as W}from"./preferences/EpubDefaults.js";import{EpubPreferencesEditor as b}from"./preferences/EpubPreferencesEditor.js";import{ReadiumCSS as j}from"./css/ReadiumCSS.js";import{UserProperties as z,RSProperties as B}from"./css/Properties.js";import{getContentWidth as K}from"../helpers/dimensions.js";import{Injector as $}from"../injection/Injector.js";import{createReadiumEpubRules as G}from"../injection/epubInjectables.js";import{NavigatorProtector as X,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as x}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as J,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as C}from"../peripherals/KeyboardPeripherals.js";import{getScriptMode as w}from"../helpers/scriptMode.js";import{EpubSettings as S}from"./preferences/EpubSettings.js";import{LineLengths as U}from"../helpers/lineLength.js";import{supportsDecorationStyle as q,decorationsEqual as Y,resolveDecorationForWire as P}from"@readium/decorator";const Q=p=>({frameLoaded:p.frameLoaded||(()=>{}),positionChanged:p.positionChanged||(()=>{}),timelineItemChanged:p.timelineItemChanged||(()=>{}),tap:p.tap||(()=>!1),click:p.click||(()=>!1),zoom:p.zoom||(()=>{}),miscPointer:p.miscPointer||(()=>{}),scroll:p.scroll||(()=>{}),customEvent:p.customEvent||(()=>{}),handleLocator:p.handleLocator||(()=>!1),textSelected:p.textSelected||(()=>{}),contentProtection:p.contentProtection||(()=>{}),contextMenu:p.contextMenu||(()=>{}),peripheral:p.peripheral||(()=>{})});function Z(p,e){return p.length===e.length&&p.every((t,i)=>t===e[i])}class k extends F{constructor(e,t,i,s=[],r=void 0,o={preferences:{},defaults:{}}){super(),this._visibleFragmentIds=[],this._notifiedVisibleFragmentIds=[],this._timelineAugmented=!1,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.reflowViewport={readingOrder:[],progressions:new Map,positions:null},this.pub=t,this.container=e,this.listeners=Q(i),this.currentLocation=r,s.length&&(this.positions=s),this._preferences=new N(o.preferences),this._defaults=new W(o.defaults),this._settings=new S(this._preferences,this._defaults);const h=w(t.metadata),f=h==="cjk-horizontal",a=h==="cjk-vertical",c=a||h==="mongolian-vertical",l=f||a;this._css=new j({rsProperties:new B({noVerticalPagination:c||void 0}),userProperties:new z({}),lineLengths:new U({optimalChars:this._settings.optimalLineLength,minChars:this._settings.minimalLineLength,maxChars:this._settings.maximalLineLength,padding:this._settings.scroll?(this._settings.scrollPaddingLeft||0)+(this._settings.scrollPaddingRight||0):(this._settings.pageGutter||0)*2,fontFace:this._settings.fontFamily,letterSpacing:this._settings.letterSpacing,wordSpacing:this._settings.wordSpacing,isCJK:l}),container:e,constraint:this._settings.constraint,isCJKVertical:c}),this._layout=k.determineLayout(t,!!this._settings.scroll),this.currentProgression=t.metadata.effectiveReadingProgression,this._injectablesConfig=o.injectables||{rules:[],allowedDomains:[]},this._readiumRulesPromise=G(t.metadata,t.readingOrder.items),this._contentProtection=o.contentProtection||{},this._decoratorConfig=o.decoratorConfig||{},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 X(this._contentProtection),this._suspiciousActivityListener=u=>{const{type:m,...L}=u.detail;m==="context_menu"?this.listeners.contextMenu(L):this.listeners.contentProtection(m,L)},window.addEventListener(x,this._suspiciousActivityListener)),this._keyboardPeripherals.length>0&&(this._keyboardPeripheralsManager=new J({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=u=>{const m=u.detail;this.listeners.peripheral(m)},window.addEventListener(C,this._keyboardPeripheralListener)),this.resizeObserver=new ResizeObserver(()=>this.ownerWindow.requestAnimationFrame(async()=>await this.resizeHandler())),this.resizeObserver.observe(this.container.parentElement||document.documentElement)}static determineLayout(e,t){const i=e.metadata.effectiveLayout;if(i===d.fixed)return d.fixed;if(e.metadata.otherMetadata&&"http://openmangaformat.org/schema/1.0#version"in e.metadata.otherMetadata)return d.fixed;if(e.metadata?.conformsTo?.includes(E.DIVINA))return d.fixed;if(i===d.scrolled)return d.scrolled;const s=w(e.metadata);return s==="cjk-vertical"||s==="mongolian-vertical"?d.scrolled:i===d.reflowable&&t?d.scrolled:d.reflowable}async load(){if(this.positions?.length||(this.positions=await this.pub.positionsFromManifest()),!this._injector){const e=await this._readiumRulesPromise;this._injector=new $({rules:[...e,...this._injectablesConfig.rules],allowedDomains:this._injectablesConfig.allowedDomains})}if(this._layout===d.fixed)this.framePool=new M(this.container,this.positions,this.pub,this._injector,this._contentProtection,this._keyboardPeripherals),this.framePool.listener=(e,t)=>{this.eventListener(e,t)};else{await this.updateCSS(!1);const e=this.compileCSSProperties(this._css);this.framePool=new A(this.container,this.positions,e,this._injector,this._contentProtection,this._keyboardPeripherals,t=>this.pub.timeline.segmentsForHref(t).flatMap(i=>i.references).map(i=>{const s=i.indexOf("#");return s>=0?i.slice(s+1):""}).filter(Boolean))}this.currentLocation===void 0&&(this.currentLocation=this.positions[0]),await this.resizeHandler(),await this.apply()}get settings(){if(this._layout===d.fixed)return Object.freeze({...this._settings});{const e=this._css.userProperties.colCount||this._css.rsProperties.colCount||this._settings.columnCount;return Object.freeze({...this._settings,columnCount:e})}}get preferencesEditor(){return this._preferencesEditor===null&&(this._preferencesEditor=new b(this._preferences,this.settings,this.pub.metadata)),this._preferencesEditor}async submitPreferences(e){this._preferences=this._preferences.merging(e),await this.applyPreferences()}async applyPreferences(){const e=this._settings;this._settings=new S(this._preferences,this._defaults),this._preferencesEditor!==null&&(this._preferencesEditor=new b(this._preferences,this.settings,this.pub.metadata)),this._layout===d.fixed?this.handleFXLPrefs(e,this._settings):await this.updateCSS(!0)}handleFXLPrefs(e,t){e.columnCount!==t.columnCount&&this.framePool.setPerPage(t.columnCount)}async updateCSS(e){this._css.update(this._settings),e&&await this.commitCSS(this._css)}compileCSSProperties(e){const t={};for(const[i,s]of Object.entries(e.rsProperties.toCSSProperties()))t[i]=s;for(const[i,s]of Object.entries(e.userProperties.toCSSProperties()))t[i]=s;return t}async commitCSS(e){if(!this.framePool)return;const t=this.compileCSSProperties(e);this.framePool.setCSSProperties(t),this._css.userProperties.view==="paged"&&this._layout===d.scrolled?await this.setLayout(d.reflowable):this._css.userProperties.view==="scroll"&&this._layout===d.reflowable&&await this.setLayout(d.scrolled),this._css.setContainerWidth()}async resizeHandler(){const e=this.container.parentElement||document.documentElement;if(this._layout===d.fixed){if(this.container.style.width=`${K(e)-this._settings.constraint}px`,!this.framePool)return;this.framePool.resizeHandler()}else{const t=this._css.userProperties.colCount,i=this._css.userProperties.lineLength;this._css.resizeHandler(),(this._css.userProperties.view!=="scroll"&&t!==this._css.userProperties.colCount||i!==this._css.userProperties.lineLength)&&await this.commitCSS(this._css)}}get layout(){return this._layout}get ownerWindow(){return this.container.ownerDocument.defaultView||window}get _cframes(){return(this.framePool?.currentFrames??[]).filter(e=>!(e instanceof V&&e.isDestroyed))}get pool(){return this.framePool}eventListener(e,t,i){switch(e){case"_pong":if(this.listeners.frameLoaded(this._cframes[0].iframe.contentWindow),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),i){const n=this._cframes.filter(l=>!!l).indexOf(i),c=n>=0?this.viewport.readingOrder[n]:void 0;c&&this._reapplyDecorationsToFrame(i,c)}else this._reapplyDecorationsToCurrentFrames();break;case"first_visible_locator":const s=v.deserialize(t);if(!s)break;this.currentLocation=new v({href:this.currentLocation.href,type:this.currentLocation.type,title:this.currentLocation.title,locations:s?.locations,text:s?.text}),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation);break;case"text_selected":{const a=t;if(i){const c=this._cframes.filter(u=>!!u).indexOf(i),l=c>=0?this.viewport.readingOrder[c]:void 0;if(l){const u=this.pub.readingOrder.findWithHref(l);a.locator=new v({href:l,type:u.type||"application/xhtml+xml",text:new D({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("http://")||n.startsWith("https://")||n.startsWith("mailto:")||n.startsWith("tel:"))this.listeners.handleLocator(new _({href:n}).locator);else try{this.goLink(new _({href:y.join(y.dirname(this.currentLocation.href),n)}),!1,()=>{})}catch(c){console.warn(`Couldn't go to link for ${n}: ${c}`),this.listeners.handleLocator(new _({href:n}).locator)}}else console.log("Clicked on",a)}else{if(this._layout===d.fixed&&this.framePool.doNotDisturb&&(r.doNotDisturb=!0),this._layout===d.fixed&&(this.currentProgression===g.rtl||this.currentProgression===g.ltr)&&this.framePool.currentFrames.length>1){const c=this.framePool.currentFrames;r.targetFrameSrc===c[this.currentProgression===g.rtl?0:1]?.source&&(r.x+=(c[this.currentProgression===g.rtl?1:0]?.iframe.contentWindow?.innerWidth??0)*window.devicePixelRatio)}if(e==="click"?this.listeners.click(r):this.listeners.tap(r))break;const n=(this._cframes.length===2?this._cframes[0].window.innerWidth+this._cframes[1].window.innerWidth:this._cframes[0].window.innerWidth)*window.devicePixelRatio/4;r.x>=n&&r.x<=n*3&&this.listeners.miscPointer(1),r.x<n?this.goLeft(!1,()=>{}):r.x>n*3&&this.goRight(!1,()=>{})}break;case"tap_more":this.listeners.miscPointer(t);break;case"no_more":this.changeResource(1);break;case"no_less":this.changeResource(-1);break;case"swipe":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 h=t,f={...h,interactiveElement:void 0};h.interactiveElement&&(f.interactiveElement=new DOMParser().parseFromString(h.interactiveElement,"text/html").body.children[0]),this.listeners.peripheral(f);break;case"log":console.log(this._cframes[0]?.source?.split("/")[3],...t);break;default:this.listeners.customEvent(e,t);break}}determineModules(){let e=Array.from(T.keys());if(this._layout===d.fixed)return e.filter(s=>H.includes(s));e=e.filter(s=>R.includes(s));const t=w(this.pub.metadata);if(t==="cjk-vertical"||t==="mongolian-vertical")return e.filter(s=>s!=="column_snapper"&&s!=="scroll_snapper");const i=e;return this._layout===d.scrolled?e=i.filter(s=>s!=="column_snapper"&&s!=="cjk_vertical_snapper"):e=i.filter(s=>s!=="scroll_snapper"&&s!=="cjk_vertical_snapper"),e}attachListener(){const e=this._cframes.filter(t=>!!t);if(e.length===0)throw Error("no cframe to attach listener to");e.forEach(t=>{t.msg&&(t.msg.listener=(i,s)=>{this.eventListener(i,s,t)})}),this._reapplyDecorationsToCurrentFrames()}async apply(){if(await this.framePool.update(this.pub,this.currentLocator,this.determineModules()),this.attachListener(),this.pub.readingOrder.findIndexWithHref(this.currentLocation.href)<0)throw Error("Link for "+this.currentLocation.href+" not found!")}supportsDecorationStyle(e){return q(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._sendDecorationActivationToFrames(e,!0)),(t.onDecorationPointerEnter||t.onDecorationPointerLeave)&&(this._decorationHoverState.set(e,!0),this._sendDecorationHoverToFrames(e,!0))}unregisterDecorationObserver(e){this._decorationObservers.forEach((t,i)=>{if(!t.has(e))return;t.delete(e);const s=[...t].some(o=>o.onDecorationActivated);this._decorationActivationState.has(i)&&!s&&(this._decorationActivationState.delete(i),this._sendDecorationActivationToFrames(i,!1));const r=[...t].some(o=>o.onDecorationPointerEnter||o.onDecorationPointerLeave);this._decorationHoverState.has(i)&&!r&&(this._decorationHoverState.delete(i),this._sendDecorationHoverToFrames(i,!1))})}_sendDecorationActivationToFrames(e,t){this._cframes.filter(s=>!!s).forEach(s=>{s.msg&&s.msg.send("decoration_activatable",{group:e,activatable:t})})}_sendDecorationHoverToFrames(e,t){this._cframes.filter(s=>!!s).forEach(s=>{s.msg&&s.msg.send("decoration_hoverable",{group:e,hoverable:t})})}applyDecorations(e,t){const i=this._decorations.get(t)??[],s=new Map(i.map(c=>[c.id,c])),r=new Map(e.map(c=>[c.id,c])),o=[],h=[],f=[];for(const[c,l]of s)r.has(c)?Y(l,r.get(c))||f.push(r.get(c)):o.push(c);for(const[c,l]of r)s.has(c)||h.push(l);this._decorations.set(t,e),this._sendDecorationOps(t,o,h,f,i);const a=this._decorationActivationState.get(t);a!==void 0&&this._sendDecorationActivationToFrames(t,a);const n=this._decorationHoverState.get(t);n!==void 0&&this._sendDecorationHoverToFrames(t,n)}_sendDecorationOps(e,t,i,s,r){const o=this._cframes.filter(a=>!!a),h=new Map(r.map(a=>[a.id,a])),f=this.viewport.readingOrder;o.forEach((a,n)=>{if(!a.msg)return;const c=f[n];if(c){for(const l of t){const u=h.get(l);!u||u.locator.href!==c||a.msg.send("decorate",{group:e,action:"remove",decoration:{id:l}})}for(const l of i)l.locator.href===c&&a.msg.send("decorate",{group:e,action:"add",decoration:P(l,this._decoratorConfig.decorationTemplates)});for(const l of s)l.locator.href===c&&a.msg.send("decorate",{group:e,action:"update",decoration:P(l,this._decoratorConfig.decorationTemplates)})}})}_reapplyDecorationsToFrame(e,t){if(e.msg){for(const[i,s]of this._decorations){const r=s.filter(o=>o.locator.href===t);if(r.length!==0){e.msg.send("decorate",{group:i,action:"clear"});for(const o of r)e.msg.send("decorate",{group:i,action:"add",decoration:P(o,this._decoratorConfig.decorationTemplates)})}}for(const[i,s]of this._decorationActivationState)e.msg.send("decoration_activatable",{group:i,activatable:s});for(const[i,s]of this._decorationHoverState)e.msg.send("decoration_hoverable",{group:i,hoverable:s})}}_reapplyDecorationsToCurrentFrames(){const e=this._cframes.filter(i=>!!i),t=this.viewport.readingOrder;e.forEach((i,s)=>{const r=t[s];r&&this._reapplyDecorationsToFrame(i,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(o=>o.id===e.decorationId);if(!i)return!1;const s={decoration:i,group:e.group,rect:e.rect,point:e.point};let r=!1;for(const o of t)o.onDecorationActivated?.(s)&&(r=!0);return r}_handleDecorationPointerEnter(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(r=>r.id===e.decorationId);if(!i)return;this._decorationHoveredDecorations.set(e.group,i);const s={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const r of t)r.onDecorationPointerEnter?.(s)}_handleDecorationPointerLeave(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(r=>r.id===e.decorationId)??this._decorationHoveredDecorations.get(e.group);if(this._decorationHoveredDecorations.delete(e.group),!i)return;const s={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const r of t)r.onDecorationPointerLeave?.(s)}async destroy(){this._suspiciousActivityListener&&window.removeEventListener(x,this._suspiciousActivityListener),this._keyboardPeripheralListener&&window.removeEventListener(C,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()}async changeResource(e){if(e===0)return!1;if(this._layout===d.fixed){const s=this.framePool,r=s.viewport.positions[0];if(e===1){if(!s.next(s.perPage))return!1}else if(e===-1){if(!s.prev(s.perPage))return!1}else throw Error("Invalid relative value for FXL");const o=s.viewport.positions[0];if(r>o){for(let h=this.positions.length-1;h>=0;h--)if(this.positions[h].href===this.pub.readingOrder.items[o-1].href){this.currentLocation=this.positions[h].copyWithLocations({progression:.999999999999});break}}else if(r<o){for(let h=0;h<this.positions.length;h++)if(this.positions[h].href===this.pub.readingOrder.items[o-1].href){this.currentLocation=this.positions[h];break}}return await this.apply(),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),!0}const t=this.pub.readingOrder.findIndexWithHref(this.currentLocation.href),i=Math.max(0,Math.min(this.pub.readingOrder.items.length-1,t+e));if(i===t)return this._cframes[0]?.msg?.send("shake",void 0,async s=>{}),!1;if(t>i){for(let s=this.positions.length-1;s>=0;s--)if(this.positions[s].href===this.pub.readingOrder.items[i].href){this.currentLocation=this.positions[s].copyWithLocations({progression:.999999999999});break}}else for(let s=0;s<this.positions.length;s++)if(this.positions[s].href===this.pub.readingOrder.items[i].href){this.currentLocation=this.positions[s];break}return await this.apply(),!0}findLastPositionInProgressionRange(e,t){const i=e.findLastIndex(s=>{const r=s.locations.progression;return!!(r&&r>t.start&&r<=t.end)});return i!==-1?e[i]:void 0}findNearestPositions(e){const t=this.positions.filter(o=>o.href===this.currentLocation.href);let i=this.currentLocation,s;const r=t.findLastIndex(o=>(o.locations.progression??0)<=e.start);if(r!==-1){i=t[r];const o=t.slice(r+1);s=this.findLastPositionInProgressionRange(o,e)}return{first:i,last:s}}updateViewport(e){this.reflowViewport.readingOrder=[],this.reflowViewport.progressions.clear(),this.reflowViewport.positions=null,this.currentLocation&&(this.reflowViewport.readingOrder.push(this.currentLocation.href),this.reflowViewport.progressions.set(this.currentLocation.href,e),this.currentLocation.locations?.position!==void 0&&(this.reflowViewport.positions=[this.currentLocation.locations.position],this.lastLocationInView?.locations?.position!==void 0&&this.reflowViewport.positions.push(this.lastLocationInView.locations.position)))}async syncLocation(e){const t=e,i=this.findNearestPositions(t);this.currentLocation=i.first.copyWithLocations({progression:t.start}),this.lastLocationInView=i.last,this.updateViewport(t),this.listeners.positionChanged(this.currentLocation);const s=t.fragmentId?this.currentLocation.copyWithLocations({fragments:[`#${t.fragmentId}`]}):this.currentLocation;this._visibleFragmentIds=t.visibleFragmentIds??[],this._notifyTimelineChange(s),await this.framePool.update(this.pub,this.currentLocation,this.determineModules())}goBackward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this._layout===d.fixed?this.changeResource(-1).then(i=>{this._isNavigating=!1,t(i)}):this._cframes[0]?.msg?.send("go_prev",void 0,async i=>{if(i)this._isNavigating=!1,t(!0);else{const s=await this.changeResource(-1);this._isNavigating=!1,t(s)}})}goForward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this._layout===d.fixed?this.changeResource(1).then(i=>{this._isNavigating=!1,t(i)}):this._cframes[0]?.msg?.send("go_next",void 0,async i=>{if(i)this._isNavigating=!1,t(!0);else{const s=await this.changeResource(1);this._isNavigating=!1,t(s)}})}get currentLocator(){return this.currentLocation}get viewport(){return this._layout===d.fixed?this.framePool?this.framePool.viewport:{readingOrder:[],progressions:new Map,positions:null}:this.reflowViewport}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.currentProgression}async setLayout(e){this._layout!==e&&(this._layout=e,await this.framePool.update(this.pub,this.currentLocator,this.determineModules(),!0),this.attachListener())}get publication(){return this.pub}get timeline(){const e=this.pub.timeline;if(!this._timelineAugmented&&this.positions?.length){const t=this.positions,i=new Set;e.augment((s,r)=>{if(s.children?.length)return{};const o=r.href.indexOf("#"),h=o>=0?r.href.slice(0,o):r.href,f=o>=0?r.href.slice(o+1):void 0,a=t.filter(l=>l.href===h);if(!a.length)return{};const n=f?a.find(l=>l.locations.fragments[0]===f):void 0;let c;return n?c=n:i.has(h)?c=void 0:(i.add(h),c=a.reduce((l,u)=>(u.locations.position??1/0)<(l.locations.position??1/0)?u:l)),c?{position:c.locations.position,scroll:n?.locations.progression}:{}}),this._timelineAugmented=!0}return this._wrappedTimeline||(this._wrappedTimeline=new Proxy(e,{get:(t,i)=>{if(i!=="navigableFrom"){const s=Reflect.get(t,i,t);return typeof s=="function"?s.bind(t):s}return s=>{const r=this._visibleFragmentIds;let o=(r.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${r[0]}`]})):void 0)??s;const h=(r.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${r[r.length-1]}`]})):void 0)??s;if(this.isScrollStart){const n=t.ancestors(o).find(c=>c.references.includes(this.currentLocation.href));n&&(o=n)}const f=t.navigableFrom(o).previous,a=t.navigableFrom(h).next;return{previous:f,next:a}}}})),this._wrappedTimeline}async loadLocator(e,t){let i=!1,s=O(e.locations);if(e.text?.highlight?i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_text",s?[e.text?.serialize(),s]:e.text?.serialize(),n=>f(n))}):s&&(i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_text",["",s],n=>f(n))})),i){t(i);return}const r=I(e.locations);if(r&&(i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_id",r,n=>f(n))})),i){t(i);return}const o=e?.locations?.progression;o&&o>0?i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_progression",o,n=>f(n))}):i=!0,t(i)}go(e,t,i){const s=e.href.split("#")[0];let r=this.pub.readingOrder.findWithHref(s);if(!r)return i(this.listeners.handleLocator(e));if(this._isNavigating){i(!1);return}this._isNavigating=!0,this.currentLocation=this.positions.find(o=>o.href===r.href),this.apply().then(()=>this.loadLocator(e,o=>{this._isNavigating=!1,i(o)})).then(()=>{this.attachListener()})}goLink(e,t,i){return this.go(e.locator,t,i)}_notifyTimelineChange(e){const t=this.timeline.locate(e),i=!Z(this._visibleFragmentIds,this._notifiedVisibleFragmentIds);(t!==this._currentTimelineItem||i)&&(this._currentTimelineItem=t,this._notifiedVisibleFragmentIds=this._visibleFragmentIds,this.listeners.timelineItemChanged(t))}}export{k as EpubNavigator};
|
|
1
|
+
import{Layout as d,Profile as E,Link as _,ReadingProgression as g,Locator as v,LocatorText as D,getCssSelector as O,getHtmlId as I}from"@readium/shared";import{VisualNavigator as F}from"../Navigator.js";import{FramePoolManager as T}from"./frame/FramePoolManager.js";import{FXLFramePoolManager as A}from"./fxl/FXLFramePoolManager.js";import{ModuleLibrary as R,FXLModules as M,ReflowableModules as H}from"@readium/navigator-html-injectables";import{p as y}from"../_virtual/index.js";import{FrameManager as z}from"./frame/FrameManager.js";import{EpubPreferences as V}from"./preferences/EpubPreferences.js";import{EpubDefaults as N}from"./preferences/EpubDefaults.js";import{EpubPreferencesEditor as b}from"./preferences/EpubPreferencesEditor.js";import{ReadiumCSS as W}from"./css/ReadiumCSS.js";import{UserProperties as j,RSProperties as B}from"./css/Properties.js";import{getContentWidth as K}from"../helpers/dimensions.js";import{Injector as $}from"../injection/Injector.js";import{createReadiumEpubRules as G}from"../injection/epubInjectables.js";import{NavigatorProtector as X,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as S}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as J,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as x}from"../peripherals/KeyboardPeripherals.js";import{getScriptMode as w}from"../helpers/scriptMode.js";import{EpubSettings as C}from"./preferences/EpubSettings.js";import{LineLengths as U}from"../helpers/lineLength.js";import{supportsDecorationStyle as q,decorationsEqual as Y,resolveDecorationForWire as P}from"@readium/decorator";const Q=p=>({frameLoaded:p.frameLoaded||(()=>{}),positionChanged:p.positionChanged||(()=>{}),timelineItemChanged:p.timelineItemChanged||(()=>{}),tap:p.tap||(()=>!1),click:p.click||(()=>!1),zoom:p.zoom||(()=>{}),miscPointer:p.miscPointer||(()=>{}),scroll:p.scroll||(()=>{}),customEvent:p.customEvent||(()=>{}),handleLocator:p.handleLocator||(()=>!1),textSelected:p.textSelected||(()=>{}),contentProtection:p.contentProtection||(()=>{}),contextMenu:p.contextMenu||(()=>{}),peripheral:p.peripheral||(()=>{})});function Z(p,e){return p.length===e.length&&p.every((t,i)=>t===e[i])}class k extends F{constructor(e,t,i,s=[],r=void 0,o={preferences:{},defaults:{}}){super(),this._visibleFragmentIds=[],this._notifiedVisibleFragmentIds=[],this._timelineAugmented=!1,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.reflowViewport={readingOrder:[],progressions:new Map,positions:null},this.pub=t,this.container=e,this.listeners=Q(i),this.currentLocation=r,s.length&&(this.positions=s),this._preferences=new V(o.preferences),this._defaults=new N(o.defaults),this._settings=new C(this._preferences,this._defaults);const h=w(t.metadata),f=h==="cjk-horizontal",a=h==="cjk-vertical",c=a||h==="mongolian-vertical",l=f||a;this._css=new W({rsProperties:new B({noVerticalPagination:c||void 0}),userProperties:new j({}),lineLengths:new U({optimalChars:this._settings.optimalLineLength,minChars:this._settings.minimalLineLength,maxChars:this._settings.maximalLineLength,padding:this._settings.scroll?(this._settings.scrollPaddingLeft||0)+(this._settings.scrollPaddingRight||0):(this._settings.pageGutter||0)*2,fontFace:this._settings.fontFamily,letterSpacing:this._settings.letterSpacing,wordSpacing:this._settings.wordSpacing,isCJK:l}),container:e,constraint:this._settings.constraint,isCJKVertical:c}),this._layout=k.determineLayout(t,!!this._settings.scroll),this.currentProgression=t.metadata.effectiveReadingProgression,this._injectablesConfig=o.injectables||{rules:[],allowedDomains:[]},this._readiumRulesPromise=G(t.metadata,t.readingOrder.items),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 X(this._contentProtection),this._suspiciousActivityListener=u=>{const{type:m,...L}=u.detail;m==="context_menu"?this.listeners.contextMenu(L):this.listeners.contentProtection(m,L)},window.addEventListener(S,this._suspiciousActivityListener)),this._keyboardPeripherals.length>0&&(this._keyboardPeripheralsManager=new J({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=u=>{const m=u.detail;this.listeners.peripheral(m)},window.addEventListener(x,this._keyboardPeripheralListener)),this.resizeObserver=new ResizeObserver(()=>this.ownerWindow.requestAnimationFrame(async()=>await this.resizeHandler())),this.resizeObserver.observe(this.container.parentElement||document.documentElement)}static determineLayout(e,t){const i=e.metadata.effectiveLayout;if(i===d.fixed)return d.fixed;if(e.metadata.otherMetadata&&"http://openmangaformat.org/schema/1.0#version"in e.metadata.otherMetadata)return d.fixed;if(e.metadata?.conformsTo?.includes(E.DIVINA))return d.fixed;if(i===d.scrolled)return d.scrolled;const s=w(e.metadata);return s==="cjk-vertical"||s==="mongolian-vertical"?d.scrolled:i===d.reflowable&&t?d.scrolled:d.reflowable}async load(){if(this.positions?.length||(this.positions=await this.pub.positionsFromManifest()),!this._injector){const e=await this._readiumRulesPromise;this._injector=new $({rules:[...e,...this._injectablesConfig.rules],allowedDomains:this._injectablesConfig.allowedDomains})}if(this._layout===d.fixed)this.framePool=new A(this.container,this.positions,this.pub,this._injector,this._contentProtection,this._keyboardPeripherals,[...this._decorationResizeSelectors]),this.framePool.listener=(e,t)=>{this.eventListener(e,t)};else{await this.updateCSS(!1);const e=this.compileCSSProperties(this._css);this.framePool=new T(this.container,this.positions,e,this._injector,this._contentProtection,this._keyboardPeripherals,t=>this.pub.timeline.segmentsForHref(t).flatMap(i=>i.references).map(i=>{const s=i.indexOf("#");return s>=0?i.slice(s+1):""}).filter(Boolean),[...this._decorationResizeSelectors])}this.currentLocation===void 0&&(this.currentLocation=this.positions[0]),await this.resizeHandler(),await this.apply()}get settings(){if(this._layout===d.fixed)return Object.freeze({...this._settings});{const e=this._css.userProperties.colCount||this._css.rsProperties.colCount||this._settings.columnCount;return Object.freeze({...this._settings,columnCount:e})}}get preferencesEditor(){return this._preferencesEditor===null&&(this._preferencesEditor=new b(this._preferences,this.settings,this.pub.metadata)),this._preferencesEditor}async submitPreferences(e){this._preferences=this._preferences.merging(e),await this.applyPreferences()}async applyPreferences(){const e=this._settings;this._settings=new C(this._preferences,this._defaults),this._preferencesEditor!==null&&(this._preferencesEditor=new b(this._preferences,this.settings,this.pub.metadata)),this._layout===d.fixed?this.handleFXLPrefs(e,this._settings):await this.updateCSS(!0)}handleFXLPrefs(e,t){e.columnCount!==t.columnCount&&this.framePool.setPerPage(t.columnCount)}async updateCSS(e){this._css.update(this._settings),e&&await this.commitCSS(this._css)}compileCSSProperties(e){const t={};for(const[i,s]of Object.entries(e.rsProperties.toCSSProperties()))t[i]=s;for(const[i,s]of Object.entries(e.userProperties.toCSSProperties()))t[i]=s;return t}async commitCSS(e){if(!this.framePool)return;const t=this.compileCSSProperties(e);this.framePool.setCSSProperties(t),this._css.userProperties.view==="paged"&&this._layout===d.scrolled?await this.setLayout(d.reflowable):this._css.userProperties.view==="scroll"&&this._layout===d.reflowable&&await this.setLayout(d.scrolled),this._css.setContainerWidth()}async resizeHandler(){const e=this.container.parentElement||document.documentElement;if(this._layout===d.fixed){if(this.container.style.width=`${K(e)-this._settings.constraint}px`,!this.framePool)return;this.framePool.resizeHandler()}else{const t=this._css.userProperties.colCount,i=this._css.userProperties.lineLength;this._css.resizeHandler(),(this._css.userProperties.view!=="scroll"&&t!==this._css.userProperties.colCount||i!==this._css.userProperties.lineLength)&&await this.commitCSS(this._css)}}get layout(){return this._layout}get ownerWindow(){return this.container.ownerDocument.defaultView||window}get _cframes(){return(this.framePool?.currentFrames??[]).filter(e=>!(e instanceof z&&e.isDestroyed))}get pool(){return this.framePool}eventListener(e,t,i){switch(e){case"_pong":if(this.listeners.frameLoaded(this._cframes[0].iframe.contentWindow),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),i){const n=this._cframes.filter(l=>!!l).indexOf(i),c=n>=0?this.viewport.readingOrder[n]:void 0;c&&this._reapplyDecorationsToFrame(i,c)}else this._reapplyDecorationsToCurrentFrames();break;case"first_visible_locator":const s=v.deserialize(t);if(!s)break;this.currentLocation=new v({href:this.currentLocation.href,type:this.currentLocation.type,title:this.currentLocation.title,locations:s?.locations,text:s?.text}),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation);break;case"text_selected":{const a=t;if(i){const c=this._cframes.filter(u=>!!u).indexOf(i),l=c>=0?this.viewport.readingOrder[c]:void 0;if(l){const u=this.pub.readingOrder.findWithHref(l);a.locator=new v({href:l,type:u.type||"application/xhtml+xml",text:new D({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("http://")||n.startsWith("https://")||n.startsWith("mailto:")||n.startsWith("tel:"))this.listeners.handleLocator(new _({href:n}).locator);else try{this.goLink(new _({href:y.join(y.dirname(this.currentLocation.href),n)}),!1,()=>{})}catch(c){console.warn(`Couldn't go to link for ${n}: ${c}`),this.listeners.handleLocator(new _({href:n}).locator)}}else console.log("Clicked on",a)}else{if(this._layout===d.fixed&&this.framePool.doNotDisturb&&(r.doNotDisturb=!0),this._layout===d.fixed&&(this.currentProgression===g.rtl||this.currentProgression===g.ltr)&&this.framePool.currentFrames.length>1){const c=this.framePool.currentFrames;r.targetFrameSrc===c[this.currentProgression===g.rtl?0:1]?.source&&(r.x+=(c[this.currentProgression===g.rtl?1:0]?.iframe.contentWindow?.innerWidth??0)*window.devicePixelRatio)}if(e==="click"?this.listeners.click(r):this.listeners.tap(r))break;const n=(this._cframes.length===2?this._cframes[0].window.innerWidth+this._cframes[1].window.innerWidth:this._cframes[0].window.innerWidth)*window.devicePixelRatio/4;r.x>=n&&r.x<=n*3&&this.listeners.miscPointer(1),r.x<n?this.goLeft(!1,()=>{}):r.x>n*3&&this.goRight(!1,()=>{})}break;case"tap_more":this.listeners.miscPointer(t);break;case"no_more":this.changeResource(1);break;case"no_less":this.changeResource(-1);break;case"swipe":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 h=t,f={...h,interactiveElement:void 0};h.interactiveElement&&(f.interactiveElement=new DOMParser().parseFromString(h.interactiveElement,"text/html").body.children[0]),this.listeners.peripheral(f);break;case"log":console.log(this._cframes[0]?.source?.split("/")[3],...t);break;default:this.listeners.customEvent(e,t);break}}determineModules(){let e=Array.from(R.keys());if(this._layout===d.fixed)return e.filter(s=>M.includes(s));e=e.filter(s=>H.includes(s));const t=w(this.pub.metadata);if(t==="cjk-vertical"||t==="mongolian-vertical")return e.filter(s=>s!=="column_snapper"&&s!=="scroll_snapper");const i=e;return this._layout===d.scrolled?e=i.filter(s=>s!=="column_snapper"&&s!=="cjk_vertical_snapper"):e=i.filter(s=>s!=="scroll_snapper"&&s!=="cjk_vertical_snapper"),e}attachListener(){const e=this._cframes.filter(t=>!!t);if(e.length===0)throw Error("no cframe to attach listener to");e.forEach(t=>{t.msg&&(t.msg.listener=(i,s)=>{this.eventListener(i,s,t)})}),this._reapplyDecorationsToCurrentFrames()}async apply(){if(await this.framePool.update(this.pub,this.currentLocator,this.determineModules()),this.attachListener(),this.pub.readingOrder.findIndexWithHref(this.currentLocation.href)<0)throw Error("Link for "+this.currentLocation.href+" not found!")}supportsDecorationStyle(e){return q(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._sendDecorationActivationToFrames(e,!0)),(t.onDecorationPointerEnter||t.onDecorationPointerLeave)&&(this._decorationHoverState.set(e,!0),this._sendDecorationHoverToFrames(e,!0))}unregisterDecorationObserver(e){this._decorationObservers.forEach((t,i)=>{if(!t.has(e))return;t.delete(e);const s=[...t].some(o=>o.onDecorationActivated);this._decorationActivationState.has(i)&&!s&&(this._decorationActivationState.delete(i),this._sendDecorationActivationToFrames(i,!1));const r=[...t].some(o=>o.onDecorationPointerEnter||o.onDecorationPointerLeave);this._decorationHoverState.has(i)&&!r&&(this._decorationHoverState.delete(i),this._sendDecorationHoverToFrames(i,!1))})}_sendDecorationActivationToFrames(e,t){this._cframes.filter(s=>!!s).forEach(s=>{s.msg&&s.msg.send("decoration_activatable",{group:e,activatable:t})})}_sendDecorationHoverToFrames(e,t){this._cframes.filter(s=>!!s).forEach(s=>{s.msg&&s.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)??[],s=new Map(i.map(c=>[c.id,c])),r=new Map(e.map(c=>[c.id,c])),o=[],h=[],f=[];for(const[c,l]of s)r.has(c)?Y(l,r.get(c))||f.push(r.get(c)):o.push(c);for(const[c,l]of r)s.has(c)||h.push(l);this._decorations.set(t,e),this._sendDecorationOps(t,o,h,f,i);const a=this._decorationActivationState.get(t);a!==void 0&&this._sendDecorationActivationToFrames(t,a);const n=this._decorationHoverState.get(t);n!==void 0&&this._sendDecorationHoverToFrames(t,n)}_sendDecorationOps(e,t,i,s,r){const o=this._cframes.filter(a=>!!a),h=new Map(r.map(a=>[a.id,a])),f=this.viewport.readingOrder;o.forEach((a,n)=>{if(!a.msg)return;const c=f[n];if(c){for(const l of t){const u=h.get(l);!u||u.locator.href!==c||a.msg.send("decorate",{group:e,action:"remove",decoration:{id:l}})}for(const l of i)l.locator.href===c&&a.msg.send("decorate",{group:e,action:"add",decoration:P(l,this._decoratorConfig.decorationTemplates)});for(const l of s)l.locator.href===c&&a.msg.send("decorate",{group:e,action:"update",decoration:P(l,this._decoratorConfig.decorationTemplates)})}})}_reapplyDecorationsToFrame(e,t){if(e.msg){for(const[i,s]of this._decorations){const r=s.filter(o=>o.locator.href===t);if(r.length!==0){e.msg.send("decorate",{group:i,action:"clear"});for(const o of r)e.msg.send("decorate",{group:i,action:"add",decoration:P(o,this._decoratorConfig.decorationTemplates)})}}for(const[i,s]of this._decorationActivationState)e.msg.send("decoration_activatable",{group:i,activatable:s});for(const[i,s]of this._decorationHoverState)e.msg.send("decoration_hoverable",{group:i,hoverable:s})}}_reapplyDecorationsToCurrentFrames(){const e=this._cframes.filter(i=>!!i),t=this.viewport.readingOrder;e.forEach((i,s)=>{const r=t[s];r&&this._reapplyDecorationsToFrame(i,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(o=>o.id===e.decorationId);if(!i)return!1;const s={decoration:i,group:e.group,rect:e.rect,point:e.point};let r=!1;for(const o of t)o.onDecorationActivated?.(s)&&(r=!0);return r}_handleDecorationPointerEnter(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(r=>r.id===e.decorationId);if(!i)return;this._decorationHoveredDecorations.set(e.group,i);const s={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const r of t)r.onDecorationPointerEnter?.(s)}_handleDecorationPointerLeave(e){const t=this._decorationObservers.get(e.group);if(!t||t.size===0)return;const i=(this._decorations.get(e.group)??[]).find(r=>r.id===e.decorationId)??this._decorationHoveredDecorations.get(e.group);if(this._decorationHoveredDecorations.delete(e.group),!i)return;const s={decoration:i,group:e.group,rect:e.rect,point:e.point};for(const r of t)r.onDecorationPointerLeave?.(s)}async destroy(){this._suspiciousActivityListener&&window.removeEventListener(S,this._suspiciousActivityListener),this._keyboardPeripheralListener&&window.removeEventListener(x,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()}async changeResource(e){if(e===0)return!1;if(this._layout===d.fixed){const s=this.framePool,r=s.viewport.positions[0];if(e===1){if(!s.next(s.perPage))return!1}else if(e===-1){if(!s.prev(s.perPage))return!1}else throw Error("Invalid relative value for FXL");const o=s.viewport.positions[0];if(r>o){for(let h=this.positions.length-1;h>=0;h--)if(this.positions[h].href===this.pub.readingOrder.items[o-1].href){this.currentLocation=this.positions[h].copyWithLocations({progression:.999999999999});break}}else if(r<o){for(let h=0;h<this.positions.length;h++)if(this.positions[h].href===this.pub.readingOrder.items[o-1].href){this.currentLocation=this.positions[h];break}}return await this.apply(),this.listeners.positionChanged(this.currentLocation),this._notifyTimelineChange(this.currentLocation),!0}const t=this.pub.readingOrder.findIndexWithHref(this.currentLocation.href),i=Math.max(0,Math.min(this.pub.readingOrder.items.length-1,t+e));if(i===t)return this._cframes[0]?.msg?.send("shake",void 0,async s=>{}),!1;if(t>i){for(let s=this.positions.length-1;s>=0;s--)if(this.positions[s].href===this.pub.readingOrder.items[i].href){this.currentLocation=this.positions[s].copyWithLocations({progression:.999999999999});break}}else for(let s=0;s<this.positions.length;s++)if(this.positions[s].href===this.pub.readingOrder.items[i].href){this.currentLocation=this.positions[s];break}return await this.apply(),!0}findLastPositionInProgressionRange(e,t){const i=e.findLastIndex(s=>{const r=s.locations.progression;return!!(r&&r>t.start&&r<=t.end)});return i!==-1?e[i]:void 0}findNearestPositions(e){const t=this.positions.filter(o=>o.href===this.currentLocation.href);let i=this.currentLocation,s;const r=t.findLastIndex(o=>(o.locations.progression??0)<=e.start);if(r!==-1){i=t[r];const o=t.slice(r+1);s=this.findLastPositionInProgressionRange(o,e)}return{first:i,last:s}}updateViewport(e){this.reflowViewport.readingOrder=[],this.reflowViewport.progressions.clear(),this.reflowViewport.positions=null,this.currentLocation&&(this.reflowViewport.readingOrder.push(this.currentLocation.href),this.reflowViewport.progressions.set(this.currentLocation.href,e),this.currentLocation.locations?.position!==void 0&&(this.reflowViewport.positions=[this.currentLocation.locations.position],this.lastLocationInView?.locations?.position!==void 0&&this.reflowViewport.positions.push(this.lastLocationInView.locations.position)))}async syncLocation(e){const t=e,i=this.findNearestPositions(t);this.currentLocation=i.first.copyWithLocations({progression:t.start}),this.lastLocationInView=i.last,this.updateViewport(t),this.listeners.positionChanged(this.currentLocation);const s=t.fragmentId?this.currentLocation.copyWithLocations({fragments:[`#${t.fragmentId}`]}):this.currentLocation;this._visibleFragmentIds=t.visibleFragmentIds??[],this._notifyTimelineChange(s),await this.framePool.update(this.pub,this.currentLocation,this.determineModules())}goBackward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this._layout===d.fixed?this.changeResource(-1).then(i=>{this._isNavigating=!1,t(i)}):this._cframes[0]?.msg?.send("go_prev",void 0,async i=>{if(i)this._isNavigating=!1,t(!0);else{const s=await this.changeResource(-1);this._isNavigating=!1,t(s)}})}goForward(e,t){if(this._isNavigating){t(!1);return}this._isNavigating=!0,this._layout===d.fixed?this.changeResource(1).then(i=>{this._isNavigating=!1,t(i)}):this._cframes[0]?.msg?.send("go_next",void 0,async i=>{if(i)this._isNavigating=!1,t(!0);else{const s=await this.changeResource(1);this._isNavigating=!1,t(s)}})}get currentLocator(){return this.currentLocation}get viewport(){return this._layout===d.fixed?this.framePool?this.framePool.viewport:{readingOrder:[],progressions:new Map,positions:null}:this.reflowViewport}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.currentProgression}async setLayout(e){this._layout!==e&&(this._layout=e,await this.framePool.update(this.pub,this.currentLocator,this.determineModules(),!0),this.attachListener())}get publication(){return this.pub}get timeline(){const e=this.pub.timeline;if(!this._timelineAugmented&&this.positions?.length){const t=this.positions,i=new Set;e.augment((s,r)=>{if(s.children?.length)return{};const o=r.href.indexOf("#"),h=o>=0?r.href.slice(0,o):r.href,f=o>=0?r.href.slice(o+1):void 0,a=t.filter(l=>l.href===h);if(!a.length)return{};const n=f?a.find(l=>l.locations.fragments[0]===f):void 0;let c;return n?c=n:i.has(h)?c=void 0:(i.add(h),c=a.reduce((l,u)=>(u.locations.position??1/0)<(l.locations.position??1/0)?u:l)),c?{position:c.locations.position,scroll:n?.locations.progression}:{}}),this._timelineAugmented=!0}return this._wrappedTimeline||(this._wrappedTimeline=new Proxy(e,{get:(t,i)=>{if(i!=="navigableFrom"){const s=Reflect.get(t,i,t);return typeof s=="function"?s.bind(t):s}return s=>{const r=this._visibleFragmentIds;let o=(r.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${r[0]}`]})):void 0)??s;const h=(r.length?t.locate(this.currentLocation.copyWithLocations({fragments:[`#${r[r.length-1]}`]})):void 0)??s;if(this.isScrollStart){const n=t.ancestors(o).find(c=>c.references.includes(this.currentLocation.href));n&&(o=n)}const f=t.navigableFrom(o).previous,a=t.navigableFrom(h).next;return{previous:f,next:a}}}})),this._wrappedTimeline}async loadLocator(e,t){let i=!1,s=O(e.locations);if(e.text?.highlight?i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_text",s?[e.text?.serialize(),s]:e.text?.serialize(),n=>f(n))}):s&&(i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_text",["",s],n=>f(n))})),i){t(i);return}const r=I(e.locations);if(r&&(i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_id",r,n=>f(n))})),i){t(i);return}const o=e?.locations?.progression;o&&o>0?i=await new Promise((f,a)=>{this._cframes[0].msg.send("go_progression",o,n=>f(n))}):i=!0,t(i)}go(e,t,i){const s=e.href.split("#")[0];let r=this.pub.readingOrder.findWithHref(s);if(!r)return i(this.listeners.handleLocator(e));if(this._isNavigating){i(!1);return}this._isNavigating=!0,this.currentLocation=this.positions.find(o=>o.href===r.href),this.apply().then(()=>this.loadLocator(e,o=>{this._isNavigating=!1,i(o)})).then(()=>{this.attachListener()})}goLink(e,t,i){return this.go(e.locator,t,i)}_notifyTimelineChange(e){const t=this.timeline.locate(e),i=!Z(this._visibleFragmentIds,this._notifiedVisibleFragmentIds);(t!==this._currentTimelineItem||i)&&(this._currentTimelineItem=t,this._notifiedVisibleFragmentIds=this._visibleFragmentIds,this.listeners.timelineItemChanged(t))}}export{k as EpubNavigator};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Loader as o}from"@readium/navigator-html-injectables";import{FrameComms as n}from"./FrameComms.js";import{sML as h}from"@readium/helpers";import{KeyboardConditionBridge as
|
|
1
|
+
import{Loader as o}from"@readium/navigator-html-injectables";import{FrameComms as n}from"./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.sandbox.value="allow-same-origin allow-scripts",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.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.blur(),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 isDestroyed(){return this.destroyed}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 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{y as FrameManager};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import y from"./FrameBlobBuilder.js";import{FrameManager as
|
|
1
|
+
import y from"./FrameBlobBuilder.js";import{FrameManager as R}from"./FrameManager.js";const b=5,m=3;class B{constructor(e,i,s,n,r,o,c,l=[]){this.pool=new Map,this.blobs=new Map,this.inprogress=new Map,this.pendingUpdates=new Map,this.injector=null,this.container=e,this.positions=i,this.currentCssProperties=s,this.injector=n??null,this.contentProtectionConfig=r||{},this.keyboardPeripheralsConfig=o||[],this.getFragmentIds=c??(()=>[]),this.resizeWatchSelectors=[...l]}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(),r=n.next();for(;r.value;)await r.value.destroy(),r=n.next();this.pool.clear(),this.blobs.forEach(o=>{this.injector?.releaseBlobUrl?.(o),URL.revokeObjectURL(o)}),this.injector?.dispose(),this.container.childNodes.forEach(o=>{(o.nodeType===Node.ELEMENT_NODE||o.nodeType===Node.TEXT_NODE)&&o.remove()})}async update(e,i,s,n=!1){let r=this.positions.findIndex(l=>l.locations.position===i.locations.position);if(r<0)throw Error(`Locator not found in position list: ${i.locations.position} > ${this.positions.reduce((l,d)=>d.locations.position||0>l?d.locations.position||0:l,0)}`);const o=this.positions[r].href;this.inprogress.has(o)&&await this.inprogress.get(o);const c=new Promise(async(l,d)=>{const u=[],f=[];this.positions.forEach((t,p)=>{(p>r+b||p<r-b)&&(u.includes(t.href)||u.push(t.href)),p<r+m&&p>r-m&&(f.includes(t.href)||f.push(t.href))}),u.forEach(async t=>{f.includes(t)||this.pool.has(t)&&(await this.pool.get(t)?.destroy(),this.pool.delete(t),this.pendingUpdates.has(t)&&this.pendingUpdates.set(t,{inPool:!1}))}),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 w=async t=>{if(n&&(this.blobs.forEach(a=>{this.injector?.releaseBlobUrl?.(a),URL.revokeObjectURL(a)}),this.blobs.clear(),this.pendingUpdates.clear()),this.pendingUpdates.has(t)&&this.pendingUpdates.get(t)?.inPool===!1){const a=this.blobs.get(t);a&&(this.injector?.releaseBlobUrl?.(a),URL.revokeObjectURL(a),this.blobs.delete(t),this.pendingUpdates.delete(t))}if(this.pool.has(t)){const a=this.pool.get(t);if(!this.blobs.has(t))await a.destroy(),this.pool.delete(t),this.pendingUpdates.delete(t);else{await a.load(s);return}}const p=e.readingOrder.findWithHref(t);if(!p)return;if(!this.blobs.has(t)){const U=await new y(e,this.currentBaseURL||"",p,{cssProperties:this.currentCssProperties,injector:this.injector}).build();this.blobs.set(t,U)}const g=new R(this.blobs.get(t),this.contentProtectionConfig,this.keyboardPeripheralsConfig,this.getFragmentIds(t),this.resizeWatchSelectors);t!==o&&await g.hide(),this.container.appendChild(g.iframe),await g.load(s),this.pool.set(t,g)};try{await Promise.all(f.map(t=>w(t)))}catch(t){d(t)}const h=this.pool.get(o);if((h?.source!==this._currentFrame?.source||n)&&(await this._currentFrame?.hide(),h&&await h.load(s),h&&await h.show(i.locations.progression),this._currentFrame=h,h)){const t=this.container.ownerDocument.activeElement;t&&t.tagName==="IFRAME"&&t!==h.iframe&&h.iframe.focus({preventScroll:!0})}l()});this.inprogress.set(o,c),await c,this.inprogress.delete(o)}setCSSProperties(e){if(!((s,n)=>{const r=Object.keys(s),o=Object.keys(n);if(r.length!==o.length)return!1;for(const c of r)if(s[c]!==n[c])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{B as FramePoolManager};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Loader as
|
|
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 +1 @@
|
|
|
1
|
-
import{ReadingProgression as S,Page as p}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 E}from"./FXLSpreader.js";const T=8,O=5,U=300,A=15e3,D=250,I=150,N=500;class z{constructor(e,t,r,a,n,s){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=r,this.injector=a??null,this.contentProtectionConfig=n||{},this.keyboardPeripheralsConfig=s||[],this.spreadPresentation=r.metadata.otherMetadata?.spread||y.auto,this.pub.metadata.effectiveReadingProgression!==S.rtl&&this.pub.metadata.effectiveReadingProgression!==S.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(l=>{const h=new M(this.peripherals,this.pub.metadata.effectiveReadingProgression,l.href,this.contentProtectionConfig,this.keyboardPeripheralsConfig);this.spineElement.appendChild(h.element),this.pool.set(l.href,h),h.width=100/this.length*(l.properties?.otherProperties.orientation===E.landscape||l.properties?.otherProperties.addBlank?this.perPage:1),h.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((r,a)=>{let n=this.pub.readingOrder.items.findIndex(h=>h.href===a);const s=this.pub.readingOrder.items[n];if(r.width=100/this.length*(s.properties?.otherProperties.orientation===E.landscape||s.properties?.otherProperties.addBlank?this.perPage:1),r.height=this.height,!r.loaded)return;const l=this.spreader.findByLink(s);r.update(this.spreadPosition(l,s))})},D)}updateDimensions(){this.width=this.bookElement.clientWidth,this.height=this.bookElement.clientHeight}get rtl(){return this.pub.metadata.effectiveReadingProgression===S.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 r="0";this.updateDimensions(),this.perPage>1&&(r=`${this.width/2}px`);const a={transition:e?`all ${t?I:N}ms ease-out`:"all 0ms ease-out",marginRight:this.rtl?r:"0",marginLeft:this.rtl?"0":r,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 r=`translate3d(${this.offset}px, 0, 0)`;this.spineElement.style.transform!==r&&(this.transform=r,this.updateSpineStyle(!0,t),this.deselect())})});else{const r=`translate3d(${this.offset}px, 0, 0)`;if(this.spineElement.style.transform===r)return;this.transform=r,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 r=[];for(;t.value;)r.push(t.value),t=e.next();r.length>0&&await Promise.allSettled(r),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(s=>URL.revokeObjectURL(s)),this.injector?.dispose(),this.container.childNodes.forEach(s=>{(s.nodeType===Node.ELEMENT_NODE||s.nodeType===Node.TEXT_NODE)&&s.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?p.center:e.length<2?p.center:t.href===e[0].href?this.rtl?p.right:p.left:this.rtl?p.left:p.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,r,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 s=this.makeSpread(this.currentSlide);this.perPage>1&&n++;for(const h of s)await this.waitForItem(h.href);const l=new Promise(async(h,L)=>{const g=[],c=[];this.positions.forEach((i,o)=>{(o>n+T||o<n-T)&&(g.includes(i.href)||g.push(i.href)),o<n+O&&o>n-O&&(c.includes(i.href)||c.push(i.href))}),g.forEach(async i=>{c.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 v=async i=>{const o=e.readingOrder.findIndexWithHref(i),d=e.readingOrder.items[o];if(d){if(!this.blobs.has(i)){const m=await new k(e,this.currentBaseURL||"",d,{injector:this.injector}).build(!0);this.blobs.set(i,m)}this.delayedShow.has(i)||this.delayedShow.set(i,new Promise((w,m)=>{let b=!1;const F=window.setTimeout(async()=>{this.delayedTimeout.set(i,0);const C=this.makeSpread(this.reAlign(o)),R=this.spreadPosition(C,d),P=this.pool.get(i);await P.load(r,this.blobs.get(i)),this.peripherals.isScaled||await P.show(R),this.delayedShow.delete(i),b=!0,w()},U);setTimeout(()=>{!b&&this.delayedShow.has(i)&&m(`Offscreen load timeout: ${i}`)},A),this.delayedTimeout.set(i,F)}))}};try{await Promise.all(c.map(i=>v(i)))}catch(i){L(i)}const u=[];for(const i of s){const o=this.pool.get(i.href),d=this.blobs.get(i.href);d&&(this.cancelShowing(i.href),await o.load(r,d),await o.show(this.spreadPosition(s,i)),this.previousFrames.push(o),await o.activate(),u.push(o))}for(;this.previousFrames.length>0;){const i=this.previousFrames.shift();i&&!u.includes(i)&&await i.unfocus()}this.previousFrames=u;const f=this.container.ownerDocument.activeElement;f&&f.tagName==="IFRAME"&&!u.some(i=>i.iframe===f)&&u[0]?.iframe.focus({preventScroll:!0}),h()});for(const h of s)this.inprogress.set(h.href,l);await l;for(const h of s)this.inprogress.delete(h.href)}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 r=t.realSize;e.x=Math.min(e.x,r.x),e.y=Math.min(e.y,r.y),e.width+=r.width,e.height=Math.max(e.height,r.height),e.top=Math.min(e.top,r.top),e.right=Math.min(e.right,r.right),e.bottom=Math.min(e.bottom,r.bottom),e.left=Math.min(e.left,r.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(r=>{e.readingOrder.push(r.href),e.progressions.set(r.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{z as FXLFramePoolManager};
|
|
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 +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
|
|
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 +1 @@
|
|
|
1
|
-
import{WebPubBlobBuilder as w}from"./WebPubBlobBuilder.js";import{WebPubFrameManager as y}from"./WebPubFrameManager.js";class
|
|
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 +1 @@
|
|
|
1
|
-
import{Feature as w,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 H}from"../injection/webpubInjectables.js";import{NavigatorProtector as M,NAVIGATOR_SUSPICIOUS_ACTIVITY_EVENT as b}from"../protection/NavigatorProtector.js";import{KeyboardPeripherals as N,NAVIGATOR_KEYBOARD_PERIPHERAL_EVENT as L}from"../peripherals/KeyboardPeripherals.js";import{supportsDecorationStyle as R,decorationsEqual as V,resolveDecorationForWire as m}from"@readium/decorator";const z=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=z(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=H(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._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 M(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 N({keyboardPeripherals:this._keyboardPeripherals}),this._keyboardPeripheralListener=a=>{const s=a.detail;this.listeners.peripheral(s)},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(){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)),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=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(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()}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,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})}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)?V(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 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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@readium/navigator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.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.
|
|
48
|
-
"@readium/
|
|
49
|
-
"@readium/
|
|
50
|
-
"@readium/
|
|
47
|
+
"@readium/decorator": "1.2.1",
|
|
48
|
+
"@readium/shared": "2.5.1",
|
|
49
|
+
"@readium/navigator-html-injectables": "2.8.1",
|
|
50
|
+
"@readium/helpers": "1.1.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@readium/css": "^2.0.5",
|
package/src/decorations/index.ts
CHANGED
|
@@ -42,4 +42,14 @@ export interface DecorableNavigator {
|
|
|
42
42
|
|
|
43
43
|
/** Unregisters a previously registered observer from all groups. */
|
|
44
44
|
unregisterDecorationObserver(observer: DecorationObserver): void;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Watches an element within the current content document for resize, so decoration
|
|
48
|
+
* overlays relay out when it resizes even if the resource's own document size doesn't
|
|
49
|
+
* change (e.g. a sidebar collapsing and the reading pane reflowing inside it).
|
|
50
|
+
*/
|
|
51
|
+
addDecorationResizeTarget(selector: string): void;
|
|
52
|
+
|
|
53
|
+
/** Stops watching an element previously registered with addDecorationResizeTarget. */
|
|
54
|
+
removeDecorationResizeTarget(selector: string): void;
|
|
45
55
|
}
|
|
@@ -114,6 +114,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
114
114
|
private _decorationActivationState: Map<string, boolean> = new Map();
|
|
115
115
|
private _decorationHoverState: Map<string, boolean> = new Map();
|
|
116
116
|
private _decorationActivationConsumed = false;
|
|
117
|
+
private _decorationResizeSelectors: Set<string>;
|
|
117
118
|
|
|
118
119
|
private reflowViewport: VisualNavigatorViewport = {
|
|
119
120
|
readingOrder: [],
|
|
@@ -175,6 +176,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
175
176
|
|
|
176
177
|
this._contentProtection = configuration.contentProtection || {};
|
|
177
178
|
this._decoratorConfig = configuration.decoratorConfig || {};
|
|
179
|
+
this._decorationResizeSelectors = new Set(this._decoratorConfig.resizeWatchSelectors ?? []);
|
|
178
180
|
|
|
179
181
|
// Merge keyboard peripherals
|
|
180
182
|
this._keyboardPeripherals = this.mergeKeyboardPeripherals(
|
|
@@ -269,7 +271,8 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
269
271
|
this.pub,
|
|
270
272
|
this._injector,
|
|
271
273
|
this._contentProtection,
|
|
272
|
-
this._keyboardPeripherals
|
|
274
|
+
this._keyboardPeripherals,
|
|
275
|
+
[...this._decorationResizeSelectors]
|
|
273
276
|
);
|
|
274
277
|
this.framePool.listener = (key: CommsEventKey | ManagerEventKey, data: unknown) => {
|
|
275
278
|
this.eventListener(key, data);
|
|
@@ -287,7 +290,8 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
287
290
|
(href) => this.pub.timeline.segmentsForHref(href)
|
|
288
291
|
.flatMap(item => item.references)
|
|
289
292
|
.map(ref => { const h = ref.indexOf('#'); return h >= 0 ? ref.slice(h + 1) : ''; })
|
|
290
|
-
.filter(Boolean)
|
|
293
|
+
.filter(Boolean),
|
|
294
|
+
[...this._decorationResizeSelectors]
|
|
291
295
|
);
|
|
292
296
|
}
|
|
293
297
|
|
|
@@ -725,6 +729,21 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
725
729
|
});
|
|
726
730
|
}
|
|
727
731
|
|
|
732
|
+
// Watches an element within the current content document(s) for resize, so decoration
|
|
733
|
+
// overlays relay out when it resizes even if the resource's own document size doesn't
|
|
734
|
+
// change. Not resource-scoped: forwarded to every frame, current and future, via
|
|
735
|
+
// framePool the same way contentProtectionConfig/keyboardPeripheralsConfig are — applied
|
|
736
|
+
// on every frame show(), not just replayed reactively off decoration state.
|
|
737
|
+
public addDecorationResizeTarget(selector: string): void {
|
|
738
|
+
this._decorationResizeSelectors.add(selector);
|
|
739
|
+
this.framePool?.addResizeTarget(selector);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
public removeDecorationResizeTarget(selector: string): void {
|
|
743
|
+
this._decorationResizeSelectors.delete(selector);
|
|
744
|
+
this.framePool?.removeResizeTarget(selector);
|
|
745
|
+
}
|
|
746
|
+
|
|
728
747
|
public applyDecorations(decorations: Decoration[], group: string): void {
|
|
729
748
|
const previous = this._decorations.get(group) ?? [];
|
|
730
749
|
const prevById = new Map(previous.map(d => [d.id, d]));
|
|
@@ -869,6 +888,7 @@ export class EpubNavigator extends VisualNavigator implements Configurable<Confi
|
|
|
869
888
|
this._decorationHoveredDecorations.clear();
|
|
870
889
|
this._decorationActivationState.clear();
|
|
871
890
|
this._decorationHoverState.clear();
|
|
891
|
+
this._decorationResizeSelectors.clear();
|
|
872
892
|
}
|
|
873
893
|
|
|
874
894
|
private async changeResource(relative: number): Promise<boolean> {
|
|
@@ -15,6 +15,8 @@ export class FrameManager {
|
|
|
15
15
|
private destroyed: boolean = false;
|
|
16
16
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
17
17
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
18
|
+
private resizeWatchSelectors: string[];
|
|
19
|
+
private pendingUnwatchSelectors: string[] = [];
|
|
18
20
|
private conditionBridge?: KeyboardConditionBridge;
|
|
19
21
|
private currModules: ModuleName[] = [];
|
|
20
22
|
|
|
@@ -22,7 +24,8 @@ export class FrameManager {
|
|
|
22
24
|
source: string,
|
|
23
25
|
contentProtectionConfig: IContentProtectionConfig = {},
|
|
24
26
|
keyboardPeripheralsConfig: IKeyboardPeripheralsConfig = [],
|
|
25
|
-
private readonly timelineFragmentIds: string[] = []
|
|
27
|
+
private readonly timelineFragmentIds: string[] = [],
|
|
28
|
+
resizeWatchSelectors: string[] = []
|
|
26
29
|
) {
|
|
27
30
|
this.frame = document.createElement("iframe");
|
|
28
31
|
this.frame.sandbox.value = "allow-same-origin allow-scripts";
|
|
@@ -38,6 +41,7 @@ export class FrameManager {
|
|
|
38
41
|
// Use the provided content protection config directly without overriding defaults
|
|
39
42
|
this.contentProtectionConfig = { ...contentProtectionConfig };
|
|
40
43
|
this.keyboardPeripheralsConfig = [...keyboardPeripheralsConfig];
|
|
44
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
41
45
|
|
|
42
46
|
}
|
|
43
47
|
|
|
@@ -99,6 +103,32 @@ export class FrameManager {
|
|
|
99
103
|
if (this.contentProtectionConfig.protectPrinting?.disable) {
|
|
100
104
|
this.comms!.send("print_protection", this.contentProtectionConfig.protectPrinting);
|
|
101
105
|
}
|
|
106
|
+
|
|
107
|
+
// Send resize-watch targets
|
|
108
|
+
this.resizeWatchSelectors.forEach(selector => {
|
|
109
|
+
this.comms!.send("decoration_resize", { action: "watch", selector });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Flush unwatches that couldn't be sent while comms was halted
|
|
113
|
+
this.pendingUnwatchSelectors.forEach(selector => {
|
|
114
|
+
this.comms!.send("decoration_resize", { action: "unwatch", selector });
|
|
115
|
+
});
|
|
116
|
+
this.pendingUnwatchSelectors = [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
addResizeTarget(selector: string): void {
|
|
120
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
121
|
+
this.pendingUnwatchSelectors = this.pendingUnwatchSelectors.filter(s => s !== selector);
|
|
122
|
+
if (this.comms?.ready) this.comms.send("decoration_resize", { action: "watch", selector });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
removeResizeTarget(selector: string): void {
|
|
126
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
127
|
+
if (this.comms?.ready) {
|
|
128
|
+
this.comms.send("decoration_resize", { action: "unwatch", selector });
|
|
129
|
+
} else if (!this.pendingUnwatchSelectors.includes(selector)) {
|
|
130
|
+
this.pendingUnwatchSelectors.push(selector);
|
|
131
|
+
}
|
|
102
132
|
}
|
|
103
133
|
|
|
104
134
|
async destroy() {
|
|
@@ -21,6 +21,7 @@ export class FramePoolManager {
|
|
|
21
21
|
private readonly injector: Injector | null = null;
|
|
22
22
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
23
23
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
24
|
+
private resizeWatchSelectors: string[];
|
|
24
25
|
private readonly getFragmentIds: (href: string) => string[];
|
|
25
26
|
|
|
26
27
|
constructor(
|
|
@@ -30,7 +31,8 @@ export class FramePoolManager {
|
|
|
30
31
|
injector?: Injector | null,
|
|
31
32
|
contentProtectionConfig?: IContentProtectionConfig,
|
|
32
33
|
keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig,
|
|
33
|
-
getFragmentIds?: (href: string) => string[]
|
|
34
|
+
getFragmentIds?: (href: string) => string[],
|
|
35
|
+
resizeWatchSelectors: string[] = []
|
|
34
36
|
) {
|
|
35
37
|
this.container = container;
|
|
36
38
|
this.positions = positions;
|
|
@@ -39,6 +41,20 @@ export class FramePoolManager {
|
|
|
39
41
|
this.contentProtectionConfig = contentProtectionConfig || {};
|
|
40
42
|
this.keyboardPeripheralsConfig = keyboardPeripheralsConfig || [];
|
|
41
43
|
this.getFragmentIds = getFragmentIds ?? (() => []);
|
|
44
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
addResizeTarget(selector: string): void {
|
|
48
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
49
|
+
// Forward to the whole pool, not just currentFrames: off-screen cached frames
|
|
50
|
+
// (preloaded within the pool's boundary window) must not keep stale state that
|
|
51
|
+
// resurfaces if they're shown again later without being recreated.
|
|
52
|
+
this.pool.forEach(f => f.addResizeTarget(selector));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
removeResizeTarget(selector: string): void {
|
|
56
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
57
|
+
this.pool.forEach(f => f.removeResizeTarget(selector));
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
async destroy() {
|
|
@@ -174,7 +190,7 @@ export class FramePoolManager {
|
|
|
174
190
|
}
|
|
175
191
|
|
|
176
192
|
// Create <iframe>
|
|
177
|
-
const fm = new FrameManager(this.blobs.get(href)!, this.contentProtectionConfig, this.keyboardPeripheralsConfig, this.getFragmentIds(href));
|
|
193
|
+
const fm = new FrameManager(this.blobs.get(href)!, this.contentProtectionConfig, this.keyboardPeripheralsConfig, this.getFragmentIds(href), this.resizeWatchSelectors);
|
|
178
194
|
if(href !== newHref) await fm.hide(); // Avoid unecessary hide
|
|
179
195
|
this.container.appendChild(fm.iframe);
|
|
180
196
|
await fm.load(modules);
|
|
@@ -14,6 +14,8 @@ export class FXLFrameManager {
|
|
|
14
14
|
private readonly peripherals: FXLPeripherals;
|
|
15
15
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
16
16
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
17
|
+
private resizeWatchSelectors: string[];
|
|
18
|
+
private pendingUnwatchSelectors: string[] = [];
|
|
17
19
|
private conditionBridge?: KeyboardConditionBridge;
|
|
18
20
|
private currModules: ModuleName[] = [];
|
|
19
21
|
|
|
@@ -28,13 +30,15 @@ export class FXLFrameManager {
|
|
|
28
30
|
direction: ReadingProgression,
|
|
29
31
|
debugHref: string,
|
|
30
32
|
contentProtectionConfig: IContentProtectionConfig = {},
|
|
31
|
-
keyboardPeripheralsConfig: IKeyboardPeripheralsConfig = []
|
|
33
|
+
keyboardPeripheralsConfig: IKeyboardPeripheralsConfig = [],
|
|
34
|
+
resizeWatchSelectors: string[] = []
|
|
32
35
|
) {
|
|
33
36
|
this.peripherals = peripherals;
|
|
34
37
|
this.debugHref = debugHref;
|
|
35
38
|
// Use the provided content protection config directly without overriding defaults
|
|
36
39
|
this.contentProtectionConfig = { ...contentProtectionConfig };
|
|
37
40
|
this.keyboardPeripheralsConfig = [...keyboardPeripheralsConfig];
|
|
41
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
38
42
|
this.frame = document.createElement("iframe");
|
|
39
43
|
this.frame.sandbox.value = "allow-same-origin allow-scripts";
|
|
40
44
|
this.frame.classList.add("readium-navigator-iframe");
|
|
@@ -236,6 +240,32 @@ export class FXLFrameManager {
|
|
|
236
240
|
if (this.contentProtectionConfig.protectPrinting?.disable) {
|
|
237
241
|
this.comms!.send("print_protection", this.contentProtectionConfig.protectPrinting);
|
|
238
242
|
}
|
|
243
|
+
|
|
244
|
+
// Send resize-watch targets
|
|
245
|
+
this.resizeWatchSelectors.forEach(selector => {
|
|
246
|
+
this.comms!.send("decoration_resize", { action: "watch", selector });
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Flush unwatches that couldn't be sent while comms was halted
|
|
250
|
+
this.pendingUnwatchSelectors.forEach(selector => {
|
|
251
|
+
this.comms!.send("decoration_resize", { action: "unwatch", selector });
|
|
252
|
+
});
|
|
253
|
+
this.pendingUnwatchSelectors = [];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
addResizeTarget(selector: string): void {
|
|
257
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
258
|
+
this.pendingUnwatchSelectors = this.pendingUnwatchSelectors.filter(s => s !== selector);
|
|
259
|
+
if (this.comms?.ready) this.comms.send("decoration_resize", { action: "watch", selector });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
removeResizeTarget(selector: string): void {
|
|
263
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
264
|
+
if (this.comms?.ready) {
|
|
265
|
+
this.comms.send("decoration_resize", { action: "unwatch", selector });
|
|
266
|
+
} else if (!this.pendingUnwatchSelectors.includes(selector)) {
|
|
267
|
+
this.pendingUnwatchSelectors.push(selector);
|
|
268
|
+
}
|
|
239
269
|
}
|
|
240
270
|
|
|
241
271
|
private cachedPage: Page | undefined = undefined;
|
|
@@ -30,6 +30,7 @@ export class FXLFramePoolManager {
|
|
|
30
30
|
private readonly injector: Injector | null = null;
|
|
31
31
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
32
32
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
33
|
+
private resizeWatchSelectors: string[];
|
|
33
34
|
|
|
34
35
|
// NEW
|
|
35
36
|
private readonly bookElement: HTMLDivElement;
|
|
@@ -55,6 +56,7 @@ export class FXLFramePoolManager {
|
|
|
55
56
|
injector?: Injector | null,
|
|
56
57
|
contentProtectionConfig?: IContentProtectionConfig,
|
|
57
58
|
keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig,
|
|
59
|
+
resizeWatchSelectors: string[] = [],
|
|
58
60
|
) {
|
|
59
61
|
this.container = container;
|
|
60
62
|
this.positions = positions;
|
|
@@ -62,6 +64,7 @@ export class FXLFramePoolManager {
|
|
|
62
64
|
this.injector = injector ?? null;
|
|
63
65
|
this.contentProtectionConfig = contentProtectionConfig || {};
|
|
64
66
|
this.keyboardPeripheralsConfig = keyboardPeripheralsConfig || [];
|
|
67
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
65
68
|
this.spreadPresentation = pub.metadata.otherMetadata?.spread || Spread.auto;
|
|
66
69
|
|
|
67
70
|
if(this.pub.metadata.effectiveReadingProgression !== ReadingProgression.rtl && this.pub.metadata.effectiveReadingProgression !== ReadingProgression.ltr)
|
|
@@ -88,7 +91,7 @@ export class FXLFramePoolManager {
|
|
|
88
91
|
|
|
89
92
|
this.pub.readingOrder.items.forEach((link) => {
|
|
90
93
|
// Create <iframe>
|
|
91
|
-
const fm = new FXLFrameManager(this.peripherals, this.pub.metadata.effectiveReadingProgression, link.href, this.contentProtectionConfig, this.keyboardPeripheralsConfig);
|
|
94
|
+
const fm = new FXLFrameManager(this.peripherals, this.pub.metadata.effectiveReadingProgression, link.href, this.contentProtectionConfig, this.keyboardPeripheralsConfig, this.resizeWatchSelectors);
|
|
92
95
|
this.spineElement.appendChild(fm.element);
|
|
93
96
|
|
|
94
97
|
// this.pages.push(fm);
|
|
@@ -595,6 +598,16 @@ export class FXLFramePoolManager {
|
|
|
595
598
|
}
|
|
596
599
|
}
|
|
597
600
|
|
|
601
|
+
addResizeTarget(selector: string): void {
|
|
602
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
603
|
+
this.pool.forEach(f => f.addResizeTarget(selector));
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
removeResizeTarget(selector: string): void {
|
|
607
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
608
|
+
this.pool.forEach(f => f.removeResizeTarget(selector));
|
|
609
|
+
}
|
|
610
|
+
|
|
598
611
|
get currentFrames(): (FXLFrameManager | undefined)[] {
|
|
599
612
|
if(this.perPage < 2) {
|
|
600
613
|
const link = this.pub.readingOrder.items[this.currentSlide];
|
|
@@ -14,6 +14,8 @@ export class WebPubFrameManager {
|
|
|
14
14
|
private destroyed: boolean = false;
|
|
15
15
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
16
16
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
17
|
+
private resizeWatchSelectors: string[];
|
|
18
|
+
private pendingUnwatchSelectors: string[] = [];
|
|
17
19
|
private conditionBridge?: KeyboardConditionBridge;
|
|
18
20
|
private currModules: ModuleName[] = [];
|
|
19
21
|
|
|
@@ -21,7 +23,8 @@ export class WebPubFrameManager {
|
|
|
21
23
|
source: string,
|
|
22
24
|
contentProtectionConfig: IContentProtectionConfig = {},
|
|
23
25
|
keyboardPeripheralsConfig: IKeyboardPeripheralsConfig = [],
|
|
24
|
-
private readonly timelineFragmentIds: string[] = []
|
|
26
|
+
private readonly timelineFragmentIds: string[] = [],
|
|
27
|
+
resizeWatchSelectors: string[] = []
|
|
25
28
|
) {
|
|
26
29
|
this.frame = document.createElement("iframe");
|
|
27
30
|
this.frame.classList.add("readium-navigator-iframe");
|
|
@@ -38,6 +41,7 @@ export class WebPubFrameManager {
|
|
|
38
41
|
// Use the provided content protection config directly without overriding defaults
|
|
39
42
|
this.contentProtectionConfig = { ...contentProtectionConfig };
|
|
40
43
|
this.keyboardPeripheralsConfig = [...keyboardPeripheralsConfig];
|
|
44
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
async load(modules: ModuleName[] = []): Promise<Window> {
|
|
@@ -97,6 +101,32 @@ export class WebPubFrameManager {
|
|
|
97
101
|
if (this.contentProtectionConfig.protectPrinting?.disable) {
|
|
98
102
|
this.comms!.send("print_protection", this.contentProtectionConfig.protectPrinting);
|
|
99
103
|
}
|
|
104
|
+
|
|
105
|
+
// Send resize-watch targets
|
|
106
|
+
this.resizeWatchSelectors.forEach(selector => {
|
|
107
|
+
this.comms!.send("decoration_resize", { action: "watch", selector });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Flush unwatches that couldn't be sent while comms was halted
|
|
111
|
+
this.pendingUnwatchSelectors.forEach(selector => {
|
|
112
|
+
this.comms!.send("decoration_resize", { action: "unwatch", selector });
|
|
113
|
+
});
|
|
114
|
+
this.pendingUnwatchSelectors = [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
addResizeTarget(selector: string): void {
|
|
118
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
119
|
+
this.pendingUnwatchSelectors = this.pendingUnwatchSelectors.filter(s => s !== selector);
|
|
120
|
+
if (this.comms?.ready) this.comms.send("decoration_resize", { action: "watch", selector });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
removeResizeTarget(selector: string): void {
|
|
124
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
125
|
+
if (this.comms?.ready) {
|
|
126
|
+
this.comms.send("decoration_resize", { action: "unwatch", selector });
|
|
127
|
+
} else if (!this.pendingUnwatchSelectors.includes(selector)) {
|
|
128
|
+
this.pendingUnwatchSelectors.push(selector);
|
|
129
|
+
}
|
|
100
130
|
}
|
|
101
131
|
|
|
102
132
|
async destroy() {
|
|
@@ -17,6 +17,7 @@ export class WebPubFramePoolManager {
|
|
|
17
17
|
private readonly injector?: Injector | null = null;
|
|
18
18
|
private readonly contentProtectionConfig: IContentProtectionConfig;
|
|
19
19
|
private readonly keyboardPeripheralsConfig: IKeyboardPeripheralsConfig;
|
|
20
|
+
private resizeWatchSelectors: string[];
|
|
20
21
|
private readonly getFragmentIds: (href: string) => string[];
|
|
21
22
|
|
|
22
23
|
constructor(
|
|
@@ -25,7 +26,8 @@ export class WebPubFramePoolManager {
|
|
|
25
26
|
injector?: Injector | null,
|
|
26
27
|
contentProtectionConfig: IContentProtectionConfig = {},
|
|
27
28
|
keyboardPeripheralsConfig: IKeyboardPeripheralsConfig = [],
|
|
28
|
-
getFragmentIds?: (href: string) => string[]
|
|
29
|
+
getFragmentIds?: (href: string) => string[],
|
|
30
|
+
resizeWatchSelectors: string[] = []
|
|
29
31
|
) {
|
|
30
32
|
this.container = container;
|
|
31
33
|
this.currentCssProperties = cssProperties;
|
|
@@ -33,6 +35,20 @@ export class WebPubFramePoolManager {
|
|
|
33
35
|
this.contentProtectionConfig = contentProtectionConfig;
|
|
34
36
|
this.keyboardPeripheralsConfig = [...keyboardPeripheralsConfig];
|
|
35
37
|
this.getFragmentIds = getFragmentIds ?? (() => []);
|
|
38
|
+
this.resizeWatchSelectors = [...resizeWatchSelectors];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
addResizeTarget(selector: string): void {
|
|
42
|
+
if (!this.resizeWatchSelectors.includes(selector)) this.resizeWatchSelectors.push(selector);
|
|
43
|
+
// Forward to the whole pool, not just currentFrames: off-screen cached frames
|
|
44
|
+
// (preloaded within the pool's boundary window) must not keep stale state that
|
|
45
|
+
// resurfaces if they're shown again later without being recreated.
|
|
46
|
+
this.pool.forEach(f => f.addResizeTarget(selector));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
removeResizeTarget(selector: string): void {
|
|
50
|
+
this.resizeWatchSelectors = this.resizeWatchSelectors.filter(s => s !== selector);
|
|
51
|
+
this.pool.forEach(f => f.removeResizeTarget(selector));
|
|
36
52
|
}
|
|
37
53
|
|
|
38
54
|
async destroy() {
|
|
@@ -157,7 +173,7 @@ export class WebPubFramePoolManager {
|
|
|
157
173
|
this.blobs.set(href, blobURL);
|
|
158
174
|
}
|
|
159
175
|
|
|
160
|
-
const fm = new WebPubFrameManager(this.blobs.get(href)!, this.contentProtectionConfig, this.keyboardPeripheralsConfig, this.getFragmentIds(href));
|
|
176
|
+
const fm = new WebPubFrameManager(this.blobs.get(href)!, this.contentProtectionConfig, this.keyboardPeripheralsConfig, this.getFragmentIds(href), this.resizeWatchSelectors);
|
|
161
177
|
if(href !== newHref) await fm.hide();
|
|
162
178
|
this.container.appendChild(fm.iframe);
|
|
163
179
|
await fm.load(modules);
|
|
@@ -100,6 +100,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
|
|
|
100
100
|
private _decorationActivationState: Map<string, boolean> = new Map();
|
|
101
101
|
private _decorationHoverState: Map<string, boolean> = new Map();
|
|
102
102
|
private _decorationActivationConsumed = false;
|
|
103
|
+
private _decorationResizeSelectors: Set<string>;
|
|
103
104
|
|
|
104
105
|
private webViewport: VisualNavigatorViewport = {
|
|
105
106
|
readingOrder: [],
|
|
@@ -134,6 +135,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
|
|
|
134
135
|
// Initialize content protection with provided config or default values
|
|
135
136
|
this._contentProtection = configuration.contentProtection || {};
|
|
136
137
|
this._decoratorConfig = configuration.decoratorConfig || {};
|
|
138
|
+
this._decorationResizeSelectors = new Set(this._decoratorConfig.resizeWatchSelectors ?? []);
|
|
137
139
|
|
|
138
140
|
// Merge keyboard peripherals
|
|
139
141
|
this._keyboardPeripherals = this.mergeKeyboardPeripherals(
|
|
@@ -200,7 +202,8 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
|
|
|
200
202
|
(href) => this.pub.timeline.segmentsForHref(href)
|
|
201
203
|
.flatMap(item => item.references)
|
|
202
204
|
.map(ref => { const h = ref.indexOf('#'); return h >= 0 ? ref.slice(h + 1) : ''; })
|
|
203
|
-
.filter(Boolean)
|
|
205
|
+
.filter(Boolean),
|
|
206
|
+
[...this._decorationResizeSelectors]
|
|
204
207
|
);
|
|
205
208
|
|
|
206
209
|
await this.apply();
|
|
@@ -467,6 +470,7 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
|
|
|
467
470
|
this._decorationHoveredDecorations.clear();
|
|
468
471
|
this._decorationActivationState.clear();
|
|
469
472
|
this._decorationHoverState.clear();
|
|
473
|
+
this._decorationResizeSelectors.clear();
|
|
470
474
|
}
|
|
471
475
|
|
|
472
476
|
// DecorableNavigator
|
|
@@ -520,6 +524,21 @@ export class WebPubNavigator extends VisualNavigator implements Configurable<Web
|
|
|
520
524
|
if (frame?.msg) frame.msg.send("decoration_hoverable", { group, hoverable });
|
|
521
525
|
}
|
|
522
526
|
|
|
527
|
+
// Watches an element within the current content document for resize, so decoration
|
|
528
|
+
// overlays relay out when it resizes even if the resource's own document size doesn't
|
|
529
|
+
// change. Forwarded to framePool the same way contentProtectionConfig/
|
|
530
|
+
// keyboardPeripheralsConfig are — applied on every frame show(), not replayed
|
|
531
|
+
// reactively off decoration state.
|
|
532
|
+
public addDecorationResizeTarget(selector: string): void {
|
|
533
|
+
this._decorationResizeSelectors.add(selector);
|
|
534
|
+
this.framePool?.addResizeTarget(selector);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
public removeDecorationResizeTarget(selector: string): void {
|
|
538
|
+
this._decorationResizeSelectors.delete(selector);
|
|
539
|
+
this.framePool?.removeResizeTarget(selector);
|
|
540
|
+
}
|
|
541
|
+
|
|
523
542
|
public applyDecorations(decorations: Decoration[], group: string): void {
|
|
524
543
|
const previous = this._decorations.get(group) ?? [];
|
|
525
544
|
const prevById = new Map(previous.map(d => [d.id, d]));
|
|
@@ -18,4 +18,12 @@ export interface DecorableNavigator {
|
|
|
18
18
|
registerDecorationObserver(group: string, observer: DecorationObserver): void;
|
|
19
19
|
/** Unregisters a previously registered observer from all groups. */
|
|
20
20
|
unregisterDecorationObserver(observer: DecorationObserver): void;
|
|
21
|
+
/**
|
|
22
|
+
* Watches an element within the current content document for resize, so decoration
|
|
23
|
+
* overlays relay out when it resizes even if the resource's own document size doesn't
|
|
24
|
+
* change (e.g. a sidebar collapsing and the reading pane reflowing inside it).
|
|
25
|
+
*/
|
|
26
|
+
addDecorationResizeTarget(selector: string): void;
|
|
27
|
+
/** Stops watching an element previously registered with addDecorationResizeTarget. */
|
|
28
|
+
removeDecorationResizeTarget(selector: string): void;
|
|
21
29
|
}
|
|
@@ -75,6 +75,7 @@ export declare class EpubNavigator extends VisualNavigator implements Configurab
|
|
|
75
75
|
private _decorationActivationState;
|
|
76
76
|
private _decorationHoverState;
|
|
77
77
|
private _decorationActivationConsumed;
|
|
78
|
+
private _decorationResizeSelectors;
|
|
78
79
|
private reflowViewport;
|
|
79
80
|
constructor(container: HTMLElement, pub: Publication, listeners: EpubNavigatorListeners, positions?: Locator[], initialPosition?: Locator | undefined, configuration?: EpubNavigatorConfiguration);
|
|
80
81
|
static determineLayout(pub: Publication, scroll?: boolean): Layout;
|
|
@@ -114,6 +115,8 @@ export declare class EpubNavigator extends VisualNavigator implements Configurab
|
|
|
114
115
|
unregisterDecorationObserver(observer: DecorationObserver): void;
|
|
115
116
|
private _sendDecorationActivationToFrames;
|
|
116
117
|
private _sendDecorationHoverToFrames;
|
|
118
|
+
addDecorationResizeTarget(selector: string): void;
|
|
119
|
+
removeDecorationResizeTarget(selector: string): void;
|
|
117
120
|
applyDecorations(decorations: Decoration[], group: string): void;
|
|
118
121
|
private _sendDecorationOps;
|
|
119
122
|
private _reapplyDecorationsToFrame;
|
|
@@ -11,11 +11,15 @@ export declare class FrameManager {
|
|
|
11
11
|
private destroyed;
|
|
12
12
|
private readonly contentProtectionConfig;
|
|
13
13
|
private readonly keyboardPeripheralsConfig;
|
|
14
|
+
private resizeWatchSelectors;
|
|
15
|
+
private pendingUnwatchSelectors;
|
|
14
16
|
private conditionBridge?;
|
|
15
17
|
private currModules;
|
|
16
|
-
constructor(source: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, timelineFragmentIds?: string[]);
|
|
18
|
+
constructor(source: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, timelineFragmentIds?: string[], resizeWatchSelectors?: string[]);
|
|
17
19
|
load(modules: ModuleName[]): Promise<Window>;
|
|
18
20
|
private applyContentProtection;
|
|
21
|
+
addResizeTarget(selector: string): void;
|
|
22
|
+
removeResizeTarget(selector: string): void;
|
|
19
23
|
destroy(): Promise<void>;
|
|
20
24
|
hide(): Promise<void>;
|
|
21
25
|
show(atProgress?: number): Promise<void>;
|
|
@@ -16,10 +16,13 @@ export declare class FramePoolManager {
|
|
|
16
16
|
private readonly injector;
|
|
17
17
|
private readonly contentProtectionConfig;
|
|
18
18
|
private readonly keyboardPeripheralsConfig;
|
|
19
|
+
private resizeWatchSelectors;
|
|
19
20
|
private readonly getFragmentIds;
|
|
20
21
|
constructor(container: HTMLElement, positions: Locator[], cssProperties?: {
|
|
21
22
|
[key: string]: string;
|
|
22
|
-
}, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, getFragmentIds?: (href: string) => string[]);
|
|
23
|
+
}, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, getFragmentIds?: (href: string) => string[], resizeWatchSelectors?: string[]);
|
|
24
|
+
addResizeTarget(selector: string): void;
|
|
25
|
+
removeResizeTarget(selector: string): void;
|
|
23
26
|
destroy(): Promise<void>;
|
|
24
27
|
update(pub: Publication, locator: Locator, modules: ModuleName[], force?: boolean): Promise<void>;
|
|
25
28
|
setCSSProperties(properties: {
|
|
@@ -11,13 +11,15 @@ export declare class FXLFrameManager {
|
|
|
11
11
|
private readonly peripherals;
|
|
12
12
|
private readonly contentProtectionConfig;
|
|
13
13
|
private readonly keyboardPeripheralsConfig;
|
|
14
|
+
private resizeWatchSelectors;
|
|
15
|
+
private pendingUnwatchSelectors;
|
|
14
16
|
private conditionBridge?;
|
|
15
17
|
private currModules;
|
|
16
18
|
wrapper: HTMLDivElement;
|
|
17
19
|
debugHref: string;
|
|
18
20
|
private loadPromise;
|
|
19
21
|
private showPromise;
|
|
20
|
-
constructor(peripherals: FXLPeripherals, direction: ReadingProgression, debugHref: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig);
|
|
22
|
+
constructor(peripherals: FXLPeripherals, direction: ReadingProgression, debugHref: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, resizeWatchSelectors?: string[]);
|
|
21
23
|
load(modules: ModuleName[], source: string): Promise<Window>;
|
|
22
24
|
loadPageSize(): {
|
|
23
25
|
width: number;
|
|
@@ -29,6 +31,8 @@ export declare class FXLFrameManager {
|
|
|
29
31
|
deselect(): void;
|
|
30
32
|
unfocus(): Promise<void>;
|
|
31
33
|
private applyContentProtection;
|
|
34
|
+
addResizeTarget(selector: string): void;
|
|
35
|
+
removeResizeTarget(selector: string): void;
|
|
32
36
|
private cachedPage;
|
|
33
37
|
show(page: Page): Promise<void>;
|
|
34
38
|
activate(): Promise<void>;
|
|
@@ -18,6 +18,7 @@ export declare class FXLFramePoolManager {
|
|
|
18
18
|
private readonly injector;
|
|
19
19
|
private readonly contentProtectionConfig;
|
|
20
20
|
private readonly keyboardPeripheralsConfig;
|
|
21
|
+
private resizeWatchSelectors;
|
|
21
22
|
private readonly bookElement;
|
|
22
23
|
readonly spineElement: HTMLDivElement;
|
|
23
24
|
private readonly pub;
|
|
@@ -32,7 +33,7 @@ export declare class FXLFramePoolManager {
|
|
|
32
33
|
private containerHeightCached;
|
|
33
34
|
private resizeTimeout;
|
|
34
35
|
readonly peripherals: FXLPeripherals;
|
|
35
|
-
constructor(container: HTMLElement, positions: Locator[], pub: Publication, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig);
|
|
36
|
+
constructor(container: HTMLElement, positions: Locator[], pub: Publication, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, resizeWatchSelectors?: string[]);
|
|
36
37
|
private _listener;
|
|
37
38
|
set listener(listener: FrameCommsListener);
|
|
38
39
|
get listener(): FrameCommsListener;
|
|
@@ -89,6 +90,8 @@ export declare class FXLFramePoolManager {
|
|
|
89
90
|
waitForItem(href: string): Promise<void>;
|
|
90
91
|
cancelShowing(href: string): Promise<void>;
|
|
91
92
|
update(pub: Publication, locator: Locator, modules: ModuleName[], _force?: boolean): Promise<void>;
|
|
93
|
+
addResizeTarget(selector: string): void;
|
|
94
|
+
removeResizeTarget(selector: string): void;
|
|
92
95
|
get currentFrames(): (FXLFrameManager | undefined)[];
|
|
93
96
|
get currentBounds(): DOMRect;
|
|
94
97
|
get viewport(): VisualNavigatorViewport;
|
|
@@ -11,11 +11,15 @@ export declare class WebPubFrameManager {
|
|
|
11
11
|
private destroyed;
|
|
12
12
|
private readonly contentProtectionConfig;
|
|
13
13
|
private readonly keyboardPeripheralsConfig;
|
|
14
|
+
private resizeWatchSelectors;
|
|
15
|
+
private pendingUnwatchSelectors;
|
|
14
16
|
private conditionBridge?;
|
|
15
17
|
private currModules;
|
|
16
|
-
constructor(source: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, timelineFragmentIds?: string[]);
|
|
18
|
+
constructor(source: string, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, timelineFragmentIds?: string[], resizeWatchSelectors?: string[]);
|
|
17
19
|
load(modules?: ModuleName[]): Promise<Window>;
|
|
18
20
|
private applyContentProtection;
|
|
21
|
+
addResizeTarget(selector: string): void;
|
|
22
|
+
removeResizeTarget(selector: string): void;
|
|
19
23
|
destroy(): Promise<void>;
|
|
20
24
|
hide(): Promise<void>;
|
|
21
25
|
show(atProgress?: number): Promise<void>;
|
|
@@ -15,10 +15,13 @@ export declare class WebPubFramePoolManager {
|
|
|
15
15
|
private readonly injector?;
|
|
16
16
|
private readonly contentProtectionConfig;
|
|
17
17
|
private readonly keyboardPeripheralsConfig;
|
|
18
|
+
private resizeWatchSelectors;
|
|
18
19
|
private readonly getFragmentIds;
|
|
19
20
|
constructor(container: HTMLElement, cssProperties?: {
|
|
20
21
|
[key: string]: string;
|
|
21
|
-
}, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, getFragmentIds?: (href: string) => string[]);
|
|
22
|
+
}, injector?: Injector | null, contentProtectionConfig?: IContentProtectionConfig, keyboardPeripheralsConfig?: IKeyboardPeripheralsConfig, getFragmentIds?: (href: string) => string[], resizeWatchSelectors?: string[]);
|
|
23
|
+
addResizeTarget(selector: string): void;
|
|
24
|
+
removeResizeTarget(selector: string): void;
|
|
22
25
|
destroy(): Promise<void>;
|
|
23
26
|
update(pub: Publication, locator: Locator, modules: ModuleName[]): Promise<void>;
|
|
24
27
|
setCSSProperties(properties: {
|
|
@@ -65,6 +65,7 @@ export declare class WebPubNavigator extends VisualNavigator implements Configur
|
|
|
65
65
|
private _decorationActivationState;
|
|
66
66
|
private _decorationHoverState;
|
|
67
67
|
private _decorationActivationConsumed;
|
|
68
|
+
private _decorationResizeSelectors;
|
|
68
69
|
private webViewport;
|
|
69
70
|
constructor(container: HTMLElement, pub: Publication, listeners: WebPubNavigatorListeners, initialPosition?: Locator | undefined, configuration?: WebPubNavigatorConfiguration);
|
|
70
71
|
load(): Promise<void>;
|
|
@@ -91,6 +92,8 @@ export declare class WebPubNavigator extends VisualNavigator implements Configur
|
|
|
91
92
|
unregisterDecorationObserver(observer: DecorationObserver): void;
|
|
92
93
|
private _sendDecorationActivatable;
|
|
93
94
|
private _sendDecorationHoverable;
|
|
95
|
+
addDecorationResizeTarget(selector: string): void;
|
|
96
|
+
removeDecorationResizeTarget(selector: string): void;
|
|
94
97
|
applyDecorations(decorations: Decoration[], group: string): void;
|
|
95
98
|
private _sendDecorationOps;
|
|
96
99
|
private _reapplyDecorationsToCurrentFrame;
|