au-text-highlight
Version:
3行代码实现划词相关功能、关键字高亮、选区检测等功能。附带React版本划词popover组件。专为解决划词翻译,划词评论,web文本高亮等这类需求!目前再探索完善。
2 lines (1 loc) • 8.54 kB
JavaScript
import{jsx as t}from"react/jsx-runtime";import{useState as e,useCallback as n,useEffect as o,useRef as i}from"react";import{createPortal as r}from"react-dom";var l=function(t,e){return l=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},l(t,e)};var c=function(){return c=Object.assign||function(t){for(var e,n=1,o=arguments.length;n<o;n++)for(var i in e=arguments[n])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t},c.apply(this,arguments)};"function"==typeof SuppressedError&&SuppressedError;var u=function(t,e){var n=null===document||void 0===document?void 0:document.getSelection();if(!n)throw new Error("No selection found");n.removeAllRanges(),e.forEach((function(e){var n=e.start,o=e.end,i=e.gid,r=void 0===i?"":i,l=function(t,e,n){void 0===e&&(e=0);void 0===n&&(n=0);var o=[],i=function(t){(function(t,e,n){if(n||2===arguments.length)for(var o,i=0,r=e.length;i<r;i++)!o&&i in e||(o||(o=Array.prototype.slice.call(e,0,i)),o[i]=e[i]);return t.concat(o||Array.prototype.slice.call(e))})([],t,!0).forEach((function(t){"#text"===t.nodeName?o.push(t):t.textContent&&i(t.childNodes)}))};i(t.childNodes);var r=null,l=0,c=null,u=0,s=l;if(o.forEach((function(t){if(!r||!c){var o=t.textContent.length,i=[s,s+o];!r&&e>=i[0]&&e<i[1]&&(r=t,l=e-i[0]),!c&&n>i[0]&&n<=i[1]&&(c=t,u=n-i[0]),s+=o}})),!r||!c)return null;return[r,l,c,u]}(t,n,o),c=l[0],u=l[1],s=l[2],a=l[3],d=document.createRange();d.setStart(c,u),d.setEnd(s,a);var v=document.createElement("span");v.setAttribute("role","text"),v.setAttribute("aria-label","高亮内容"),v.className="word_comment_mark",r&&v.setAttribute("id",r);try{d.surroundContents(v)}catch(t){console.error("存在不可高亮的元素,多半由于选区交叉导致")}}))};var s=0;function a(){if(document){var t=null===document||void 0===document?void 0:document.getSelection();if(t)return{content:t.toString(),section:t};throw new Error("selection is undefined")}throw new Error("document is undefined")}function d(t,e){s=0;var n=document.getSelection(),o=n.getRangeAt(0);!function(t,e,n){var o=1e3,i=[],r=t.childNodes,l=function(t,e){if(void 0===e&&(e=0),e>o)throw new Error("DOM tree is too deep");for(var n=0;n<t.length;n++){var r=t[n];r.textContent&&("#text"===r.nodeName?i.push(r):l(r.childNodes,e+1))}};l(r),i.length>0&&i.some((function(t){return t.textContent===e.textContent?(s+=n,!0):(t.textContent&&(s+=t.textContent.length),!1)}))}(t,o.startContainer,o.startOffset);var i=s+n.toString().trim().length;return[s,i]}function v(t,e){for(var n,o=function(t){var e=function(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")};if("string"==typeof t)return new RegExp("".concat(e(t)),"gi");if(Array.isArray(t)){var n=t.map(e);return new RegExp("(".concat(n.join("|"),")"),"gi")}}(e),i=[];null!==(n=o.exec(t));)i.push({keyword:n[0],start:n.index,end:n.index+n[0].length});return i}function p(t){return v(t.text,t.keywords)}var f=function(t){function e(e,n){return void 0===n&&(n={}),t.call(this,e,n)||this}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}l(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}(e,t),e}(function(){function t(t,e){var n;void 0===e&&(e={}),this.popoverEle=null,this.distance=5,this.distance=null!==(n=null==e?void 0:e.distance)&&void 0!==n?n:this.distance,this.init(t),this.initEvent()}return t.prototype.init=function(t){var e=document.getElementById(t);if(!e)throw new Error("popoverId is not found");this.popoverEle=e,this.popoverEle.style.visibility="hidden",this.popoverEle.style.display="none",this.popoverEle.style.position="fixed",document.body.appendChild(this.popoverEle)},t.prototype.initEvent=function(){var t=this;document.addEventListener("mouseup",(function(){setTimeout((function(){var e=t.getTriggerPosition();e?t.show(e):t.hide()}),100)}))},t.prototype.show=function(t){var e=t.x,n=void 0===e?0:e,o=t.y,i=void 0===o?0:o,r=t.width,l=void 0===r?0:r;if(this.popoverEle){var c=n+l/2-this.popoverEle.offsetWidth/2,u=i-this.popoverEle.offsetHeight-this.distance;t.height>30&&(c=n+l-this.popoverEle.offsetWidth),this.popoverEle.style.left="".concat(c,"px"),this.popoverEle.style.top="".concat(u,"px"),this.popoverEle.style.display="block",this.popoverEle.style.visibility="visible"}},t.prototype.hide=function(){this.popoverEle&&(this.popoverEle.style.display="none",this.popoverEle.style.visibility="hidden")},t.prototype.getTriggerPosition=function(){var t,e=document.getSelection();if(e){var n=null===(t=document.getSelection())||void 0===t?void 0:t.toString();if(n){var o=e.getRangeAt(0).getBoundingClientRect();return 0===o.width&&0===o.height?null:{text:n,x:o.left+window.scrollX,y:o.top+window.scrollY,width:o.width,height:o.height}}return null}console.error("no selection")},t}());function h(t){void 0===t&&(t={});var i=t.delay,r=void 0===i?100:i,l=t.container,c=t.selectionChange,u=e(null),s=u[0],a=u[1],d=e(!1),v=d[0],p=d[1],f=n((function(){var t=document.getSelection();if(!t)return null;var e=t.toString();if(!e)return null;if(l)try{var n=t.getRangeAt(0);if(!l.contains(n.startContainer)||!l.contains(n.endContainer))return null}catch(t){return null}try{var o=(n=t.getRangeAt(0)).getBoundingClientRect();return 0===o.width&&0===o.height?null:{text:e,x:o.left,y:o.top,width:o.width,height:o.height}}catch(t){return console.error("获取选区位置失败:",t),null}}),[l]),h=n((function(){a(null),p(!1),null==c||c(null)}),[c]),g=n((function(){p(!0),a(null),null==c||c(null)}),[c]),y=n((function(){setTimeout((function(){var t=f();t?(a(t),null==c||c(t)):(a(null),null==c||c(null)),p(!1)}),r)}),[f,r,c]),m=n((function(){v||(f()||(a(null),null==c||c(null)))}),[f,v,c]);return o((function(){var t=l||document;return t.addEventListener("mousedown",g),t.addEventListener("mouseup",y),document.addEventListener("selectionchange",m),function(){t.removeEventListener("mousedown",g),t.removeEventListener("mouseup",y),document.removeEventListener("selectionchange",m)}}),[l,g,y,m]),{selection:s,isSelecting:v,clearSelection:h,getTriggerPosition:f}}var g=function(l){var u,s,a=l.children,d=l.distance,v=void 0===d?10:d,p=l.className,f=void 0===p?"":p,g=l.style,y=void 0===g?{}:g,m=l.container,w=l.onShow,E=l.onHide,x=l.disabled,b=void 0!==x&&x,S=l.zIndex,C=void 0===S?9999:S,A=l.portal,L=void 0===A||A,R=i(null),N=e(!1),O=N[0],T=N[1],_=e({}),P=_[0],j=_[1],k=n((function(t){if(!R.current)return{};var e=t.x,n=t.y,o=t.width,i=t.height,r=R.current.getBoundingClientRect(),l=e+o/2-r.width/2,c=n-r.height-v,u=window.innerWidth,s=window.scrollX,a=window.scrollY;return l<s?l=s+8:l+r.width>s+u&&(l=s+u-r.width-8),c<a&&(c=n+i+v),i>30&&(l=e+o-r.width)+r.width>s+u&&(l=s+u-r.width-8),{position:"fixed",left:"".concat(l,"px"),top:"".concat(c,"px"),zIndex:C,opacity:1,visibility:"visible",transform:"translateY(0)",transition:"opacity 0.2s ease, transform 0.2s ease"}}),[v,C]),z=h({delay:100,container:m,selectionChange:n((function(t){if(b)T(!1);else if(t){var e=k(t);j(e),T(!0),null==w||w(t)}else T(!1),j((function(t){return c(c({},t),{opacity:0,visibility:"hidden",transform:"translateY(-4px)"})})),null==E||E()}),[b,k,w,E])}),B=z.selection,I=z.clearSelection,Y=z.getTriggerPosition;o((function(){var t=function(t){O&&R.current&&!R.current.contains(t.target)&&I()};return document.addEventListener("mousedown",t),function(){document.removeEventListener("mousedown",t)}}),[O,I]),o((function(){if(O&&B){var t,e,n,o,i=(t=function(){var t=Y();if(t){var e=k(t);j(e)}},e=50,n=null,o=0,function(){for(var i=[],r=0;r<arguments.length;r++)i[r]=arguments[r];var l=Date.now();if(l-o>e)return o=l,t.apply(void 0,i);n&&clearTimeout(n),n=window.setTimeout((function(){o=Date.now(),t.apply(void 0,i),n=null}),e-(l-o))});return window.addEventListener("resize",i),window.addEventListener("scroll",i),function(){window.removeEventListener("resize",i),window.removeEventListener("scroll",i)}}}),[O,B,k]);var D=t("div",{ref:R,className:"au-text-highlight-popover ".concat(f),style:c(c(c({},P),y),{position:P.position||"fixed",pointerEvents:O?"auto":"none",userSelect:"none",opacity:null!==(u=P.opacity)&&void 0!==u?u:0,visibility:null!==(s=P.visibility)&&void 0!==s?s:"hidden"}),children:a});return L?r(D,document.body):D};export{f as DrawWordConstituencyPopover,g as ReactAuSelectionPopover,p as auExtractText,d as getSelectionRange,a as getSelectionRangeContent,u as sectionRangeHighlight,h as useTextSelection};