@whitesev/domutils 1.5.11 → 1.6.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.
package/dist/index.esm.js CHANGED
@@ -278,7 +278,7 @@ const createLoadOrReturnBroker = (loadBroker, worker) => {
278
278
  };
279
279
 
280
280
  // This is the minified and stringified code of the worker-timers-worker package.
281
- const worker = `(()=>{var e={455:function(e,t){!function(e){"use strict";var t=function(e){return function(t){var r=e(t);return t.add(r),r}},r=function(e){return function(t,r){return e.set(t,r),r}},n=void 0===Number.MAX_SAFE_INTEGER?9007199254740991:Number.MAX_SAFE_INTEGER,o=536870912,s=2*o,a=function(e,t){return function(r){var a=t.get(r),i=void 0===a?r.size:a<s?a+1:0;if(!r.has(i))return e(r,i);if(r.size<o){for(;r.has(i);)i=Math.floor(Math.random()*s);return e(r,i)}if(r.size>n)throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");for(;r.has(i);)i=Math.floor(Math.random()*n);return e(r,i)}},i=new WeakMap,u=r(i),c=a(u,i),d=t(c);e.addUniqueNumber=d,e.generateUniqueNumber=c}(t)}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var s=t[n]={exports:{}};return e[n].call(s.exports,s,s.exports,r),s.exports}(()=>{"use strict";const e=-32603,t=-32602,n=-32601,o=(e,t)=>Object.assign(new Error(e),{status:t}),s=t=>o('The handler of the method called "'.concat(t,'" returned an unexpected result.'),e),a=(t,r)=>async({data:{id:a,method:i,params:u}})=>{const c=r[i];try{if(void 0===c)throw(e=>o('The requested method called "'.concat(e,'" is not supported.'),n))(i);const r=void 0===u?c():c(u);if(void 0===r)throw(t=>o('The handler of the method called "'.concat(t,'" returned no required result.'),e))(i);const d=r instanceof Promise?await r:r;if(null===a){if(void 0!==d.result)throw s(i)}else{if(void 0===d.result)throw s(i);const{result:e,transferables:r=[]}=d;t.postMessage({id:a,result:e},r)}}catch(e){const{message:r,status:n=-32603}=e;t.postMessage({error:{code:n,message:r},id:a})}};var i=r(455);const u=new Map,c=(e,r,n)=>({...r,connect:({port:t})=>{t.start();const n=e(t,r),o=(0,i.generateUniqueNumber)(u);return u.set(o,(()=>{n(),t.close(),u.delete(o)})),{result:o}},disconnect:({portId:e})=>{const r=u.get(e);if(void 0===r)throw(e=>o('The specified parameter called "portId" with the given value "'.concat(e,'" does not identify a port connected to this worker.'),t))(e);return r(),{result:null}},isSupported:async()=>{if(await new Promise((e=>{const t=new ArrayBuffer(0),{port1:r,port2:n}=new MessageChannel;r.onmessage=({data:t})=>e(null!==t),n.postMessage(t,[t])}))){const e=n();return{result:e instanceof Promise?await e:e}}return{result:!1}}}),d=(e,t,r=()=>!0)=>{const n=c(d,t,r),o=a(e,n);return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},l=e=>t=>{const r=e.get(t);if(void 0===r)return Promise.resolve(!1);const[n,o]=r;return clearTimeout(n),e.delete(t),o(!1),Promise.resolve(!0)},f=(e,t,r)=>(n,o,s)=>{const{expected:a,remainingDelay:i}=e(n,o);return new Promise((e=>{t.set(s,[setTimeout(r,i,a,t,e,s),e])}))},m=(e,t)=>{const r=performance.now(),n=e+t-r-performance.timeOrigin;return{expected:r+n,remainingDelay:n}},p=(e,t,r,n)=>{const o=e-performance.now();o>0?t.set(n,[setTimeout(p,o,e,t,r,n),r]):(t.delete(n),r(!0))},h=new Map,v=l(h),w=new Map,g=l(w),M=f(m,h,p),y=f(m,w,p);d(self,{clear:async({timerId:e,timerType:t})=>({result:await("interval"===t?v(e):g(e))}),set:async({delay:e,now:t,timerId:r,timerType:n})=>({result:await("interval"===n?M:y)(e,t,r)})})})()})();`; // tslint:disable-line:max-line-length
281
+ const worker = `(()=>{var e={455:function(e,t){!function(e){"use strict";var t=function(e){return function(t){var r=e(t);return t.add(r),r}},r=function(e){return function(t,r){return e.set(t,r),r}},n=void 0===Number.MAX_SAFE_INTEGER?9007199254740991:Number.MAX_SAFE_INTEGER,o=536870912,s=2*o,a=function(e,t){return function(r){var a=t.get(r),i=void 0===a?r.size:a<s?a+1:0;if(!r.has(i))return e(r,i);if(r.size<o){for(;r.has(i);)i=Math.floor(Math.random()*s);return e(r,i)}if(r.size>n)throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");for(;r.has(i);)i=Math.floor(Math.random()*n);return e(r,i)}},i=new WeakMap,u=r(i),c=a(u,i),l=t(c);e.addUniqueNumber=l,e.generateUniqueNumber=c}(t)}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var s=t[n]={exports:{}};return e[n].call(s.exports,s,s.exports,r),s.exports}(()=>{"use strict";const e=-32603,t=-32602,n=-32601,o=(e,t)=>Object.assign(new Error(e),{status:t}),s=t=>o('The handler of the method called "'.concat(t,'" returned an unexpected result.'),e),a=(t,r)=>async({data:{id:a,method:i,params:u}})=>{const c=r[i];try{if(void 0===c)throw(e=>o('The requested method called "'.concat(e,'" is not supported.'),n))(i);const r=void 0===u?c():c(u);if(void 0===r)throw(t=>o('The handler of the method called "'.concat(t,'" returned no required result.'),e))(i);const l=r instanceof Promise?await r:r;if(null===a){if(void 0!==l.result)throw s(i)}else{if(void 0===l.result)throw s(i);const{result:e,transferables:r=[]}=l;t.postMessage({id:a,result:e},r)}}catch(e){const{message:r,status:n=-32603}=e;t.postMessage({error:{code:n,message:r},id:a})}};var i=r(455);const u=new Map,c=(e,r,n)=>({...r,connect:({port:t})=>{t.start();const n=e(t,r),o=(0,i.generateUniqueNumber)(u);return u.set(o,(()=>{n(),t.close(),u.delete(o)})),{result:o}},disconnect:({portId:e})=>{const r=u.get(e);if(void 0===r)throw(e=>o('The specified parameter called "portId" with the given value "'.concat(e,'" does not identify a port connected to this worker.'),t))(e);return r(),{result:null}},isSupported:async()=>{if(await new Promise((e=>{const t=new ArrayBuffer(0),{port1:r,port2:n}=new MessageChannel;r.onmessage=({data:t})=>e(null!==t),n.postMessage(t,[t])}))){const e=n();return{result:e instanceof Promise?await e:e}}return{result:!1}}}),l=(e,t,r=()=>!0)=>{const n=c(l,t,r),o=a(e,n);return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},d=(e,t)=>r=>{const n=t.get(r);if(void 0===n)return Promise.resolve(!1);const[o,s]=n;return e(o),t.delete(r),s(!1),Promise.resolve(!0)},f=(e,t,r,n)=>(o,s,a)=>{const i=o+s-t.timeOrigin,u=i-t.now();return new Promise((t=>{e.set(a,[r(n,u,i,e,t,a),t])}))},m=new Map,h=d(globalThis.clearTimeout,m),p=new Map,v=d(globalThis.clearTimeout,p),w=((e,t)=>{const r=(n,o,s,a)=>{const i=n-e.now();i>0?o.set(a,[t(r,i,n,o,s,a),s]):(o.delete(a),s(!0))};return r})(performance,globalThis.setTimeout),g=f(m,performance,globalThis.setTimeout,w),T=f(p,performance,globalThis.setTimeout,w);l(self,{clear:async({timerId:e,timerType:t})=>({result:await("interval"===t?h(e):v(e))}),set:async({delay:e,now:t,timerId:r,timerType:n})=>({result:await("interval"===n?g:T)(e,t,r)})})})()})();`; // tslint:disable-line:max-line-length
282
282
 
