wsemi 1.9.5 → 1.9.6

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.
Files changed (490) hide show
  1. package/README.md +1 -1
  2. package/dist/wsemi.umd.js +5 -5
  3. package/dist/wsemi.umd.js.map +1 -1
  4. package/docs/-_class.mjs.html +1 -1
  5. package/docs/-_const.mjs.html +1 -1
  6. package/docs/ab2blob.mjs.html +1 -1
  7. package/docs/ab2u8arr.mjs.html +1 -1
  8. package/docs/addExcelWorksheetFromData.mjs.html +1 -1
  9. package/docs/addMonth.mjs.html +1 -1
  10. package/docs/aes2str.mjs.html +1 -1
  11. package/docs/alive.mjs.html +1 -1
  12. package/docs/arr2dt.mjs.html +1 -1
  13. package/docs/arrAccum.mjs.html +1 -1
  14. package/docs/arrAdd.mjs.html +1 -1
  15. package/docs/arrAt.mjs.html +1 -1
  16. package/docs/arrDiff.mjs.html +1 -1
  17. package/docs/arrFilterByKeywords.mjs.html +1 -1
  18. package/docs/arrFilterByNum.mjs.html +1 -1
  19. package/docs/arrFilterByPnum.mjs.html +1 -1
  20. package/docs/arrFilterByPnumAndToLog.mjs.html +1 -1
  21. package/docs/arrFind.mjs.html +1 -1
  22. package/docs/arrGroupByMaxmin.mjs.html +1 -1
  23. package/docs/arrHas.mjs.html +1 -1
  24. package/docs/arrInsert.mjs.html +1 -1
  25. package/docs/arrLookupByMaxmin.mjs.html +1 -1
  26. package/docs/arrMax.mjs.html +1 -1
  27. package/docs/arrMin.mjs.html +1 -1
  28. package/docs/arrMulti.mjs.html +1 -1
  29. package/docs/arrNorm.mjs.html +1 -1
  30. package/docs/arrProduct.mjs.html +1 -1
  31. package/docs/arrPull.mjs.html +1 -1
  32. package/docs/arrPullAt.mjs.html +1 -1
  33. package/docs/arrReduce.mjs.html +1 -1
  34. package/docs/arrReverse.mjs.html +1 -1
  35. package/docs/arrSep.mjs.html +1 -1
  36. package/docs/arrSort.mjs.html +1 -1
  37. package/docs/asind.mjs.html +1 -1
  38. package/docs/atan2d.mjs.html +1 -1
  39. package/docs/atand.mjs.html +1 -1
  40. package/docs/attstr.mjs.html +1 -1
  41. package/docs/b642obj.mjs.html +1 -1
  42. package/docs/b642str.mjs.html +1 -1
  43. package/docs/b642u16arr.mjs.html +1 -1
  44. package/docs/b642u8arr.mjs.html +1 -1
  45. package/docs/binstr.mjs.html +1 -1
  46. package/docs/blob2ab.mjs.html +1 -1
  47. package/docs/blob2b64.mjs.html +1 -1
  48. package/docs/blob2str.mjs.html +1 -1
  49. package/docs/blob2u8arr.mjs.html +1 -1
  50. package/docs/blobs2b64s.mjs.html +1 -1
  51. package/docs/blobs2u8arrs.mjs.html +1 -1
  52. package/docs/bodyLog.mjs.html +1 -1
  53. package/docs/browserView.mjs.html +1 -1
  54. package/docs/browserViewFromBlob.mjs.html +1 -1
  55. package/docs/browserViewFromText.mjs.html +1 -1
  56. package/docs/browserViewFromU8arr.mjs.html +1 -1
  57. package/docs/bs2u8arr.mjs.html +1 -1
  58. package/docs/bufRead.mjs.html +1 -1
  59. package/docs/bufReadDbl.mjs.html +1 -1
  60. package/docs/bufWrite.mjs.html +1 -1
  61. package/docs/bufWriteDbl.mjs.html +1 -1
  62. package/docs/cache.mjs.html +1 -1
  63. package/docs/cacheBd.mjs.html +1 -1
  64. package/docs/cacheSt.mjs.html +1 -1
  65. package/docs/cbol.mjs.html +1 -1
  66. package/docs/cdbl.mjs.html +1 -1
  67. package/docs/ceil.mjs.html +1 -1
  68. package/docs/cfilesize.mjs.html +1 -1
  69. package/docs/cfinancial.mjs.html +1 -1
  70. package/docs/cint.mjs.html +1 -1
  71. package/docs/clearXSS.mjs.html +1 -1
  72. package/docs/clearXSSDyn.mjs.html +1 -1
  73. package/docs/color.mjs.html +1 -1
  74. package/docs/composeToTree.mjs.html +1 -1
  75. package/docs/convertToTree.mjs.html +1 -1
  76. package/docs/copyStrToClipboard.mjs.html +1 -1
  77. package/docs/cosd.mjs.html +1 -1
  78. package/docs/cotd.mjs.html +1 -1
  79. package/docs/createExcelWorkbook.mjs.html +1 -1
  80. package/docs/cscd.mjs.html +1 -1
  81. package/docs/cstr.mjs.html +1 -1
  82. package/docs/day2cht.mjs.html +1 -1
  83. package/docs/debounce.mjs.html +1 -1
  84. package/docs/delay.mjs.html +1 -1
  85. package/docs/dig.mjs.html +1 -1
  86. package/docs/digExp.mjs.html +1 -1
  87. package/docs/domAlert.mjs.html +1 -1
  88. package/docs/domAppend.mjs.html +1 -1
  89. package/docs/domCancelEvent.mjs.html +1 -1
  90. package/docs/domCompareText.mjs.html +1 -1
  91. package/docs/domConvertToPic.mjs.html +1 -1
  92. package/docs/domConvertToPicDyn.mjs.html +1 -1
  93. package/docs/domDetect.mjs.html +707 -462
  94. package/docs/domDrag.mjs.html +1 -1
  95. package/docs/domDragBarAndScroll.mjs.html +1 -1
  96. package/docs/domDragPointer.mjs.html +1 -1
  97. package/docs/domDragPreview.mjs.html +1 -1
  98. package/docs/domDropFiles.mjs.html +1 -1
  99. package/docs/domElementsFromPoint.mjs.html +1 -1
  100. package/docs/domFadeIn.mjs.html +1 -1
  101. package/docs/domFadeOut.mjs.html +1 -1
  102. package/docs/domFind.mjs.html +1 -1
  103. package/docs/domFinds.mjs.html +1 -1
  104. package/docs/domGetAttr.mjs.html +1 -1
  105. package/docs/domGetBoudRect.mjs.html +1 -1
  106. package/docs/domGetBoudRectRefSelf.mjs.html +1 -1
  107. package/docs/domGetFileAccept.mjs.html +1 -1
  108. package/docs/domGetFiles.mjs.html +1 -1
  109. package/docs/domGetParents.mjs.html +1 -1
  110. package/docs/domGetPointFromEvent.mjs.html +1 -1
  111. package/docs/domGetScrollableParent.mjs.html +1 -1
  112. package/docs/domGetWindowSize.mjs.html +1 -1
  113. package/docs/domIsClientXYIn.mjs.html +1 -1
  114. package/docs/domIsFocused.mjs.html +1 -1
  115. package/docs/domIsStable.mjs.html +1 -1
  116. package/docs/domIsVisible.mjs.html +1 -1
  117. package/docs/domPrepend.mjs.html +1 -1
  118. package/docs/domRemove.mjs.html +1 -1
  119. package/docs/domRenderMarkdownMind.mjs.html +1 -1
  120. package/docs/domRenderMarkdownMindDyn.mjs.html +1 -1
  121. package/docs/domRipple.mjs.html +1 -1
  122. package/docs/domScrollIntoView.mjs.html +1 -1
  123. package/docs/domScrollTo.mjs.html +1 -1
  124. package/docs/domSetAttr.mjs.html +1 -1
  125. package/docs/domShowImages.mjs.html +1 -1
  126. package/docs/domShowImagesDyn.mjs.html +1 -1
  127. package/docs/domShowInputAndGetFiles.mjs.html +1 -1
  128. package/docs/domShowInputAndGetFilesU8Arrs.mjs.html +1 -1
  129. package/docs/domShowInputDatatime.mjs.html +1 -1
  130. package/docs/domTooltip.mjs.html +1 -1
  131. package/docs/domTriggerEvent.mjs.html +1 -1
  132. package/docs/domVirtualCreate.mjs.html +1 -1
  133. package/docs/domVirtualCreateQueue.mjs.html +1 -1
  134. package/docs/downloadExcelFileFromData.mjs.html +1 -1
  135. package/docs/downloadExcelFileFromDataDyn.mjs.html +1 -1
  136. package/docs/downloadFileFromB64.mjs.html +1 -1
  137. package/docs/downloadFileFromBlob.mjs.html +1 -1
  138. package/docs/downloadFileFromText.mjs.html +1 -1
  139. package/docs/downloadFileFromU8Arr.mjs.html +1 -1
  140. package/docs/dtmapping.mjs.html +1 -1
  141. package/docs/dtpick.mjs.html +1 -1
  142. package/docs/estimateTicks.mjs.html +1 -1
  143. package/docs/evEmit.mjs.html +1 -1
  144. package/docs/evEmitDelay.mjs.html +1 -1
  145. package/docs/evem.mjs.html +1 -1
  146. package/docs/examples/ex-blob2b64.html +1 -1
  147. package/docs/examples/ex-clearXSS.html +1 -1
  148. package/docs/examples/ex-clearXSSDyn.html +1 -1
  149. package/docs/examples/ex-colorConverter.html +1 -1
  150. package/docs/examples/ex-domCompareText.html +1 -1
  151. package/docs/examples/ex-domConvertToPic.html +1 -1
  152. package/docs/examples/ex-domDrag.html +1 -1
  153. package/docs/examples/ex-domDropFiles.html +1 -1
  154. package/docs/examples/ex-domIsVisible.html +1 -1
  155. package/docs/examples/ex-domRenderMarkdownMind.html +1 -1
  156. package/docs/examples/ex-domRenderMarkdownMindDyn.html +1 -1
  157. package/docs/examples/ex-domRipple.html +1 -1
  158. package/docs/examples/ex-domScrollIntoView.html +1 -1
  159. package/docs/examples/ex-domScrollTo.html +1 -1
  160. package/docs/examples/ex-domShowImages.html +1 -1
  161. package/docs/examples/ex-domShowImagesDyn.html +1 -1
  162. package/docs/examples/ex-domShowInputAndGetFiles.html +1 -1
  163. package/docs/examples/ex-domTooltip.html +1 -1
  164. package/docs/examples/ex-getFileHash.html +1 -1
  165. package/docs/examples/ex-getUserAgent.html +1 -1
  166. package/docs/examples/ex-getUserAgentDyn.html +1 -1
  167. package/docs/examples/ex-html2str.html +1 -1
  168. package/docs/examples/ex-obj2u8arr-u8arr2obj.html +1 -1
  169. package/docs/examples/ex-openLink.html +1 -1
  170. package/docs/examples/ex-str2aes-aes2str.html +1 -1
  171. package/docs/examples/ex-str2b64-b642str.html +1 -1
  172. package/docs/examples/ex-strFindFuzz.html +1 -1
  173. package/docs/examples/ex-timeTZ2expire-timeTZ2past.html +1 -1
  174. package/docs/examples/ex-xlsx.html +1 -1
  175. package/docs/execCli.mjs.html +1 -1
  176. package/docs/execCliCore.mjs.html +1 -1
  177. package/docs/execCliJsonRpc.mjs.html +1 -1
  178. package/docs/execCliSession.mjs.html +1 -1
  179. package/docs/execJsCode.mjs.html +1 -1
  180. package/docs/execProcess.mjs.html +1 -1
  181. package/docs/execProcessKillPid.mjs.html +1 -1
  182. package/docs/filepathToTree.mjs.html +1 -1
  183. package/docs/files2data.mjs.html +1 -1
  184. package/docs/flattenToConn.mjs.html +1 -1
  185. package/docs/flattenTree.mjs.html +1 -1
  186. package/docs/floor.mjs.html +1 -1
  187. package/docs/fsBuildReadStreamText.mjs.html +1 -1
  188. package/docs/fsBuildWriteStreamText.mjs.html +1 -1
  189. package/docs/fsCleanFolder.mjs.html +1 -1
  190. package/docs/fsCleanFolderCore.mjs.html +1 -1
  191. package/docs/fsCopyFile.mjs.html +1 -1
  192. package/docs/fsCopyFileCore.mjs.html +1 -1
  193. package/docs/fsCopyFolder.mjs.html +1 -1
  194. package/docs/fsCopyFolderCore.mjs.html +1 -1
  195. package/docs/fsCreateFile.mjs.html +1 -1
  196. package/docs/fsCreateFileCore.mjs.html +1 -1
  197. package/docs/fsCreateFolder.mjs.html +1 -1
  198. package/docs/fsCreateFolderCore.mjs.html +1 -1
  199. package/docs/fsDeleteFile.mjs.html +1 -1
  200. package/docs/fsDeleteFileCore.mjs.html +1 -1
  201. package/docs/fsDeleteFileSafe.mjs.html +1 -1
  202. package/docs/fsDeleteFileSafeCore.mjs.html +1 -1
  203. package/docs/fsDeleteFolder.mjs.html +1 -1
  204. package/docs/fsDeleteFolderCore.mjs.html +1 -1
  205. package/docs/fsDeleteFolderSafe.mjs.html +1 -1
  206. package/docs/fsDeleteFolderSafeCore.mjs.html +1 -1
  207. package/docs/fsDownloadFile.mjs.html +1 -1
  208. package/docs/fsDownloadFileCore.mjs.html +1 -1
  209. package/docs/fsEvem.mjs.html +1 -1
  210. package/docs/fsExists.mjs.html +1 -1
  211. package/docs/fsExistsCore.mjs.html +1 -1
  212. package/docs/fsGetFileBasicHash.mjs.html +1 -1
  213. package/docs/fsGetFileBasicHashCore.mjs.html +1 -1
  214. package/docs/fsGetFileHash.mjs.html +1 -1
  215. package/docs/fsGetFileHashCore.mjs.html +1 -1
  216. package/docs/fsGetFileXxHash.mjs.html +1 -1
  217. package/docs/fsGetFileXxHashCore.mjs.html +1 -1
  218. package/docs/fsGetFilesInFolder.mjs.html +1 -1
  219. package/docs/fsGetFilesInFolderCore.mjs.html +1 -1
  220. package/docs/fsGetFilesWithHashInFolder.mjs.html +1 -1
  221. package/docs/fsGetFilesWithHashInFolderCore.mjs.html +1 -1
  222. package/docs/fsGetFolderBasicHash.mjs.html +1 -1
  223. package/docs/fsGetFolderBasicHashCore.mjs.html +1 -1
  224. package/docs/fsGetFoldersInFolder.mjs.html +1 -1
  225. package/docs/fsGetFoldersInFolderCore.mjs.html +1 -1
  226. package/docs/fsIsFile.mjs.html +1 -1
  227. package/docs/fsIsFileCore.mjs.html +1 -1
  228. package/docs/fsIsFolder.mjs.html +1 -1
  229. package/docs/fsIsFolderCore.mjs.html +1 -1
  230. package/docs/fsMergeFiles.mjs.html +1 -1
  231. package/docs/fsMergeFilesCore.mjs.html +1 -1
  232. package/docs/fsReadJson.mjs.html +1 -1
  233. package/docs/fsReadText.mjs.html +1 -1
  234. package/docs/fsReadTextCore.mjs.html +1 -1
  235. package/docs/fsRenameFile.mjs.html +1 -1
  236. package/docs/fsRenameFileCore.mjs.html +1 -1
  237. package/docs/fsRenameFolder.mjs.html +1 -1
  238. package/docs/fsRenameFolderCore.mjs.html +1 -1
  239. package/docs/fsSrlog.mjs.html +1 -1
  240. package/docs/fsSyncFolder.mjs.html +1 -1
  241. package/docs/fsSyncFolderCore.mjs.html +1 -1
  242. package/docs/fsTask.mjs.html +1 -1
  243. package/docs/fsTaskCp.mjs.html +1 -1
  244. package/docs/fsTreeFolder.mjs.html +1 -1
  245. package/docs/fsTreeFolderCore.mjs.html +1 -1
  246. package/docs/fsTreeFolderWithHash.mjs.html +1 -1
  247. package/docs/fsTreeFolderWithHashCore.mjs.html +1 -1
  248. package/docs/fsWatchFile.mjs.html +1 -1
  249. package/docs/fsWatchFolder.mjs.html +1 -1
  250. package/docs/fsWriteJson.mjs.html +1 -1
  251. package/docs/fsWriteText.mjs.html +1 -1
  252. package/docs/fsWriteTextCore.mjs.html +1 -1
  253. package/docs/genGradientColor.mjs.html +1 -1
  254. package/docs/genID.mjs.html +1 -1
  255. package/docs/genIDSeq.mjs.html +1 -1
  256. package/docs/genPm.mjs.html +1 -1
  257. package/docs/getBufferSize.mjs.html +1 -1
  258. package/docs/getClearPathName.mjs.html +1 -1
  259. package/docs/getCsvStrFromData.mjs.html +1 -1
  260. package/docs/getDataFromExcelFileU8Arr.mjs.html +1 -1
  261. package/docs/getDataFromExcelFileU8ArrDyn.mjs.html +1 -1
  262. package/docs/getEnv.mjs.html +1 -1
  263. package/docs/getErrorMessage.mjs.html +1 -1
  264. package/docs/getExcelU8ArrFromData.mjs.html +1 -1
  265. package/docs/getExcelU8ArrFromWorkbook.mjs.html +1 -1
  266. package/docs/getExcelWorkbookFromData.mjs.html +1 -1
  267. package/docs/getExcelWorkbookFromWorksheet.mjs.html +1 -1
  268. package/docs/getExcelWorksheetFromData.mjs.html +1 -1
  269. package/docs/getFileAccept.mjs.html +1 -1
  270. package/docs/getFileBasicHash.mjs.html +1 -1
  271. package/docs/getFileHash.mjs.html +1 -1
  272. package/docs/getFileName.mjs.html +1 -1
  273. package/docs/getFileNameExt.mjs.html +1 -1
  274. package/docs/getFileTrueName.mjs.html +1 -1
  275. package/docs/getFileType.mjs.html +1 -1
  276. package/docs/getFileXxHash.mjs.html +1 -1
  277. package/docs/getGlobal.mjs.html +1 -1
  278. package/docs/getObjSize.mjs.html +1 -1
  279. package/docs/getPathParent.mjs.html +1 -1
  280. package/docs/getTimeBetween.mjs.html +1 -1
  281. package/docs/getTimeFromUnit.mjs.html +1 -1
  282. package/docs/getTimeHp.mjs.html +1 -1
  283. package/docs/getTimeObject.mjs.html +1 -1
  284. package/docs/getTimeRange.mjs.html +1 -1
  285. package/docs/getUserAgent.mjs.html +1 -1
  286. package/docs/getUserAgentDyn.mjs.html +1 -1
  287. package/docs/getltdtkeys.mjs.html +1 -1
  288. package/docs/global.html +1 -1
  289. package/docs/haskey.mjs.html +1 -1
  290. package/docs/html2str.mjs.html +1 -1
  291. package/docs/htmlDecode.mjs.html +1 -1
  292. package/docs/htmlEncode.mjs.html +1 -1
  293. package/docs/importResources.mjs.html +1 -1
  294. package/docs/index.html +1 -1
  295. package/docs/interp1.mjs.html +1 -1
  296. package/docs/isDate.mjs.html +1 -1
  297. package/docs/isDev.mjs.html +1 -1
  298. package/docs/isEle.mjs.html +1 -1
  299. package/docs/isEleExistByID.mjs.html +1 -1
  300. package/docs/isEmail.mjs.html +1 -1
  301. package/docs/isErr.mjs.html +1 -1
  302. package/docs/isIE.mjs.html +1 -1
  303. package/docs/isNarrow.mjs.html +1 -1
  304. package/docs/isStrHasCapital.mjs.html +1 -1
  305. package/docs/isStrHasLetter.mjs.html +1 -1
  306. package/docs/isStrHasLowerCase.mjs.html +1 -1
  307. package/docs/isStrHasNumber.mjs.html +1 -1
  308. package/docs/isStrHasSpace.mjs.html +1 -1
  309. package/docs/isStrHasSymbol.mjs.html +1 -1
  310. package/docs/isUserIdentify.mjs.html +1 -1
  311. package/docs/isUserName.mjs.html +1 -1
  312. package/docs/isUserPw.mjs.html +1 -1
  313. package/docs/isWindow.mjs.html +1 -1
  314. package/docs/isab.mjs.html +1 -1
  315. package/docs/isarr.mjs.html +1 -1
  316. package/docs/isarr0.mjs.html +1 -1
  317. package/docs/isarr1.mjs.html +1 -1
  318. package/docs/isbigint.mjs.html +1 -1
  319. package/docs/isblob.mjs.html +1 -1
  320. package/docs/isbol.mjs.html +1 -1
  321. package/docs/isday.mjs.html +1 -1
  322. package/docs/isearr.mjs.html +1 -1
  323. package/docs/iseobj.mjs.html +1 -1
  324. package/docs/iser.mjs.html +1 -1
  325. package/docs/isernot.mjs.html +1 -1
  326. package/docs/isestr.mjs.html +1 -1
  327. package/docs/isfile.mjs.html +1 -1
  328. package/docs/isfun.mjs.html +1 -1
  329. package/docs/isint.mjs.html +1 -1
  330. package/docs/ismonth.mjs.html +1 -1
  331. package/docs/isn0int.mjs.html +1 -1
  332. package/docs/isn0num.mjs.html +1 -1
  333. package/docs/isnan.mjs.html +1 -1
  334. package/docs/isnbr.mjs.html +1 -1
  335. package/docs/isnint.mjs.html +1 -1
  336. package/docs/isnnum.mjs.html +1 -1
  337. package/docs/isnull.mjs.html +1 -1
  338. package/docs/isnum.mjs.html +1 -1
  339. package/docs/isobj.mjs.html +1 -1
  340. package/docs/isobj0.mjs.html +1 -1
  341. package/docs/isp0int.mjs.html +1 -1
  342. package/docs/isp0num.mjs.html +1 -1
  343. package/docs/ispint.mjs.html +1 -1
  344. package/docs/ispm.mjs.html +1 -1
  345. package/docs/ispnum.mjs.html +1 -1
  346. package/docs/isstr.mjs.html +1 -1
  347. package/docs/isstr0.mjs.html +1 -1
  348. package/docs/istime.mjs.html +1 -1
  349. package/docs/istimeTZ.mjs.html +1 -1
  350. package/docs/istimems.mjs.html +1 -1
  351. package/docs/istimemsTZ.mjs.html +1 -1
  352. package/docs/isu16arr.mjs.html +1 -1
  353. package/docs/isu8arr.mjs.html +1 -1
  354. package/docs/isundefined.mjs.html +1 -1
  355. package/docs/j2o.mjs.html +1 -1
  356. package/docs/judge.mjs.html +1 -1
  357. package/docs/keysmat2ltdt.mjs.html +1 -1
  358. package/docs/ltdt2vrtsable.mjs.html +1 -1
  359. package/docs/ltdtDiff.mjs.html +1 -1
  360. package/docs/ltdtDiffByKey.mjs.html +1 -1
  361. package/docs/ltdtkeys2mat.mjs.html +1 -1
  362. package/docs/ltdtkeysheads2mat.mjs.html +1 -1
  363. package/docs/ltdtmapping.mjs.html +1 -1
  364. package/docs/ltdtmerge.mjs.html +1 -1
  365. package/docs/ltdtpick.mjs.html +1 -1
  366. package/docs/ltdtpull.mjs.html +1 -1
  367. package/docs/mat2ltdt.mjs.html +1 -1
  368. package/docs/matConcat.mjs.html +1 -1
  369. package/docs/matDiff.mjs.html +1 -1
  370. package/docs/matat.mjs.html +1 -1
  371. package/docs/now2str.mjs.html +1 -1
  372. package/docs/now2strp.mjs.html +1 -1
  373. package/docs/nowDay2str.mjs.html +1 -1
  374. package/docs/nowms2str.mjs.html +1 -1
  375. package/docs/nowms2strp.mjs.html +1 -1
  376. package/docs/o2j.mjs.html +1 -1
  377. package/docs/obj2b64.mjs.html +1 -1
  378. package/docs/obj2pb64.mjs.html +1 -1
  379. package/docs/obj2str.mjs.html +1 -1
  380. package/docs/obj2stru8arr.mjs.html +1 -1
  381. package/docs/obj2u8arr.mjs.html +1 -1
  382. package/docs/objSortBy.mjs.html +1 -1
  383. package/docs/objSortByKeys.mjs.html +1 -1
  384. package/docs/oo.mjs.html +1 -1
  385. package/docs/openLink.mjs.html +1 -1
  386. package/docs/pb642obj.mjs.html +1 -1
  387. package/docs/pmChain.mjs.html +1 -1
  388. package/docs/pmConvertResolve.mjs.html +1 -1
  389. package/docs/pmDebounce.mjs.html +1 -1
  390. package/docs/pmHook.mjs.html +1 -1
  391. package/docs/pmHookReject.mjs.html +1 -1
  392. package/docs/pmIni.mjs.html +1 -1
  393. package/docs/pmInvResolve.mjs.html +1 -1
  394. package/docs/pmKeyMutex.mjs.html +1 -1
  395. package/docs/pmMap.mjs.html +1 -1
  396. package/docs/pmQueue.mjs.html +1 -1
  397. package/docs/pmSeries.mjs.html +1 -1
  398. package/docs/pmThrottle.mjs.html +1 -1
  399. package/docs/pmTimeout.mjs.html +1 -1
  400. package/docs/preciseNum.mjs.html +1 -1
  401. package/docs/pseudoRandom.mjs.html +1 -1
  402. package/docs/pseudoRandomIntRange.mjs.html +1 -1
  403. package/docs/pseudoRandomIntsNdpRange.mjs.html +1 -1
  404. package/docs/pseudoRandomIntsRange.mjs.html +1 -1
  405. package/docs/pseudoRandomRange.mjs.html +1 -1
  406. package/docs/pseudoRandomsRange.mjs.html +1 -1
  407. package/docs/queue.mjs.html +1 -1
  408. package/docs/random.mjs.html +1 -1
  409. package/docs/randomIntRange.mjs.html +1 -1
  410. package/docs/randomIntsNdpRange.mjs.html +1 -1
  411. package/docs/randomIntsRange.mjs.html +1 -1
  412. package/docs/randomRange.mjs.html +1 -1
  413. package/docs/randomsRange.mjs.html +1 -1
  414. package/docs/rang.mjs.html +1 -1
  415. package/docs/rep.mjs.html +1 -1
  416. package/docs/repObj.mjs.html +1 -1
  417. package/docs/replace.mjs.html +1 -1
  418. package/docs/replaceObj.mjs.html +1 -1
  419. package/docs/replacePlus.mjs.html +1 -1
  420. package/docs/round.mjs.html +1 -1
  421. package/docs/secd.mjs.html +1 -1
  422. package/docs/sep.mjs.html +1 -1
  423. package/docs/sepInt.mjs.html +1 -1
  424. package/docs/setIntervalHp.mjs.html +1 -1
  425. package/docs/setTimeoutHp.mjs.html +1 -1
  426. package/docs/sind.mjs.html +1 -1
  427. package/docs/split.mjs.html +1 -1
  428. package/docs/str2aes.mjs.html +1 -1
  429. package/docs/str2b64.mjs.html +1 -1
  430. package/docs/str2hint.mjs.html +1 -1
  431. package/docs/str2md5.mjs.html +1 -1
  432. package/docs/str2obj.mjs.html +1 -1
  433. package/docs/str2sha.mjs.html +1 -1
  434. package/docs/str2sha512.mjs.html +1 -1
  435. package/docs/str2u8arr.mjs.html +1 -1
  436. package/docs/strCompare.mjs.html +1 -1
  437. package/docs/strCompareForVersion.mjs.html +1 -1
  438. package/docs/strDiff.mjs.html +1 -1
  439. package/docs/strDiffToHtml.mjs.html +1 -1
  440. package/docs/strFindFuzz.mjs.html +1 -1
  441. package/docs/strFindSimilar.mjs.html +1 -1
  442. package/docs/strTruncate.mjs.html +1 -1
  443. package/docs/strdelleft.mjs.html +1 -1
  444. package/docs/strdelright.mjs.html +1 -1
  445. package/docs/strleft.mjs.html +1 -1
  446. package/docs/strmid.mjs.html +1 -1
  447. package/docs/strright.mjs.html +1 -1
  448. package/docs/stru8arr2obj.mjs.html +1 -1
  449. package/docs/tand.mjs.html +1 -1
  450. package/docs/time2day.mjs.html +1 -1
  451. package/docs/time2hour.mjs.html +1 -1
  452. package/docs/time2min.mjs.html +1 -1
  453. package/docs/timeTZ2day.mjs.html +1 -1
  454. package/docs/timeTZ2expire.mjs.html +1 -1
  455. package/docs/timeTZ2hour.mjs.html +1 -1
  456. package/docs/timeTZ2min.mjs.html +1 -1
  457. package/docs/timeTZ2past.mjs.html +1 -1
  458. package/docs/timems2day.mjs.html +1 -1
  459. package/docs/timems2hour.mjs.html +1 -1
  460. package/docs/timems2min.mjs.html +1 -1
  461. package/docs/timems2time.mjs.html +1 -1
  462. package/docs/timemsTZ2day.mjs.html +1 -1
  463. package/docs/timemsTZ2expire.mjs.html +1 -1
  464. package/docs/timemsTZ2hour.mjs.html +1 -1
  465. package/docs/timemsTZ2min.mjs.html +1 -1
  466. package/docs/timemsTZ2past.mjs.html +1 -1
  467. package/docs/timemsTZ2time.mjs.html +1 -1
  468. package/docs/treeObj.mjs.html +1 -1
  469. package/docs/treeToFilepath.mjs.html +1 -1
  470. package/docs/trim.mjs.html +1 -1
  471. package/docs/u16arr2b64.mjs.html +1 -1
  472. package/docs/u16arr2u8arr.mjs.html +1 -1
  473. package/docs/u8arr2ab.mjs.html +1 -1
  474. package/docs/u8arr2b64.mjs.html +1 -1
  475. package/docs/u8arr2blob.mjs.html +1 -1
  476. package/docs/u8arr2bs.mjs.html +1 -1
  477. package/docs/u8arr2obj.mjs.html +1 -1
  478. package/docs/u8arr2str.mjs.html +1 -1
  479. package/docs/u8arr2u16arr.mjs.html +1 -1
  480. package/docs/urlParse.mjs.html +1 -1
  481. package/docs/verifyValue.mjs.html +1 -1
  482. package/docs/waitFun.mjs.html +1 -1
  483. package/docs/wsemi.html +140 -6
  484. package/package.json +1 -1
  485. package/src/domDetect.mjs +706 -461
  486. package/test/domDetect.test.mjs +1921 -854
  487. package/toolfp/dist/wsemip.umd.js +1 -1
  488. package/toolparfor/dist/wpf.umd.js +1 -1
  489. package/toolparfor/dist/wpf_pmSeries.umd.js +1 -1
  490. package//345/273/272/350/255/260wsemi/350/252/277/346/225/264.md +0 -457
