@readium/navigator-html-injectables 2.7.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,24 @@
1
- import{Locator as D}from"@readium/shared";import{Module as P}from"./Module.js";import{rangeFromLocator as N}from"../helpers/locator.js";import{getClientRectsNoOverlap as T,rectContainsPoint as $,getTextClientRects as U}from"../helpers/rect.js";import{getProperty as I}from"../helpers/css.js";import{sML as j,adjustColorForContrast as E,getContrastingTextColor as O,colorToRgba as M,isDarkColor as q}from"@readium/helpers";import{makeWritingContext as R}from"../helpers/document.js";import{sanitizeHTML as V}from"../helpers/sanitize.js";function z(S){switch(S){case c.Mask:return"rgba(255, 255, 255, 0.5)";case c.Highlight:case c.HighlightUnderline:return"#FFFF00";default:return"#FF0000"}}const c={Highlight:"highlight",HighlightUnderline:"highlightUnderline",Underline:"underline",Strikethrough:"strikethrough",Outline:"outline",TextColor:"textColor",Mask:"mask",Template:"template"};var G=(S=>(S.Wrap="wrap",S.Viewport="viewport",S.Bounds="bounds",S.Page="page",S))(G||{}),X=(S=>(S.Boxes="boxes",S.Bounds="bounds",S))(X||{});const Z=()=>"Highlight"in window,F=["IMG","IMAGE","AUDIO","VIDEO","SVG"];class Y{constructor(e,t,i,o){this.wnd=e,this.comms=t,this.id=i,this.name=o,this.items=[],this.lastItemId=0,this.container=void 0,this._activatable=!1,this._hoverable=!1,this.hoveredItem=void 0,this.experimentalHighlights=!1,this._tintSubKeys=new Map,this._subKeyCounter=0,this.maskSvg=void 0,this.shadowHost=void 0,this.shadowRoot=void 0,this.currentRender=0,Z()&&(this.experimentalHighlights=!0,this.notTextFlag=new Map),this.activationHandler=this.handleActivation.bind(this),this.wnd.document.addEventListener("pointerup",this.activationHandler),this.hoverHandler=this.handleHover.bind(this),this.wnd.document.addEventListener("pointermove",this.hoverHandler)}get activatable(){return this._activatable}set activatable(e){this._activatable=e}get hoverable(){return this._hoverable}get hasOverlayItems(){return!this.experimentalHighlights||(this.notTextFlag?.size??0)>0}set hoverable(e){if(this._hoverable=e,!e&&this.hoveredItem){const t=this.hoveredItem.range.getBoundingClientRect(),i=this.wnd.devicePixelRatio;this.comms.send("decoration_pointer_leave",{decorationId:this.hoveredItem.decoration.id,group:this.name,rect:{top:t.top*i,left:t.left*i,width:t.width*i,height:t.height*i}}),this.hoveredItem=void 0}}add(e){const t=`${this.id}-${this.lastItemId++}`,i=N(this.wnd.document,e.locator);if(!i){this.comms.log("Can't locate DOM range for decoration",e);return}const o=i.commonAncestorContainer;if(o.nodeType!==Node.TEXT_NODE&&this.experimentalHighlights&&(F.includes(o.nodeName.toUpperCase())&&this.notTextFlag?.set(t,!0),i.cloneContents().querySelector(F.join(", ").toLowerCase())&&this.notTextFlag?.set(t,!0),(o.textContent?.trim()||"").length===0&&this.notTextFlag?.set(t,!0)),this.experimentalHighlights&&!this.notTextFlag?.has(t)){const n=r=>{for(;r&&r.nodeType===Node.ELEMENT_NODE;){if(r.namespaceURI?.includes("svg"))return!0;r=r.parentNode}return!1};(n(i.startContainer)||n(i.endContainer))&&this.notTextFlag?.set(t,!0)}if(this.experimentalHighlights){const{type:n}=e.style,{layout:r,width:p,expand:a}=e.style;n!==c.TextColor&&(n===c.Outline||n===c.Template||n===c.Mask||r!==void 0&&r!=="boxes"||p!==void 0&&p!=="wrap"||a)&&this.notTextFlag?.set(t,!0)}const s={decoration:e,id:t,range:i,hitRects:[],clickableElements:void 0,container:void 0};this.items.push(s),this.layout(s),s.hitRects=this.clientRectsToDocCoords(T(s.range,!1,!1,(s.decoration.style.expand??0)+this.hitGap())),this.renderLayout([s])}remove(e){const t=this.items.findIndex(s=>s.decoration.id===e);if(t<0)return;const i=this.items[t],o=i.decoration.style?.type===c.Mask;if(this.items.splice(t,1),i.clickableElements=void 0,i.container&&(i.container.remove(),i.container=void 0),this.experimentalHighlights&&!this.notTextFlag?.has(i.id)&&i.highlightSubKey){const s=this.wnd.CSS.highlights;s.get(i.highlightSubKey)?.delete(i.range),this.items.some(r=>r.highlightSubKey===i.highlightSubKey)||s.delete(i.highlightSubKey);const n=this.wnd.document.getElementById(`${this.id}-style`);n&&this._rebuildHighlightStylesheet(n)}this.notTextFlag?.delete(i.id),this.hoveredItem===i&&(this.hoveredItem=void 0),o&&this.updateSharedMask()}update(e){this.remove(e.id),this.add(e)}clear(){this.clearContainer(),this.items.length=0,this.notTextFlag?.clear(),this.hoveredItem=void 0,this.maskSvg&&(this.maskSvg.remove(),this.maskSvg=void 0),this.shadowHost&&(this.shadowHost.remove(),this.shadowHost=void 0,this.shadowRoot=void 0)}destroy(){this.clear(),this.wnd.document.removeEventListener("pointerup",this.activationHandler),this.wnd.document.removeEventListener("pointermove",this.hoverHandler)}clientRectsToDocCoords(e,t=R(this.wnd)){const i=t.xDocOffset,o=t.yDocOffset;return i===0&&o===0?e:e.map(s=>({left:s.left+i,top:s.top+o,right:s.right+i,bottom:s.bottom+o,width:s.width,height:s.height}))}pointerToDocCoords(e){const t=R(this.wnd);return{docX:e.clientX+t.xDocOffset,docY:e.clientY+t.yDocOffset}}effectiveZoom(){if(!j.UA.Blink)return 1;const e=parseFloat(this.wnd.getComputedStyle(this.wnd.document.documentElement).zoom),t=parseFloat(this.wnd.getComputedStyle(this.wnd.document.body).zoom);return(e||1)*(t||1)}hitGap(){return 2*this.effectiveZoom()}handleActivation(e){if(!this._activatable)return;const{docX:t,docY:i}=this.pointerToDocCoords(e),o=this.wnd.devicePixelRatio;for(const s of this.items){let n;if(s.decoration.style.type===c.Template)for(const r of s.clickableElements??[]){const p=r.getBoundingClientRect();if($(p,e.clientX,e.clientY,0)){n=p;break}}else for(const r of s.hitRects)if($(r,t,i,0)){n=s.range.getBoundingClientRect();break}if(n){this.comms.send("decoration_activated",{decorationId:s.decoration.id,group:this.name,rect:{top:n.top*o,left:n.left*o,width:n.width*o,height:n.height*o},point:{x:e.clientX*o,y:e.clientY*o}});return}}}handleHover(e){if(!this._hoverable)return;const{docX:t,docY:i}=this.pointerToDocCoords(e),o=this.wnd.devicePixelRatio;let s,n;for(const r of this.items){if(r.decoration.style.type===c.Template)for(const p of r.clickableElements??[]){const a=p.getBoundingClientRect();if($(a,e.clientX,e.clientY,0)){s=r,n=a;break}}else for(const p of r.hitRects)if($(p,t,i,0)){s=r,n=r.range.getBoundingClientRect();break}if(s)break}if(s!==this.hoveredItem){if(this.hoveredItem){const p=this.hoveredItem.range.commonAncestorContainer.isConnected?this.hoveredItem.range.getBoundingClientRect():null;this.comms.send("decoration_pointer_leave",{decorationId:this.hoveredItem.decoration.id,group:this.name,rect:p?{top:p.top*o,left:p.left*o,width:p.width*o,height:p.height*o}:void 0,point:{x:e.clientX*o,y:e.clientY*o}})}this.hoveredItem=s,s&&n&&this.comms.send("decoration_pointer_enter",{decorationId:s.decoration.id,group:this.name,rect:{top:n.top*o,left:n.left*o,width:n.width*o,height:n.height*o},point:{x:e.clientX*o,y:e.clientY*o}})}}requestLayout(){this.wnd.cancelAnimationFrame(this.currentRender),this.clearContainer(),this.wnd.document.fonts.ready.then(()=>{this.currentRender=this.wnd.requestAnimationFrame(()=>{this.items.forEach(e=>{this.layout(e),e.hitRects=this.clientRectsToDocCoords(T(e.range,!1,!1,(e.decoration.style.expand??0)+this.hitGap()))}),this.renderLayout(this.items),this.updateSharedMask()})})}repositionOverlays(){let e=!1;const t=[],i=R(this.wnd);this.items.forEach(o=>{if(!(this.experimentalHighlights&&!this.notTextFlag?.has(o.id))){if(o.decoration.style?.type===c.Mask){e=!0;return}this.repositionItem(o,i)||(o.container?.remove(),this.layout(o),t.push(o)),o.hitRects=this.clientRectsToDocCoords(T(o.range,!1,!1,(o.decoration.style.expand??0)+this.hitGap()),i)}}),t.length&&this.renderLayout(t),e&&this.updateSharedMask()}experimentalLayout(e){const t=this.requireContainer(!0),i=this.wnd.CSS.highlights,o=e.decoration.style,s=o.type??c.Highlight,n=o.tint??z(s),r=o.width,p=o.layout,a=this._getSubKey(s,n);e.highlightSubKey&&(i.get(e.highlightSubKey)?.delete(e.range),e.highlightSubKey!==a&&!this.items.some(f=>f!==e&&f.highlightSubKey===e.highlightSubKey)&&i.delete(e.highlightSubKey)),e.highlightSubKey=a;let g;i.has(a)?g=i.get(a):(g=new this.wnd.Highlight,i.set(a,g));const h=(d,f)=>this.wnd.document.caretPositionFromPoint?.(d,f)??null;if(s===c.TextColor&&(p==="bounds"||r==="bounds"||r==="page")){const d=R(this.wnd);if(d.isVertical)console.warn("Vertical writing detected: caretPositionFromPoint has known bugs, falling back to original range"),g.add(e.range);else{const f=e.range.getBoundingClientRect();let k,v;r==="page"?(k=Math.floor(d.inlineStart(f)/d.pageInlineSize)*d.pageInlineSize,v=d.pageInlineSize):(k=d.inlineStart(f),v=d.inlineSize(f));const y=h(k,d.blockStart(f)+1),w=h(k+v,d.blockStart(f)+d.blockSize(f)-1);if(y&&w){const C=this.wnd.document.createRange();C.setStart(y.offsetNode,y.offset),C.setEnd(w.offsetNode,w.offset),g.add(C),e.range=C}else g.add(e.range)}}else g.add(e.range);const l=this.getBackgroundColor(),b=o.enforceContrast!==!1?E(n,l):n;let m;switch(s){case c.Underline:m=`::highlight(${a}) {
1
+ import{Locator as K}from"@readium/shared";import{Module as N}from"./Module.js";import{rangeFromLocator as P}from"../helpers/locator.js";import{getClientRectsNoOverlap as H,rectContainsPoint as E,getTextClientRects as U}from"../helpers/rect.js";import{getProperty as I}from"../helpers/css.js";import{sML as j,adjustColorForContrast as T,getContrastingTextColor as O,colorToRgba as M,isDarkColor as q}from"@readium/helpers";import{makeWritingContext as z}from"../helpers/document.js";import{sanitizeHTML as V}from"../helpers/sanitize.js";function x(S){switch(S){case d.Mask:return"rgba(255, 255, 255, 0.5)";case d.Highlight:case d.HighlightUnderline:return"#FFFF00";default:return"#FF0000"}}const d={Highlight:"highlight",HighlightUnderline:"highlightUnderline",Underline:"underline",Strikethrough:"strikethrough",Outline:"outline",TextColor:"textColor",Mask:"mask",Template:"template"};var G=(S=>(S.Wrap="wrap",S.Viewport="viewport",S.Bounds="bounds",S.Page="page",S))(G||{}),X=(S=>(S.Boxes="boxes",S.Bounds="bounds",S))(X||{});const Z=()=>"Highlight"in window,F=["IMG","IMAGE","AUDIO","VIDEO","SVG"];class Y{constructor(e,t,i,o){this.wnd=e,this.comms=t,this.id=i,this.name=o,this.items=[],this.lastItemId=0,this.container=void 0,this._activatable=!1,this._hoverable=!1,this.hoveredItem=void 0,this.experimentalHighlights=!1,this._tintSubKeys=new Map,this._subKeyCounter=0,this.maskSvg=void 0,this.shadowHost=void 0,this.shadowRoot=void 0,this.currentRender=0,Z()&&(this.experimentalHighlights=!0,this.notTextFlag=new Map),this.activationHandler=this.handleActivation.bind(this),this.wnd.document.addEventListener("pointerup",this.activationHandler),this.hoverHandler=this.handleHover.bind(this),this.wnd.document.addEventListener("pointermove",this.hoverHandler)}get activatable(){return this._activatable}set activatable(e){this._activatable=e}get hoverable(){return this._hoverable}get hasOverlayItems(){return!this.experimentalHighlights||(this.notTextFlag?.size??0)>0}set hoverable(e){if(this._hoverable=e,!e&&this.hoveredItem){const t=this.hoveredItem.range.getBoundingClientRect(),i=this.wnd.devicePixelRatio;this.comms.send("decoration_pointer_leave",{decorationId:this.hoveredItem.decoration.id,group:this.name,rect:{top:t.top*i,left:t.left*i,width:t.width*i,height:t.height*i}}),this.hoveredItem=void 0}}add(e){const t=`${this.id}-${this.lastItemId++}`,i=P(this.wnd.document,e.locator);if(!i){this.comms.log("Can't locate DOM range for decoration",e);return}const o=i.commonAncestorContainer;if(o.nodeType!==Node.TEXT_NODE&&this.experimentalHighlights&&(F.includes(o.nodeName.toUpperCase())&&this.notTextFlag?.set(t,!0),i.cloneContents().querySelector(F.join(", ").toLowerCase())&&this.notTextFlag?.set(t,!0),(o.textContent?.trim()||"").length===0&&this.notTextFlag?.set(t,!0)),this.experimentalHighlights&&!this.notTextFlag?.has(t)){const n=r=>{for(;r&&r.nodeType===Node.ELEMENT_NODE;){if(r.namespaceURI?.includes("svg"))return!0;r=r.parentNode}return!1};(n(i.startContainer)||n(i.endContainer))&&this.notTextFlag?.set(t,!0)}if(this.experimentalHighlights){const{type:n}=e.style,{layout:r,width:p,expand:a}=e.style;n!==d.TextColor&&(n===d.Outline||n===d.Template||n===d.Mask||r!==void 0&&r!=="boxes"||p!==void 0&&p!=="wrap"||a)&&this.notTextFlag?.set(t,!0)}const s={decoration:e,id:t,range:i,hitRects:[],clickableElements:void 0,container:void 0};this.items.push(s),this.layout(s),s.hitRects=this.clientRectsToDocCoords(H(s.range,!1,!1,(s.decoration.style.expand??0)+this.hitGap())),this.renderLayout([s])}remove(e){const t=this.items.findIndex(s=>s.decoration.id===e);if(t<0)return;const i=this.items[t],o=i.decoration.style?.type===d.Mask;if(this.items.splice(t,1),i.clickableElements=void 0,i.container&&(i.container.remove(),i.container=void 0),this.experimentalHighlights&&!this.notTextFlag?.has(i.id)&&i.highlightSubKey){const s=this.wnd.CSS.highlights;s.get(i.highlightSubKey)?.delete(i.range),this.items.some(r=>r.highlightSubKey===i.highlightSubKey)||s.delete(i.highlightSubKey);const n=this.wnd.document.getElementById(`${this.id}-style`);n&&this._rebuildHighlightStylesheet(n)}this.notTextFlag?.delete(i.id),this.hoveredItem===i&&(this.hoveredItem=void 0),o&&this.updateSharedMask()}update(e){this.remove(e.id),this.add(e)}clear(){this.clearContainer(),this.items.length=0,this.notTextFlag?.clear(),this.hoveredItem=void 0,this.maskSvg&&(this.maskSvg.remove(),this.maskSvg=void 0),this.shadowHost&&(this.shadowHost.remove(),this.shadowHost=void 0,this.shadowRoot=void 0)}destroy(){this.clear(),this.wnd.document.removeEventListener("pointerup",this.activationHandler),this.wnd.document.removeEventListener("pointermove",this.hoverHandler)}clientRectsToDocCoords(e,t=z(this.wnd)){const i=t.xDocOffset,o=t.yDocOffset;return i===0&&o===0?e:e.map(s=>({left:s.left+i,top:s.top+o,right:s.right+i,bottom:s.bottom+o,width:s.width,height:s.height}))}pointerToDocCoords(e){const t=z(this.wnd);return{docX:e.clientX+t.xDocOffset,docY:e.clientY+t.yDocOffset}}effectiveZoom(){if(!j.UA.Blink)return 1;const e=parseFloat(this.wnd.getComputedStyle(this.wnd.document.documentElement).zoom),t=parseFloat(this.wnd.getComputedStyle(this.wnd.document.body).zoom);return(e||1)*(t||1)}hitGap(){return 2*this.effectiveZoom()}handleActivation(e){if(!this._activatable)return;const{docX:t,docY:i}=this.pointerToDocCoords(e),o=this.wnd.devicePixelRatio;for(const s of this.items){let n;if(s.decoration.style.type===d.Template)for(const r of s.clickableElements??[]){const p=r.getBoundingClientRect();if(E(p,e.clientX,e.clientY,0)){n=p;break}}else for(const r of s.hitRects)if(E(r,t,i,0)){n=s.range.getBoundingClientRect();break}if(n){this.comms.send("decoration_activated",{decorationId:s.decoration.id,group:this.name,rect:{top:n.top*o,left:n.left*o,width:n.width*o,height:n.height*o},point:{x:e.clientX*o,y:e.clientY*o}});return}}}handleHover(e){if(!this._hoverable)return;const{docX:t,docY:i}=this.pointerToDocCoords(e),o=this.wnd.devicePixelRatio;let s,n;for(const r of this.items){if(r.decoration.style.type===d.Template)for(const p of r.clickableElements??[]){const a=p.getBoundingClientRect();if(E(a,e.clientX,e.clientY,0)){s=r,n=a;break}}else for(const p of r.hitRects)if(E(p,t,i,0)){s=r,n=r.range.getBoundingClientRect();break}if(s)break}if(s!==this.hoveredItem){if(this.hoveredItem){const p=this.hoveredItem.range.commonAncestorContainer.isConnected?this.hoveredItem.range.getBoundingClientRect():null;this.comms.send("decoration_pointer_leave",{decorationId:this.hoveredItem.decoration.id,group:this.name,rect:p?{top:p.top*o,left:p.left*o,width:p.width*o,height:p.height*o}:void 0,point:{x:e.clientX*o,y:e.clientY*o}})}this.hoveredItem=s,s&&n&&this.comms.send("decoration_pointer_enter",{decorationId:s.decoration.id,group:this.name,rect:{top:n.top*o,left:n.left*o,width:n.width*o,height:n.height*o},point:{x:e.clientX*o,y:e.clientY*o}})}}requestLayout(){this.wnd.cancelAnimationFrame(this.currentRender),this.clearContainer(),this.wnd.document.fonts.ready.then(()=>{this.currentRender=this.wnd.requestAnimationFrame(()=>{this.items.forEach(e=>{this.layout(e),e.hitRects=this.clientRectsToDocCoords(H(e.range,!1,!1,(e.decoration.style.expand??0)+this.hitGap()))}),this.renderLayout(this.items),this.updateSharedMask()})})}repositionOverlays(){let e=!1;const t=[],i=z(this.wnd);this.items.forEach(o=>{if(!(this.experimentalHighlights&&!this.notTextFlag?.has(o.id))){if(o.decoration.style?.type===d.Mask){e=!0;return}this.repositionItem(o,i)||(o.container?.remove(),this.layout(o),t.push(o)),o.hitRects=this.clientRectsToDocCoords(H(o.range,!1,!1,(o.decoration.style.expand??0)+this.hitGap()),i)}}),t.length&&this.renderLayout(t),e&&this.updateSharedMask()}experimentalLayout(e){const t=this.requireContainer(!0),i=this.wnd.CSS.highlights,o=e.decoration.style,s=o.type??d.Highlight,n=o.tint??x(s),r=o.width,p=o.layout,a=this._getSubKey(s,n);e.highlightSubKey&&(i.get(e.highlightSubKey)?.delete(e.range),e.highlightSubKey!==a&&!this.items.some(f=>f!==e&&f.highlightSubKey===e.highlightSubKey)&&i.delete(e.highlightSubKey)),e.highlightSubKey=a;let g;i.has(a)?g=i.get(a):(g=new this.wnd.Highlight,i.set(a,g));const h=(c,f)=>this.wnd.document.caretPositionFromPoint?.(c,f)??null;if(s===d.TextColor&&(p==="bounds"||r==="bounds"||r==="page")){const c=z(this.wnd);if(c.isVertical)console.warn("Vertical writing detected: caretPositionFromPoint has known bugs, falling back to original range"),g.add(e.range);else{const f=e.range.getBoundingClientRect();let k,y;r==="page"?(k=Math.floor(c.inlineStart(f)/c.pageInlineSize)*c.pageInlineSize,y=c.pageInlineSize):(k=c.inlineStart(f),y=c.inlineSize(f));const v=h(k,c.blockStart(f)+1),w=h(k+y,c.blockStart(f)+c.blockSize(f)-1);if(v&&w){const C=this.wnd.document.createRange();C.setStart(v.offsetNode,v.offset),C.setEnd(w.offsetNode,w.offset),g.add(C),e.range=C}else g.add(e.range)}}else g.add(e.range);const l=this.getBackgroundColor(),b=o.enforceContrast!==!1?T(n,l):n;let m;switch(s){case d.Underline:m=`::highlight(${a}) {
2
2
  text-decoration: underline;
3
3
  text-decoration-color: ${b};
4
4
  text-decoration-thickness: 0.1em;
5
- }`;break;case c.Strikethrough:m=`::highlight(${a}) {
5
+ }`;break;case d.Strikethrough:m=`::highlight(${a}) {
6
6
  text-decoration: line-through;
7
7
  text-decoration-color: ${b};
8
8
  text-decoration-thickness: 0.1em;
9
- }`;break;case c.Outline:m=`::highlight(${a}) {
9
+ }`;break;case d.Outline:m=`::highlight(${a}) {
10
10
  outline: 2px solid ${b};
11
11
  outline-offset: 1px;
12
- }`;break;case c.TextColor:m=`::highlight(${a}) {
12
+ }`;break;case d.TextColor:m=`::highlight(${a}) {
13
13
  color: ${b};
14
- }`;break;case c.HighlightUnderline:{const{r:d,g:f,b:k}=M(b),v=`rgba(${d}, ${f}, ${k}, 0.3)`;m=`::highlight(${a}) {
14
+ }`;break;case d.HighlightUnderline:{const{r:c,g:f,b:k}=M(b),y=`rgba(${c}, ${f}, ${k}, 0.3)`;m=`::highlight(${a}) {
15
15
  color: ${O(b,l)};
16
- background-color: ${v};
16
+ background-color: ${y};
17
17
  text-decoration: underline;
18
18
  text-decoration-color: ${b};
19
19
  text-decoration-thickness: 0.1em;
20
- }`;break}case c.Highlight:default:m=`::highlight(${a}) {
20
+ }`;break}case d.Highlight:default:m=`::highlight(${a}) {
21
21
  color: ${O(b,l)};
22
22
  background-color: ${b};
23
23
  }`}e.highlightCSS=m,this._rebuildHighlightStylesheet(t)}_getSubKey(e,t){const i=`${e}::${t}`;let o=this._tintSubKeys.get(i);return o||(o=`${this.id}--${this._subKeyCounter++}`,this._tintSubKeys.set(i,o)),o}_rebuildHighlightStylesheet(e){const t=new Set,i=[];for(const o of this.items)o.highlightSubKey&&o.highlightCSS&&!t.has(o.highlightSubKey)&&(t.add(o.highlightSubKey),i.push(o.highlightCSS));e.innerHTML=i.join(`
24
- `)}positionElement(e,t,i,o,s,n,r=0){const p=e.decoration?.style?.width,a=s;switch(p){case"viewport":{const g=Math.floor(t.inlineStart(a)/t.viewportInlineSize)*t.viewportInlineSize;t.applyPosition(o,g+t.inlineScrollOffset+r,t.blockStart(a)+t.blockScrollOffset,t.viewportInlineSize-2*r,t.blockSize(a),i);break}case"page":{const g=Math.floor(t.inlineStart(a)/t.pageInlineSize)*t.pageInlineSize;t.applyPosition(o,g+t.inlineScrollOffset+r,t.blockStart(a)+t.blockScrollOffset,t.pageInlineSize-2*r,t.blockSize(a),i);break}case"bounds":{t.applyPosition(o,t.inlineStart(n)+t.inlineScrollOffset,t.blockStart(a)+t.blockScrollOffset,t.inlineSize(n),t.blockSize(a),i);break}default:t.applyPosition(o,t.inlineStart(a)+t.inlineScrollOffset,t.blockStart(a)+t.blockScrollOffset,t.inlineSize(a),t.blockSize(a),i)}}computeOverlayRects(e,t,i,o){if(e.decoration?.style?.layout==="bounds")return[o?{left:i.left-o,right:i.right+o,top:i.top-o,bottom:i.bottom+o,width:i.width+o*2,height:i.height+o*2}:i];const n=e.decoration.style.type,r=n===c.Underline||n===c.Strikethrough,p=n===c.Strikethrough,a=r?U(e.range,["rt","rp"]):e.range;let g=T(a,!0,t.isVertical,r?0:o);return g=g.sort((h,l)=>t.isVertical?(t.isVertLR?1:-1)*(h.left-l.left):h.top-l.top),g.map(h=>{let l=h;if(p){const u=t.blockSize(h)*.1,m=t.blockStart(h)+t.blockSize(h)/2-u/2;l=t.isVertical?{left:m,right:m+u,top:h.top,bottom:h.bottom,width:u,height:h.height}:{top:m,bottom:m+u,left:h.left,right:h.right,height:u,width:h.width}}return o&&r&&(l=t.isVertical?{...l,top:l.top-o,bottom:l.bottom+o,height:l.height+o*2}:{...l,left:l.left-o,right:l.right+o,width:l.width+o*2}),l})}repositionItem(e,t){if(!e.container)return!0;const i=e.decoration.style;if(i.type!==c.Template){const g=i.type??c.Highlight;if(g===c.TextColor||g===c.Mask)return!0}const o=1/this.effectiveZoom(),s=i.expand??0,n=e.range.getBoundingClientRect(),r=(()=>{if(i.type!==c.Outline)return 0;const g=i.width;return g==="page"||g==="viewport"?3:0})(),p=this.computeOverlayRects(e,t,n,s),a=Array.from(e.container.children);return a.length!==p.length?!1:(a.forEach((g,h)=>this.positionElement(e,t,o,g,p[h],n,r)),!0)}layout(e){if(this.experimentalHighlights&&!this.notTextFlag?.has(e.id))return this.experimentalLayout(e);const t=this.wnd.document.createElement("div");t.setAttribute("id",e.id),t.dataset.highlightId=e.decoration.id,t.style.setProperty("pointer-events","none");const i=R(this.wnd),o=1/this.effectiveZoom(),s=e.decoration.style.expand??0,n=e.range.getBoundingClientRect(),r=e.decoration.style,p=(()=>{if(r.type!==c.Outline)return 0;const h=r.width;return h==="page"||h==="viewport"?3:0})();let a;if(r.type===c.Template){r.stylesheet&&this.injectCustomStylesheet(r.stylesheet);const h=V(this.wnd,r.element);if(!h){e.container=t,e.clickableElements=[];return}h.style.setProperty("pointer-events","none"),a=h}else{const h=r,l=h.type??c.Highlight,u=h.tint??z(l);if(l===c.TextColor){e.container=t,e.clickableElements=[];return}if(l===c.Mask){e.container=t,e.clickableElements=[],this.updateSharedMask();return}const b=this.getCurrentDarkMode(),m=this.getBackgroundColor(),d=h.enforceContrast!==!1,f=(()=>{switch(l){case c.Underline:{const y=d?E(u,m):u,w=h.layout==="bounds",[C,x]=i.isVertical?["border-right","border-left"]:["border-bottom","border-top"];return[w?`${x}: 0.1em solid ${y} !important`:null,`${C}: 0.1em solid ${y} !important`,"background-color: transparent !important","box-sizing: border-box !important"].filter(Boolean).join("; ")}case c.Strikethrough:{const y=d?E(u,m):u;return h.layout==="bounds"?[`background: repeating-linear-gradient(-45deg, transparent, transparent 19px, ${y} 19px, ${y} 20px) !important`,"background-color: transparent !important","box-sizing: border-box !important"].join("; "):[`background-color: ${y} !important`,"box-sizing: border-box !important"].join("; ")}case c.Outline:return[`outline: 2px solid ${d?E(u,m):u} !important`,"outline-offset: 1px !important","background-color: transparent !important","box-sizing: border-box !important"].join("; ");case c.HighlightUnderline:{const y=d?E(u,m):u,{r:w,g:C,b:x}=M(y),_=`rgba(${w}, ${C}, ${x}, 0.3)`,B=h.layout==="bounds",[L,K]=i.isVertical?["border-right","border-left"]:["border-bottom","border-top"];return[`background-color: ${_} !important`,B?`${K}: 0.1em solid ${y} !important`:null,`${L}: 0.1em solid ${y} !important`,"box-sizing: border-box !important"].filter(Boolean).join("; ")}case c.Highlight:default:return[`background-color: ${d?E(u,m):u} !important`,`mix-blend-mode: ${b?"exclusion":"multiply"} !important`,"opacity: 1 !important","box-sizing: border-box !important","transform: translateZ(0) !important"].join("; ")}})(),k=this.wnd.document.createElement("template");k.innerHTML=`<div data-readium="true" class="readium-${l}" style="${f}"></div>`.trim(),a=k.content.firstElementChild}const g=this.computeOverlayRects(e,i,n,s);for(const h of g){const l=a.cloneNode(!0);l.style.setProperty("pointer-events","none"),this.positionElement(e,i,o,l,h,n,p),t.append(l)}e.container=t,e.clickableElements=Array.from(t.querySelectorAll("[data-activable='1']")),e.clickableElements.length||(e.clickableElements=Array.from(t.children))}renderLayout(e){this.wnd.cancelAnimationFrame(this.currentRender),this.currentRender=this.wnd.requestAnimationFrame(()=>{if(e=e.filter(i=>!this.experimentalHighlights||!!this.notTextFlag?.has(i.id)),!e||e.length===0)return;this.requireContainer().append(...e.map(i=>i.container).filter(i=>!!i))})}requireContainer(e=!1){if(e){let t;return this.wnd.document.getElementById(`${this.id}-style`)?t=this.wnd.document.getElementById(`${this.id}-style`):(t=this.wnd.document.createElement("style"),t.dataset.readium="true",t.id=`${this.id}-style`,this.wnd.document.head.appendChild(t)),t}return this.container||(this.shadowRoot||(this.shadowHost=this.wnd.document.createElement("div"),this.shadowHost.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none",this.wnd.document.body.appendChild(this.shadowHost),this.shadowRoot=this.shadowHost.attachShadow({mode:"open"})),this.container=this.wnd.document.createElement("div"),this.container.setAttribute("id",this.id),this.container.dataset.group=this.name,this.container.dataset.readium="true",this.container.style.setProperty("pointer-events","none"),this.container.style.display="contents",this.shadowRoot.appendChild(this.container)),this.container}getCurrentDarkMode(){return I(this.wnd,"--USER__appearance")==="readium-night-on"||q(this.getBackgroundColor())}getBackgroundColor(){return I(this.wnd,"--USER__backgroundColor")||this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color")}updateSharedMask(){const e=this.items.filter(l=>l.decoration.style?.type===c.Mask);if(e.length===0){this.maskSvg&&(this.maskSvg.remove(),this.maskSvg=void 0),this.shadowRoot&&(this.shadowRoot.innerHTML="");return}const t=R(this.wnd),i=1/this.effectiveZoom(),o=this.wnd.document.documentElement,s=o.scrollWidth,n=o.scrollHeight,r=[];for(const l of e){const u=l.decoration.style,b=u.layout??"boxes",m=u.width??"wrap",d=u.expand??0,f=l.range.getBoundingClientRect(),k=b==="bounds"?[d?{left:f.left-d,top:f.top-d,right:f.right+d,bottom:f.bottom+d,width:f.width+d*2,height:f.height+d*2}:f]:T(l.range,!1,!1,d);for(const v of k){let y;switch(m){case"viewport":{const w=Math.floor(t.inlineStart(v)/t.viewportInlineSize)*t.viewportInlineSize;y=t.toRect(w,t.blockStart(v),t.viewportInlineSize,t.blockSize(v));break}case"page":{const w=Math.floor(t.inlineStart(v)/t.pageInlineSize)*t.pageInlineSize;y=t.toRect(w,t.blockStart(v),t.pageInlineSize,t.blockSize(v));break}case"bounds":{y=t.toRect(t.inlineStart(f),t.blockStart(v),t.inlineSize(f),t.blockSize(v));break}default:y=t.toRect(t.inlineStart(v),t.blockStart(v),t.inlineSize(v),t.blockSize(v))}r.push(y)}}const p=[`M0 0 H${s} V${n} H0 Z`,...r.map(l=>{const u=(l.left+t.xDocOffset)*i,b=(l.top+t.yDocOffset)*i,m=(l.right+t.xDocOffset)*i,d=(l.bottom+t.yDocOffset)*i;return`M${u} ${b} H${m} V${d} H${u} Z`})].join(" "),a="http://www.w3.org/2000/svg";if(!this.maskSvg){this.shadowRoot||(this.shadowHost=this.wnd.document.createElement("div"),this.shadowHost.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none",this.wnd.document.body.appendChild(this.shadowHost),this.shadowRoot=this.shadowHost.attachShadow({mode:"open"})),this.maskSvg=this.wnd.document.createElementNS(a,"svg"),this.maskSvg.style.cssText=`position:absolute;top:0;left:0;width:${s}px;height:${n}px;pointer-events:none;z-index:9999`,this.maskSvg.dataset.readium="true";const l=this.wnd.document.createElementNS(a,"defs"),u=this.wnd.document.createElementNS(a,"clipPath"),b=`${this.id}-mask-clip`;u.setAttribute("id",b),u.setAttribute("clipPathUnits","userSpaceOnUse");const m=this.wnd.document.createElementNS(a,"path");m.setAttribute("clip-rule","evenodd"),u.appendChild(m),l.appendChild(u),this.maskSvg.appendChild(l);const d=this.wnd.document.createElementNS(a,"rect");d.setAttribute("id",`${this.id}-mask-rect`),d.setAttribute("clip-path",`url(#${b})`),d.style.pointerEvents="none",this.maskSvg.appendChild(d),this.shadowRoot.appendChild(this.maskSvg)}this.maskSvg.style.width=`${s}px`,this.maskSvg.style.height=`${n}px`;const g=this.maskSvg.querySelector("path");g&&g.setAttribute("d",p);const h=this.maskSvg.querySelector("rect");if(h){const u=e[0].decoration.style.tint,b=u??this.getBackgroundColor()??z(c.Mask),m=u?"1":"0.5";h.setAttribute("x","0"),h.setAttribute("y","0"),h.setAttribute("width",String(s)),h.setAttribute("height",String(n)),h.setAttribute("fill",b),h.setAttribute("fill-opacity",m)}}injectCustomStylesheet(e){const t=`${this.id}-custom-style`;let i=this.wnd.document.getElementById(t);i||(i=this.wnd.document.createElement("style"),i.id=t,i.dataset.readium="true",this.wnd.document.head.appendChild(i)),i.innerHTML=e}clearContainer(){if(this.experimentalHighlights){const e=this.wnd.CSS.highlights;for(const t of this._tintSubKeys.values())e.delete(t);this._tintSubKeys.clear(),this._subKeyCounter=0}this.wnd.document.getElementById(`${this.id}-custom-style`)?.remove(),this.container&&(this.container.remove(),this.container=void 0)}}const H=class H extends P{constructor(){super(...arguments),this.resizeFrame=0,this.lastGroupId=0,this.groups=new Map,this.handleResizer=this.handleResize.bind(this),this.scrollScheduled=!1,this.handleScroller=this.handleScroll.bind(this)}cleanup(){this.groups.forEach(e=>e.destroy()),this.groups.clear()}updateHighlightStyles(){this.groups.forEach(e=>{e.requestLayout()})}handleResize(){this.wnd.clearTimeout(this.resizeFrame),this.resizeFrame=this.wnd.setTimeout(()=>{this.groups.forEach(e=>e.requestLayout())},50)}handleScroll(){this.scrollScheduled||(this.scrollScheduled=!0,this.wnd.requestAnimationFrame(()=>{this.scrollScheduled=!1,this.groups.forEach(e=>{e.hasOverlayItems&&e.repositionOverlays()})}))}mount(e,t){return this.wnd=e,t.register("decorate",H.moduleName,(i,o)=>{const s=i;(s.action==="add"||s.action==="update")&&s.decoration.locator&&(s.decoration.locator=D.deserialize(s.decoration.locator)),this.groups.has(s.group)||this.groups.set(s.group,new Y(e,t,`readium-decoration-${this.lastGroupId++}`,s.group));const n=this.groups.get(s.group);switch(s.action){case"add":n?.add(s.decoration);break;case"remove":n?.remove(s.decoration.id);break;case"clear":n?.clear();break;case"update":n?.update(s.decoration);break}o(!0)}),t.register("decoration_activatable",H.moduleName,(i,o)=>{const s=i,n=this.groups.get(s.group);n&&(n.activatable=s.activatable),o(!0)}),t.register("decoration_hoverable",H.moduleName,(i,o)=>{const s=i,n=this.groups.get(s.group);n&&(n.hoverable=s.hoverable),o(!0)}),this.resizeObserver=new ResizeObserver(()=>e.requestAnimationFrame(()=>this.handleResize())),this.resizeObserver.observe(e.document.documentElement),e.addEventListener("orientationchange",this.handleResizer),e.addEventListener("resize",this.handleResizer),e.addEventListener("scroll",this.handleScroller,{passive:!0,capture:!0}),this.styleObserver=new MutationObserver(i=>{i.some(s=>s.type==="attributes"&&s.attributeName==="style"&&s.oldValue!==s.target.getAttribute("style"))&&this.updateHighlightStyles()}),this.styleObserver.observe(e.document.documentElement,{attributes:!0,attributeFilter:["style"],attributeOldValue:!0}),t.log("Decorator Mounted"),!0}unmount(e,t){return e.removeEventListener("orientationchange",this.handleResizer),e.removeEventListener("resize",this.handleResizer),e.removeEventListener("scroll",this.handleScroller,{capture:!0}),t.unregisterAll(H.moduleName),this.resizeObserver.disconnect(),this.styleObserver.disconnect(),this.cleanup(),t.log("Decorator Unmounted"),!0}};H.moduleName="decorator";let A=H;export{X as DecorationLayout,c as DecorationStyleType,G as DecorationWidth,A as Decorator};
24
+ `)}positionElement(e,t,i,o,s,n,r=0){const p=e.decoration?.style?.width,a=s;switch(p){case"viewport":{const g=Math.floor(t.inlineStart(a)/t.viewportInlineSize)*t.viewportInlineSize;t.applyPosition(o,g+t.inlineScrollOffset+r,t.blockStart(a)+t.blockScrollOffset,t.viewportInlineSize-2*r,t.blockSize(a),i);break}case"page":{const g=Math.floor(t.inlineStart(a)/t.pageInlineSize)*t.pageInlineSize;t.applyPosition(o,g+t.inlineScrollOffset+r,t.blockStart(a)+t.blockScrollOffset,t.pageInlineSize-2*r,t.blockSize(a),i);break}case"bounds":{t.applyPosition(o,t.inlineStart(n)+t.inlineScrollOffset,t.blockStart(a)+t.blockScrollOffset,t.inlineSize(n),t.blockSize(a),i);break}default:t.applyPosition(o,t.inlineStart(a)+t.inlineScrollOffset,t.blockStart(a)+t.blockScrollOffset,t.inlineSize(a),t.blockSize(a),i)}}computeOverlayRects(e,t,i,o){if(e.decoration?.style?.layout==="bounds")return[o?{left:i.left-o,right:i.right+o,top:i.top-o,bottom:i.bottom+o,width:i.width+o*2,height:i.height+o*2}:i];const n=e.decoration.style.type,r=n===d.Underline||n===d.Strikethrough,p=n===d.Strikethrough,a=r?U(e.range,["rt","rp"]):e.range;let g=H(a,!0,t.isVertical,r?0:o);return g=g.sort((h,l)=>t.isVertical?(t.isVertLR?1:-1)*(h.left-l.left):h.top-l.top),g.map(h=>{let l=h;if(p){const u=t.blockSize(h)*.1,m=t.blockStart(h)+t.blockSize(h)/2-u/2;l=t.isVertical?{left:m,right:m+u,top:h.top,bottom:h.bottom,width:u,height:h.height}:{top:m,bottom:m+u,left:h.left,right:h.right,height:u,width:h.width}}return o&&r&&(l=t.isVertical?{...l,top:l.top-o,bottom:l.bottom+o,height:l.height+o*2}:{...l,left:l.left-o,right:l.right+o,width:l.width+o*2}),l})}repositionItem(e,t){if(!e.container)return!0;const i=e.decoration.style;if(i.type!==d.Template){const g=i.type??d.Highlight;if(g===d.TextColor||g===d.Mask)return!0}const o=1/this.effectiveZoom(),s=i.expand??0,n=e.range.getBoundingClientRect(),r=(()=>{if(i.type!==d.Outline)return 0;const g=i.width;return g==="page"||g==="viewport"?3:0})(),p=this.computeOverlayRects(e,t,n,s),a=Array.from(e.container.children);return a.length!==p.length?!1:(a.forEach((g,h)=>this.positionElement(e,t,o,g,p[h],n,r)),!0)}layout(e){if(this.experimentalHighlights&&!this.notTextFlag?.has(e.id))return this.experimentalLayout(e);const t=this.wnd.document.createElement("div");t.setAttribute("id",e.id),t.dataset.highlightId=e.decoration.id,t.style.setProperty("pointer-events","none");const i=z(this.wnd),o=1/this.effectiveZoom(),s=e.decoration.style.expand??0,n=e.range.getBoundingClientRect(),r=e.decoration.style,p=(()=>{if(r.type!==d.Outline)return 0;const h=r.width;return h==="page"||h==="viewport"?3:0})();let a;if(r.type===d.Template){r.stylesheet&&this.injectCustomStylesheet(r.stylesheet);const h=V(this.wnd,r.element);if(!h){e.container=t,e.clickableElements=[];return}h.style.setProperty("pointer-events","none"),a=h}else{const h=r,l=h.type??d.Highlight,u=h.tint??x(l);if(l===d.TextColor){e.container=t,e.clickableElements=[];return}if(l===d.Mask){e.container=t,e.clickableElements=[],this.updateSharedMask();return}const b=this.getCurrentDarkMode(),m=this.getBackgroundColor(),c=h.enforceContrast!==!1,f=(()=>{switch(l){case d.Underline:{const v=c?T(u,m):u,w=h.layout==="bounds",[C,$]=i.isVertical?["border-right","border-left"]:["border-bottom","border-top"];return[w?`${$}: 0.1em solid ${v} !important`:null,`${C}: 0.1em solid ${v} !important`,"background-color: transparent !important","box-sizing: border-box !important"].filter(Boolean).join("; ")}case d.Strikethrough:{const v=c?T(u,m):u;return h.layout==="bounds"?[`background: repeating-linear-gradient(-45deg, transparent, transparent 19px, ${v} 19px, ${v} 20px) !important`,"background-color: transparent !important","box-sizing: border-box !important"].join("; "):[`background-color: ${v} !important`,"box-sizing: border-box !important"].join("; ")}case d.Outline:return[`outline: 2px solid ${c?T(u,m):u} !important`,"outline-offset: 1px !important","background-color: transparent !important","box-sizing: border-box !important"].join("; ");case d.HighlightUnderline:{const v=c?T(u,m):u,{r:w,g:C,b:$}=M(v),_=`rgba(${w}, ${C}, ${$}, 0.3)`,B=h.layout==="bounds",[D,L]=i.isVertical?["border-right","border-left"]:["border-bottom","border-top"];return[`background-color: ${_} !important`,B?`${L}: 0.1em solid ${v} !important`:null,`${D}: 0.1em solid ${v} !important`,"box-sizing: border-box !important"].filter(Boolean).join("; ")}case d.Highlight:default:return[`background-color: ${c?T(u,m):u} !important`,`mix-blend-mode: ${b?"exclusion":"multiply"} !important`,"opacity: 1 !important","box-sizing: border-box !important","transform: translateZ(0) !important"].join("; ")}})(),k=this.wnd.document.createElement("template");k.innerHTML=`<div data-readium="true" class="readium-${l}" style="${f}"></div>`.trim(),a=k.content.firstElementChild}const g=this.computeOverlayRects(e,i,n,s);for(const h of g){const l=a.cloneNode(!0);l.style.setProperty("pointer-events","none"),this.positionElement(e,i,o,l,h,n,p),t.append(l)}e.container=t,e.clickableElements=Array.from(t.querySelectorAll("[data-activable='1']")),e.clickableElements.length||(e.clickableElements=Array.from(t.children))}renderLayout(e){this.wnd.cancelAnimationFrame(this.currentRender),this.currentRender=this.wnd.requestAnimationFrame(()=>{if(e=e.filter(i=>!this.experimentalHighlights||!!this.notTextFlag?.has(i.id)),!e||e.length===0)return;this.requireContainer().append(...e.map(i=>i.container).filter(i=>!!i))})}requireContainer(e=!1){if(e){let t;return this.wnd.document.getElementById(`${this.id}-style`)?t=this.wnd.document.getElementById(`${this.id}-style`):(t=this.wnd.document.createElement("style"),t.dataset.readium="true",t.id=`${this.id}-style`,this.wnd.document.head.appendChild(t)),t}return this.container||(this.shadowRoot||(this.shadowHost=this.wnd.document.createElement("div"),this.shadowHost.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none",this.wnd.document.body.appendChild(this.shadowHost),this.shadowRoot=this.shadowHost.attachShadow({mode:"open"})),this.container=this.wnd.document.createElement("div"),this.container.setAttribute("id",this.id),this.container.dataset.group=this.name,this.container.dataset.readium="true",this.container.style.setProperty("pointer-events","none"),this.container.style.display="contents",this.shadowRoot.appendChild(this.container)),this.container}getCurrentDarkMode(){return I(this.wnd,"--USER__appearance")==="readium-night-on"||q(this.getBackgroundColor())}getBackgroundColor(){return I(this.wnd,"--USER__backgroundColor")||this.wnd.getComputedStyle(this.wnd.document.documentElement).getPropertyValue("background-color")}updateSharedMask(){const e=this.items.filter(l=>l.decoration.style?.type===d.Mask);if(e.length===0){this.maskSvg&&(this.maskSvg.remove(),this.maskSvg=void 0),this.shadowHost&&!this.container&&(this.shadowHost.remove(),this.shadowRoot=void 0,this.shadowHost=void 0);return}const t=z(this.wnd),i=1/this.effectiveZoom(),o=this.wnd.document.documentElement,s=o.scrollWidth,n=o.scrollHeight,r=[];for(const l of e){const u=l.decoration.style,b=u.layout??"boxes",m=u.width??"wrap",c=u.expand??0,f=l.range.getBoundingClientRect(),k=b==="bounds"?[c?{left:f.left-c,top:f.top-c,right:f.right+c,bottom:f.bottom+c,width:f.width+c*2,height:f.height+c*2}:f]:H(l.range,!1,!1,c);for(const y of k){let v;switch(m){case"viewport":{const w=Math.floor(t.inlineStart(y)/t.viewportInlineSize)*t.viewportInlineSize;v=t.toRect(w,t.blockStart(y),t.viewportInlineSize,t.blockSize(y));break}case"page":{const w=Math.floor(t.inlineStart(y)/t.pageInlineSize)*t.pageInlineSize;v=t.toRect(w,t.blockStart(y),t.pageInlineSize,t.blockSize(y));break}case"bounds":{v=t.toRect(t.inlineStart(f),t.blockStart(y),t.inlineSize(f),t.blockSize(y));break}default:v=t.toRect(t.inlineStart(y),t.blockStart(y),t.inlineSize(y),t.blockSize(y))}r.push(v)}}const p=[`M0 0 H${s} V${n} H0 Z`,...r.map(l=>{const u=(l.left+t.xDocOffset)*i,b=(l.top+t.yDocOffset)*i,m=(l.right+t.xDocOffset)*i,c=(l.bottom+t.yDocOffset)*i;return`M${u} ${b} H${m} V${c} H${u} Z`})].join(" "),a="http://www.w3.org/2000/svg";if(!this.maskSvg){this.shadowRoot||(this.shadowHost=this.wnd.document.createElement("div"),this.shadowHost.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none",this.wnd.document.body.appendChild(this.shadowHost),this.shadowRoot=this.shadowHost.attachShadow({mode:"open"})),this.maskSvg=this.wnd.document.createElementNS(a,"svg"),this.maskSvg.style.cssText=`position:absolute;top:0;left:0;width:${s}px;height:${n}px;pointer-events:none;z-index:9999`,this.maskSvg.dataset.readium="true";const l=this.wnd.document.createElementNS(a,"defs"),u=this.wnd.document.createElementNS(a,"clipPath"),b=`${this.id}-mask-clip`;u.setAttribute("id",b),u.setAttribute("clipPathUnits","userSpaceOnUse");const m=this.wnd.document.createElementNS(a,"path");m.setAttribute("clip-rule","evenodd"),u.appendChild(m),l.appendChild(u),this.maskSvg.appendChild(l);const c=this.wnd.document.createElementNS(a,"rect");c.setAttribute("id",`${this.id}-mask-rect`),c.setAttribute("clip-path",`url(#${b})`),c.style.pointerEvents="none",this.maskSvg.appendChild(c),this.shadowRoot.appendChild(this.maskSvg)}this.maskSvg.style.width=`${s}px`,this.maskSvg.style.height=`${n}px`;const g=this.maskSvg.querySelector("path");g&&g.setAttribute("d",p);const h=this.maskSvg.querySelector("rect");if(h){const u=e[0].decoration.style.tint,b=u??this.getBackgroundColor()??x(d.Mask),m=u?"1":"0.5";h.setAttribute("x","0"),h.setAttribute("y","0"),h.setAttribute("width",String(s)),h.setAttribute("height",String(n)),h.setAttribute("fill",b),h.setAttribute("fill-opacity",m)}}injectCustomStylesheet(e){const t=`${this.id}-custom-style`;let i=this.wnd.document.getElementById(t);i||(i=this.wnd.document.createElement("style"),i.id=t,i.dataset.readium="true",this.wnd.document.head.appendChild(i)),i.innerHTML=e}clearContainer(){if(this.experimentalHighlights){const e=this.wnd.CSS.highlights;for(const t of this._tintSubKeys.values())e.delete(t);this._tintSubKeys.clear(),this._subKeyCounter=0}this.wnd.document.getElementById(`${this.id}-custom-style`)?.remove(),this.container&&(this.container.remove(),this.container=void 0)}}const R=class R extends N{constructor(){super(...arguments),this.observedResizeTargets=new Map,this.resizeFrame=0,this.lastGroupId=0,this.groups=new Map,this.handleResizer=this.handleResize.bind(this),this.scrollScheduled=!1,this.handleScroller=this.handleScroll.bind(this)}cleanup(){this.groups.forEach(e=>e.destroy()),this.groups.clear(),this.observedResizeTargets.clear()}updateHighlightStyles(){this.groups.forEach(e=>{e.requestLayout()})}handleResize(){this.wnd.clearTimeout(this.resizeFrame),this.resizeFrame=this.wnd.setTimeout(()=>{this.groups.forEach(e=>e.requestLayout())},50)}handleScroll(){this.scrollScheduled||(this.scrollScheduled=!0,this.wnd.requestAnimationFrame(()=>{this.scrollScheduled=!1,this.groups.forEach(e=>{e.hasOverlayItems&&e.repositionOverlays()})}))}mount(e,t){return this.wnd=e,t.register("decorate",R.moduleName,(i,o)=>{const s=i;(s.action==="add"||s.action==="update")&&s.decoration.locator&&(s.decoration.locator=K.deserialize(s.decoration.locator)),this.groups.has(s.group)||this.groups.set(s.group,new Y(e,t,`readium-decoration-${this.lastGroupId++}`,s.group));const n=this.groups.get(s.group);switch(s.action){case"add":n?.add(s.decoration);break;case"remove":n?.remove(s.decoration.id);break;case"clear":n?.clear();break;case"update":n?.update(s.decoration);break}o(!0)}),t.register("decoration_resize",R.moduleName,(i,o)=>{const s=i;s.action==="watch"?this.addDecorationResizeTarget(s.selector):this.removeDecorationResizeTarget(s.selector),o(!0)}),t.register("decoration_activatable",R.moduleName,(i,o)=>{const s=i,n=this.groups.get(s.group);n&&(n.activatable=s.activatable),o(!0)}),t.register("decoration_hoverable",R.moduleName,(i,o)=>{const s=i,n=this.groups.get(s.group);n&&(n.hoverable=s.hoverable),o(!0)}),this.resizeObserver=new ResizeObserver(()=>e.requestAnimationFrame(()=>this.handleResize())),this.resizeObserver.observe(e.document.documentElement),e.addEventListener("orientationchange",this.handleResizer),e.addEventListener("resize",this.handleResizer),e.addEventListener("scroll",this.handleScroller,{passive:!0,capture:!0}),this.styleObserver=new MutationObserver(i=>{i.some(s=>s.type==="attributes"&&s.attributeName==="style"&&s.oldValue!==s.target.getAttribute("style"))&&this.updateHighlightStyles()}),this.styleObserver.observe(e.document.documentElement,{attributes:!0,attributeFilter:["style"],attributeOldValue:!0}),t.log("Decorator Mounted"),!0}unmount(e,t){return e.removeEventListener("orientationchange",this.handleResizer),e.removeEventListener("resize",this.handleResizer),e.removeEventListener("scroll",this.handleScroller,{capture:!0}),t.unregisterAll(R.moduleName),this.resizeObserver.disconnect(),this.styleObserver.disconnect(),this.cleanup(),t.log("Decorator Unmounted"),!0}addDecorationResizeTarget(e){const t=this.observedResizeTargets.get(e);t&&this.resizeObserver.unobserve(t);const i=this.wnd.document.querySelector(e);i?(this.resizeObserver.observe(i),this.observedResizeTargets.set(e,i)):this.observedResizeTargets.delete(e)}removeDecorationResizeTarget(e){const t=this.observedResizeTargets.get(e);t&&(this.resizeObserver.unobserve(t),this.observedResizeTargets.delete(e))}};R.moduleName="decorator";let A=R;export{X as DecorationLayout,d as DecorationStyleType,G as DecorationWidth,A as Decorator};
@@ -1 +1 @@
1
- import{Module as l}from"../Module.js";const i=class i extends l{constructor(){super(...arguments),this.mediaPlayingCount=0,this.allAnimations=new Set}wndOnErr(e){this.comms?.send("error",{message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno})}unblock(e){for(e._readium_blockEvents=!1;e._readium_blockedEvents?.length>0;){const t=e._readium_blockedEvents.shift();switch(t[0]){case 0:Reflect.apply(t[1],t[2],t[3]);break;case 1:const a=t[1],n=t[2];e.removeEventListener(a.type,e._readium_eventBlocker,!0);const s=new Event(a.type,{bubbles:a.bubbles,cancelable:a.cancelable});n?n.dispatchEvent(s):e.dispatchEvent(s);break}}}onMediaPlayEvent(){this.mediaPlayingCount++,this.comms?.send("media_play",this.mediaPlayingCount)}onMediaPauseEvent(){this.mediaPlayingCount>0&&this.mediaPlayingCount--,this.comms?.send("media_pause",this.mediaPlayingCount)}pauseAllMedia(e){const t=e.document.querySelectorAll("audio,video");for(let a=0;a<t.length;a++)t[a].pause()}mount(e,t){this.comms=t,e.addEventListener("error",this.wndOnErr,!1),Reflect.defineProperty(e.navigator,"epubReadingSystem",{value:{name:"readium-ts-toolkit",version:"2.7.1",hasFeature:(n,s="")=>{switch(n){case"dom-manipulation":return!0;case"layout-changes":return!0;case"touch-events":return!0;case"mouse-events":return!0;case"keyboard-events":return!0;case"spine-scripting":return!0;case"embedded-web-content":return!0;default:return!1}}},writable:!1}),"getAnimations"in e.document&&e.document.getAnimations().forEach(n=>{n.cancel(),this.allAnimations.add(n)}),t.register("activate",i.moduleName,(n,s)=>{this.allAnimations.forEach(r=>{r.cancel(),r.play()}),s(!0)}),t.register("unfocus",i.moduleName,(n,s)=>{this.pauseAllMedia(e),this.allAnimations.forEach(r=>r.pause()),s(!0)});const a=e.document.querySelectorAll("audio,video");for(let n=0;n<a.length;n++){const s=a[n];s.addEventListener("play",this.onMediaPlayEvent,{passive:!0}),s.addEventListener("pause",this.onMediaPauseEvent,{passive:!0})}return t.log("Setup Mounted"),!0}unmount(e,t){return e.removeEventListener("error",this.wndOnErr),e.removeEventListener("play",this.onMediaPlayEvent),e.removeEventListener("pause",this.onMediaPauseEvent),this.allAnimations.forEach(a=>a.cancel()),this.allAnimations.clear(),t.log("Setup Unmounted"),!0}};i.moduleName="setup";let o=i;export{o as Setup};
1
+ import{Module as l}from"../Module.js";const i=class i extends l{constructor(){super(...arguments),this.mediaPlayingCount=0,this.allAnimations=new Set}wndOnErr(e){this.comms?.send("error",{message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno})}unblock(e){for(e._readium_blockEvents=!1;e._readium_blockedEvents?.length>0;){const t=e._readium_blockedEvents.shift();switch(t[0]){case 0:Reflect.apply(t[1],t[2],t[3]);break;case 1:const a=t[1],n=t[2];e.removeEventListener(a.type,e._readium_eventBlocker,!0);const s=new Event(a.type,{bubbles:a.bubbles,cancelable:a.cancelable});n?n.dispatchEvent(s):e.dispatchEvent(s);break}}}onMediaPlayEvent(){this.mediaPlayingCount++,this.comms?.send("media_play",this.mediaPlayingCount)}onMediaPauseEvent(){this.mediaPlayingCount>0&&this.mediaPlayingCount--,this.comms?.send("media_pause",this.mediaPlayingCount)}pauseAllMedia(e){const t=e.document.querySelectorAll("audio,video");for(let a=0;a<t.length;a++)t[a].pause()}mount(e,t){this.comms=t,e.addEventListener("error",this.wndOnErr,!1),Reflect.defineProperty(e.navigator,"epubReadingSystem",{value:{name:"readium-ts-toolkit",version:"2.8.0",hasFeature:(n,s="")=>{switch(n){case"dom-manipulation":return!0;case"layout-changes":return!0;case"touch-events":return!0;case"mouse-events":return!0;case"keyboard-events":return!0;case"spine-scripting":return!0;case"embedded-web-content":return!0;default:return!1}}},writable:!1}),"getAnimations"in e.document&&e.document.getAnimations().forEach(n=>{n.cancel(),this.allAnimations.add(n)}),t.register("activate",i.moduleName,(n,s)=>{this.allAnimations.forEach(r=>{r.cancel(),r.play()}),s(!0)}),t.register("unfocus",i.moduleName,(n,s)=>{this.pauseAllMedia(e),this.allAnimations.forEach(r=>r.pause()),s(!0)});const a=e.document.querySelectorAll("audio,video");for(let n=0;n<a.length;n++){const s=a[n];s.addEventListener("play",this.onMediaPlayEvent,{passive:!0}),s.addEventListener("pause",this.onMediaPauseEvent,{passive:!0})}return t.log("Setup Mounted"),!0}unmount(e,t){return e.removeEventListener("error",this.wndOnErr),e.removeEventListener("play",this.onMediaPlayEvent),e.removeEventListener("pause",this.onMediaPauseEvent),this.allAnimations.forEach(a=>a.cancel()),this.allAnimations.clear(),t.log("Setup Unmounted"),!0}};i.moduleName="setup";let o=i;export{o as Setup};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/navigator-html-injectables",
3
- "version": "2.7.1",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
5
  "description": "An embeddable solution for connecting frames of HTML publications with a Readium Navigator",
6
6
  "author": "readium",
package/src/comms/keys.ts CHANGED
@@ -41,6 +41,7 @@ export type CommsCommandKey =
41
41
  // "exact_progress" |
42
42
  "first_visible_locator" |
43
43
  "decorate" |
44
+ "decoration_resize" |
44
45
  "decoration_activatable" |
45
46
  "decoration_hoverable" |
46
47
  "protect" |
@@ -103,6 +103,10 @@ export type DecoratorRequest =
103
103
  | { group: string; action: "remove"; decoration: Pick<Decoration, "id"> }
104
104
  | { group: string; action: "clear" };
105
105
 
106
+ export type DecorationResizeRequest =
107
+ | { action: "watch"; selector: string }
108
+ | { action: "unwatch"; selector: string };
109
+
106
110
  interface DecorationItem {
107
111
  id: string;
108
112
  decoration: Decoration;
@@ -1051,8 +1055,11 @@ class DecorationGroup {
1051
1055
  this.maskSvg.remove();
1052
1056
  this.maskSvg = undefined;
1053
1057
  }
1054
- if (this.shadowRoot) {
1055
- this.shadowRoot.innerHTML = '';
1058
+ // Only tear down the shared shadow host if no other decorations use it
1059
+ if (this.shadowHost && !this.container) {
1060
+ this.shadowHost.remove();
1061
+ this.shadowRoot = undefined;
1062
+ this.shadowHost = undefined;
1056
1063
  }
1057
1064
  return;
1058
1065
  }
@@ -1218,6 +1225,7 @@ export class Decorator extends Module {
1218
1225
  private resizeObserver!: ResizeObserver;
1219
1226
  private styleObserver!: MutationObserver;
1220
1227
  private wnd!: Window;
1228
+ private observedResizeTargets = new Map<string, Element>();
1221
1229
  /*private readonly lastSize = {
1222
1230
  width: 0,
1223
1231
  height: 0
@@ -1230,6 +1238,7 @@ export class Decorator extends Module {
1230
1238
  private cleanup() {
1231
1239
  this.groups.forEach(g => g.destroy());
1232
1240
  this.groups.clear();
1241
+ this.observedResizeTargets.clear();
1233
1242
  }
1234
1243
 
1235
1244
  private updateHighlightStyles() {
@@ -1297,6 +1306,13 @@ export class Decorator extends Module {
1297
1306
  ack(true);
1298
1307
  });
1299
1308
 
1309
+ comms.register("decoration_resize", Decorator.moduleName, (data, ack) => {
1310
+ const req = data as DecorationResizeRequest;
1311
+ if (req.action === "watch") this.addDecorationResizeTarget(req.selector);
1312
+ else this.removeDecorationResizeTarget(req.selector);
1313
+ ack(true);
1314
+ });
1315
+
1300
1316
  comms.register("decoration_activatable", Decorator.moduleName, (data, ack) => {
1301
1317
  const req = data as { group: string; activatable: boolean };
1302
1318
  const group = this.groups.get(req.group);
@@ -1358,4 +1374,25 @@ export class Decorator extends Module {
1358
1374
  comms.log("Decorator Unmounted");
1359
1375
  return true;
1360
1376
  }
1377
+
1378
+ private addDecorationResizeTarget(selector: string): void {
1379
+ const existing = this.observedResizeTargets.get(selector);
1380
+ if (existing) this.resizeObserver.unobserve(existing);
1381
+
1382
+ const el = this.wnd.document.querySelector(selector);
1383
+ if (el) {
1384
+ this.resizeObserver.observe(el);
1385
+ this.observedResizeTargets.set(selector, el);
1386
+ } else {
1387
+ this.observedResizeTargets.delete(selector);
1388
+ }
1389
+ }
1390
+
1391
+ private removeDecorationResizeTarget(selector: string): void {
1392
+ const el = this.observedResizeTargets.get(selector);
1393
+ if (el) {
1394
+ this.resizeObserver.unobserve(el);
1395
+ this.observedResizeTargets.delete(selector);
1396
+ }
1397
+ }
1361
1398
  }
@@ -1,3 +1,3 @@
1
1
  export type CommsEventKey = "_pong" | "_unhandled" | "_ack" | "log" | "error" | "click" | "tap" | "tap_more" | "no_more" | "no_less" | "swipe" | "scroll" | "progress" | "first_visible_locator" | "text_selected" | "context_menu" | "media_play" | "media_pause" | "content_protection" | "keyboard_peripherals" | "decoration_activated" | "decoration_pointer_enter" | "decoration_pointer_leave";
2
- export type CommsCommandKey = "_ping" | "go_prev" | "go_next" | "go_id" | "go_text" | "go_end" | "go_start" | "go_progression" | "get_properties" | "update_properties" | "set_property" | "remove_property" | "first_visible_locator" | "decorate" | "decoration_activatable" | "decoration_hoverable" | "protect" | "unprotect" | "unfocus" | "focus" | "activate" | "shake" | "force_webkit_recalc" | "peripherals_protection" | "keyboard_peripherals" | "scroll_protection" | "print_protection" | "timeline_entries";
2
+ export type CommsCommandKey = "_ping" | "go_prev" | "go_next" | "go_id" | "go_text" | "go_end" | "go_start" | "go_progression" | "get_properties" | "update_properties" | "set_property" | "remove_property" | "first_visible_locator" | "decorate" | "decoration_resize" | "decoration_activatable" | "decoration_hoverable" | "protect" | "unprotect" | "unfocus" | "focus" | "activate" | "shake" | "force_webkit_recalc" | "peripherals_protection" | "keyboard_peripherals" | "scroll_protection" | "print_protection" | "timeline_entries";
3
3
  export type SuspiciousActivityType = "developer_tools" | "select_all" | "save" | "suspicious_selection" | "bulk_copy" | "suspicious_scrolling" | "suspicious_snapping" | "drag_detected" | "drop_detected" | "print";
@@ -103,11 +103,19 @@ export type DecoratorRequest = {
103
103
  group: string;
104
104
  action: "clear";
105
105
  };
106
+ export type DecorationResizeRequest = {
107
+ action: "watch";
108
+ selector: string;
109
+ } | {
110
+ action: "unwatch";
111
+ selector: string;
112
+ };
106
113
  export declare class Decorator extends Module {
107
114
  static readonly moduleName: ModuleName;
108
115
  private resizeObserver;
109
116
  private styleObserver;
110
117
  private wnd;
118
+ private observedResizeTargets;
111
119
  private resizeFrame;
112
120
  private lastGroupId;
113
121
  private groups;
@@ -120,5 +128,7 @@ export declare class Decorator extends Module {
120
128
  private readonly handleScroller;
121
129
  mount(wnd: Window, comms: IComms): boolean;
122
130
  unmount(wnd: Window, comms: IComms): boolean;
131
+ private addDecorationResizeTarget;
132
+ private removeDecorationResizeTarget;
123
133
  }
124
134
  export {};