@readium/helpers 1.1.1 → 1.2.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/index.js CHANGED
@@ -1 +1 @@
1
- import{adjustColorForContrast as r,checkContrast as o,colorToRgba as n,getContrastingTextColor as a,getLuminance as g,isDarkColor as i,isLightColor as m}from"./color.js";import{sML as F,sMLWithRequest as c}from"./sML.js";import{decodeTextFragmentDirective as l}from"./textFragmentDirective.js";import{forTesting as f,internal as p,processTextFragmentDirective as T}from"./vendor/text-fragments-polyfill/textFragmentMatcher.js";import{GenerateFragmentStatus as d,generateFragment as L,generateFragmentFromRange as R,isValidRangeForFragmentGeneration as h,setFragmentGenerationTimeout as D}from"./vendor/text-fragments-polyfill/textFragmentGenerator.js";export{d as GenerateFragmentStatus,r as adjustColorForContrast,o as checkContrast,n as colorToRgba,l as decodeTextFragmentDirective,f as forTesting,L as generateFragment,R as generateFragmentFromRange,a as getContrastingTextColor,g as getLuminance,p as internal,i as isDarkColor,m as isLightColor,h as isValidRangeForFragmentGeneration,T as processTextFragmentDirective,F as sML,c as sMLWithRequest,D as setFragmentGenerationTimeout};
1
+ import{adjustColorForContrast as r,checkContrast as o,colorToRgba as n,getContrastingTextColor as a,getLuminance as s,isDarkColor as i,isLightColor as g}from"./color.js";import{sML as c,sMLWithRequest as x}from"./sML.js";import{BINDING_PUNCT_CLASS as l,ssmlAttrEscape as p,ssmlTextEscape as C,startsWithBindingPunct as T}from"./text.js";import{decodeTextFragmentDirective as u}from"./textFragmentDirective.js";import{forTesting as L,internal as h,processTextFragmentDirective as D}from"./vendor/text-fragments-polyfill/textFragmentMatcher.js";import{GenerateFragmentStatus as R,generateFragment as N,generateFragmentFromRange as S,isValidRangeForFragmentGeneration as k,setFragmentGenerationTimeout as v}from"./vendor/text-fragments-polyfill/textFragmentGenerator.js";export{l as BINDING_PUNCT_CLASS,R as GenerateFragmentStatus,r as adjustColorForContrast,o as checkContrast,n as colorToRgba,u as decodeTextFragmentDirective,L as forTesting,N as generateFragment,S as generateFragmentFromRange,a as getContrastingTextColor,s as getLuminance,h as internal,i as isDarkColor,g as isLightColor,k as isValidRangeForFragmentGeneration,D as processTextFragmentDirective,c as sML,x as sMLWithRequest,v as setFragmentGenerationTimeout,p as ssmlAttrEscape,C as ssmlTextEscape,T as startsWithBindingPunct};
package/dist/text.js ADDED
@@ -0,0 +1 @@
1
+ const t="\\p{Pe}\\p{Pf}.,;:!?,。、;:!?،؛؟",c=new RegExp(`^[${t}]`,"u");function p(e){return c.test(e)}const s=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),a=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");export{t as BINDING_PUNCT_CLASS,a as ssmlAttrEscape,s as ssmlTextEscape,p as startsWithBindingPunct};
@@ -1 +1 @@
1
- const O=["ADDRESS","ARTICLE","ASIDE","BLOCKQUOTE","BR","DETAILS","DIALOG","DD","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","LI","MAIN","NAV","OL","P","PRE","SECTION","TABLE","UL","TR","TH","TD","COLGROUP","COL","CAPTION","THEAD","TBODY","TFOOT"],f=/[\t-\r -#%-\*,-\/:;\?@\[-\]_\{\}\x85\xA0\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/u,b=/[^\t-\r -#%-\*,-\/:;\?@\[-\]_\{\}\x85\xA0\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/u,U=(u,e,t)=>{const n=[],D=e.createRange();for(D.selectNodeContents(t??e);!D.collapsed&&n.length<2;){let F;if(u.prefix){const r=a(u.prefix,D);if(r==null)break;c(D,r.startContainer,r.startOffset);const i=e.createRange();if(i.setStart(r.endContainer,r.endOffset),i.setEnd(D.endContainer,D.endOffset),B(i),i.collapsed||(F=a(u.textStart,i),F==null))break;if(F.compareBoundaryPoints(Range.START_TO_START,i)!==0)continue}else{if(F=a(u.textStart,D),F==null)break;c(D,F.startContainer,F.startOffset)}if(u.textEnd){const r=e.createRange();r.setStart(F.endContainer,F.endOffset),r.setEnd(D.endContainer,D.endOffset);let i=!1;for(;!r.collapsed&&n.length<2;){const s=a(u.textEnd,r);if(s==null)break;if(c(r,s.startContainer,s.startOffset),F.setEnd(s.endContainer,s.endOffset),u.suffix){const o=R(u.suffix,F,D,e);if(o===E.NO_SUFFIX_MATCH)break;if(o===E.SUFFIX_MATCH){i=!0,n.push(F.cloneRange());continue}else if(o===E.MISPLACED_SUFFIX)continue}else i=!0,n.push(F.cloneRange())}if(!i)break}else if(u.suffix){const r=R(u.suffix,F,D,e);if(r===E.NO_SUFFIX_MATCH)break;if(r===E.SUFFIX_MATCH){n.push(F.cloneRange()),c(D,D.startContainer,D.startOffset);continue}else if(r===E.MISPLACED_SUFFIX)continue}else n.push(F.cloneRange())}return n},E={NO_SUFFIX_MATCH:0,SUFFIX_MATCH:1,MISPLACED_SUFFIX:2},R=(u,e,t,n)=>{const D=n.createRange();D.setStart(e.endContainer,e.endOffset),D.setEnd(t.endContainer,t.endOffset),B(D);const F=a(u,D);return F==null?E.NO_SUFFIX_MATCH:F.compareBoundaryPoints(Range.START_TO_START,D)!==0?E.MISPLACED_SUFFIX:E.SUFFIX_MATCH},c=(u,e,t)=>{try{u.setStart(e,t+1)}catch{u.setStartAfter(e)}},B=u=>{const e=g(u);let t=e.nextNode();for(;!u.collapsed&&t!=null;){if(t!==u.startContainer&&u.setStart(t,0),t.textContent.length>u.startOffset&&!t.textContent[u.startOffset].match(/\s/))return;try{u.setStart(t,u.startOffset+1)}catch{t=e.nextNode(),t==null?u.collapse():u.setStart(t,0)}}},g=u=>(u.commonAncestorContainer.ownerDocument??u.commonAncestorContainer).createTreeWalker(u.commonAncestorContainer,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT,{acceptNode:t=>N(t,u)}),H=u=>{if(u.hidden==="until-found")return!0;const e=u.attributes;return!!(e&&e.hidden&&e.hidden.value==="until-found")},T=u=>{let e=u;for(;e!=null&&!(e instanceof HTMLElement);)e=e.parentNode;const t=e?.ownerDocument?.defaultView;if(e!=null&&t!=null){if(H(e))return!0;const n=t.getComputedStyle(e);if(n.visibility==="hidden"||n.display==="none"||parseInt(n.height,10)===0&&n.overflowY!="visible"||parseInt(n.width,10)===0&&n.overflowX!="visible"||parseInt(n.opacity,10)===0)return!1}return!0},I=(u,e)=>e!=null&&!e.intersectsNode(u)?NodeFilter.FILTER_REJECT:T(u)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT,N=(u,e)=>e!=null&&!e.intersectsNode(u)||!T(u)?NodeFilter.FILTER_REJECT:u.nodeType===Node.TEXT_NODE?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP,p=(u,e)=>{const t=[];let n=[];const D=Array.from(M(u,F=>I(F,e)));for(const F of D)F.nodeType===Node.TEXT_NODE?n.push(F):F instanceof HTMLElement&&O.includes(F.tagName.toUpperCase())&&n.length>0&&(t.push(n),n=[]);return n.length>0&&t.push(n),t},v=(u,e,t)=>{let n="";return u.length===1?n=u[0].textContent.substring(e,t):n=u[0].textContent.substring(e)+u.slice(1,-1).reduce((D,F)=>D+F.textContent,"")+u.slice(-1)[0].textContent.substring(0,t),n.replace(/[\t\n\r ]+/g," ")};function*M(u,e){const n=(u.ownerDocument??u).createTreeWalker(u,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode:e}),D=new Set;for(;h(n,D)!==null;)yield n.currentNode}const a=(u,e)=>{const t=p(e.commonAncestorContainer,e),n=S(e.commonAncestorContainer.ownerDocument??void 0);for(const D of t){const F=_(u,e,D,n);if(F!==void 0)return F}},_=(u,e,t,n)=>{if(!u||!e||!(t||[]).length)return;const D=t[0]===e.startContainer?e.startOffset:0,F=A(v(t,D,void 0)),r=A(u);let i=0,s,o;for(;i<F.length;){const C=F.indexOf(r,i);if(C===-1)return;if(m(F,C,r.length,n)){const l=A(t[0].data.slice(0,D)).length;s=d(l+C,t,!1),o=d(l+C+r.length,t,!0)}if(s!=null&&o!=null){const l=new Range;if(l.setStart(s.node,s.offset),l.setEnd(o.node,o.offset),e.compareBoundaryPoints(Range.START_TO_START,l)<=0&&e.compareBoundaryPoints(Range.END_TO_END,l)>=0)return l}i=C+1}},d=(u,e,t)=>{let n=0,D;for(let F=0;F<e.length;F++){const r=e[F];D||(D=A(r.data));let i=n+D.length;if(t&&(i+=1),i>u){const s=u-n;let o=Math.min(u-n,r.data.length);const C=t?D.substring(0,s):D.substring(s);let l=A(t?r.data.substring(0,o):r.data.substring(o));const L=(t?-1:1)*(C.length>l.length?-1:1);for(;o>=0&&o<=r.data.length;){if(l.length===C.length)return{node:r,offset:o};o+=L,l=A(t?r.data.substring(0,o):r.data.substring(o))}}if(n+=D.length,F+1<e.length){const s=A(e[F+1].data);D.slice(-1)===" "&&s.slice(0,1)===" "&&(n-=1),D=s}}},m=(u,e,t,n)=>{if(e<0||e>=u.length||t<=0||e+t>u.length)return!1;if(n){const D=n.segment(u),F=D.containing(e);if(!F||F.isWordLike&&F.index!=e)return!1;const r=e+t,i=D.containing(r);if(i&&i.isWordLike&&i.index!=r)return!1}else if(u[e].match(f)&&(++e,--t,!t)||u[e+t-1].match(f)&&(--t,!t)||e!==0&&!u[e-1].match(f)||e+t!==u.length&&!u[e+t].match(f))return!1;return!0},A=u=>(u||"").normalize("NFKD").replace(/\s+/g," ").replace(/[\u0300-\u036f]/g,"").toLowerCase(),S=u=>{if(Intl.Segmenter){const e=u?.documentElement?.lang||u?.defaultView?.navigator?.language||void 0;return new Intl.Segmenter(e,{granularity:"word"})}},h=(u,e)=>{if(!e.has(u.currentNode)){const D=u.firstChild();if(D!==null)return D}const t=u.nextSibling();if(t!==null)return t;const n=u.parentNode();return n!==null&&e.add(n),n},x=(u,e)=>{if(!e.has(u.currentNode)){const D=u.lastChild();if(D!==null)return D}const t=u.previousSibling();if(t!==null)return t;const n=u.parentNode();return n!==null&&e.add(n),n},w={advanceRangeStartPastOffset:c,advanceRangeStartToNonWhitespace:B,findRangeFromNodeList:_,findTextInRange:a,getBoundaryPointAtIndex:d,isWordBounded:m,makeNewSegmenter:S,normalizeString:A,forwardTraverse:h,backwardTraverse:x,getAllTextNodes:p,acceptTextNodeIfVisibleInRange:N},y={BLOCK_ELEMENTS:O,BOUNDARY_CHARS:f,NON_BOUNDARY_CHARS:b,acceptNodeIfVisibleInRange:I,normalizeString:A,makeNewSegmenter:S,forwardTraverse:h,backwardTraverse:x,makeTextNodeWalker:g,isNodeVisible:T};export{w as forTesting,y as internal,U as processTextFragmentDirective};
1
+ const N=["ADDRESS","ARTICLE","ASIDE","BLOCKQUOTE","BR","DETAILS","DIALOG","DD","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","LI","MAIN","NAV","OL","P","PRE","SECTION","TABLE","UL","TR","TH","TD","COLGROUP","COL","CAPTION","THEAD","TBODY","TFOOT"],f=/[\t-\r -#%-\*,-\/:;\?@\[-\]_\{\}\x85\xA0\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/u,b=/[^\t-\r -#%-\*,-\/:;\?@\[-\]_\{\}\x85\xA0\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/u,U=(u,e,t)=>{const D=[],n=e.createRange();for(n.selectNodeContents(t??e);!n.collapsed&&D.length<2;){let F;if(u.prefix){const r=a(u.prefix,n);if(r==null)break;c(n,r.startContainer,r.startOffset);const i=e.createRange();if(i.setStart(r.endContainer,r.endOffset),i.setEnd(n.endContainer,n.endOffset),B(i),i.collapsed||(F=a(u.textStart,i),F==null))break;if(F.compareBoundaryPoints(Range.START_TO_START,i)!==0)continue}else{if(F=a(u.textStart,n),F==null)break;c(n,F.startContainer,F.startOffset)}if(u.textEnd){const r=e.createRange();r.setStart(F.endContainer,F.endOffset),r.setEnd(n.endContainer,n.endOffset);let i=!1;for(;!r.collapsed&&D.length<2;){const s=a(u.textEnd,r);if(s==null)break;if(c(r,s.startContainer,s.startOffset),F.setEnd(s.endContainer,s.endOffset),u.suffix){const o=R(u.suffix,F,n,e);if(o===A.NO_SUFFIX_MATCH)break;if(o===A.SUFFIX_MATCH){i=!0,D.push(F.cloneRange());continue}else if(o===A.MISPLACED_SUFFIX)continue}else i=!0,D.push(F.cloneRange())}if(!i)break}else if(u.suffix){const r=R(u.suffix,F,n,e);if(r===A.NO_SUFFIX_MATCH)break;if(r===A.SUFFIX_MATCH){D.push(F.cloneRange()),c(n,n.startContainer,n.startOffset);continue}else if(r===A.MISPLACED_SUFFIX)continue}else D.push(F.cloneRange())}return D},A={NO_SUFFIX_MATCH:0,SUFFIX_MATCH:1,MISPLACED_SUFFIX:2},R=(u,e,t,D)=>{const n=D.createRange();n.setStart(e.endContainer,e.endOffset),n.setEnd(t.endContainer,t.endOffset),B(n);const F=a(u,n);return F==null?A.NO_SUFFIX_MATCH:F.compareBoundaryPoints(Range.START_TO_START,n)!==0?A.MISPLACED_SUFFIX:A.SUFFIX_MATCH},c=(u,e,t)=>{try{u.setStart(e,t+1)}catch{u.setStartAfter(e)}},B=u=>{const e=O(u);let t=e.nextNode();for(;!u.collapsed&&t!=null;){if(t!==u.startContainer&&u.setStart(t,0),t.textContent.length>u.startOffset&&!t.textContent[u.startOffset].match(/\s/))return;try{u.setStart(t,u.startOffset+1)}catch{t=e.nextNode(),t==null?u.collapse():u.setStart(t,0)}}},O=u=>(u.commonAncestorContainer.ownerDocument??u.commonAncestorContainer).createTreeWalker(u.commonAncestorContainer,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT,{acceptNode:t=>p(t,u)}),v=u=>{if(u.hidden==="until-found")return!0;const e=u.attributes;return!!(e&&e.hidden&&e.hidden.value==="until-found")},T=u=>{let e=u;for(;e!=null&&e.nodeType!==Node.ELEMENT_NODE;)e=e.parentNode;const t=e,D=t?.ownerDocument?.defaultView;if(t!=null&&D!=null){if(v(t))return!0;const n=D.getComputedStyle(t);if(n.visibility==="hidden"||n.display==="none"||parseInt(n.height,10)===0&&n.overflowY!="visible"||parseInt(n.width,10)===0&&n.overflowX!="visible"||parseInt(n.opacity,10)===0)return!1}return!0},g=(u,e)=>e!=null&&!e.intersectsNode(u)?NodeFilter.FILTER_REJECT:T(u)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT,p=(u,e)=>e!=null&&!e.intersectsNode(u)||!T(u)?NodeFilter.FILTER_REJECT:u.nodeType===Node.TEXT_NODE?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP,I=(u,e)=>{const t=[];let D=[];const n=Array.from(M(u,F=>g(F,e)));for(const F of n)F.nodeType===Node.TEXT_NODE?D.push(F):F.nodeType===Node.ELEMENT_NODE&&N.includes(F.tagName.toUpperCase())&&D.length>0&&(t.push(D),D=[]);return D.length>0&&t.push(D),t},H=(u,e,t)=>{let D="";return u.length===1?D=u[0].textContent.substring(e,t):D=u[0].textContent.substring(e)+u.slice(1,-1).reduce((n,F)=>n+F.textContent,"")+u.slice(-1)[0].textContent.substring(0,t),D.replace(/[\t\n\r ]+/g," ")};function*M(u,e){const D=(u.ownerDocument??u).createTreeWalker(u,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,{acceptNode:e}),n=new Set;for(;h(D,n)!==null;)yield D.currentNode}const a=(u,e)=>{const t=I(e.commonAncestorContainer,e),D=S(e.commonAncestorContainer.ownerDocument??void 0);for(const n of t){const F=_(u,e,n,D);if(F!==void 0)return F}},_=(u,e,t,D)=>{if(!u||!e||!(t||[]).length)return;const n=t[0]===e.startContainer?e.startOffset:0,F=l(H(t,n,void 0)),r=l(u);let i=0,s,o;for(;i<F.length;){const C=F.indexOf(r,i);if(C===-1)return;if(m(F,C,r.length,D)){const E=l(t[0].data.slice(0,n)).length;s=d(E+C,t,!1),o=d(E+C+r.length,t,!0)}if(s!=null&&o!=null){const E=new Range;if(E.setStart(s.node,s.offset),E.setEnd(o.node,o.offset),e.compareBoundaryPoints(Range.START_TO_START,E)<=0&&e.compareBoundaryPoints(Range.END_TO_END,E)>=0)return E}i=C+1}},d=(u,e,t)=>{let D=0,n;for(let F=0;F<e.length;F++){const r=e[F];n||(n=l(r.data));let i=D+n.length;if(t&&(i+=1),i>u){const s=u-D;let o=Math.min(u-D,r.data.length);const C=t?n.substring(0,s):n.substring(s);let E=l(t?r.data.substring(0,o):r.data.substring(o));const L=(t?-1:1)*(C.length>E.length?-1:1);for(;o>=0&&o<=r.data.length;){if(E.length===C.length)return{node:r,offset:o};o+=L,E=l(t?r.data.substring(0,o):r.data.substring(o))}}if(D+=n.length,F+1<e.length){const s=l(e[F+1].data);n.slice(-1)===" "&&s.slice(0,1)===" "&&(D-=1),n=s}}},m=(u,e,t,D)=>{if(e<0||e>=u.length||t<=0||e+t>u.length)return!1;if(D){const n=D.segment(u),F=n.containing(e);if(!F||F.isWordLike&&F.index!=e)return!1;const r=e+t,i=n.containing(r);if(i&&i.isWordLike&&i.index!=r)return!1}else if(u[e].match(f)&&(++e,--t,!t)||u[e+t-1].match(f)&&(--t,!t)||e!==0&&!u[e-1].match(f)||e+t!==u.length&&!u[e+t].match(f))return!1;return!0},l=u=>(u||"").normalize("NFKD").replace(/\s+/g," ").replace(/[\u0300-\u036f]/g,"").toLowerCase(),S=u=>{if(Intl.Segmenter){const e=u?.documentElement?.lang||u?.defaultView?.navigator?.language||void 0;return new Intl.Segmenter(e,{granularity:"word"})}},h=(u,e)=>{if(!e.has(u.currentNode)){const n=u.firstChild();if(n!==null)return n}const t=u.nextSibling();if(t!==null)return t;const D=u.parentNode();return D!==null&&e.add(D),D},x=(u,e)=>{if(!e.has(u.currentNode)){const n=u.lastChild();if(n!==null)return n}const t=u.previousSibling();if(t!==null)return t;const D=u.parentNode();return D!==null&&e.add(D),D},w={advanceRangeStartPastOffset:c,advanceRangeStartToNonWhitespace:B,findRangeFromNodeList:_,findTextInRange:a,getBoundaryPointAtIndex:d,isWordBounded:m,makeNewSegmenter:S,normalizeString:l,forwardTraverse:h,backwardTraverse:x,getAllTextNodes:I,acceptTextNodeIfVisibleInRange:p},y={BLOCK_ELEMENTS:N,BOUNDARY_CHARS:f,NON_BOUNDARY_CHARS:b,acceptNodeIfVisibleInRange:g,normalizeString:l,makeNewSegmenter:S,forwardTraverse:h,backwardTraverse:x,makeTextNodeWalker:O,isNodeVisible:T};export{w as forTesting,y as internal,U as processTextFragmentDirective};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@readium/helpers",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "description": "General-purpose browser helpers for Readium packages",
6
6
  "author": "readium",
@@ -29,7 +29,7 @@
29
29
  "types"
30
30
  ],
31
31
  "engines": {
32
- "node": ">=18"
32
+ "node": ">=24"
33
33
  },
34
34
  "dependencies": {
35
35
  "user-agent-data-types": "^0.4.2"
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from "./color.ts";
2
2
  export * from "./sML.ts";
3
+ export * from "./text.ts";
3
4
  export * from "./textFragmentDirective.ts";
4
5
  export * from "./vendor/text-fragments-polyfill/textFragmentMatcher.ts";
5
6
  export * from "./vendor/text-fragments-polyfill/textFragmentGenerator.ts";
package/src/text.ts ADDED
@@ -0,0 +1,13 @@
1
+ // Backward-binding: closing brackets/quotes (Pe/Pf) plus terminal marks (.,;:!? and CJK/Arabic equivalents).
2
+ export const BINDING_PUNCT_CLASS = "\\p{Pe}\\p{Pf}.,;:!?,。、;:!?،؛؟";
3
+
4
+ const BINDING_PUNCT_RE = new RegExp(`^[${BINDING_PUNCT_CLASS}]`, "u");
5
+
6
+ export function startsWithBindingPunct(s: string): boolean {
7
+ return BINDING_PUNCT_RE.test(s);
8
+ }
9
+
10
+ export const ssmlTextEscape = (s: string) =>
11
+ s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12
+ export const ssmlAttrEscape = (s: string) =>
13
+ s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -364,8 +364,10 @@ const isHiddenUntilFound = (elt: Element): boolean => {
364
364
  const isNodeVisible = (node: Node): boolean => {
365
365
  // Find an HTMLElement (this node or an ancestor) so we can check
366
366
  // visibility.
367
- let elt: Node | null = node;
368
- while (elt != null && !(elt instanceof HTMLElement)) elt = elt.parentNode;
367
+ let parent: Node | null = node;
368
+ // nodeType, not instanceof: the document may belong to another realm (e.g. a frame).
369
+ while (parent != null && parent.nodeType !== Node.ELEMENT_NODE) parent = parent.parentNode;
370
+ const elt = parent as Element | null;
369
371
  // A document parsed via DOMParser (as opposed to one attached to a
370
372
  // real browsing context) has no defaultView, and therefore no
371
373
  // rendering/layout at all — nothing to check visibility against, so
@@ -455,8 +457,8 @@ const getAllTextNodes = (root: Node, range?: Range): Text[][] => {
455
457
  if (node.nodeType === Node.TEXT_NODE) {
456
458
  tmp.push(node as Text);
457
459
  } else if (
458
- node instanceof HTMLElement &&
459
- BLOCK_ELEMENTS.includes(node.tagName.toUpperCase()) && tmp.length > 0) {
460
+ node.nodeType === Node.ELEMENT_NODE &&
461
+ BLOCK_ELEMENTS.includes((node as Element).tagName.toUpperCase()) && tmp.length > 0) {
460
462
  // If this is a block element, the current set of text nodes in |tmp| is
461
463
  // complete, and we need to move on to a new one.
462
464
  blocks.push(tmp);
@@ -1,5 +1,6 @@
1
1
  export * from "./color.ts";
2
2
  export * from "./sML.ts";
3
+ export * from "./text.ts";
3
4
  export * from "./textFragmentDirective.ts";
4
5
  export * from "./vendor/text-fragments-polyfill/textFragmentMatcher.ts";
5
6
  export * from "./vendor/text-fragments-polyfill/textFragmentGenerator.ts";
@@ -0,0 +1,4 @@
1
+ export declare const BINDING_PUNCT_CLASS = "\\p{Pe}\\p{Pf}.,;:!?\uFF0C\u3002\u3001\uFF1B\uFF1A\uFF01\uFF1F\u060C\u061B\u061F";
2
+ export declare function startsWithBindingPunct(s: string): boolean;
3
+ export declare const ssmlTextEscape: (s: string) => string;
4
+ export declare const ssmlAttrEscape: (s: string) => string;