@@ -45,467 +45,712 @@
45
45
 
46
46
  <section>
47
47
  <article>
48
- <pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
49
- import ispint from './ispint.mjs'
50
- import isp0int from './isp0int.mjs'
51
- import evem from './evem.mjs'
52
- import isfun from './isfun.mjs'
53
-
54
-
55
- //2020年曾以IntersectionObserver與ResizeObserver實作(詳細請查git紀錄), 因實作缺陷致WTextSelect下拉選單不穩而改為輪詢:
56
- //1.元素尺寸為0(隱藏或移出DOM)時仍發出resize, 使用端讀到高度0而算錯版面
57
- //2.clear未防空值, 元素尚未取得即clear時拋錯, 且已建立之觀察器與已排定之事件未解除
58
- //3.觀察器只綁首次取得之元素, 元素被換成新節點後即失去偵測
59
-
60
- //現已恢復並用以ResizeObserver偵測尺寸, 並以共用MutationObserver於[元素取不到、不在頁面中或尺寸為0]時重新取得元素, 逐一對應上述缺陷; 無ResizeObserver或MutationObserver時退回輪詢
61
-
62
-
63
- //waiting, 等待重新取得元素之偵測器; mo, 共用之MutationObserver, 僅於有偵測器等待時啟用
64
- let waiting = new Set()
65
- let mo = null
66
-
67
-
68
- function waitAdd(fn) {
69
- waiting.add(fn)
70
- if (!mo) {
71
- mo = new window.MutationObserver(() => {
72
- for (let g of Array.from(waiting)) {
73
- g()
74
- }
75
- })
76
- mo.observe(document.documentElement, { childList: true, subtree: true })
77
- }
78
- }
79
-
80
-
81
- function waitRemove(fn) {
82
- waiting.delete(fn)
83
- if (waiting.size === 0 &amp;&amp; mo) {
84
- mo.disconnect()
85
- mo = null
86
- }
87
- }
88
-
89
-
90
- function getTimeInterval(opt) {
91
- let timeInterval = get(opt, 'timeInterval', null)
92
- if (!ispint(timeInterval)) {
93
- timeInterval = 20
94
- }
95
- return timeInterval
96
- }
97
-
98
-
99
- function getTolerancePixel(opt) {
100
- let tolerancePixel = get(opt, 'tolerancePixel', null)
101
- if (!isp0int(tolerancePixel)) { //可給0, 表示任何變化皆發出
102
- tolerancePixel = 1
103
- }
104
- return tolerancePixel
105
- }
106
-
107
-
108
- //getEle, f()拋錯或回傳非元素時視為取不到, 不中斷偵測
109
- function getEle(f) {
110
- let p = null
111
- try {
112
- p = f()
113
- }
114
- catch (err) {
115
- p = null
116
- }
117
- return (p &amp;&amp; p.nodeType === 1) ? p : null
118
- }
119
-
120
-
121
- function sizeZero() {
122
- return {
123
- offsetWidth: 0,
124
- offsetHeight: 0,
125
- clientWidth: 0,
126
- clientHeight: 0,
127
- windowWidth: 0,
128
- windowHeight: 0,
129
- }
130
- }
131
-
132
-
133
- function measure(p) {
134
- return {
135
- offsetWidth: p.offsetWidth,
136
- offsetHeight: p.offsetHeight,
137
- clientWidth: p.clientWidth,
138
- clientHeight: p.clientHeight,
139
- windowWidth: window.innerWidth,
140
- windowHeight: window.innerHeight,
141
- }
142
- }
143
-
144
-
145
- //createCore, 輪詢與ResizeObserver兩種模式共用之比較、發出、視窗事件與清除, 使兩者之規則只寫一處
146
- // 比較基準sb為上次發出事件時之尺寸, 差值超過容許誤差才更新; 若每次量測皆更新基準, 緩慢之連續小變化(如逐px拖曳或縮放視窗)永遠不會超過容許誤差, 累積再大也不發出
147
- // 尺寸為0時差值必超過容許誤差而使基準歸0, 故由隱藏恢復顯示時必發出
148
- function createCore(ev, opt) {
149
-
150
- //tolerancePixel
151
- let tolerancePixel = getTolerancePixel(opt)
152
-
153
- //sync, 於ResizeObserver回呼內同步發出事件(繪製前), 供須於同一幀更新版面之使用端(例如圖表重繪); 預設以setTimeout脫勾
154
- let sync = get(opt, 'sync', false) === true
155
-
156
- //cleared, sd, sb, timers
157
- let cleared = false
158
- let sd = sizeZero() //最新量測
159
- let sb = sizeZero() //比較基準, 上次發出事件時之尺寸
160
- let timers = new Set()
161
-
162
- //emit
163
- let emit = (sold, snew, sm, p) => {
164
-
165
- //cleared, clear後不再發出已排定之事件
166
- if (cleared) {
167
- return
168
- }
169
-
170
- //detect resize, 尺寸為0(隱藏或移出DOM)不發出
171
- if (snew.offsetWidth > 0 &amp;&amp; snew.offsetHeight > 0) {
172
- ev.emit('resize', {
173
- sold,
174
- snew,
175
- smode: sm,
176
- ele: p,
177
- })
178
-
179
- //cleared, resize之監聽器內可能呼叫clear
180
- if (cleared) {
181
- return
182
- }
183
-
184
- ev.emit('resizeWithWindow', {
185
- sold,
186
- snew,
187
- smode: sm,
188
- ele: p,
189
- from: 'dom',
190
- })
191
- }
192
-
193
- }
194
-
195
- //check, 量測並與比較基準比較
196
- let check = (p, allowSync) => {
197
- if (cleared || !p) {
198
- return
199
- }
200
-
201
- //new size
202
- let snew = measure(p)
203
-
204
- //dw, dh
205
- let dw = sb.offsetWidth - snew.offsetWidth
206
- let dh = sb.offsetHeight - snew.offsetHeight
207
-
208
- //bw, bh
209
- let bw = Math.abs(dw) > tolerancePixel
210
- let bh = Math.abs(dh) > tolerancePixel
211
-
212
- //save
213
- sd = snew
214
-
215
- //check
216
- if (!bw &amp;&amp; !bh) {
217
- return
218
- }
219
-
220
- //sold, sb
221
- let sold = sb
222
- sb = snew
223
-
224
- //sm, 方向只於該軸超過容許誤差時給: 容許誤差內之差值視同未變化(不發事件), 若仍給方向, 另一軸觸發之事件會帶出該軸之殘餘方向
225
- let sm = {
226
- width: bw ? (dw > 0 ? 'smaller' : 'larger') : '',
227
- height: bh ? (dh > 0 ? 'smaller' : 'larger') : '',
228
- }
229
-
230
- //emit
231
- if (allowSync &amp;&amp; sync) {
232
- emit(sold, snew, sm, p)
233
- return
234
- }
235
- let t = setTimeout(() => { //emit觸發事件為同步, 用setTimeout脫勾
236
- timers.delete(t)
237
- emit(sold, snew, sm, p)
238
- }, 1)
239
- timers.add(t)
240
-
241
- }
242
-
243
- //fWindowResize, 視窗尺寸取當下值, 否則元素尺寸未變時會一直帶著上次量測時之視窗尺寸
244
- // sold為比較基準, 與dom事件同義; 任何超過容許誤差之變化皆已立即更新比較基準, 故最新量測與比較基準之差必在容許誤差內, 方向恆為空
245
- let fWindowResize = (e) => {
246
- if (cleared) {
247
- return
248
- }
249
- sd = {
250
- ...sd,
251
- windowWidth: window.innerWidth,
252
- windowHeight: window.innerHeight,
253
- }
254
- ev.emit('resizeWithWindow', {
255
- sold: sb,
256
- snew: sd,
257
- smode: {
258
- width: '',
259
- height: '',
260
- },
261
- from: 'window',
262
- })
263
- }
264
- window.addEventListener('resize', fWindowResize)
265
-
266
- //clear
267
- let clear = () => {
268
- cleared = true
269
- for (let t of timers) {
270
- clearTimeout(t)
271
- }
272
- timers.clear()
273
- window.removeEventListener('resize', fWindowResize)
274
- }
275
-
276
- return {
277
- check,
278
- clear,
279
- isCleared: () => cleared,
280
- isVisible: () => sd.offsetWidth > 0 &amp;&amp; sd.offsetHeight > 0,
281
- }
282
- }
283
-
284
-
285
- function domDetectByPolling(f, opt = {}) {
286
-
287
- //check
288
- if (!isfun(f)) {
289
- console.log('invalid f', f)
290
- return null
291
- }
292
-
293
- //ev, core
294
- let ev = evem()
295
- let core = createCore(ev, opt)
296
-
297
- //setInterval
298
- let timer = setInterval(() => {
299
- let p = getEle(f)
300
- if (p) {
301
- core.check(p, false)
302
- }
303
- }, getTimeInterval(opt))
304
-
305
- //clear
306
- ev.clear = () => {
307
- clearInterval(timer)
308
- core.clear()
309
- }
310
-
311
- return ev
312
- }
313
-
314
-
315
- function domDetectByObserver(f, opt = {}) {
316
-
317
- //check
318
- if (!isfun(f)) {
319
- console.log('invalid f', f)
320
- return null
321
- }
322
-
323
- //watchIdentity, 元素可見時亦持續於DOM變動時重新取得元素, 供f()可能於舊元素仍可見時改回傳他元素之使用端
324
- let watchIdentity = get(opt, 'watchIdentity', false) === true
325
-
326
- //timeInterval, 行內元素改以定期量測時使用
327
- let timeInterval = getTimeInterval(opt)
328
-
329
- //ev, core
330
- let ev = evem()
331
- let core = createCore(ev, opt)
332
-
333
- //ele, timerInline, inlineConn, eleInline, roBorder, roContent
334
- let ele = null
335
- let timerInline = null
336
- let inlineConn = false //上次判定是否為行內時元素是否在頁面中
337
- let eleInline = false //目前元素是否曾判定為行內, 換成新節點時歸零
338
- let roBorder = null
339
- let roContent = null
340
-
341
- //syncInline, 非替換之行內元素ResizeObserver不回報(規範明定), 取得之元素為display:inline時改以定期量測, 不為inline時停止
342
- // 元素自身隱藏(display:none, 如v-show)時看不出顯示後之型別: 曾判定為行內者持續定期量測, 否則顯示時ResizeObserver會回報; 不在頁面中時display為空字串, 停止量測, 待插入頁面時(onDomChange)重判
343
- let syncInline = () => {
344
- let display = ''
345
- if (ele) {
346
- try {
347
- display = window.getComputedStyle(ele).display
348
- }
349
- catch (err) {
350
- display = ''
351
- }
352
- }
353
- inlineConn = !!(ele &amp;&amp; ele.isConnected)
354
- if (display === 'inline') {
355
- eleInline = true
356
- }
357
- else if (display !== 'none' &amp;&amp; display !== '') {
358
- eleInline = false
359
- }
360
- let inline = display === 'inline' || (display === 'none' &amp;&amp; eleInline)
361
- if (inline &amp;&amp; timerInline === null) {
362
- timerInline = setInterval(onResize, timeInterval)
363
- }
364
- else if (!inline &amp;&amp; timerInline !== null) {
365
- clearInterval(timerInline)
366
- timerInline = null
367
- }
368
- }
369
-
370
- //retarget, 重新取得元素: 換成新節點時改觀察新節點, 新節點之首次回報由check比較
371
- // 同時觀察border-box與content-box: 比較用之offsetWidth即border-box, 只觀察content-box會漏掉只改padding或border之變化; content-box則使捲軸出現或消失時clientWidth保持最新
372
- let retarget = () => {
373
- if (core.isCleared()) {
374
- return
375
- }
376
- let p = getEle(f)
377
- if (p === ele) {
378
- return
379
- }
380
- if (ele) {
381
- roBorder.unobserve(ele)
382
- roContent.unobserve(ele)
383
- }
384
- ele = p
385
- eleInline = false
386
- if (ele) {
387
- roBorder.observe(ele, { box: 'border-box' })
388
- roContent.observe(ele)
389
- }
390
- syncInline()
391
- }
392
-
393
- //updateWaiting, 元素取不到、不在頁面中或尺寸為0時登記等待DOM變動:
394
- // 元素消失(移除或換新節點)時ResizeObserver無從得知新節點, 且已隱藏(尺寸0)之元素再被移除時尺寸0→0不會回報, 故尺寸為0時亦須等待
395
- let updateWaiting = () => {
396
- if (core.isCleared()) {
397
- return
398
- }
399
- let visible = ele &amp;&amp; ele.isConnected &amp;&amp; core.isVisible()
400
- if (visible &amp;&amp; !watchIdentity) {
401
- waitRemove(onDomChange)
402
- }
403
- else {
404
- waitAdd(onDomChange)
405
- }
406
- }
407
-
408
- //onDomChange, 僅重新取得元素不量測, 避免強制重排版; 換新節點後由ResizeObserver之首次回報觸發check
409
- // 元素插入或移出頁面時重判是否為行內: 不在頁面中之元素取不到display而判為非行內(如Vue指令之bind時元素尚未插入, 或行內元素移出後定期量測已停止), 行內元素ResizeObserver又不回報, 不於插入後重判則永不量測
410
- // 僅於在頁面與否改變時重判, 等待中之其他DOM變動不重複讀取樣式
411
- let onDomChange = () => {
412
- retarget()
413
- if (ele &amp;&amp; ele.isConnected !== inlineConn) {
414
- syncInline()
415
- }
416
- updateWaiting()
417
- }
418
-
419
- //onResize
420
- let onResize = () => {
421
- retarget()
422
- try {
423
- core.check(ele, true)
424
- }
425
- finally {
426
- //sync模式下監聽器拋錯時仍須更新行內與等待狀態
427
- syncInline()
428
- updateWaiting()
429
- }
430
- }
431
-
432
- //roBorder, roContent
433
- roBorder = new window.ResizeObserver(onResize)
434
- roContent = new window.ResizeObserver(onResize)
435
-
436
- //initialize
437
- retarget()
438
- updateWaiting()
439
-
440
- //clear, 可於任何時點呼叫(含元素尚未取得), 並取消已排定之事件
441
- ev.clear = () => {
442
- if (core.isCleared()) {
443
- return
444
- }
445
- core.clear()
446
- waitRemove(onDomChange)
447
- roBorder.disconnect()
448
- roContent.disconnect()
449
- if (timerInline !== null) {
450
- clearInterval(timerInline)
451
- timerInline = null
452
- }
453
- ele = null
454
- }
455
-
456
- return ev
457
- }
458
-
459
-
460
- /**
461
- * 前端針對DOM元素監聽resize、resizeWithWindow事件,其中resizeWithWindow為dom resize與window resize皆會觸發的事件
462
- *
463
- * 瀏覽器支援ResizeObserver與MutationObserver時以其偵測(即時且閒置時不耗資源),否則退回定期輪詢,兩者之比較規則與事件相同:以offsetWidth、offsetHeight與比較基準之差超過容許誤差即發出,比較基準為上次發出事件時之尺寸,故緩慢之連續小變化累積超過容許誤差亦會發出;尺寸為0(隱藏或移出DOM)不發出,由隱藏恢復顯示時會發出,首次取得非0尺寸時會發出
464
- *
465
- * 元素可取不到、中途消失或重建為新節點:取不到、不在頁面中或尺寸為0時,於DOM變動時重新以f取得元素並改觀察之。行內元素(display:inline)ResizeObserver不回報,該偵測器改以定期量測,元素自身隱藏(display:none,如v-show)期間亦持續,顯示後即可量得;是否為行內於取得元素、ResizeObserver回報、定期量測及元素插入或移出頁面時判定
466
- *
467
- * 事件內容:sold為比較基準(上次發出事件時之尺寸),snew為本次量測,smode為寬與高相對比較基準之變化方向('larger'、'smaller'或''),僅該軸之差超過容許誤差時給方向,否則為'',ele為元素;from為'window'之事件無ele,其snew為最新量測,其中視窗尺寸取事件當下之值,其smode寬與高恆為''(視窗事件不代表元素尺寸變化,且最新量測與比較基準之差必在容許誤差內)
468
- *
469
- * 已知限制:ResizeObserver模式下,僅屬性變化(如class)使f改指他元素、或Shadow DOM內之節點被替換時不會跟隨,行內元素自取得起即自身為display:none(未曾以行內顯示過)、之後僅以style或class改為顯示者不會開始量測,此類使用端請用mode:'polling';sync為true時監聽器不得使所監聽元素之尺寸於同一幀內再變,否則瀏覽器回報ResizeObserver loop錯誤;Safari 15.4以前不支援觀察border-box,只改padding或border之變化於該處不會發出
470
- *
471
- * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domDetect.test.mjs Github}
472
- * @memberOf wsemi
473
- * @param {Function} f 輸入取得dom函數,可回傳null表示目前取不到
474
- * @param {Object} [opt={}] 輸入設定物件,預設{}
475
- * @param {String} [opt.mode=''] 輸入偵測模式字串,給'polling'則強制使用定期輪詢,預設''
476
- * @param {Integer} [opt.timeInterval=20] 輸入定期偵測時間整數,單位毫秒,用於輪詢模式與行內元素,預設20
477
- * @param {Integer} [opt.tolerancePixel=1] 輸入容許誤差整數,單位px,可給0表示任何變化皆發出,預設1
478
- * @param {Boolean} [opt.sync=false] 輸入是否於ResizeObserver回呼內同步發出事件布林值,true時使用端可於瀏覽器繪製前更新版面(例如圖表重繪),僅ResizeObserver模式有效,預設false
479
- * @param {Boolean} [opt.watchIdentity=false] 輸入元素可見時是否仍於DOM變動時重新取得元素布林值,f可能於舊元素仍可見時改回傳另一元素者給true,僅ResizeObserver模式有效,預設false
480
- * @returns {Object} 回傳物件,可使用on與clear函數,on可監聽resize與resizeWithWindow事件,clear為釋放監聽,可於任何時點呼叫(含元素尚未取得),並取消已排定之事件
481
- * @example
482
- * need test in browser
483
- *
484
- * //監聽dom
485
- * let de = domDetect(() => {
486
- * return document.querySelector('#id')
487
- * })
488
- * de.on('resize', (s) => {
489
- * console.log('resize', s)
490
- * })
491
- * de.on('resizeWithWindow', (s) => {
492
- * console.log('resizeWithWindow', s)
493
- * })
494
- *
495
- * //釋放監聽
496
- * de.clear()
497
- *
498
- */
499
- function domDetect(f, opt = {}) {
500
- let useObserver = typeof window !== 'undefined' &amp;&amp; !!window.ResizeObserver &amp;&amp; !!window.MutationObserver &amp;&amp; get(opt, 'mode', '') !== 'polling'
501
- if (useObserver) {
502
- return domDetectByObserver(f, opt)
503
- }
504
- return domDetectByPolling(f, opt)
505
- }
506
-
507
-
508
- export default domDetect
48
+ <pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
49
+ import throttle from 'lodash-es/throttle.js'
50
+ import ispint from './ispint.mjs'
51
+ import isp0int from './isp0int.mjs'
52
+ import isnum from './isnum.mjs'
53
+ import cdbl from './cdbl.mjs'
54
+ import evem from './evem.mjs'
55
+ import isfun from './isfun.mjs'
56
+
57
+
58
+ //2020年曾以IntersectionObserver與ResizeObserver實作(詳細請查git紀錄), 因實作缺陷致WTextSelect下拉選單不穩而改為輪詢:
59
+ //1.元素尺寸為0(隱藏或移出DOM)時仍發出resize, 使用端讀到高度0而算錯版面
60
+ //2.clear未防空值, 元素尚未取得即clear時拋錯, 且已建立之觀察器與已排定之事件未解除
61
+ //3.觀察器只綁首次取得之元素, 元素被換成新節點後即失去偵測
62
+
63
+ //現已恢復並用以ResizeObserver偵測尺寸, 並以共用MutationObserver於[元素取不到、不在頁面中或尺寸為0]時重新取得元素, 逐一對應上述缺陷; 無ResizeObserver或MutationObserver時退回輪詢
64
+
65
+
66
+ //waiting, 等待重新取得元素之偵測器; mo, 共用之MutationObserver, 僅於有偵測器等待時啟用
67
+ let waiting = new Set()
68
+ let mo = null
69
+
70
+
71
+ function waitAdd(fn) {
72
+ waiting.add(fn)
73
+ if (!mo) {
74
+ mo = new window.MutationObserver(() => {
75
+ for (let g of Array.from(waiting)) {
76
+ g()
77
+ }
78
+ })
79
+ mo.observe(document.documentElement, { childList: true, subtree: true })
80
+ }
81
+ }
82
+
83
+
84
+ function waitRemove(fn) {
85
+ waiting.delete(fn)
86
+ if (waiting.size === 0 &amp;&amp; mo) {
87
+ mo.disconnect()
88
+ mo = null
89
+ }
90
+ }
91
+
92
+
93
+ function getTimeInterval(opt) {
94
+ let timeInterval = get(opt, 'timeInterval', null)
95
+ if (!ispint(timeInterval)) {
96
+ timeInterval = 20
97
+ }
98
+ return timeInterval
99
+ }
100
+
101
+
102
+ function getTolerancePixel(opt) {
103
+ let tolerancePixel = get(opt, 'tolerancePixel', null)
104
+ if (!isp0int(tolerancePixel)) { //可給0, 表示任何變化皆發出
105
+ tolerancePixel = 1
106
+ }
107
+ return tolerancePixel
108
+ }
109
+
110
+
111
+ function getThrottle(opt) {
112
+ let t = get(opt, 'throttle', null)
113
+ if (!ispint(t)) { //未給或0表示不節流
114
+ t = 0
115
+ }
116
+ return t
117
+ }
118
+
119
+
120
+ function getFun(opt, key) {
121
+ let f = get(opt, key, null)
122
+ return isfun(f) ? f : null
123
+ }
124
+
125
+
126
+ //getEle, f()拋錯或回傳非元素時視為取不到, 不中斷偵測
127
+ function getEle(f) {
128
+ let p = null
129
+ try {
130
+ p = f()
131
+ }
132
+ catch (err) {
133
+ p = null
134
+ }
135
+ return (p &amp;&amp; p.nodeType === 1) ? p : null
136
+ }
137
+
138
+
139
+ //toNum, 非數字(含拋錯、未給)者為null
140
+ function toNum(v) {
141
+ return isnum(v) ? cdbl(v) : null
142
+ }
143
+
144
+
145
+ function sizeZero() {
146
+ return {
147
+ offsetWidth: 0,
148
+ offsetHeight: 0,
149
+ clientWidth: 0,
150
+ clientHeight: 0,
151
+ windowWidth: 0,
152
+ windowHeight: 0,
153
+ width: 0,
154
+ height: 0,
155
+ }
156
+ }
157
+
158
+
159
+ //measure, width與height為比較用尺寸: 預設同offsetWidth與offsetHeight(border-box), 有給getSize時取其回傳(例如使用端依內容區繪製者)
160
+ function measure(p, getSize) {
161
+ let r = {
162
+ offsetWidth: p.offsetWidth,
163
+ offsetHeight: p.offsetHeight,
164
+ clientWidth: p.clientWidth,
165
+ clientHeight: p.clientHeight,
166
+ windowWidth: window.innerWidth,
167
+ windowHeight: window.innerHeight,
168
+ width: p.offsetWidth,
169
+ height: p.offsetHeight,
170
+ }
171
+ if (getSize) {
172
+ let s = null
173
+ try {
174
+ s = getSize(p)
175
+ }
176
+ catch (err) {
177
+ s = null
178
+ }
179
+ r.width = toNum(get(s, 'width', null)) || 0
180
+ r.height = toNum(get(s, 'height', null)) || 0
181
+ }
182
+ return r
183
+ }
184
+
185
+
186
+ //isShown, 量測時元素可見(外框非0)且比較用尺寸非0
187
+ function isShown(s) {
188
+ return s.offsetWidth > 0 &amp;&amp; s.offsetHeight > 0 &amp;&amp; s.width > 0 &amp;&amp; s.height > 0
189
+ }
190
+
191
+
192
+ //isRendered, 元素當下是否被繪製: 在頁面中且自身與祖先皆非display:none
193
+ // 只需計算樣式不需排版: 若讀外框(offsetWidth)確認, 前一個監聽器改動DOM後(同步寫入或Vue於microtask更新)之每次確認皆強制重排, N個偵測器即N次排版
194
+ // 有checkVisibility時以其判定(另涵蓋content-visibility:hidden等), 否則逐層檢查display; 不讀外框, 故元素仍被繪製而尺寸縮為0者視為被繪製
195
+ function isRendered(p) {
196
+ if (!p || !p.isConnected) {
197
+ return false
198
+ }
199
+ if (isfun(p.checkVisibility)) {
200
+ return p.checkVisibility()
201
+ }
202
+ let e = p
203
+ while (e &amp;&amp; e.nodeType === 1) {
204
+ let display = ''
205
+ try {
206
+ display = window.getComputedStyle(e).display
207
+ }
208
+ catch (err) {
209
+ display = ''
210
+ }
211
+ if (display === 'none') {
212
+ return false
213
+ }
214
+ e = e.parentElement || (e.parentNode &amp;&amp; e.parentNode.host) || null //Shadow DOM內之頂層節點改查其宿主
215
+ }
216
+ return true
217
+ }
218
+
219
+
220
+ //createCore, 輪詢與ResizeObserver兩種模式共用之比較、發出、視窗事件與清除, 使兩者之規則只寫一處
221
+ // 比較基準預設為上次判定變化時之尺寸sb, 差值超過容許誤差才更新; 若每次量測皆更新基準, 緩慢之連續小變化(如逐px拖曳或縮放視窗)永遠不會超過容許誤差, 累積再大也不發出
222
+ // 尺寸為0時差值必超過容許誤差而使基準歸0, 故由隱藏恢復顯示時必發出
223
+ // 有給getBase時比較基準改為使用端目前套用之尺寸(例如圖表目前寬高), 故掛載時尺寸已一致者不發出, 且與偵測器之回報次序無關
224
+ // onReobserve為延後發出因元素已不被繪製而略過時, 請觀察層重新觀察目前元素並登記等待之函數(輪詢模式不需要, 下一次取樣即重新比較)
225
+ function createCore(ev, opt, onReobserve) {
226
+
227
+ //tolerancePixel
228
+ let tolerancePixel = getTolerancePixel(opt)
229
+
230
+ //sync, 於ResizeObserver回呼內同步發出事件(繪製前), 供須於同一幀更新版面之使用端(例如圖表重繪); 預設以setTimeout脫勾
231
+ let sync = get(opt, 'sync', false) === true
232
+
233
+ //getSize, getBase, throttleTime
234
+ let getSize = getFun(opt, 'getSize')
235
+ let getBase = getFun(opt, 'getBase')
236
+ let throttleTime = getThrottle(opt)
237
+
238
+ //cleared, sd, sb, pLast, timers, seqCheck, seqPost
239
+ let cleared = false
240
+ let sd = sizeZero() //最新量測
241
+ let sb = sizeZero() //上次判定變化時之尺寸
242
+ let pLast = null //最新量測之元素, 供視窗事件確認其當下是否被繪製
243
+ let timers = new Set()
244
+ let seqCheck = 0 //判定變化之序號
245
+ let seqPost = 0 //已處理(發出, 或因尺寸0、不被繪製、使用端已同步而不發出)之最新序號
246
+
247
+ //readBase, 比較基準: 有給getBase時取其回傳(該軸非數字表示該軸不比較, 例如固定寬度), 否則為sb
248
+ // pending為判定變化時: 有給getBase且尚有未處理之延後發出者, 使用端尺寸將被其更新, 故比較之軸改以其量測(sb)比較;
249
+ // 否則之後量得與使用端當下相近之尺寸會被判為未變化, 待延後發出套用後使用端即停在過期尺寸; 發出前之再比較(pending為false)則以使用端當下之尺寸比較
250
+ let readBase = (pending) => {
251
+ if (!getBase) {
252
+ return {
253
+ width: sb.width,
254
+ height: sb.height,
255
+ }
256
+ }
257
+ let b = null
258
+ try {
259
+ b = getBase()
260
+ }
261
+ catch (err) {
262
+ b = null
263
+ }
264
+ let width = toNum(get(b, 'width', null))
265
+ let height = toNum(get(b, 'height', null))
266
+ if (pending &amp;&amp; seqPost &lt; seqCheck) {
267
+ return {
268
+ width: width === null ? null : sb.width,
269
+ height: height === null ? null : sb.height,
270
+ }
271
+ }
272
+ return {
273
+ width,
274
+ height,
275
+ }
276
+ }
277
+
278
+ //diff, 各軸相對比較基準之差與是否超過容許誤差
279
+ let diff = (snew, pending) => {
280
+ let base = readBase(pending)
281
+ let dw = base.width === null ? 0 : base.width - snew.width
282
+ let dh = base.height === null ? 0 : base.height - snew.height
283
+ return {
284
+ dw,
285
+ dh,
286
+ bw: Math.abs(dw) > tolerancePixel,
287
+ bh: Math.abs(dh) > tolerancePixel,
288
+ }
289
+ }
290
+
291
+ //mode, 方向只於該軸超過容許誤差時給: 容許誤差內之差值視同未變化(不發事件), 若仍給方向, 另一軸觸發之事件會帶出該軸之殘餘方向
292
+ let mode = (d) => {
293
+ return {
294
+ width: d.bw ? (d.dw > 0 ? 'smaller' : 'larger') : '',
295
+ height: d.bh ? (d.dh > 0 ? 'smaller' : 'larger') : '',
296
+ }
297
+ }
298
+
299
+ //skip, 延後發出前元素已不被繪製而不發出:
300
+ // 若此為最近一次判定之變化(之後未再判定), 比較基準與最新量測歸0, 並請觀察層重新觀察目前元素; 否則元素於下一幀前恢復顯示且尺寸與隱藏前相同時ResizeObserver不再回報(上次回報之尺寸未變), 此次變化即永不發出
301
+ // 之後已再判定變化者由該次發出處理, 不得歸0, 否則覆蓋較新之比較基準
302
+ let skip = (snew) => {
303
+ if (sb !== snew) {
304
+ return
305
+ }
306
+ sb = sizeZero()
307
+ sd = sizeZero()
308
+ if (onReobserve) {
309
+ onReobserve()
310
+ }
311
+ }
312
+
313
+ //post, 發出事件
314
+ // deferred為延後發出(setTimeout、節流之後續呼叫或refresh): 自量測至發出之間元素可能已隱藏或移出頁面, 若照發則使用端讀到尺寸0而算錯版面(即上方2020年缺陷1), 故發出前確認元素當下仍被繪製;
315
+ // 有給getBase者亦再比較一次, 期間使用端已自行同步尺寸時不發出, 方向亦依當下比較重給
316
+ let post = (sold, snew, sm, p, seq, deferred) => {
317
+
318
+ //cleared, clear後不再發出已排定之事件
319
+ if (cleared) {
320
+ return
321
+ }
322
+
323
+ //seq, 已處理較新之量測者不發出較舊者: sync時refresh或節流之後續發出為延後發出, 可能晚於其後已同步發出之事件, 照發則使用端最後收到過期尺寸
324
+ if (seq &lt; seqPost) {
325
+ return
326
+ }
327
+ seqPost = seq
328
+
329
+ //尺寸為0(隱藏或移出DOM)不發出
330
+ if (!isShown(snew)) {
331
+ return
332
+ }
333
+
334
+ //deferred
335
+ if (deferred) {
336
+ if (!isRendered(p)) {
337
+ skip(snew)
338
+ return
339
+ }
340
+ if (getBase) {
341
+ let d = diff(snew, false)
342
+ if (!d.bw &amp;&amp; !d.bh) {
343
+ return
344
+ }
345
+ sm = mode(d)
346
+ }
347
+ }
348
+
349
+ ev.emit('resize', {
350
+ sold,
351
+ snew,
352
+ smode: sm,
353
+ ele: p,
354
+ })
355
+
356
+ //cleared, resize之監聽器內可能呼叫clear
357
+ if (cleared) {
358
+ return
359
+ }
360
+
361
+ ev.emit('resizeWithWindow', {
362
+ sold,
363
+ snew,
364
+ smode: sm,
365
+ ele: p,
366
+ from: 'dom',
367
+ })
368
+
369
+ }
370
+
371
+ //fire, 於ResizeObserver回呼內同步發出(inSync)或延後發出
372
+ // 延後發出各自一個task: 前一個監聽器於microtask之DOM異動(如Vue之非同步更新)於下一個發出前已套用, 且監聽器不集中於同一個task; 發出前之確認只需樣式(isRendered), 故不因此強制重排
373
+ let inSync = false
374
+ let fire = (sold, snew, sm, p, seq) => {
375
+ if (inSync) {
376
+ post(sold, snew, sm, p, seq, false)
377
+ return
378
+ }
379
+ let t = setTimeout(() => { //emit觸發事件為同步, 用setTimeout脫勾
380
+ timers.delete(t)
381
+ post(sold, snew, sm, p, seq, true)
382
+ }, 1)
383
+ timers.add(t)
384
+ }
385
+
386
+ //fireThrottled, 節流: 首次立即(同步或延後), 其後throttleTime內至多一次並以最後一次之量測延後發出
387
+ let fireThrottled = null
388
+ if (throttleTime > 0) {
389
+ fireThrottled = throttle(fire, throttleTime)
390
+ }
391
+
392
+ //deliver, now為於ResizeObserver回呼內同步發出
393
+ let deliver = (sold, snew, sm, p, seq, now) => {
394
+ inSync = now
395
+ try {
396
+ if (fireThrottled) {
397
+ fireThrottled(sold, snew, sm, p, seq)
398
+ }
399
+ else {
400
+ fire(sold, snew, sm, p, seq)
401
+ }
402
+ }
403
+ finally {
404
+ inSync = false
405
+ }
406
+ }
407
+
408
+ //check, 量測並與比較基準比較
409
+ let check = (p, allowSync) => {
410
+ if (cleared) {
411
+ return
412
+ }
413
+
414
+ //取不到元素: 最新量測歸0, 視窗事件不發出(同移出頁面); 比較基準不動, 同尺寸之元素再出現時與既有行為相同不發出dom事件
415
+ if (!p) {
416
+ sd = sizeZero()
417
+ pLast = null
418
+ return
419
+ }
420
+
421
+ //new size
422
+ let snew = measure(p, getSize)
423
+
424
+ //save
425
+ sd = snew
426
+ pLast = p
427
+
428
+ //diff
429
+ let d = diff(snew, true)
430
+ if (!d.bw &amp;&amp; !d.bh) {
431
+ return
432
+ }
433
+
434
+ //sold, sb
435
+ let sold = sb
436
+ sb = snew
437
+
438
+ //deliver
439
+ seqCheck++
440
+ deliver(sold, snew, mode(d), p, seqCheck, allowSync &amp;&amp; sync)
441
+
442
+ }
443
+
444
+ //fWindowResize, 視窗尺寸取當下值, 否則元素尺寸未變時會一直帶著上次量測時之視窗尺寸
445
+ // sold為比較基準, 與dom事件同義; 任何超過容許誤差之變化皆已立即更新比較基準, 故最新量測與比較基準之差必在容許誤差內, 方向恆為空
446
+ // 元素隱藏、移出頁面、取不到或尚未量得尺寸(最新量測為0)時不發出, 與dom事件之規則一致, 否則使用端於視窗改變時讀到尺寸0而算錯版面
447
+ // 視窗事件於同一幀之ResizeObserver回報前派發, 視窗改變本身使元素隱藏時(如媒體查詢)最新量測仍為隱藏前之尺寸, 故另確認元素當下仍被繪製(只需樣式, 不強制重排)
448
+ let fWindowResize = (e) => {
449
+ if (cleared) {
450
+ return
451
+ }
452
+ sd = {
453
+ ...sd,
454
+ windowWidth: window.innerWidth,
455
+ windowHeight: window.innerHeight,
456
+ }
457
+ if (!isShown(sd) || !isRendered(pLast)) {
458
+ return
459
+ }
460
+ ev.emit('resizeWithWindow', {
461
+ sold: sb,
462
+ snew: sd,
463
+ smode: {
464
+ width: '',
465
+ height: '',
466
+ },
467
+ from: 'window',
468
+ })
469
+ }
470
+ window.addEventListener('resize', fWindowResize)
471
+
472
+ //clear
473
+ let clear = () => {
474
+ cleared = true
475
+ for (let t of timers) {
476
+ clearTimeout(t)
477
+ }
478
+ timers.clear()
479
+ if (fireThrottled) {
480
+ fireThrottled.cancel()
481
+ }
482
+ window.removeEventListener('resize', fWindowResize)
483
+ pLast = null
484
+ }
485
+
486
+ return {
487
+ check,
488
+ clear,
489
+ isCleared: () => cleared,
490
+ isVisible: () => sd.offsetWidth > 0 &amp;&amp; sd.offsetHeight > 0,
491
+ }
492
+ }
493
+
494
+
495
+ function domDetectByPolling(f, opt = {}) {
496
+
497
+ //check
498
+ if (!isfun(f)) {
499
+ console.log('invalid f', f)
500
+ return null
501
+ }
502
+
503
+ //ev, core
504
+ let ev = evem()
505
+ let core = createCore(ev, opt)
506
+
507
+ //setInterval, 取不到元素時亦交check處理(最新量測歸0)
508
+ let timer = setInterval(() => {
509
+ core.check(getEle(f), false)
510
+ }, getTimeInterval(opt))
511
+
512
+ //refresh, 立即重新取得元素並比較(延後發出); clear後不再呼叫f, 同ResizeObserver模式
513
+ ev.refresh = () => {
514
+ if (core.isCleared()) {
515
+ return
516
+ }
517
+ core.check(getEle(f), false)
518
+ }
519
+
520
+ //clear
521
+ ev.clear = () => {
522
+ clearInterval(timer)
523
+ core.clear()
524
+ }
525
+
526
+ return ev
527
+ }
528
+
529
+
530
+ function domDetectByObserver(f, opt = {}) {
531
+
532
+ //check
533
+ if (!isfun(f)) {
534
+ console.log('invalid f', f)
535
+ return null
536
+ }
537
+
538
+ //watchIdentity, 元素可見時亦持續於DOM變動時重新取得元素, 供f()可能於舊元素仍可見時改回傳他元素之使用端
539
+ let watchIdentity = get(opt, 'watchIdentity', false) === true
540
+
541
+ //timeInterval, 行內元素改以定期量測時使用
542
+ let timeInterval = getTimeInterval(opt)
543
+
544
+ //ev, core
545
+ // 延後發出略過時重新觀察目前元素, 並依[尺寸為0時等待DOM變動]登記等待(最新量測已歸0), 不依賴重新觀察之首次回報(舊版Safari對0尺寸之新觀察不回報)
546
+ let ev = evem()
547
+ let core = createCore(ev, opt, () => {
548
+ reobserve()
549
+ updateWaiting()
550
+ })
551
+
552
+ //ele, timerInline, inlineConn, eleInline, roBorder, roContent
553
+ let ele = null
554
+ let timerInline = null
555
+ let inlineConn = false //上次判定是否為行內時元素是否在頁面中
556
+ let eleInline = false //目前元素是否曾判定為行內, 換成新節點時歸零
557
+ let roBorder = null
558
+ let roContent = null
559
+
560
+ //observe, 同時觀察border-box與content-box: 比較用之offsetWidth即border-box, 只觀察content-box會漏掉只改padding或border之變化; content-box則使捲軸出現或消失時clientWidth保持最新, 且getSize依內容區量測時只改padding之變化亦會回報
561
+ let observe = () => {
562
+ roBorder.observe(ele, { box: 'border-box' })
563
+ roContent.observe(ele)
564
+ }
565
+
566
+ //reobserve, 重新觀察目前元素: 新建之觀察於下一幀回報一次, 供延後發出被略過後重新比較
567
+ // 須先unobserve: 瀏覽器對已以同一盒觀察之元素再observe直接返回, 不重建觀察(Chromium實測)
568
+ let reobserve = () => {
569
+ if (core.isCleared() || !ele) {
570
+ return
571
+ }
572
+ roBorder.unobserve(ele)
573
+ roContent.unobserve(ele)
574
+ observe()
575
+ }
576
+
577
+ //syncInline, 非替換之行內元素ResizeObserver不回報(規範明定), 取得之元素為display:inline時改以定期量測, 不為inline時停止
578
+ // 元素自身隱藏(display:none, 如v-show)時看不出顯示後之型別: 曾判定為行內者持續定期量測, 否則顯示時ResizeObserver會回報; 不在頁面中時display為空字串, 停止量測, 待插入頁面時(onDomChange)重判
579
+ let syncInline = () => {
580
+ let display = ''
581
+ if (ele) {
582
+ try {
583
+ display = window.getComputedStyle(ele).display
584
+ }
585
+ catch (err) {
586
+ display = ''
587
+ }
588
+ }
589
+ inlineConn = !!(ele &amp;&amp; ele.isConnected)
590
+ if (display === 'inline') {
591
+ eleInline = true
592
+ }
593
+ else if (display !== 'none' &amp;&amp; display !== '') {
594
+ eleInline = false
595
+ }
596
+ let inline = display === 'inline' || (display === 'none' &amp;&amp; eleInline)
597
+ if (inline &amp;&amp; timerInline === null) {
598
+ timerInline = setInterval(onResize, timeInterval)
599
+ }
600
+ else if (!inline &amp;&amp; timerInline !== null) {
601
+ clearInterval(timerInline)
602
+ timerInline = null
603
+ }
604
+ }
605
+
606
+ //retarget, 重新取得元素: 換成新節點時改觀察新節點, 新節點之首次回報由check比較
607
+ let retarget = () => {
608
+ if (core.isCleared()) {
609
+ return
610
+ }
611
+ let p = getEle(f)
612
+ if (p === ele) {
613
+ return
614
+ }
615
+ if (ele) {
616
+ roBorder.unobserve(ele)
617
+ roContent.unobserve(ele)
618
+ }
619
+ ele = p
620
+ eleInline = false
621
+ if (ele) {
622
+ observe()
623
+ }
624
+ syncInline()
625
+ }
626
+
627
+ //updateWaiting, 元素取不到、不在頁面中或尺寸為0時登記等待DOM變動:
628
+ // 元素消失(移除或換新節點)時ResizeObserver無從得知新節點, 且已隱藏(尺寸0)之元素再被移除時尺寸0→0不會回報, 故尺寸為0時亦須等待
629
+ let updateWaiting = () => {
630
+ if (core.isCleared()) {
631
+ return
632
+ }
633
+ let visible = ele &amp;&amp; ele.isConnected &amp;&amp; core.isVisible()
634
+ if (visible &amp;&amp; !watchIdentity) {
635
+ waitRemove(onDomChange)
636
+ }
637
+ else {
638
+ waitAdd(onDomChange)
639
+ }
640
+ }
641
+
642
+ //onDomChange, 僅重新取得元素不量測, 避免強制重排版; 換新節點後由ResizeObserver之首次回報觸發check
643
+ // 元素插入或移出頁面時重判是否為行內: 不在頁面中之元素取不到display而判為非行內(如Vue指令之bind時元素尚未插入, 或行內元素移出後定期量測已停止), 行內元素ResizeObserver又不回報, 不於插入後重判則永不量測
644
+ // 僅於在頁面與否改變時重判, 等待中之其他DOM變動不重複讀取樣式
645
+ let onDomChange = () => {
646
+ retarget()
647
+ if (ele &amp;&amp; ele.isConnected !== inlineConn) {
648
+ syncInline()
649
+ }
650
+ updateWaiting()
651
+ }
652
+
653
+ //onResize
654
+ let onResize = () => {
655
+ retarget()
656
+ try {
657
+ core.check(ele, true)
658
+ }
659
+ finally {
660
+ //sync模式下監聽器拋錯時仍須更新行內與等待狀態
661
+ syncInline()
662
+ updateWaiting()
663
+ }
664
+ }
665
+
666
+ //roBorder, roContent
667
+ roBorder = new window.ResizeObserver(onResize)
668
+ roContent = new window.ResizeObserver(onResize)
669
+
670
+ //initialize
671
+ retarget()
672
+ updateWaiting()
673
+
674
+ //refresh, 立即重新取得元素並比較(延後發出), 供比較基準因尺寸以外之原因改變時使用(例如getBase之固定寬度被取消)
675
+ ev.refresh = () => {
676
+ retarget()
677
+ core.check(ele, false)
678
+ syncInline()
679
+ updateWaiting()
680
+ }
681
+
682
+ //clear, 可於任何時點呼叫(含元素尚未取得), 並取消已排定之事件
683
+ ev.clear = () => {
684
+ if (core.isCleared()) {
685
+ return
686
+ }
687
+ core.clear()
688
+ waitRemove(onDomChange)
689
+ roBorder.disconnect()
690
+ roContent.disconnect()
691
+ if (timerInline !== null) {
692
+ clearInterval(timerInline)
693
+ timerInline = null
694
+ }
695
+ ele = null
696
+ }
697
+
698
+ return ev
699
+ }
700
+
701
+
702
+ /**
703
+ * 前端針對DOM元素監聽resize、resizeWithWindow事件,其中resizeWithWindow為dom resize與window resize皆會觸發的事件
704
+ *
705
+ * 瀏覽器支援ResizeObserver與MutationObserver時以其偵測(即時且閒置時不耗資源),否則退回定期輪詢,兩者之比較規則與事件相同:以比較用尺寸(預設offsetWidth、offsetHeight)與比較基準之差超過容許誤差即發出,比較基準預設為上次發出事件時之尺寸,故緩慢之連續小變化累積超過容許誤差亦會發出;尺寸為0(隱藏或移出DOM)不發出,由隱藏恢復顯示時會發出,首次取得非0尺寸時會發出;延後發出(非同步、節流或refresh)時,發出前元素已不被繪製(移出頁面,或自身或祖先為display:none)者不發出,待其再顯示時重新比較(同由隱藏恢復顯示,sold為0、smode兩軸為'larger'),此確認只計算樣式而不讀外框,故元素仍被繪製而尺寸於空檔內縮為0者照發;sync為true時refresh與節流之後續發出仍為延後發出,其量測早於已處理之事件者不發出
706
+ *
707
+ * 元素可取不到、中途消失或重建為新節點:取不到、不在頁面中或尺寸為0時,於DOM變動時重新以f取得元素並改觀察之。行內元素(display:inline)ResizeObserver不回報,該偵測器改以定期量測,元素自身隱藏(display:none,如v-show)期間亦持續,顯示後即可量得;是否為行內於取得元素、ResizeObserver回報、定期量測及元素插入或移出頁面時判定
708
+ *
709
+ * 事件內容:sold為上次判定變化時之量測,snew為本次量測(另含width、height為比較用尺寸),smode為寬與高相對比較基準之變化方向('larger'、'smaller'或''),僅該軸之差超過容許誤差時給方向,否則為'',有給getBase者延後發出時依發出當下與使用端尺寸之比較重給,ele為元素;from為'window'之事件無ele,其snew為最新量測,其中視窗尺寸取事件當下之值,其smode寬與高恆為''(視窗事件不代表元素尺寸變化,且最新量測與比較基準之差必在容許誤差內);視窗事件於最新量測之任一維為0(隱藏、移出頁面、取不到元素、尚未量得尺寸,或寬高其一為0之元素),或元素當下不被繪製(例如媒體查詢隨視窗改變而隱藏)時不發出,與dom事件之規則一致
710
+ *
711
+ * 已知限制:ResizeObserver模式下,僅屬性變化(如class)使f改指他元素、或Shadow DOM內之節點被替換時不會跟隨,行內元素自取得起即自身為display:none(未曾以行內顯示過)、之後僅以style或class改為顯示者不會開始量測,此類使用端請用mode:'polling';sync為true時監聽器不得使所監聽元素之尺寸於同一幀內再變,否則瀏覽器回報ResizeObserver loop錯誤;Safari 15.4以前不支援觀察border-box,只改padding或border之變化於該處不會發出
712
+ *
713
+ * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domDetect.test.mjs Github}
714
+ * @memberOf wsemi
715
+ * @param {Function} f 輸入取得dom函數,可回傳null表示目前取不到
716
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
717
+ * @param {String} [opt.mode=''] 輸入偵測模式字串,給'polling'則強制使用定期輪詢,預設''
718
+ * @param {Integer} [opt.timeInterval=20] 輸入定期偵測時間整數,單位毫秒,用於輪詢模式與行內元素,預設20
719
+ * @param {Integer} [opt.tolerancePixel=1] 輸入容許誤差整數,單位px,可給0表示任何變化皆發出,預設1
720
+ * @param {Boolean} [opt.sync=false] 輸入是否於ResizeObserver回呼內同步發出事件布林值,true時使用端可於瀏覽器繪製前更新版面(例如圖表重繪),僅ResizeObserver模式有效,預設false
721
+ * @param {Boolean} [opt.watchIdentity=false] 輸入元素可見時是否仍於DOM變動時重新取得元素布林值,f可能於舊元素仍可見時改回傳另一元素者給true,僅ResizeObserver模式有效,預設false
722
+ * @param {Function} [opt.getSize=null] 輸入比較用尺寸函數,傳入元素,回傳{width,height},供依內容區或特定量測方式繪製之使用端(例如圖表依clientWidth扣除padding),給予時只改padding、元素內出現或消失捲軸等外框不變之變化亦會發出,回傳非數字或拋錯之軸視為0(不發出),預設null表示使用offsetWidth、offsetHeight
723
+ * @param {Function} [opt.getBase=null] 輸入比較基準函數,回傳使用端目前套用之尺寸{width,height},該軸非數字(含拋錯)表示該軸不比較(例如固定寬度),給予時以其取代上次發出事件時之尺寸,故掛載時尺寸已一致者不發出(其後事件之sold於首次判定變化前為0),由隱藏恢復顯示時若與使用端尺寸相同亦不發出;使用端須於事件內套用新尺寸(getBase之回傳隨之更新),否則之後每次回報皆判定為變化而發出,預設null
724
+ * @param {Integer} [opt.throttle=0] 輸入節流時間整數,單位毫秒,首次立即發出,其後每throttle毫秒至多發出一次並以最後一次之量測發出(其sold為最後一次判定變化前之量測,可能未曾發出),clear時取消待發出者,僅作用於元素尺寸之事件(resize與from為'dom'之resizeWithWindow),視窗事件不節流,預設0表示不節流
725
+ * @returns {Object} 回傳物件,可使用on、refresh與clear函數,on可監聽resize與resizeWithWindow事件,refresh為立即重新量測並比較(延後發出,給throttle時併入節流而至多延後throttle毫秒),供比較基準因尺寸以外之原因改變時使用,clear為釋放監聽,可於任何時點呼叫(含元素尚未取得),並取消已排定之事件
726
+ * @example
727
+ * need test in browser
728
+ *
729
+ * //監聽dom
730
+ * let de = domDetect(() => {
731
+ * return document.querySelector('#id')
732
+ * })
733
+ * de.on('resize', (s) => {
734
+ * console.log('resize', s)
735
+ * })
736
+ * de.on('resizeWithWindow', (s) => {
737
+ * console.log('resizeWithWindow', s)
738
+ * })
739
+ *
740
+ * //釋放監聽
741
+ * de.clear()
742
+ *
743
+ */
744
+ function domDetect(f, opt = {}) {
745
+ let useObserver = typeof window !== 'undefined' &amp;&amp; !!window.ResizeObserver &amp;&amp; !!window.MutationObserver &amp;&amp; get(opt, 'mode', '') !== 'polling'
746
+ if (useObserver) {
747
+ return domDetectByObserver(f, opt)
748
+ }
749
+ return domDetectByPolling(f, opt)
750
+ }
751
+
752
+
753
+ export default domDetect
509
754
  </code></pre>
510
755
  </article>
511
756
  </section>
@@ -520,7 +765,7 @@ export default domDetect
520
765
  <br class="clear">
521
766
 
522
767
  <footer>
523
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sat Sep 26 2026 08:34:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
768
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sat Sep 26 2026 22:05:36 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
524
769
  </footer>
525
770
 
526
771
  <script>prettyPrint();</script>