283
283
  const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
284
284
  const clearInterval = (timerId) => loadOrReturnBroker().clearInterval(timerId);
@@ -600,8 +600,7 @@ class DOMUtilsEvent {
600
600
  : event.target;
601
601
  let totalParent = elementItem;
602
602
  if (DOMUtilsCommonUtils.isWin(totalParent)) {
603
- if (totalParent ===
604
- DOMUtilsContext.windowApi.document) {
603
+ if (totalParent === DOMUtilsContext.windowApi.document) {
605
604
  totalParent = DOMUtilsContext.windowApi.document.documentElement;
606
605
  }
607
606
  }
@@ -669,8 +668,7 @@ class DOMUtilsEvent {
669
668
  if (typeof currentParam === "boolean") {
670
669
  option.capture = currentParam;
671
670
  }
672
- else if (typeof currentParam === "object" &&
673
- "capture" in currentParam) {
671
+ else if (typeof currentParam === "object" && "capture" in currentParam) {
674
672
  option.capture = currentParam.capture;
675
673
  }
676
674
  return option;
@@ -732,8 +730,7 @@ class DOMUtilsEvent {
732
730
  // 目标函数、事件名
733
731
  isRemoveAll = true;
734
732
  }
735
- else if ((args.length === 3 && typeof args[2] === "string") ||
736
- Array.isArray(args[2])) {
733
+ else if ((args.length === 3 && typeof args[2] === "string") || Array.isArray(args[2])) {
737
734
  // 目标函数、事件名、子元素选择器
738
735
  isRemoveAll = true;
739
736
  }
@@ -748,9 +745,7 @@ class DOMUtilsEvent {
748
745
  for (let index = 0; index < handlers.length; index++) {
749
746
  let handler = handlers[index];
750
747
  let flag = true;
751
- if (flag &&
752
- listenerCallBack &&
753
- handler.originCallBack !== listenerCallBack) {
748
+ if (flag && listenerCallBack && handler.originCallBack !== listenerCallBack) {
754
749
  // callback不同
755
750
  flag = false;
756
751
  }
@@ -810,9 +805,7 @@ class DOMUtilsEvent {
810
805
  return;
811
806
  }
812
807
  let elementEvents = elementItem[symbolEvents] || {};
813
- let iterEventNameList = eventTypeList.length
814
- ? eventTypeList
815
- : Object.keys(elementEvents);
808
+ let iterEventNameList = eventTypeList.length ? eventTypeList : Object.keys(elementEvents);
816
809
  iterEventNameList.forEach((eventName) => {
817
810
  let handlers = elementEvents[eventName];
818
811
  if (!handlers) {
@@ -849,8 +842,7 @@ class DOMUtilsEvent {
849
842
  try {
850
843
  if (DOMUtilsContext.windowApi.document.readyState === "complete" ||
851
844
  (DOMUtilsContext.windowApi.document.readyState !== "loading" &&
852
- !DOMUtilsContext.windowApi.document.documentElement
853
- .doScroll)) {
845
+ !DOMUtilsContext.windowApi.document.documentElement.doScroll)) {
854
846
  return true;
855
847
  }
856
848
  else {
@@ -1485,7 +1477,7 @@ class DOMUtils extends DOMUtilsEvent {
1485
1477
  super(option);
1486
1478
  }
1487
1479
  /** 版本号 */
1488
- version = "2025.6.26";
1480
+ version = "2025.8.9";
1489
1481
  attr(element, attrName, attrValue) {
1490
1482
  let DOMUtilsContext = this;
1491
1483
  if (typeof element === "string") {
@@ -1579,15 +1571,7 @@ class DOMUtils extends DOMUtilsEvent {
1579
1571
  * 把纯数字没有px的加上
1580
1572
  */
1581
1573
  function handlePixe(propertyName, propertyValue) {
1582
- let allowAddPixe = [
1583
- "width",
1584
- "height",
1585
- "top",
1586
- "left",
1587
- "right",
1588
- "bottom",
1589
- "font-size",
1590
- ];
1574
+ let allowAddPixe = ["width", "height", "top", "left", "right", "bottom", "font-size"];
1591
1575
  if (typeof propertyValue === "number") {
1592
1576
  propertyValue = propertyValue.toString();
1593
1577
  }
@@ -1629,8 +1613,7 @@ class DOMUtils extends DOMUtilsEvent {
1629
1613
  return;
1630
1614
  }
1631
1615
  let setStyleProperty = (propertyName, propertyValue) => {
1632
- if (typeof propertyValue === "string" &&
1633
- propertyValue.trim().endsWith("!important")) {
1616
+ if (typeof propertyValue === "string" && propertyValue.trim().endsWith("!important")) {
1634
1617
  propertyValue = propertyValue
1635
1618
  .trim()
1636
1619
  .replace(/!important$/gi, "")
@@ -1644,9 +1627,7 @@ class DOMUtils extends DOMUtilsEvent {
1644
1627
  };
1645
1628
  if (typeof property === "string") {
1646
1629
  if (value == null) {
1647
- return DOMUtilsContext.windowApi.globalThis
1648
- .getComputedStyle(element)
1649
- .getPropertyValue(property);
1630
+ return DOMUtilsContext.windowApi.globalThis.getComputedStyle(element).getPropertyValue(property);
1650
1631
  }
1651
1632
  else {
1652
1633
  setStyleProperty(property, value);
@@ -1749,12 +1730,8 @@ class DOMUtils extends DOMUtilsEvent {
1749
1730
  return transformInfo;
1750
1731
  }
1751
1732
  let elementTransform = DOMUtilsContext.windowApi.globalThis.getComputedStyle(element).transform;
1752
- if (elementTransform != null &&
1753
- elementTransform !== "none" &&
1754
- elementTransform !== "") {
1755
- let elementTransformSplit = elementTransform
1756
- .match(/\((.+)\)/)?.[1]
1757
- .split(",");
1733
+ if (elementTransform != null && elementTransform !== "none" && elementTransform !== "") {
1734
+ let elementTransformSplit = elementTransform.match(/\((.+)\)/)?.[1].split(",");
1758
1735
  if (elementTransformSplit) {
1759
1736
  transform_left = Math.abs(parseInt(elementTransformSplit[4]));
1760
1737
  transform_top = Math.abs(parseInt(elementTransformSplit[5]));
@@ -1792,8 +1769,7 @@ class DOMUtils extends DOMUtilsEvent {
1792
1769
  }
1793
1770
  if (value == null) {
1794
1771
  // 获取
1795
- if (element.localName === "input" &&
1796
- (element.type === "checkbox" || element.type === "radio")) {
1772
+ if (element.localName === "input" && (element.type === "checkbox" || element.type === "radio")) {
1797
1773
  return element.checked;
1798
1774
  }
1799
1775
  else {
@@ -1802,8 +1778,7 @@ class DOMUtils extends DOMUtilsEvent {
1802
1778
  }
1803
1779
  else {
1804
1780
  // 设置
1805
- if (element.localName === "input" &&
1806
- (element.type === "checkbox" || element.type === "radio")) {
1781
+ if (element.localName === "input" && (element.type === "checkbox" || element.type === "radio")) {
1807
1782
  element.checked = !!value;
1808
1783
  }
1809
1784
  else {
@@ -2057,7 +2032,15 @@ class DOMUtils extends DOMUtilsEvent {
2057
2032
  }
2058
2033
  function elementAppendChild(ele, text) {
2059
2034
  if (typeof content === "string") {
2060
- ele.insertAdjacentHTML("beforeend", DOMUtilsCommonUtils.getSafeHTML(text));
2035
+ if (ele instanceof DocumentFragment) {
2036
+ if (typeof text === "string") {
2037
+ text = DOMUtilsContext.parseHTML(text, true, false);
2038
+ }
2039
+ ele.appendChild(text);
2040
+ }
2041
+ else {
2042
+ ele.insertAdjacentHTML("beforeend", DOMUtilsCommonUtils.getSafeHTML(text));
2043
+ }
2061
2044
  }
2062
2045
  else {
2063
2046
  ele.appendChild(text);
@@ -2068,6 +2051,7 @@ class DOMUtils extends DOMUtilsEvent {
2068
2051
  let fragment = DOMUtilsContext.windowApi.document.createDocumentFragment();
2069
2052
  content.forEach((ele) => {
2070
2053
  if (typeof ele === "string") {
2054
+ // 转为元素
2071
2055
  ele = DOMUtilsContext.parseHTML(ele, true, false);
2072
2056
  }
2073
2057
  fragment.appendChild(ele);
@@ -2103,7 +2087,13 @@ class DOMUtils extends DOMUtilsEvent {
2103
2087
  return;
2104
2088
  }
2105
2089
  if (typeof content === "string") {
2106
- element.insertAdjacentHTML("afterbegin", DOMUtilsCommonUtils.getSafeHTML(content));
2090
+ if (element instanceof DocumentFragment) {
2091
+ content = DOMUtilsContext.parseHTML(content, true, false);
2092
+ element.prepend(content);
2093
+ }
2094
+ else {
2095
+ element.insertAdjacentHTML("afterbegin", DOMUtilsCommonUtils.getSafeHTML(content));
2096
+ }
2107
2097
  }
2108
2098
  else {
2109
2099
  let $firstChild = element.firstChild;
@@ -2276,16 +2266,14 @@ class DOMUtils extends DOMUtilsEvent {
2276
2266
  return;
2277
2267
  }
2278
2268
  if (DOMUtilsCommonUtils.isWin(element)) {
2279
- return DOMUtilsContext.windowApi.window.document.documentElement
2280
- .clientWidth;
2269
+ return DOMUtilsContext.windowApi.window.document.documentElement.clientWidth;
2281
2270
  }
2282
2271
  if (element.nodeType === 9) {
2283
2272
  /* Document文档节点 */
2284
2273
  element = element;
2285
2274
  return Math.max(element.body.scrollWidth, element.documentElement.scrollWidth, element.body.offsetWidth, element.documentElement.offsetWidth, element.documentElement.clientWidth);
2286
2275
  }
2287
- if (isShow ||
2288
- (!isShow && DOMUtilsCommonUtils.isShow(element))) {
2276
+ if (isShow || (!isShow && DOMUtilsCommonUtils.isShow(element))) {
2289
2277
  /* 已显示 */
2290
2278
  /* 不从style中获取对应的宽度,因为可能使用了class定义了width !important */
2291
2279
  element = element;
@@ -2320,8 +2308,7 @@ class DOMUtils extends DOMUtilsEvent {
2320
2308
  height(element, isShow = false) {
2321
2309
  let DOMUtilsContext = this;
2322
2310
  if (DOMUtilsCommonUtils.isWin(element)) {
2323
- return DOMUtilsContext.windowApi.window.document.documentElement
2324
- .clientHeight;
2311
+ return DOMUtilsContext.windowApi.window.document.documentElement.clientHeight;
2325
2312
  }
2326
2313
  if (typeof element === "string") {
2327
2314
  element = DOMUtilsContext.selector(element);
@@ -2335,8 +2322,7 @@ class DOMUtils extends DOMUtilsEvent {
2335
2322
  /* Document文档节点 */
2336
2323
  return Math.max(element.body.scrollHeight, element.documentElement.scrollHeight, element.body.offsetHeight, element.documentElement.offsetHeight, element.documentElement.clientHeight);
2337
2324
  }
2338
- if (isShow ||
2339
- (!isShow && DOMUtilsCommonUtils.isShow(element))) {
2325
+ if (isShow || (!isShow && DOMUtilsCommonUtils.isShow(element))) {
2340
2326
  element = element;
2341
2327
  /* 已显示 */
2342
2328
  /* 从style中获取对应的高度,因为可能使用了class定义了width !important */
@@ -2464,8 +2450,7 @@ class DOMUtils extends DOMUtilsEvent {
2464
2450
  let to = {};
2465
2451
  for (let prop in styles) {
2466
2452
  from[prop] =
2467
- element.style[prop] ||
2468
- DOMUtilsContext.windowApi.globalThis.getComputedStyle(element)[prop];
2453
+ element.style[prop] || DOMUtilsContext.windowApi.globalThis.getComputedStyle(element)[prop];
2469
2454
  to[prop] = styles[prop];
2470
2455
  }
2471
2456
  let timer = DOMUtilsCommonUtils.setInterval(function () {
@@ -2475,8 +2460,7 @@ class DOMUtils extends DOMUtilsEvent {
2475
2460
  progress = 1;
2476
2461
  }
2477
2462
  for (let prop in styles) {
2478
- element.style[prop] =
2479
- from[prop] + (to[prop] - from[prop]) * progress + "px";
2463
+ element.style[prop] = from[prop] + (to[prop] - from[prop]) * progress + "px";
2480
2464
  }
2481
2465
  if (progress === 1) {
2482
2466
  DOMUtilsCommonUtils.clearInterval(timer);
@@ -2561,8 +2545,7 @@ class DOMUtils extends DOMUtilsEvent {
2561
2545
  if (element == null) {
2562
2546
  return;
2563
2547
  }
2564
- return Array.from(element.parentElement
2565
- .children).filter((child) => child !== element);
2548
+ return Array.from(element.parentElement.children).filter((child) => child !== element);
2566
2549
  }
2567
2550
  /**
2568
2551
  * 获取当前元素的父元素
@@ -2638,14 +2621,7 @@ class DOMUtils extends DOMUtilsEvent {
2638
2621
  if (element.name &&
2639
2622
  !element.disabled &&
2640
2623
  (element.checked ||
2641
- [
2642
- "text",
2643
- "hidden",
2644
- "password",
2645
- "textarea",
2646
- "select-one",
2647
- "select-multiple",
2648
- ].includes(element.type))) {
2624
+ ["text", "hidden", "password", "textarea", "select-one", "select-multiple"].includes(element.type))) {
2649
2625
  if (element.type === "select-multiple") {
2650
2626
  for (let j = 0; j < element.options.length; j++) {
2651
2627
  if (element.options[j].selected) {
@@ -2865,9 +2841,7 @@ class DOMUtils extends DOMUtilsEvent {
2865
2841
  });
2866
2842
  return;
2867
2843
  }
2868
- if (DOMUtilsContext.windowApi.globalThis
2869
- .getComputedStyle(element)
2870
- .getPropertyValue("display") === "none") {
2844
+ if (DOMUtilsContext.windowApi.globalThis.getComputedStyle(element).getPropertyValue("display") === "none") {
2871
2845
  DOMUtilsContext.show(element, checkVisiblie);
2872
2846
  }
2873
2847
  else {
@@ -2912,9 +2886,7 @@ class DOMUtils extends DOMUtilsEvent {
2912
2886
  selectionStart = Math.min($input.value.length, selectionStart);
2913
2887
  if (typeof selectionEnd == "string")
2914
2888
  selectionEnd = parseFloat(selectionEnd);
2915
- if (typeof selectionEnd != "number" ||
2916
- isNaN(selectionEnd) ||
2917
- selectionEnd < selectionStart) {
2889
+ if (typeof selectionEnd != "number" || isNaN(selectionEnd) || selectionEnd < selectionStart) {
2918
2890
  selectionEnd = selectionStart;
2919
2891
  }
2920
2892
  if (selectionEnd < 0)
@@ -3001,11 +2973,7 @@ class DOMUtils extends DOMUtilsEvent {
3001
2973
  var isBoxModel = $box.offsetWidth == 2;
3002
2974
  body.removeChild($box);
3003
2975
  let $boxRect = $input.getBoundingClientRect();
3004
- var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, scrollTop = win.pageYOffset ||
3005
- (isBoxModel && docElem.scrollTop) ||
3006
- body.scrollTop, scrollLeft = win.pageXOffset ||
3007
- (isBoxModel && docElem.scrollLeft) ||
3008
- body.scrollLeft;
2976
+ var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, scrollTop = win.pageYOffset || (isBoxModel && docElem.scrollTop) || body.scrollTop, scrollLeft = win.pageXOffset || (isBoxModel && docElem.scrollLeft) || body.scrollLeft;
3009
2977
  return {
3010
2978
  top: $boxRect.top + scrollTop - clientTop,
3011
2979
  left: $boxRect.left + scrollLeft - clientLeft,