@codady/utils 0.0.38 → 0.0.39
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/CHANGELOG.md +18 -0
- package/dist/utils.cjs.js +472 -23
- package/dist/utils.cjs.min.js +2 -2
- package/dist/utils.esm.js +472 -23
- package/dist/utils.esm.min.js +2 -2
- package/dist/utils.umd.js +472 -23
- package/dist/utils.umd.min.js +2 -2
- package/dist.zip +0 -0
- package/examples/ajax-get.html +59 -0
- package/examples/ajax-hook.html +55 -0
- package/examples/ajax-method.html +36 -0
- package/examples/ajax-post.html +37 -0
- package/examples/buildUrl.html +99 -0
- package/examples/getUrlHash.html +71 -0
- package/modules.js +13 -1
- package/modules.ts +13 -1
- package/package.json +1 -1
- package/src/ajax.js +363 -0
- package/src/ajax.ts +450 -0
- package/src/buildUrl.js +64 -0
- package/src/buildUrl.ts +86 -0
- package/src/capitalize - /345/211/257/346/234/254.js" +19 -0
- package/src/capitalize.js +19 -0
- package/src/capitalize.ts +20 -0
- package/src/cleanQueryString.js +19 -0
- package/src/cleanQueryString.ts +20 -0
- package/src/getBodyHTML.js +53 -0
- package/src/getBodyHTML.ts +61 -0
- package/src/getEl.js +1 -1
- package/src/getEl.ts +6 -5
- package/src/getEls.js +1 -1
- package/src/getEls.ts +5 -5
- package/src/getUrlHash.js +37 -0
- package/src/getUrlHash.ts +39 -0
- package/src/isEmpty.js +24 -23
- package/src/isEmpty.ts +26 -23
- package/src/sliceStrEnd.js +63 -0
- package/src/sliceStrEnd.ts +60 -0
package/dist/utils.cjs.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2026-1-16
|
|
2
|
+
* @since Last modified: 2026-1-20 16:40:28
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
4
|
* @version 0.0.38
|
|
5
5
|
* @author AXUI development team <3217728223@qq.com>
|
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
|
|
13
13
|
* @license MIT license
|
|
14
14
|
*/
|
|
15
|
-
"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let s,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const s of r)t[s]=deepClone(e[s],{...a,parent:e});s=t}else if("Array"===r&&a.cloneArray)s=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,s]of e)t.set(deepClone(r,a),deepClone(s,{...a,parent:e}));s=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));s=t}else if("Date"===r&&a.cloneDate)s=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;s=new RegExp(t.source,t.flags)}else s=e,n=!1;return a.onAfterClone?.({output:s,input:e,type:r,cloned:n,parent:a.parent}),s},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let o of a)n[o]=function(...a){const n={},l=e.length;switch(o){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,s=t<0?Math.max(l+t,0):Math.min(t,l),o=void 0===r?l-s:r;n.deletedItems=e.slice(s,s+o);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,c=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,c),n.start=i,n.end=c}t?.(n);const i=Array.prototype[o].apply(e,a),c={value:i,key:o,args:a,context:n,target:e,...s};return r?.(c),i};return n},escapeCharsMaps={basic:{"&":"&","<":"<",">":">"},attribute:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},content:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},uri:{"&":"&","<":"<",">":">",'"':""","'":"'","(":"(",")":")","[":"[","]":"]"},paranoid:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/","=":"=","!":"!","#":"#","(":"(",")":")","[":"[","]":"]","{":"{","}":"}",":":":",";":";"}},escapeRegexMaps=Object.keys(escapeCharsMaps).reduce((e,t)=>{const r=Object.keys(escapeCharsMaps[t]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[t]=new RegExp(`[${r.join("")}]`,"g"),e},{}),escapeHTML=(e,t="attribute")=>{if("string"!=typeof e)return"";const r=escapeCharsMaps[t],a=escapeRegexMaps[t];return e.replace(a,e=>r[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,s=e.base36;return`${t?t+"-":""}${Date.now()}${s?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],s=getDataType(e),n=s.toLowerCase(),o=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`)}catch(e){r(e,s)}else if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`);return s},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},renderTpl=(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let a=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let s,n=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),o=n.start.split("").map(e=>"\\"+e).join(""),l=n.end.split("").map(e=>"\\"+e).join(""),i=new RegExp(`${o}([\\s\\S]+?)?${l}`,"g"),c='"use strict";let str=[];\n',p=0,u="",g=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(n.suffix)?c+=e.slice(0,-n.suffix.length)+"\n":c+=n.escape?`str.push(${g}(String(${e}), "${n.escape}"));\n`:`str.push(${e});\n`:c+=""!==e?'str.push("'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")+'");\n':"",add);for(;s=i.exec(e);)add(e.slice(p,s.index))(s[1],!0),p=s.index+s[0].length;add(e.slice(p)),c+="return str.join('');",c=toSingleLine(c);try{if(n.strict||"Array"===a)u=new Function(g,c).apply(t,[escapeHTML]);else{let e=Object.keys(t),r=Object.values(t);u=new Function(...e,g,c).bind(t)(...r,escapeHTML)}}catch(e){}return u},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"add":{const[t]=n;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=n;o.existed=e.has(t),o.deletedItem=o.existed?t:void 0;break}case"clear":o.clearedItems=Array.from(e),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"set":{const[t,r]=n;o.key=t,o.newValue=r,o.existed=e.has(t),o.oldValue=o.existed?e.get(t):void 0;break}case"delete":{const[t]=n;o.key=t,o.existed=e.has(t),o.value=o.existed?e.get(t):void 0;break}case"clear":o.clearedItems=Array.from(e.entries()),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let s,n,o=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,targetType:o,sourceType:l,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:l,parent:a.parent}),"Object"===o&&"Object"===l?(n=deepMergeObjects(e,t,a),s="Object"):"Array"===o&&"Array"===l?(n=deepMergeArrays(e,t,a),s="Array"):"Set"===o&&"Set"===l?(n=deepMergeSets(e,t,a),s="Set"):"Map"===o&&"Map"===l?(n=deepMergeMaps(e,t,a),s="Map"):(i=!1,n=e),a?.onAfterMerge?.({result:n,target:e,source:t,targetType:o,sourceType:l,mergeType:s,parent:r.parent}),{result:n,flag:i,mergeType:s}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),s=getDataType(t);if("Object"!==a||"Object"!==s)return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=n.targetClone?shallowCopy(e):e;for(let e in t){const a=o[e],s=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(a,s,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=s;else{let t=n.useEnable?mergeEnableObject(a,s):s;a!==t&&null===t?"ignore"===n.nullBehavior||("delete"===n.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):a!==t&&void 0===t?"ignore"===n.undefinedBehavior||("delete"===n.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=s):o[e]=s}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&n.inheritMissing&&(o[e]=s)}if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)o[r]=t[r]}return o},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),s=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=s.length));e++){smartMerger(s[e],t[e],{...a,parent:s}).flag||(s[e]=t[e])}else"concat"===a.dataMode||(s.length=0),s.push(...t);return s},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(s.has(e)){const t=s.get(e),r=n,o=smartMerger(t,r,a);o.flag?"Object"===o.mergeType&&s.set(e,o.result):s.set(e,r)}else r.inheritMissing&&s.set(e,n);return s},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...s],r=[...t],n=smartMerger(e,r,a);s.clear();for(let e of n.result)s.add(e)}else if("concat"===a.dataMode)for(let e of t)s.add(e);else{s.clear();for(let e of t)s.add(e)}return s};return smartMerger(e,t,a).result},getEl=(e,t=document.body)=>{let r=getDataType(e),a=getDataType(t),s=a.includes("HTML")||"ShadowRoot"===a?t:document.querySelector(t),n=s&&s instanceof HTMLTemplateElement?s.content:s,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(n||document).querySelector(e.trim())}catch{o=null}return o},isEmpty=e=>{let t,r=getDataType(e);return t=!e||("Object"===r?0===Object.keys(e).length:"Array"===r?""===e.join(""):"Function"===r?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===r?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===r||"Map"===r?0===e.size:"Date"===r?isNaN(e.getTime()):"RegExp"===r?""===e.source:"ArrayBuffer"===r?0===e.byteLength:"NodeList"===r||"HTMLCollection"===r||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===r||e instanceof Error?""===e.message:!(!r.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(r))&&0===e.length),t},getEls=(e,t=document.body)=>{let r=getDataType(e),a=getEl(t),s=a&&a instanceof HTMLTemplateElement?a.content:a||document,n=[];return isEmpty(e)?n:(r.includes("HTML")?n.push(e):"String"===r?n=(e=e.trim()).split(",").map(e=>[...s.querySelectorAll(e)]).flat():"Array"===r&&(n=e.map(e=>getEl(e,a))),n.filter(Boolean))},createEl=(e,t,r)=>{let a=(e=e||"div").toUpperCase().trim(),s=document.createElement(a),n=getDataType(t);if(t&&"Object"===n)for(let e in t)t.hasOwnProperty(e)&&s.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let r=getDataType(t);if("TEMPLATE"===a)e.innerHTML=t.toString();else if("Array"===r&&t.length>0)for(let r of t){if(getDataType(r).includes("HTML"))e.appendChild(r);else{let t=createEl(r.name,r.attrs,r.content);t&&e.appendChild(t)}}else if(r.includes("HTML"))e.appendChild(t);else if("String"===r&&t.trim().startsWith("#")&&t.trim().length>1){let r=getEl(t);if(!r)return;"TEMPLATE"===r.nodeName?e.appendChild(r.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",r.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(s,r),s},getSvgUri=e=>`data:image/svg+xml;utf8,${e.replace(/\n/g,"").replace(/\s+/g," ").trim().replace(/%/g,"%25").replace(/#/g,"%23").replace(/{/g,"%7B").replace(/}/g,"%7D").replace(/</g,"%3C").replace(/>/g,"%3E")}`,fileToBase64=e=>new Promise((t,r)=>{const a=new FileReader;a.onload=()=>{"string"==typeof a.result?t(a.result):r(new Error("FileReader result is not a string"))},a.onerror=()=>{r(a.error||new Error("Unknown error occurred during file reading"))},a.readAsDataURL(e)}),NAMESPACE="ax",ALIAS="rep",COMMA=",",SPACE=" ",trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,r=[];return Array.isArray(e)?r=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",r=e.split(t)),r.map(e=>trim(e,"global")).filter(Boolean)},addClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.add(e):"string"==typeof t&&t&&a.classList.add(t)):a.classList.add(e)})},createTools=e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?'<i rep="arrow"></i>':"",a=(e.icon?`<i rep="icon">${e.icon}</i>`:"")+(e.disk?`<i rep="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i rep="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i rep="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i rep="label">${e.label}</i>`:"")+r;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),a),e.iconEl=e.wrapEl.querySelector('[rep="icon"]'),e.cubeEl=e.wrapEl.querySelector('[rep="cube"]'),e.diskEl=e.wrapEl.querySelector('[rep="disk"]'),e.imageEl=e.wrapEl.querySelector('[rep="image"]'),e.labelEl=e.wrapEl.querySelector('[rep="label"]'),!isEmpty(e.classes)&&addClasses(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let r of e)renderFn(r),t.appendChild(r.wrapEl),r?.action?.(r);return t},getClasses=e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},removeClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.remove(e):"string"==typeof t&&t&&a.classList.remove(t)):a.classList.remove(e)})},typeWriter=(e,t)=>{const r=t.speed||100;return new Promise(a=>{t?.onBeforeType?.(e);let s=0;const n=setInterval(()=>{if(s<e.length){const r=e.charAt(s),a=e.substring(0,s+1);t?.onDuringType?.(r,a),s++}else clearInterval(n),a(e),t?.onAfterType?.(e)},r)})},parseLLMStream=async(e,t)=>{if(!(e&&e instanceof ReadableStream))throw new Error("Invalid input: ReadableStream is missing or not an instance of ReadableStream.");const r=e.getReader(),a=new TextDecoder("utf-8");let s="";const n={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;s+=a.decode(o,{stream:!0});let l=s.split("\n");s=l.pop()||"";for(const e of l){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const a=r.substring(6);if("[DONE]"!==a)try{const e=JSON.parse(a),r=e.choices?.[0],s=r?.delta?.content||"";s&&(n.fullText+=s,t?.(s)),r?.finish_reason&&(n.finishReason=r.finish_reason),e.usage&&(n.usage=e.usage)}catch(e){}else n.isCompleted=!0}}}catch(e){throw e}return n},toKebabCase=(e,t="",r="")=>`${t}${e.replace(/([A-Z])/g,"-$1").toLowerCase()}${r}`,trimEmptyLines=e=>null==e?"":e.replace(/^\s*\n|\n\s*$/g,"")||"",decodeHtmlEntities=e=>{if(!e)return"";const t=document.createElement("textarea");return t.innerHTML=e,t.value},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:getEls,createEl:createEl,getSvgUri:getSvgUri,fileToBase64:fileToBase64,NAMESPACE:"ax",ALIAS:"rep",COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:getClasses,addClasses:addClasses,removeClasses:removeClasses,createTools:createTools,typeWriter:typeWriter,parseLLMStream:parseLLMStream,toKebabCase:toKebabCase,trimEmptyLines:trimEmptyLines,decodeHtmlEntities:decodeHtmlEntities,escapeCharsMaps:escapeCharsMaps,escapeRegexMaps:escapeRegexMaps,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:renderTpl};module.exports=utils;
|
|
15
|
+
"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let n,s=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const n of r)t[n]=deepClone(e[n],{...a,parent:e});n=t}else if("Array"===r&&a.cloneArray)n=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,n]of e)t.set(deepClone(r,a),deepClone(n,{...a,parent:e}));n=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));n=t}else if("Date"===r&&a.cloneDate)n=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;n=new RegExp(t.source,t.flags)}else n=e,s=!1;return a.onAfterClone?.({output:n,input:e,type:r,cloned:s,parent:a.parent}),n},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:n={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const s={};for(let o of a)s[o]=function(...a){const s={},l=e.length;switch(o){case"push":case"unshift":s.addedItems=[...a];break;case"pop":s.poppedItem=e[l-1];break;case"shift":s.shiftedItem=e[0];break;case"splice":const[t,r]=a,n=t<0?Math.max(l+t,0):Math.min(t,l),o=void 0===r?l-n:r;s.deletedItems=e.slice(n,n+o);break;case"sort":case"reverse":s.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,c=void 0===a[2]?l:a[2];s.oldItems=e.slice(i,c),s.start=i,s.end=c}t?.(s);const i=Array.prototype[o].apply(e,a),c={value:i,key:o,args:a,context:s,target:e,...n};return r?.(c),i};return s},escapeCharsMaps={basic:{"&":"&","<":"<",">":">"},attribute:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},content:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},uri:{"&":"&","<":"<",">":">",'"':""","'":"'","(":"(",")":")","[":"[","]":"]"},paranoid:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/","=":"=","!":"!","#":"#","(":"(",")":")","[":"[","]":"]","{":"{","}":"}",":":":",";":";"}},escapeRegexMaps=Object.keys(escapeCharsMaps).reduce((e,t)=>{const r=Object.keys(escapeCharsMaps[t]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[t]=new RegExp(`[${r.join("")}]`,"g"),e},{}),escapeHTML=(e,t="attribute")=>{if("string"!=typeof e)return"";const r=escapeCharsMaps[t],a=escapeRegexMaps[t];return e.replace(a,e=>r[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,n=e.base36;return`${t?t+"-":""}${Date.now()}${n?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],n=getDataType(e),s=n.toLowerCase(),o=a.map(e=>e.toLowerCase()),l=s.includes("html")?"element":s;if(r)try{if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`)}catch(e){r(e,n)}else if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`);return n},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},renderTpl=(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let a=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let n,s=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),o=s.start.split("").map(e=>"\\"+e).join(""),l=s.end.split("").map(e=>"\\"+e).join(""),i=new RegExp(`${o}([\\s\\S]+?)?${l}`,"g"),c='"use strict";let str=[];\n',p=0,u="",d=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(s.suffix)?c+=e.slice(0,-s.suffix.length)+"\n":c+=s.escape?`str.push(${d}(String(${e}), "${s.escape}"));\n`:`str.push(${e});\n`:c+=""!==e?'str.push("'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")+'");\n':"",add);for(;n=i.exec(e);)add(e.slice(p,n.index))(n[1],!0),p=n.index+n[0].length;add(e.slice(p)),c+="return str.join('');",c=toSingleLine(c);try{if(s.strict||"Array"===a)u=new Function(d,c).apply(t,[escapeHTML]);else{let e=Object.keys(t),r=Object.values(t);u=new Function(...e,d,c).bind(t)(...r,escapeHTML)}}catch(e){}return u},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:n={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=a=>function(...s){const o={};switch(a){case"add":{const[t]=s;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=s;o.existed=e.has(t),o.deletedItem=o.existed?t:void 0;break}case"clear":o.clearedItems=Array.from(e),o.previousSize=e.size}t(o);const l=e[a].apply(e,s),i={method:a,result:l,args:s,context:o,target:e,...n};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:n={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=a=>function(...s){const o={};switch(a){case"set":{const[t,r]=s;o.key=t,o.newValue=r,o.existed=e.has(t),o.oldValue=o.existed?e.get(t):void 0;break}case"delete":{const[t]=s;o.key=t,o.existed=e.has(t),o.value=o.existed?e.get(t):void 0;break}case"clear":o.clearedItems=Array.from(e.entries()),o.previousSize=e.size}t(o);const l=e[a].apply(e,s),i={method:a,result:l,args:s,context:o,target:e,...n};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let n,s,o=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,targetType:o,sourceType:l,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:l,parent:a.parent}),"Object"===o&&"Object"===l?(s=deepMergeObjects(e,t,a),n="Object"):"Array"===o&&"Array"===l?(s=deepMergeArrays(e,t,a),n="Array"):"Set"===o&&"Set"===l?(s=deepMergeSets(e,t,a),n="Set"):"Map"===o&&"Map"===l?(s=deepMergeMaps(e,t,a),n="Map"):(i=!1,s=e),a?.onAfterMerge?.({result:s,target:e,source:t,targetType:o,sourceType:l,mergeType:n,parent:r.parent}),{result:s,flag:i,mergeType:n}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),n=getDataType(t);if("Object"!==a||"Object"!==n)return e;const s=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=s.targetClone?shallowCopy(e):e;for(let e in t){const a=o[e],n=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(a,n,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=n;else{let t=s.useEnable?mergeEnableObject(a,n):n;a!==t&&null===t?"ignore"===s.nullBehavior||("delete"===s.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):a!==t&&void 0===t?"ignore"===s.undefinedBehavior||("delete"===s.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=n):o[e]=n}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&s.inheritMissing&&(o[e]=n)}if(s.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)o[r]=t[r]}return o},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),n=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=n.length));e++){smartMerger(n[e],t[e],{...a,parent:n}).flag||(n[e]=t[e])}else"concat"===a.dataMode||(n.length=0),n.push(...t);return n},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),n=a.targetClone?new Map([...e]):e;for(const[e,s]of t.entries())if(n.has(e)){const t=n.get(e),r=s,o=smartMerger(t,r,a);o.flag?"Object"===o.mergeType&&n.set(e,o.result):n.set(e,r)}else r.inheritMissing&&n.set(e,s);return n},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),n=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...n],r=[...t],s=smartMerger(e,r,a);n.clear();for(let e of s.result)n.add(e)}else if("concat"===a.dataMode)for(let e of t)n.add(e);else{n.clear();for(let e of t)n.add(e)}return n};return smartMerger(e,t,a).result},getEl=(e,t=document.body)=>{let r=getDataType(e),a=getDataType(t),n=a.includes("HTML")||"ShadowRoot"===a?t:document.querySelector(t),s=n&&n instanceof HTMLTemplateElement?n.content:n,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(s||document).querySelector(e.trim())}catch{o=null}return o},isEmpty=e=>{let t,r=getDataType(e);return!e||!["String","Number","Boolean"].includes(r)&&(t="Object"===r?0===Object.keys(e).length:"Array"===r?""===e.join(""):"Function"===r?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===r?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===r||"Map"===r?0===e.size:"Date"===r?isNaN(e.getTime()):"RegExp"===r?""===e.source:"ArrayBuffer"===r?0===e.byteLength:"NodeList"===r||"HTMLCollection"===r||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===r||e instanceof Error?""===e.message:!(!r.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(r))&&0===e.length,t)},getEls=(e,t=document.body)=>{let r=getDataType(e),a=getEl(t),n=a&&a instanceof HTMLTemplateElement?a.content:a||document,s=[];return isEmpty(e)?s:(r.includes("HTML")?s.push(e):"String"===r?s=(e=e.trim()).split(",").map(e=>[...n.querySelectorAll(e)]).flat():"Array"===r&&(s=e.map(e=>getEl(e,a))),s.filter(Boolean))},createEl=(e,t,r)=>{let a=(e=e||"div").toUpperCase().trim(),n=document.createElement(a),s=getDataType(t);if(t&&"Object"===s)for(let e in t)t.hasOwnProperty(e)&&n.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let r=getDataType(t);if("TEMPLATE"===a)e.innerHTML=t.toString();else if("Array"===r&&t.length>0)for(let r of t){if(getDataType(r).includes("HTML"))e.appendChild(r);else{let t=createEl(r.name,r.attrs,r.content);t&&e.appendChild(t)}}else if(r.includes("HTML"))e.appendChild(t);else if("String"===r&&t.trim().startsWith("#")&&t.trim().length>1){let r=getEl(t);if(!r)return;"TEMPLATE"===r.nodeName?e.appendChild(r.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",r.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(n,r),n},getSvgUri=e=>`data:image/svg+xml;utf8,${e.replace(/\n/g,"").replace(/\s+/g," ").trim().replace(/%/g,"%25").replace(/#/g,"%23").replace(/{/g,"%7B").replace(/}/g,"%7D").replace(/</g,"%3C").replace(/>/g,"%3E")}`,fileToBase64=e=>new Promise((t,r)=>{const a=new FileReader;a.onload=()=>{"string"==typeof a.result?t(a.result):r(new Error("FileReader result is not a string"))},a.onerror=()=>{r(a.error||new Error("Unknown error occurred during file reading"))},a.readAsDataURL(e)}),NAMESPACE="ax",ALIAS="rep",COMMA=",",SPACE=" ",trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,r=[];return Array.isArray(e)?r=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",r=e.split(t)),r.map(e=>trim(e,"global")).filter(Boolean)},addClasses=(e,t,r)=>{const a=getEl(e),n=parseClasses(t);a&&0!==n.length&&n.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.add(e):"string"==typeof t&&t&&a.classList.add(t)):a.classList.add(e)})},createTools=e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?'<i rep="arrow"></i>':"",a=(e.icon?`<i rep="icon">${e.icon}</i>`:"")+(e.disk?`<i rep="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i rep="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i rep="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i rep="label">${e.label}</i>`:"")+r;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),a),e.iconEl=e.wrapEl.querySelector('[rep="icon"]'),e.cubeEl=e.wrapEl.querySelector('[rep="cube"]'),e.diskEl=e.wrapEl.querySelector('[rep="disk"]'),e.imageEl=e.wrapEl.querySelector('[rep="image"]'),e.labelEl=e.wrapEl.querySelector('[rep="label"]'),!isEmpty(e.classes)&&addClasses(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let r of e)renderFn(r),t.appendChild(r.wrapEl),r?.action?.(r);return t},getClasses=e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},removeClasses=(e,t,r)=>{const a=getEl(e),n=parseClasses(t);a&&0!==n.length&&n.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.remove(e):"string"==typeof t&&t&&a.classList.remove(t)):a.classList.remove(e)})},typeWriter=(e,t)=>{const r=t.speed||100;return new Promise(a=>{t?.onBeforeType?.(e);let n=0;const s=setInterval(()=>{if(n<e.length){const r=e.charAt(n),a=e.substring(0,n+1);t?.onDuringType?.(r,a),n++}else clearInterval(s),a(e),t?.onAfterType?.(e)},r)})},parseLLMStream=async(e,t)=>{if(!(e&&e instanceof ReadableStream))throw new Error("Invalid input: ReadableStream is missing or not an instance of ReadableStream.");const r=e.getReader(),a=new TextDecoder("utf-8");let n="";const s={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;n+=a.decode(o,{stream:!0});let l=n.split("\n");n=l.pop()||"";for(const e of l){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const a=r.substring(6);if("[DONE]"!==a)try{const e=JSON.parse(a),r=e.choices?.[0],n=r?.delta?.content||"";n&&(s.fullText+=n,t?.(n)),r?.finish_reason&&(s.finishReason=r.finish_reason),e.usage&&(s.usage=e.usage)}catch(e){}else s.isCompleted=!0}}}catch(e){throw e}return s},toKebabCase=(e,t="",r="")=>`${t}${e.replace(/([A-Z])/g,"-$1").toLowerCase()}${r}`,trimEmptyLines=e=>null==e?"":e.replace(/^\s*\n|\n\s*$/g,"")||"",decodeHtmlEntities=e=>{if(!e)return"";const t=document.createElement("textarea");return t.innerHTML=e,t.value},getBodyHTML=(e,t)=>{if(!e||"string"!=typeof e)return"";try{const r=(new DOMParser).parseFromString(e,"text/html"),a=r.body.innerHTML;if(t){const e=r.querySelector(t);if(e)return e.innerHTML}return a?a.trim():e}catch(t){return e}},getUrlHash=e=>{if(!e||"string"!=typeof e)return"";try{const t=window?.location?.origin||"https://www.axui.cn";return new URL(e,t).hash}catch(e){return""}},cleanQueryString=e=>"string"==typeof e&&(e.startsWith("?")||e.startsWith("&"))?e.slice(1):e,buildUrl=({url:e,data:t,cacheBustKey:r="_t",appendCacheBust:a=!0})=>{const n=e.indexOf("#");let s="",o=e;-1!==n&&(s=e.slice(n),o=e.slice(0,n));const l=new URL(o,window.location.origin);if(!isEmpty(t)){let e,r=getDataType(t);e="URLSearchParams"===r?t:"object"===r?new URLSearchParams(t):new URLSearchParams(cleanQueryString(t)),e.forEach((e,t)=>{l.searchParams.append(t,e)})}return a&&r&&l.searchParams.set(r,Date.now().toString()),l.toString()+s},capitalize=e=>e?e.charAt(0).toUpperCase()+e.slice(1):e,ajax=e=>{if(isEmpty(e))return Promise.reject(new Error("Options are required"));if(!e.url||"string"!=typeof e.url)return Promise.reject(new Error("URL is required and must be a string"));const t={url:"",method:"POST",async:!0,selector:"",data:null,timeout:36e5,headers:{},responseType:"",catchError:!1,signal:null,xhrFields:{},cacheBustKey:"_t",onAbort:null,onTimeout:null,onBeforeSend:null,onCreated:null,onOpened:null,onHeadersReceived:null,onLoading:null,onSuccess:null,onFailure:null,onInformation:null,onRedirection:null,onClientError:null,onServerError:null,onUnknownError:null,onError:null,onFinish:null,onDownload:null,onUpload:null,onComplete:null};Object.assign(t,e);const r=t.method.toUpperCase()||"POST",a=["GET","HEAD","TRACE"];let n=new XMLHttpRequest,s=null,o=t?.headers?.["Content-Type"]||t?.headers?.["content-type"];if(!isEmpty(t.data)){let e=getDataType(t.data);"FormData"===e?(s=t.data,o&&(delete t.headers["Content-Type"],delete t.headers["content-type"])):"Object"===e?o?s=o?.includes("application/json")?JSON.stringify(t.data):t.data:(s=new URLSearchParams(t.data).toString(),a.includes(r)||(t.headers["Content-Type"]="application/x-www-form-urlencoded")):"String"===e&&(!o||o.includes("urlencoded"))?(s=cleanQueryString(t.data.trim()),a.includes(r)||o||(t.headers["Content-Type"]="application/x-www-form-urlencoded")):s=t.data}n.timeout=t.timeout,t.responseType&&(n.responseType=t.responseType);const l=new Promise((e,o)=>{const timeoutHandler=()=>{cleanup();let r={...l,status:n.status,content:n.response,type:"timeout"};t?.onTimeout?.(r),t.catchError?o(r):e(r)},errorHandler=r=>{"client-error"===r.type?t?.onClientError?.({...l}):"server-error"===r.type?t?.onServerError?.({...l}):"unknown-error"===r.type&&t?.onUnknownError?.({...l}),t?.onError?.(r),t.catchError?o(r):e(r)},abortHandler=()=>{cleanup();const r={...l,status:n.status,type:"abort"};t.catchError?o(r):e(r),t?.onAbort?.(r)},abortHandlerWithSignal=()=>{n.abort(),abortHandler()},cleanup=()=>{t.signal&&t.signal.removeEventListener("abort",abortHandlerWithSignal),t.onError&&n.removeEventListener("error",errorHandler),t.onTimeout&&n.removeEventListener("timeout",timeoutHandler),t.onUpload&&n.upload.removeEventListener("progress",uploadProgressHandler),t.onDownload&&n.removeEventListener("progress",downloadProgressHandler),n.onreadystatechange=null},l={xhr:n,data:s,abort:abortHandler,status:"",content:null,stage:0,type:"unset",progress:{}},progressHandler=(e,r,a)=>{if(r.lengthComputable){const s={...l,status:n.status},o=r.loaded/r.total;s.progress={name:e,loaded:r.loaded,total:r.total,timestamp:new Date(r.timeStamp).getTime(),ratio:o,percent:Math.round(100*o)},a?.(s),s.progress.percent>=100&&(s.progress.percent=100,t?.onComplete?.(s))}},uploadProgressHandler=e=>{progressHandler("upload",e,e=>t.onUpload(e))},downloadProgressHandler=e=>{progressHandler("download",e,e=>t.onDownload(e))};if(t.signal){if(t.signal.aborted)return abortHandlerWithSignal();t.signal.addEventListener("abort",abortHandlerWithSignal)}t.onUpload&&n.upload.addEventListener("progress",uploadProgressHandler),t.onDownload&&n.addEventListener("progress",downloadProgressHandler),t.onError&&n.addEventListener("error",errorHandler),t.onTimeout&&n.addEventListener("timeout",timeoutHandler),t.onAbort&&n.addEventListener("abort",abortHandler),t.onCreated?.({...l,type:"created"}),n.onreadystatechange=function(){l.stage=n.readyState,l.status=n.status;const r={1:"opened",2:"headersReceived",3:"loading"};if(n.readyState<4){if(!n.readyState)return;return l.type=r[n.readyState],void t[`on${capitalize(l.type)}`]?.({...l})}cleanup();const a=n.status>=100&&n.status<200,s=n.status>=200&&n.status<300||304===n.status,o=n.status>=300&&n.status<400,i=n.status>=400&&n.status<500,c=n.status>=500&&n.status<600;if(s){if(t.responseType&&"text"!==n.responseType)l.content=n.response;else{let e=n.responseText.trim(),r="";if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{r=JSON.parse(e)}catch{r=n.responseText}else if(/(<\/html>|<\/body>)/i.test(e)){let a=getUrlHash(t.url);r=getBodyHTML(e,t.selector||a)}else r=n.responseText;l.content=r}l.type="success",p={...l},t?.onSuccess?.(p),e(p)}else l.content=n.response,l.type=a?"infomation":o?"redirection":i?"client-error":c?"server-error":"unknown-error",a?t?.onInformation?.({...l}):o?t?.onRedirection?.({...l}):errorHandler({...l}),t?.onFailure?.({...l});var p;t?.onFinish?.({...l})};let i=[r,t.url,t.async];if(a.includes(r)){const e=buildUrl({url:t.url,data:s,cacheBustKey:t.cacheBustKey,appendCacheBust:!0});i=[r,e,t.async]}for(let e in t.xhrFields)t.xhrFields.hasOwnProperty(e)&&(n[e]=t.xhrFields[e]);n.open(...i);for(let e in t.headers)t.headers.hasOwnProperty(e)&&!isEmpty(t.headers[e])&&n.setRequestHeader(e,t.headers[e]);t?.onBeforeSend?.({...l,status:n.status,type:"beforeSend"}),n.send(a.includes(r)?null:s||null)});return l.xhr=n,l.abort=()=>n.abort(),l};["post","put","delete","patch","options","get","head","trace"].forEach(e=>{ajax[e]=(t,r,a={url:""})=>ajax({...a,method:e,url:t,data:r})}),ajax.all=e=>Promise.all(e.map(ajax));const utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:getEls,createEl:createEl,getSvgUri:getSvgUri,fileToBase64:fileToBase64,NAMESPACE:"ax",ALIAS:"rep",COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:getClasses,addClasses:addClasses,removeClasses:removeClasses,createTools:createTools,typeWriter:typeWriter,parseLLMStream:parseLLMStream,toKebabCase:toKebabCase,trimEmptyLines:trimEmptyLines,decodeHtmlEntities:decodeHtmlEntities,escapeCharsMaps:escapeCharsMaps,escapeRegexMaps:escapeRegexMaps,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:renderTpl,getBodyHTML:getBodyHTML,getUrlHash:getUrlHash,buildUrl:buildUrl,ajax:ajax,capitalize:capitalize,cleanQueryString:cleanQueryString};module.exports=utils;
|
package/dist/utils.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2026-1-16
|
|
3
|
+
* @since Last modified: 2026-1-20 16:40:28
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
5
|
* @version 0.0.38
|
|
6
6
|
* @author AXUI development team <3217728223@qq.com>
|
|
@@ -941,30 +941,31 @@ const isEmpty = (data) => {
|
|
|
941
941
|
let type = getDataType(data), flag;
|
|
942
942
|
if (!data) {
|
|
943
943
|
//0,'',false,undefined,null
|
|
944
|
-
|
|
944
|
+
return true;
|
|
945
945
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
//[null]|[undefined]|['']|[""]
|
|
949
|
-
//[]|{}
|
|
950
|
-
//Symbol()|Symbol.for()
|
|
951
|
-
//Set,Map
|
|
952
|
-
//Date/Regex
|
|
953
|
-
flag = (type === 'Object') ? (Object.keys(data).length === 0) :
|
|
954
|
-
(type === 'Array') ? data.join('') === '' :
|
|
955
|
-
(type === 'Function') ? (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}') :
|
|
956
|
-
(type === 'Symbol') ? (data.toString().replace(/\s+/g, '').match(/\(.*\)/g)[0] === '()') :
|
|
957
|
-
(type === 'Set' || type === 'Map') ? data.size === 0 :
|
|
958
|
-
type === 'Date' ? isNaN(data.getTime()) :
|
|
959
|
-
type === 'RegExp' ? data.source === '' :
|
|
960
|
-
type === 'ArrayBuffer' ? data.byteLength === 0 :
|
|
961
|
-
(type === 'NodeList' || type === 'HTMLCollection') ? data.length === 0 :
|
|
962
|
-
('length' in data && typeof data.length === 'number') ? data.length === 0 :
|
|
963
|
-
('size' in data && typeof data.size === 'number') ? data.size === 0 :
|
|
964
|
-
(type === 'Error' || data instanceof Error) ? data.message === '' :
|
|
965
|
-
(type.includes('Array') && (['Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array'].includes(type))) ? data.length === 0 :
|
|
966
|
-
false;
|
|
946
|
+
if (['String', 'Number', 'Boolean'].includes(type)) {
|
|
947
|
+
return false;
|
|
967
948
|
}
|
|
949
|
+
//function(){}|()=>{}
|
|
950
|
+
//[null]|[undefined]|['']|[""]
|
|
951
|
+
//[]|{}
|
|
952
|
+
//Symbol()|Symbol.for()
|
|
953
|
+
//Set,Map
|
|
954
|
+
//Date/Regex
|
|
955
|
+
flag = (type === 'Object') ? (Object.keys(data).length === 0) :
|
|
956
|
+
(type === 'Array') ? data.join('') === '' :
|
|
957
|
+
(type === 'Function') ? (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}') :
|
|
958
|
+
(type === 'Symbol') ? (data.toString().replace(/\s+/g, '').match(/\(.*\)/g)[0] === '()') :
|
|
959
|
+
(type === 'Set' || type === 'Map') ? data.size === 0 :
|
|
960
|
+
type === 'Date' ? isNaN(data.getTime()) :
|
|
961
|
+
type === 'RegExp' ? data.source === '' :
|
|
962
|
+
type === 'ArrayBuffer' ? data.byteLength === 0 :
|
|
963
|
+
(type === 'NodeList' || type === 'HTMLCollection') ? data.length === 0 :
|
|
964
|
+
('length' in data && typeof data.length === 'number') ? data.length === 0 :
|
|
965
|
+
('size' in data && typeof data.size === 'number') ? data.size === 0 :
|
|
966
|
+
(type === 'Error' || data instanceof Error) ? data.message === '' :
|
|
967
|
+
(type.includes('Array') && (['Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array'].includes(type))) ? data.length === 0 :
|
|
968
|
+
false;
|
|
968
969
|
return flag;
|
|
969
970
|
};
|
|
970
971
|
|
|
@@ -1338,6 +1339,448 @@ const decodeHtmlEntities = (text) => {
|
|
|
1338
1339
|
return textArea.value; // Get the decoded string from the text area
|
|
1339
1340
|
};
|
|
1340
1341
|
|
|
1342
|
+
const getBodyHTML = (htmlText, selector) => {
|
|
1343
|
+
// Return early if the input is not a valid string or doesn't look like HTML
|
|
1344
|
+
if (!htmlText || typeof htmlText !== 'string') {
|
|
1345
|
+
return '';
|
|
1346
|
+
}
|
|
1347
|
+
try {
|
|
1348
|
+
|
|
1349
|
+
const parser = new DOMParser(),
|
|
1350
|
+
|
|
1351
|
+
doc = parser.parseFromString(htmlText, 'text/html'),
|
|
1352
|
+
|
|
1353
|
+
bodyContent = doc.body.innerHTML;
|
|
1354
|
+
if (selector) {
|
|
1355
|
+
// Normalize hash: ensure it's a valid ID selector
|
|
1356
|
+
const targetEl = doc.querySelector(selector);
|
|
1357
|
+
if (targetEl) {
|
|
1358
|
+
return targetEl.innerHTML;
|
|
1359
|
+
}
|
|
1360
|
+
// If hash is provided but element not found, we fallback to body or warn
|
|
1361
|
+
console.warn(`Element with selector "${selector}" not found in the HTML.`);
|
|
1362
|
+
}
|
|
1363
|
+
return bodyContent ? bodyContent.trim() : htmlText;
|
|
1364
|
+
}
|
|
1365
|
+
catch (error) {
|
|
1366
|
+
|
|
1367
|
+
console.error("Failed to parse HTML content using DOMParser:", error);
|
|
1368
|
+
return htmlText;
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
const getUrlHash = (url) => {
|
|
1373
|
+
// Return empty if input is null, undefined, or not a string
|
|
1374
|
+
if (!url || typeof url !== 'string') {
|
|
1375
|
+
return '';
|
|
1376
|
+
}
|
|
1377
|
+
try {
|
|
1378
|
+
|
|
1379
|
+
const baseUrl = window?.location?.origin || 'https://www.axui.cn', urlObj = new URL(url, baseUrl);
|
|
1380
|
+
return urlObj.hash;
|
|
1381
|
+
}
|
|
1382
|
+
catch (error) {
|
|
1383
|
+
|
|
1384
|
+
return '';
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
const cleanQueryString = (data) => {
|
|
1389
|
+
return typeof data === 'string' && (data.startsWith('?') || data.startsWith('&'))
|
|
1390
|
+
? data.slice(1) // Remove the leading '?' or '&'
|
|
1391
|
+
: data; // Return the string as-is if no leading character is present
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
const buildUrl = ({ url, data, cacheBustKey = '_t', appendCacheBust = true }) => {
|
|
1395
|
+
// 1. Extract and remove the hash (e.g., /page#section -> hash="#section")
|
|
1396
|
+
const hashIndex = url.indexOf('#');
|
|
1397
|
+
let hash = '', pureUrl = url;
|
|
1398
|
+
// If a hash exists, separate it from the base URL
|
|
1399
|
+
if (hashIndex !== -1) {
|
|
1400
|
+
hash = url.slice(hashIndex);
|
|
1401
|
+
pureUrl = url.slice(0, hashIndex);
|
|
1402
|
+
}
|
|
1403
|
+
// 2. Use the URL object to handle the base URL and existing query parameters.
|
|
1404
|
+
// `window.location.origin` ensures the support for relative paths (e.g., '/api/list').
|
|
1405
|
+
const urlObj = new URL(pureUrl, window.location.origin);
|
|
1406
|
+
// 3. Append business data (query parameters) to the URL if data is not empty
|
|
1407
|
+
if (!isEmpty(data)) {
|
|
1408
|
+
let params, dataType = getDataType(data);
|
|
1409
|
+
// If the data is a URLSearchParams object, directly use it
|
|
1410
|
+
if (dataType === 'URLSearchParams') {
|
|
1411
|
+
params = data;
|
|
1412
|
+
}
|
|
1413
|
+
else if (dataType === 'object') {
|
|
1414
|
+
// If the data is an object, convert it to URLSearchParams
|
|
1415
|
+
params = new URLSearchParams(data);
|
|
1416
|
+
}
|
|
1417
|
+
else {
|
|
1418
|
+
// If the data is a string, clean it up (remove leading '?' or '&')
|
|
1419
|
+
params = new URLSearchParams(cleanQueryString(data));
|
|
1420
|
+
}
|
|
1421
|
+
// Append new parameters to the existing URL search parameters
|
|
1422
|
+
params.forEach((value, key) => {
|
|
1423
|
+
urlObj.searchParams.append(key, value);
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
// 4. Optionally add the cache-busting parameter if the flag is set
|
|
1427
|
+
appendCacheBust && cacheBustKey && urlObj.searchParams.set(cacheBustKey, Date.now().toString());
|
|
1428
|
+
// 5. Return the final URL: base URL + query parameters + original hash (if any)
|
|
1429
|
+
return urlObj.toString() + hash;
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
const capitalize = (str) => {
|
|
1433
|
+
// Check if the input string is empty or undefined
|
|
1434
|
+
if (!str)
|
|
1435
|
+
return str;
|
|
1436
|
+
// Capitalize the first letter and return the new string
|
|
1437
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1438
|
+
};
|
|
1439
|
+
|
|
1440
|
+
const ajax = (options) => {
|
|
1441
|
+
// Validation
|
|
1442
|
+
if (isEmpty(options)) {
|
|
1443
|
+
return Promise.reject(new Error('Options are required'));
|
|
1444
|
+
}
|
|
1445
|
+
if (!options.url || typeof options.url !== 'string') {
|
|
1446
|
+
return Promise.reject(new Error('URL is required and must be a string'));
|
|
1447
|
+
}
|
|
1448
|
+
// Default configuration
|
|
1449
|
+
const config = {
|
|
1450
|
+
url: '',
|
|
1451
|
+
method: 'POST',
|
|
1452
|
+
async: true,
|
|
1453
|
+
selector: '',
|
|
1454
|
+
data: null,
|
|
1455
|
+
timeout: 3600000,
|
|
1456
|
+
headers: {},
|
|
1457
|
+
responseType: '',
|
|
1458
|
+
catchError: false,
|
|
1459
|
+
signal: null,
|
|
1460
|
+
xhrFields: {},
|
|
1461
|
+
cacheBustKey: '_t',
|
|
1462
|
+
//
|
|
1463
|
+
onAbort: null,
|
|
1464
|
+
onTimeout: null,
|
|
1465
|
+
//
|
|
1466
|
+
onBeforeSend: null,
|
|
1467
|
+
//
|
|
1468
|
+
onCreated: null,
|
|
1469
|
+
onOpened: null,
|
|
1470
|
+
onHeadersReceived: null,
|
|
1471
|
+
onLoading: null,
|
|
1472
|
+
//
|
|
1473
|
+
onSuccess: null,
|
|
1474
|
+
onFailure: null,
|
|
1475
|
+
onInformation: null,
|
|
1476
|
+
onRedirection: null,
|
|
1477
|
+
onClientError: null,
|
|
1478
|
+
onServerError: null,
|
|
1479
|
+
onUnknownError: null,
|
|
1480
|
+
onError: null,
|
|
1481
|
+
onFinish: null,
|
|
1482
|
+
//
|
|
1483
|
+
onDownload: null,
|
|
1484
|
+
onUpload: null,
|
|
1485
|
+
onComplete: null,
|
|
1486
|
+
};
|
|
1487
|
+
//合并参数
|
|
1488
|
+
Object.assign(config, options);
|
|
1489
|
+
//
|
|
1490
|
+
const method = config.method.toUpperCase() || 'POST', methodsWithoutBody = ['GET', 'HEAD', 'TRACE'];
|
|
1491
|
+
//创建XMLHttpRequest
|
|
1492
|
+
let xhr = new XMLHttpRequest(),
|
|
1493
|
+
//设置发送数据和预设请求头
|
|
1494
|
+
requestData = null, headerContentType = config?.headers?.['Content-Type'] || config?.headers?.['content-type'], removeHeader = () => {
|
|
1495
|
+
if (headerContentType) {
|
|
1496
|
+
delete config.headers['Content-Type'];
|
|
1497
|
+
delete config.headers['content-type'];
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
if (!isEmpty(config.data)) {
|
|
1501
|
+
let dataType = getDataType(config.data);
|
|
1502
|
+
if (dataType === 'FormData') {
|
|
1503
|
+
//如果是new FormData格式,直接相等
|
|
1504
|
+
requestData = config.data;
|
|
1505
|
+
// 不需要手动设置Content-Type,浏览器会自动设置
|
|
1506
|
+
//config.contType = 'multipart/form-data';
|
|
1507
|
+
removeHeader();
|
|
1508
|
+
}
|
|
1509
|
+
else if (dataType === 'Object') {
|
|
1510
|
+
//如果是对象格式{name:'',age:''}
|
|
1511
|
+
//并且此时已经设置了contType
|
|
1512
|
+
if (!headerContentType) {
|
|
1513
|
+
//如果未设置则默认设为如下contType
|
|
1514
|
+
//Content-Type=application/x-www-form-urlencoded
|
|
1515
|
+
|
|
1516
|
+
requestData = new URLSearchParams(config.data).toString();
|
|
1517
|
+
//URLSearchParams.toString => `a=1&b=3`
|
|
1518
|
+
//非get、head方法修正content-type
|
|
1519
|
+
if (!methodsWithoutBody.includes(method)) {
|
|
1520
|
+
config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
else if (headerContentType?.includes('application/json')) {
|
|
1524
|
+
//Content-Type=application/json或contentType=application/json
|
|
1525
|
+
requestData = JSON.stringify(config.data);
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
requestData = config.data;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
else if (dataType === 'String') {
|
|
1532
|
+
//未设置或,已经设置了Content-Type=application/x-www-form-urlencoded
|
|
1533
|
+
if (!headerContentType || headerContentType.includes('urlencoded')) {
|
|
1534
|
+
//如果是name=''&age=''字符串
|
|
1535
|
+
//?name=''&age=''或&name=''&age=''统一去掉第一个&/?
|
|
1536
|
+
requestData = cleanQueryString(config.data.trim());
|
|
1537
|
+
//非get、head方法修正content-type
|
|
1538
|
+
if (!methodsWithoutBody.includes(method) && !headerContentType) {
|
|
1539
|
+
config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
else {
|
|
1543
|
+
requestData = config.data;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
else {
|
|
1547
|
+
requestData = config.data;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
//设置超时时间
|
|
1551
|
+
xhr.timeout = config.timeout;
|
|
1552
|
+
// 响应类型
|
|
1553
|
+
if (config.responseType) {
|
|
1554
|
+
xhr.responseType = config.responseType;
|
|
1555
|
+
}
|
|
1556
|
+
//返回promise
|
|
1557
|
+
const result = new Promise((resolve, reject) => {
|
|
1558
|
+
//超时监听
|
|
1559
|
+
const timeoutHandler = () => {
|
|
1560
|
+
cleanup();
|
|
1561
|
+
let resp = { ...context, status: xhr.status, content: xhr.response, type: 'timeout' };
|
|
1562
|
+
//回调,status和content在此确认
|
|
1563
|
+
config?.onTimeout?.(resp);
|
|
1564
|
+
//reject只能接受一个参数
|
|
1565
|
+
config.catchError ? reject(resp) : resolve(resp);
|
|
1566
|
+
},
|
|
1567
|
+
//报错监听
|
|
1568
|
+
errorHandler = (resp) => {
|
|
1569
|
+
//这几个错误来自xhr.onreadystatechange
|
|
1570
|
+
if (resp.type === 'client-error') {
|
|
1571
|
+
config?.onClientError?.({ ...context });
|
|
1572
|
+
}
|
|
1573
|
+
else if (resp.type === 'server-error') {
|
|
1574
|
+
config?.onServerError?.({ ...context });
|
|
1575
|
+
}
|
|
1576
|
+
else if (resp.type === 'unknown-error') {
|
|
1577
|
+
config?.onUnknownError?.({ ...context });
|
|
1578
|
+
}
|
|
1579
|
+
//此外还会有xhr.onerror的错误,所以需要统一使用onError监听
|
|
1580
|
+
config?.onError?.(resp);
|
|
1581
|
+
//reject只能接受一个参数
|
|
1582
|
+
config.catchError ? reject(resp) : resolve(resp);
|
|
1583
|
+
},
|
|
1584
|
+
//取消监听
|
|
1585
|
+
abortHandler = () => {
|
|
1586
|
+
cleanup();
|
|
1587
|
+
const resp = { ...context, status: xhr.status, type: 'abort' };
|
|
1588
|
+
config.catchError ? reject(resp) : resolve(resp);
|
|
1589
|
+
//回调,status和content在此确认
|
|
1590
|
+
config?.onAbort?.(resp);
|
|
1591
|
+
}, abortHandlerWithSignal = () => {
|
|
1592
|
+
//先中止请求,防止触发其他 readystate 事件
|
|
1593
|
+
xhr.abort();
|
|
1594
|
+
abortHandler();
|
|
1595
|
+
},
|
|
1596
|
+
//成功监听
|
|
1597
|
+
successHandler = (resp) => {
|
|
1598
|
+
//成功回调
|
|
1599
|
+
config?.onSuccess?.(resp);
|
|
1600
|
+
//resolve只能接受一个参数
|
|
1601
|
+
resolve(resp);
|
|
1602
|
+
},
|
|
1603
|
+
//统一处理abort
|
|
1604
|
+
cleanup = () => {
|
|
1605
|
+
// 如果使用了AbortSignal,则移除它的事件监听器
|
|
1606
|
+
config.signal && config.signal.removeEventListener('abort', abortHandlerWithSignal);
|
|
1607
|
+
// 移除各类事件监听器
|
|
1608
|
+
config.onError && xhr.removeEventListener('error', errorHandler);
|
|
1609
|
+
config.onTimeout && xhr.removeEventListener('timeout', timeoutHandler);
|
|
1610
|
+
// 解绑上传/下载进度事件
|
|
1611
|
+
config.onUpload && xhr.upload.removeEventListener('progress', uploadProgressHandler);
|
|
1612
|
+
config.onDownload && xhr.removeEventListener('progress', downloadProgressHandler);
|
|
1613
|
+
//销毁
|
|
1614
|
+
xhr.onreadystatechange = null;
|
|
1615
|
+
},
|
|
1616
|
+
// Context object to track state
|
|
1617
|
+
context = {
|
|
1618
|
+
//原始xhr
|
|
1619
|
+
xhr,
|
|
1620
|
+
//发送的数据
|
|
1621
|
+
data: requestData,
|
|
1622
|
+
//可取消的函数
|
|
1623
|
+
abort: abortHandler,
|
|
1624
|
+
//xhr.status
|
|
1625
|
+
status: '',
|
|
1626
|
+
//响应的内容
|
|
1627
|
+
content: null,
|
|
1628
|
+
//0~4阶段编号
|
|
1629
|
+
stage: 0,
|
|
1630
|
+
//阶段名称
|
|
1631
|
+
type: 'unset',
|
|
1632
|
+
//上传和下载进度
|
|
1633
|
+
progress: {}
|
|
1634
|
+
},
|
|
1635
|
+
//定义进度函数
|
|
1636
|
+
progressHandler = (name, data, callback) => {
|
|
1637
|
+
if (data.lengthComputable) {
|
|
1638
|
+
const resp = { ...context, status: xhr.status }, ratio = data.loaded / data.total;
|
|
1639
|
+
resp.progress = {
|
|
1640
|
+
name,
|
|
1641
|
+
loaded: data.loaded,
|
|
1642
|
+
total: data.total,
|
|
1643
|
+
timestamp: (new Date(data.timeStamp)).getTime(),
|
|
1644
|
+
ratio,
|
|
1645
|
+
percent: Math.round(ratio * 100),
|
|
1646
|
+
};
|
|
1647
|
+
callback?.(resp);
|
|
1648
|
+
//到达100%执行complete
|
|
1649
|
+
if (resp.progress.percent >= 100) {
|
|
1650
|
+
resp.progress.percent = 100;
|
|
1651
|
+
config?.onComplete?.(resp);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
}, uploadProgressHandler = (data) => {
|
|
1655
|
+
progressHandler('upload', data, (resp) => config.onUpload(resp));
|
|
1656
|
+
}, downloadProgressHandler = (data) => {
|
|
1657
|
+
progressHandler('download', data, (resp) => config.onDownload(resp));
|
|
1658
|
+
};
|
|
1659
|
+
//使用AbortSignal
|
|
1660
|
+
if (config.signal) {
|
|
1661
|
+
if (config.signal.aborted)
|
|
1662
|
+
return abortHandlerWithSignal();
|
|
1663
|
+
config.signal.addEventListener('abort', abortHandlerWithSignal);
|
|
1664
|
+
}
|
|
1665
|
+
//监听上传进度
|
|
1666
|
+
config.onUpload && xhr.upload.addEventListener('progress', uploadProgressHandler);
|
|
1667
|
+
//监听下载进度
|
|
1668
|
+
config.onDownload && xhr.addEventListener('progress', downloadProgressHandler);
|
|
1669
|
+
// 事件监听器
|
|
1670
|
+
config.onError && xhr.addEventListener('error', errorHandler);
|
|
1671
|
+
config.onTimeout && xhr.addEventListener('timeout', timeoutHandler);
|
|
1672
|
+
config.onAbort && xhr.addEventListener('abort', abortHandler);
|
|
1673
|
+
// 手动触发 Created 状态
|
|
1674
|
+
config.onCreated?.({ ...context, type: 'created' });
|
|
1675
|
+
//状态判断
|
|
1676
|
+
xhr.onreadystatechange = function () {
|
|
1677
|
+
context.stage = xhr.readyState;
|
|
1678
|
+
context.status = xhr.status;
|
|
1679
|
+
const statusMap = { 1: 'opened', 2: 'headersReceived', 3: 'loading' };
|
|
1680
|
+
//0=created放在外侧确保能触发,如果放在.onreadystatechange可能触发不了
|
|
1681
|
+
if (xhr.readyState < 4) {
|
|
1682
|
+
if (!xhr.readyState)
|
|
1683
|
+
return;
|
|
1684
|
+
context.type = statusMap[xhr.readyState];
|
|
1685
|
+
config[`on${capitalize(context.type)}`]?.({ ...context });
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
//已经请求成功,不会有timeout事件,也不需要abort了,所以移除abort事件
|
|
1689
|
+
cleanup();
|
|
1690
|
+
const isInformation = xhr.status >= 100 && xhr.status < 200, isSuccess = (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304, isRedirection = xhr.status >= 300 && xhr.status < 400, isClientError = xhr.status >= 400 && xhr.status < 500, isServerError = xhr.status >= 500 && xhr.status < 600;
|
|
1691
|
+
//已经获得返回数据
|
|
1692
|
+
if (isSuccess) {
|
|
1693
|
+
if (!config.responseType || xhr.responseType === 'text') {
|
|
1694
|
+
//可能返回字符串类型的对象,wordpress的REST API
|
|
1695
|
+
let trim = xhr.responseText.trim(), content = '';
|
|
1696
|
+
if ((trim.startsWith('[') && trim.endsWith(']')) || (trim.startsWith('{') && trim.endsWith('}'))) {
|
|
1697
|
+
//通过判断开头字符是{或[来确定异步页面是否是JSON内容,如果是则转成JSON对象
|
|
1698
|
+
try {
|
|
1699
|
+
content = JSON.parse(trim);
|
|
1700
|
+
}
|
|
1701
|
+
catch {
|
|
1702
|
+
console.warn('Malformed JSON detected, falling back to text.');
|
|
1703
|
+
content = xhr.responseText;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
else if (/(<\/html>|<\/body>)/i.test(trim)) {
|
|
1707
|
+
//请求了一个HTML页面
|
|
1708
|
+
//返回文本类型DOMstring
|
|
1709
|
+
let urlHash = getUrlHash(config.url);
|
|
1710
|
+
content = getBodyHTML(trim, config.selector || urlHash);
|
|
1711
|
+
}
|
|
1712
|
+
else {
|
|
1713
|
+
//普通文本,不做任何处理
|
|
1714
|
+
content = xhr.responseText;
|
|
1715
|
+
}
|
|
1716
|
+
//content=文本字符串/json
|
|
1717
|
+
context.content = content;
|
|
1718
|
+
}
|
|
1719
|
+
else {
|
|
1720
|
+
//content=json、blob、document、arraybuffer等类型,如果知道服务器返回的XML, xhr.responseType应该为document
|
|
1721
|
+
context.content = xhr.response;
|
|
1722
|
+
}
|
|
1723
|
+
context.type = 'success';
|
|
1724
|
+
successHandler({ ...context });
|
|
1725
|
+
}
|
|
1726
|
+
else {
|
|
1727
|
+
//失败回调
|
|
1728
|
+
context.content = xhr.response;
|
|
1729
|
+
context.type = isInformation ? 'infomation' : isRedirection ? 'redirection' : isClientError ? 'client-error' : isServerError ? 'server-error' : 'unknown-error';
|
|
1730
|
+
//
|
|
1731
|
+
if (isInformation) {
|
|
1732
|
+
config?.onInformation?.({ ...context });
|
|
1733
|
+
}
|
|
1734
|
+
else if (isRedirection) {
|
|
1735
|
+
config?.onRedirection?.({ ...context });
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1738
|
+
errorHandler({ ...context });
|
|
1739
|
+
}
|
|
1740
|
+
//
|
|
1741
|
+
config?.onFailure?.({ ...context });
|
|
1742
|
+
}
|
|
1743
|
+
config?.onFinish?.({ ...context });
|
|
1744
|
+
};
|
|
1745
|
+
//发送异步请求
|
|
1746
|
+
let openParams = [method, config.url, config.async];
|
|
1747
|
+
if (methodsWithoutBody.includes(method)) {
|
|
1748
|
+
// 拼接url => xxx.com?a=0&b=1#hello
|
|
1749
|
+
const url = buildUrl({
|
|
1750
|
+
url: config.url,
|
|
1751
|
+
data: requestData,
|
|
1752
|
+
cacheBustKey: config.cacheBustKey,
|
|
1753
|
+
appendCacheBust: true,
|
|
1754
|
+
});
|
|
1755
|
+
openParams = [method, url, config.async];
|
|
1756
|
+
}
|
|
1757
|
+
//设置xhr其他字段
|
|
1758
|
+
for (let k in config.xhrFields) {
|
|
1759
|
+
config.xhrFields.hasOwnProperty(k) && (xhr[k] = config.xhrFields[k]);
|
|
1760
|
+
}
|
|
1761
|
+
//与服务器建立连接
|
|
1762
|
+
xhr.open(...openParams);
|
|
1763
|
+
//有则设置,仅跳过空内容
|
|
1764
|
+
for (let k in config.headers) {
|
|
1765
|
+
config.headers.hasOwnProperty(k) && !isEmpty(config.headers[k]) && xhr.setRequestHeader(k, config.headers[k]);
|
|
1766
|
+
}
|
|
1767
|
+
config?.onBeforeSend?.(({ ...context, status: xhr.status, type: 'beforeSend' }));
|
|
1768
|
+
//发送请求,get和head不需要发送数据
|
|
1769
|
+
xhr.send(methodsWithoutBody.includes(method) ? null : (requestData || null));
|
|
1770
|
+
//open和send阶段已经是异步了,无法使用try+catch捕获错误
|
|
1771
|
+
});
|
|
1772
|
+
//绑定xhr和abort
|
|
1773
|
+
result.xhr = xhr;
|
|
1774
|
+
result.abort = () => xhr.abort();
|
|
1775
|
+
return result;
|
|
1776
|
+
};
|
|
1777
|
+
// Static Helper Methods
|
|
1778
|
+
//get、head、trace是不需要发送数据的,data将被转为url参数处理
|
|
1779
|
+
['post', 'put', 'delete', 'patch', 'options', 'get', 'head', 'trace'].forEach(method => {
|
|
1780
|
+
ajax[method] = (url, data, options = { url: '' }) => ajax({ ...options, method, url, data });
|
|
1781
|
+
});
|
|
1782
|
+
ajax.all = (requests) => Promise.all(requests.map(ajax));
|
|
1783
|
+
|
|
1341
1784
|
const utils = {
|
|
1342
1785
|
//executeStr,
|
|
1343
1786
|
getDataType,
|
|
@@ -1381,6 +1824,12 @@ const utils = {
|
|
|
1381
1824
|
escapeHTML,
|
|
1382
1825
|
toSingleLine,
|
|
1383
1826
|
renderTpl,
|
|
1827
|
+
getBodyHTML,
|
|
1828
|
+
getUrlHash,
|
|
1829
|
+
buildUrl,
|
|
1830
|
+
ajax,
|
|
1831
|
+
capitalize,
|
|
1832
|
+
cleanQueryString,
|
|
1384
1833
|
};
|
|
1385
1834
|
|
|
1386
1835
|
export { utils as default };
|