@codady/utils 0.0.38 → 0.0.40
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 +37 -0
- package/dist/utils.cjs.js +576 -24
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +576 -24
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd.js +576 -24
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/examples/ajax-download.html +94 -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/ajax-signal.html +91 -0
- package/examples/ajax-timeout.html +85 -0
- package/examples/buildUrl.html +99 -0
- package/examples/getUrlHash.html +71 -0
- package/examples/stringToEncodings-collision-test-registry.html +117 -0
- package/examples/stringToEncodings-collision-test.html +71 -0
- package/examples/stringToEncodings.html +138 -0
- package/examples/unicodeToEncodings.html +195 -0
- package/modules.js +17 -1
- package/modules.ts +17 -1
- package/package.json +1 -1
- package/src/ajax.js +380 -0
- package/src/ajax.ts +470 -0
- package/src/buildUrl.js +64 -0
- package/src/buildUrl.ts +86 -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/src/stringToEncodings.js +56 -0
- package/src/stringToEncodings.ts +110 -0
- package/src/unicodeToEncodings.js +51 -0
- package/src/unicodeToEncodings.ts +55 -0
- package/src/arrayMutableMethods - /345/211/257/346/234/254.js" +0 -5
- package/src/comma - /345/211/257/346/234/254.js" +0 -2
- package/src/deepCloneToJSON - /345/211/257/346/234/254.js" +0 -47
- package/src/deepMergeMaps - /345/211/257/346/234/254.js" +0 -78
- package/src/escapeHTML - /345/211/257/346/234/254.js" +0 -29
- package/src/getDataType - /345/211/257/346/234/254.js" +0 -38
- package/src/isEmpty - /345/211/257/346/234/254.js" +0 -45
- package/src/mapMutableMethods - /345/211/257/346/234/254.js" +0 -5
- package/src/setMutableMethods - /345/211/257/346/234/254.js" +0 -5
- package/src/wrapMap - /345/211/257/346/234/254.js" +0 -119
package/dist/utils.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2026-
|
|
2
|
+
* @since Last modified: 2026-2-5 17:4:41
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.40
|
|
5
5
|
* @author AXUI development team <3217728223@qq.com>
|
|
6
6
|
* @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
|
|
7
7
|
* @see {@link https://www.axui.cn|Official website}
|
|
@@ -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
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"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),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let a,s=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const a of r)t[a]=deepClone(e[a],{...n,parent:e});a=t}else if("Array"===r&&n.cloneArray)a=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,a]of e)t.set(deepClone(r,n),deepClone(a,{...n,parent:e}));a=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));a=t}else if("Date"===r&&n.cloneDate)a=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;a=new RegExp(t.source,t.flags)}else a=e,s=!1;return n.onAfterClone?.({output:a,input:e,type:r,cloned:s,parent:n.parent}),a},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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t={basic:{"&":"&","<":"<",">":">"},attribute:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},content:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},uri:{"&":"&","<":"<",">":">",'"':""","'":"'","(":"(",")":")","[":"[","]":"]"},paranoid:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/","=":"=","!":"!","#":"#","(":"(",")":")","[":"[","]":"]","{":"{","}":"}",":":":",";":";"}},r=Object.keys(t).reduce((e,r)=>{const n=Object.keys(t[r]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[r]=new RegExp(`[${n.join("")}]`,"g"),e},{}),escapeHTML=(e,n="attribute")=>{if("string"!=typeof e)return"";const a=t[n],s=r[n];return e.replace(s,e=>a[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,a=e.base36;return`${t?t+"-":""}${Date.now()}${a?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let n=Array.isArray(t)?t:[t],a=getDataType(e),s=a.toLowerCase(),o=n.map(e=>e.toLowerCase()),i=s.includes("html")?"element":s;if(r)try{if(!o.includes(i))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${i}`)}catch(e){r(e,a)}else if(!o.includes(i))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${i}`);return a},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},n=["add","delete","clear"],a=["set","delete","clear"],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},getEl=(e,t=document.body)=>{let r=getDataType(e),n=getDataType(t),a=n.includes("HTML")||"ShadowRoot"===n?t:document.querySelector(t),s=a&&a instanceof HTMLTemplateElement?a.content:a,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 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},createEl=(e,t,r)=>{let n=(e=e||"div").toUpperCase().trim(),a=document.createElement(n),s=getDataType(t);if(t&&"Object"===s)for(let e in t)t.hasOwnProperty(e)&&a.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"===n)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)})(a,r),a},s="rep",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 n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.add(e):"string"==typeof t&&t&&n.classList.add(t)):n.classList.add(e)})};return{getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=e);const o={};for(let e of a)o[e]=function(...a){const o={},i=t.length;switch(e){case"push":case"unshift":o.addedItems=[...a];break;case"pop":o.poppedItem=t[i-1];break;case"shift":o.shiftedItem=t[0];break;case"splice":const[e,r]=a,n=e<0?Math.max(i+e,0):Math.min(e,i),s=void 0===r?i-n:r;o.deletedItems=t.slice(n,n+s);break;case"sort":case"reverse":o.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=a[1]||0,c=void 0===a[2]?i:a[2];o.oldItems=t.slice(l,c),o.start=l,o.end=c}r?.(o);const l=Array.prototype[e].apply(t,a),c={value:l,key:e,args:a,context:o,target:t,...s};return n?.(c),l};return o},arrayMutableMethods:e,setMutableMethods:n,mapMutableMethods:a,wrapSetMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=n,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const o={},createWrappedMethod=n=>function(...a){const o={};switch(n){case"add":{const[t]=a;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=a;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 i=e[n].apply(e,a),l={method:n,result:i,args:a,context:o,target:e,...s};return r(l),i};for(const e of a)n.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:n=a,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const o={},createWrappedMethod=n=>function(...a){const o={};switch(n){case"set":{const[t,r]=a;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]=a;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 i=e[n].apply(e,a),l={method:n,result:i,args:a,context:o,target:e,...s};return r(l),i};for(const e of n)a.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},getUniqueId:getUniqueId,deepMerge:(e,t,r={})=>{const n=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,n)=>{let a,s,o=getDataType(e),i=getDataType(t),l=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:o,sourceType:i,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:i,parent:n.parent}),"Object"===o&&"Object"===i?(s=deepMergeObjects(e,t,n),a="Object"):"Array"===o&&"Array"===i?(s=deepMergeArrays(e,t,n),a="Array"):"Set"===o&&"Set"===i?(s=deepMergeSets(e,t,n),a="Set"):"Map"===o&&"Map"===i?(s=deepMergeMaps(e,t,n),a="Map"):(l=!1,s=e),n?.onAfterMerge?.({result:s,target:e,source:t,targetType:o,sourceType:i,mergeType:a,parent:r.parent}),{result:s,flag:l,mergeType:a}},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 n=getDataType(e),a=getDataType(t);if("Object"!==n||"Object"!==a)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 n=o[e],a=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(n,a,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=a;else{let t=s.useEnable?mergeEnableObject(n,a):a;n!==t&&null===t?"ignore"===s.nullBehavior||("delete"===s.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):n!==t&&void 0===t?"ignore"===s.undefinedBehavior||("delete"===s.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=a):o[e]=a}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&s.inheritMissing&&(o[e]=a)}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 n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),a=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=a.length));e++){smartMerger(a[e],t[e],{...n,parent:a}).flag||(a[e]=t[e])}else"concat"===n.dataMode||(a.length=0),a.push(...t);return a},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Map([...e]):e;for(const[e,s]of t.entries())if(a.has(e)){const t=a.get(e),r=s,o=smartMerger(t,r,n);o.flag?"Object"===o.mergeType&&a.set(e,o.result):a.set(e,r)}else r.inheritMissing&&a.set(e,s);return a},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...a],r=[...t],s=smartMerger(e,r,n);a.clear();for(let e of s.result)a.add(e)}else if("concat"===n.dataMode)for(let e of t)a.add(e);else{a.clear();for(let e of t)a.add(e)}return a};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:(e,t=document.body)=>{let r=getDataType(e),n=getEl(t),a=n&&n instanceof HTMLTemplateElement?n.content:n||document,s=[];return isEmpty(e)?s:(r.includes("HTML")?s.push(e):"String"===r?s=(e=e.trim()).split(",").map(e=>[...a.querySelectorAll(e)]).flat():"Array"===r&&(s=e.map(e=>getEl(e,n))),s.filter(Boolean))},createEl:createEl,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 n=new FileReader;n.onload=()=>{"string"==typeof n.result?t(n.result):r(new Error("FileReader result is not a string"))},n.onerror=()=>{r(n.error||new Error("Unknown error occurred during file reading"))},n.readAsDataURL(e)}),NAMESPACE:"ax",ALIAS:s,COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},addClasses:addClasses,removeClasses:(e,t,r)=>{const n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.remove(e):"string"==typeof t&&t&&n.classList.remove(t)):n.classList.remove(e)})},createTools:e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?`<i ${s}="arrow"></i>`:"",n=(e.icon?`<i ${s}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${s}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${s}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${s}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${s}="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),n),e.iconEl=e.wrapEl.querySelector(`[${s}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${s}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${s}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${s}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${s}="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},typeWriter:(e,t)=>{const r=t.speed||100;return new Promise(n=>{t?.onBeforeType?.(e);let a=0;const s=setInterval(()=>{if(a<e.length){const r=e.charAt(a),n=e.substring(0,a+1);t?.onDuringType?.(r,n),a++}else clearInterval(s),n(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(),n=new TextDecoder("utf-8");let a="";const s={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;a+=n.decode(o,{stream:!0});let i=a.split("\n");a=i.pop()||"";for(const e of i){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const n=r.substring(6);if("[DONE]"!==n)try{const e=JSON.parse(n),r=e.choices?.[0],a=r?.delta?.content||"";a&&(s.fullText+=a,t?.(a)),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},escapeCharsMaps:t,escapeRegexMaps:r,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let n=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let a,s=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),o=s.start.split("").map(e=>"\\"+e).join(""),i=s.end.split("").map(e=>"\\"+e).join(""),l=new RegExp(`${o}([\\s\\S]+?)?${i}`,"g"),c='"use strict";let str=[];\n',p=0,u="",f=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(s.suffix)?c+=e.slice(0,-s.suffix.length)+"\n":c+=s.escape?`str.push(${f}(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(;a=l.exec(e);)add(e.slice(p,a.index))(a[1],!0),p=a.index+a[0].length;add(e.slice(p)),c+="return str.join('');",c=toSingleLine(c);try{if(s.strict||"Array"===n)u=new Function(f,c).apply(t,[escapeHTML]);else{let e=Object.keys(t),r=Object.values(t);u=new Function(...e,f,c).bind(t)(...r,escapeHTML)}}catch(e){}return u}}});
|
|
15
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"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),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let s,o=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const s of r)t[s]=deepClone(e[s],{...n,parent:e});s=t}else if("Array"===r&&n.cloneArray)s=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,s]of e)t.set(deepClone(r,n),deepClone(s,{...n,parent:e}));s=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));s=t}else if("Date"===r&&n.cloneDate)s=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;s=new RegExp(t.source,t.flags)}else s=e,o=!1;return n.onAfterClone?.({output:s,input:e,type:r,cloned:o,parent:n.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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t={basic:{"&":"&","<":"<",">":">"},attribute:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},content:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},uri:{"&":"&","<":"<",">":">",'"':""","'":"'","(":"(",")":")","[":"[","]":"]"},paranoid:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/","=":"=","!":"!","#":"#","(":"(",")":")","[":"[","]":"]","{":"{","}":"}",":":":",";":";"}},r=Object.keys(t).reduce((e,r)=>{const n=Object.keys(t[r]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[r]=new RegExp(`[${n.join("")}]`,"g"),e},{}),escapeHTML=(e,n="attribute")=>{if("string"!=typeof e)return"";const s=t[n],o=r[n];return e.replace(o,e=>s[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,s=e.base36;return`${t?t+"-":""}${Date.now()}${s?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let n=Array.isArray(t)?t:[t],s=getDataType(e),o=s.toLowerCase(),a=n.map(e=>e.toLowerCase()),i=o.includes("html")?"element":o;if(r)try{if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`)}catch(e){r(e,s)}else if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`);return s},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},n=["add","delete","clear"],s=["set","delete","clear"],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},getEl=(e,t=document.body)=>{let r=getDataType(e),n=getDataType(t),s=n.includes("HTML")||"ShadowRoot"===n?t:document.querySelector(t),o=s&&s instanceof HTMLTemplateElement?s.content:s,a=null;if(e)if(r.includes("HTML"))a=e;else if("String"===r)try{a=(o||document).querySelector(e.trim())}catch{a=null}return a},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)},createEl=(e,t,r)=>{let n=(e=e||"div").toUpperCase().trim(),s=document.createElement(n),o=getDataType(t);if(t&&"Object"===o)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"===n)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},o="rep",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 n=getEl(e),s=parseClasses(t);n&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.add(e):"string"==typeof t&&t&&n.classList.add(t)):n.classList.add(e)})},getBodyHTML=(e,t)=>{if(!e||"string"!=typeof e)return"";try{const r=(new DOMParser).parseFromString(e,"text/html"),n=r.body.innerHTML;if(t){const e=r.querySelector(t);if(e)return e.innerHTML}return n?n.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:n=!0})=>{const s=e.indexOf("#");let o="",a=e;-1!==s&&(o=e.slice(s),a=e.slice(0,s));const i=new URL(a,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)=>{i.searchParams.append(t,e)})}return n&&r&&i.searchParams.set(r,Date.now().toString()),i.toString()+o},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",precision:2,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",n=["GET","HEAD","TRACE"];let s=new XMLHttpRequest,o=null,a=t?.headers?.["Content-Type"]||t?.headers?.["content-type"];if(!isEmpty(t.data)){let e=getDataType(t.data);"FormData"===e?(o=t.data,a&&(delete t.headers["Content-Type"],delete t.headers["content-type"])):"Object"===e?a?o=a?.includes("application/json")?JSON.stringify(t.data):t.data:(o=new URLSearchParams(t.data).toString(),n.includes(r)||(t.headers["Content-Type"]="application/x-www-form-urlencoded")):"String"===e&&(!a||a.includes("urlencoded"))?(o=cleanQueryString(t.data.trim()),n.includes(r)||a||(t.headers["Content-Type"]="application/x-www-form-urlencoded")):o=t.data}s.timeout=t.timeout,t.responseType&&(s.responseType=t.responseType);const i=new Promise((e,a)=>{const timeoutHandler=()=>{cleanup();let r={...i,status:s.status,content:s.response,type:"timeout"};t?.onTimeout?.(r),t.catchError?a(r):e(r),t?.onFailure?.(r),t?.onFinish?.(r)},errorHandler=r=>{"client-error"===r.type?t?.onClientError?.({...i}):"server-error"===r.type?t?.onServerError?.({...i}):"unknown-error"===r.type&&t?.onUnknownError?.({...i}),t?.onError?.(r),t.catchError?a(r):e(r)},abortHandler=()=>{cleanup();const r={...i,status:s.status,type:"abort"};t.catchError?a(r):e(r),t?.onAbort?.(r),t?.onFinish?.(r)},abortHandlerWithSignal=()=>{s.abort(),abortHandler()},cleanup=()=>{t.signal&&t.signal.removeEventListener("abort",abortHandlerWithSignal),t.onError&&s.removeEventListener("error",errorHandler),t.onTimeout&&s.removeEventListener("timeout",timeoutHandler),t.onUpload&&s.upload.removeEventListener("progress",uploadProgressHandler),t.onDownload&&s.removeEventListener("progress",downloadProgressHandler),s.onreadystatechange=null},i={xhr:s,data:o,abort:abortHandler,status:"",content:null,stage:0,type:"unset",progress:{}},getProgressValues=e=>{let r=(100*e).toFixed(t.precision);return{percent:parseFloat(r),text:r}},progressHandler=(e,r,n)=>{if(r.lengthComputable){const o={...i,status:s.status},a=r.loaded/r.total,{percent:l,text:c}=getProgressValues(a);o.progress={name:e,loaded:r.loaded,total:r.total,timestamp:new Date(r.timeStamp).getTime(),ratio:a,percent:l,text:c},n?.(o),a>=1&&(Object.assign(o.progress,getProgressValues(1)),t?.onComplete?.(o))}},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&&s.upload.addEventListener("progress",uploadProgressHandler),t.onDownload&&s.addEventListener("progress",downloadProgressHandler),t.onError&&s.addEventListener("error",errorHandler),t.onTimeout&&s.addEventListener("timeout",timeoutHandler),t.onAbort&&s.addEventListener("abort",abortHandler),t.onCreated?.({...i,type:"created"}),s.onreadystatechange=function(){i.stage=s.readyState,i.status=s.status;const r={1:"opened",2:"headersReceived",3:"loading"};if(s.readyState<4){if(!s.readyState)return;return i.type=r[s.readyState],void t[`on${capitalize(i.type)}`]?.({...i})}if(0===s.status&&"abort"!==i.type)return;cleanup();const n=s.status>=100&&s.status<200,o=s.status>=200&&s.status<300||304===s.status,a=s.status>=300&&s.status<400,l=s.status>=400&&s.status<500,c=s.status>=500&&s.status<600;if(o){if(t.responseType&&"text"!==s.responseType)i.content=s.response;else{let e=s.responseText.trim(),r="";if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{r=JSON.parse(e)}catch{r=s.responseText}else if(/(<\/html>|<\/body>)/i.test(e)){let n=getUrlHash(t.url);r=getBodyHTML(e,t.selector||n)}else r=s.responseText;i.content=r}i.type="success",p={...i},t?.onSuccess?.(p),e(p)}else i.content=s.response,i.type=n?"infomation":a?"redirection":l?"client-error":c?"server-error":"unknown-error",n?t?.onInformation?.({...i}):a?t?.onRedirection?.({...i}):errorHandler({...i}),t?.onFailure?.({...i});var p;t?.onFinish?.({...i})};let l=[r,t.url,t.async];if(n.includes(r)){const e=buildUrl({url:t.url,data:o,cacheBustKey:t.cacheBustKey,appendCacheBust:!0});l=[r,e,t.async]}for(let e in t.xhrFields)t.xhrFields.hasOwnProperty(e)&&(s[e]=t.xhrFields[e]);s.open(...l);for(let e in t.headers)t.headers.hasOwnProperty(e)&&!isEmpty(t.headers[e])&&s.setRequestHeader(e,t.headers[e]);t?.onBeforeSend?.({...i,status:s.status,type:"beforeSend"}),s.send(n.includes(r)?null:o||null)});return i.xhr=s,i.abort=()=>s.abort(),i};["post","put","delete","patch","options","get","head","trace"].forEach(e=>{ajax[e]=(t,r,n={url:""})=>ajax({...n,method:e,url:t,data:r})}),ajax.all=e=>Promise.all(e.map(ajax));return{getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:s,props:o={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");s&&!s?.length||(s=e);const a={};for(let e of s)a[e]=function(...s){const a={},i=t.length;switch(e){case"push":case"unshift":a.addedItems=[...s];break;case"pop":a.poppedItem=t[i-1];break;case"shift":a.shiftedItem=t[0];break;case"splice":const[e,r]=s,n=e<0?Math.max(i+e,0):Math.min(e,i),o=void 0===r?i-n:r;a.deletedItems=t.slice(n,n+o);break;case"sort":case"reverse":a.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=s[1]||0,c=void 0===s[2]?i:s[2];a.oldItems=t.slice(l,c),a.start=l,a.end=c}r?.(a);const l=Array.prototype[e].apply(t,s),c={value:l,key:e,args:s,context:a,target:t,...o};return n?.(c),l};return a},arrayMutableMethods:e,setMutableMethods:n,mapMutableMethods:s,wrapSetMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:s=n,props:o={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const a={},createWrappedMethod=n=>function(...s){const a={};switch(n){case"add":{const[t]=s;a.addedItem=t,a.existed=e.has(t);break}case"delete":{const[t]=s;a.existed=e.has(t),a.deletedItem=a.existed?t:void 0;break}case"clear":a.clearedItems=Array.from(e),a.previousSize=e.size}t(a);const i=e[n].apply(e,s),l={method:n,result:i,args:s,context:a,target:e,...o};return r(l),i};for(const e of s)n.includes(e)&&(a[e]=createWrappedMethod(e));return Object.defineProperty(a,"target",{get:()=>e,enumerable:!1,configurable:!1}),a},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:n=s,props:o={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const a={},createWrappedMethod=n=>function(...s){const a={};switch(n){case"set":{const[t,r]=s;a.key=t,a.newValue=r,a.existed=e.has(t),a.oldValue=a.existed?e.get(t):void 0;break}case"delete":{const[t]=s;a.key=t,a.existed=e.has(t),a.value=a.existed?e.get(t):void 0;break}case"clear":a.clearedItems=Array.from(e.entries()),a.previousSize=e.size}t(a);const i=e[n].apply(e,s),l={method:n,result:i,args:s,context:a,target:e,...o};return r(l),i};for(const e of n)s.includes(e)&&(a[e]=createWrappedMethod(e));return Object.defineProperty(a,"target",{get:()=>e,enumerable:!1,configurable:!1}),a},getUniqueId:getUniqueId,deepMerge:(e,t,r={})=>{const n=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,n)=>{let s,o,a=getDataType(e),i=getDataType(t),l=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:a,sourceType:i,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:a,sourceType:i,parent:n.parent}),"Object"===a&&"Object"===i?(o=deepMergeObjects(e,t,n),s="Object"):"Array"===a&&"Array"===i?(o=deepMergeArrays(e,t,n),s="Array"):"Set"===a&&"Set"===i?(o=deepMergeSets(e,t,n),s="Set"):"Map"===a&&"Map"===i?(o=deepMergeMaps(e,t,n),s="Map"):(l=!1,o=e),n?.onAfterMerge?.({result:o,target:e,source:t,targetType:a,sourceType:i,mergeType:s,parent:r.parent}),{result:o,flag:l,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 n=getDataType(e),s=getDataType(t);if("Object"!==n||"Object"!==s)return e;const o=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let a={};a=o.targetClone?shallowCopy(e):e;for(let e in t){const n=a[e],s=t[e];if(t.hasOwnProperty(e)&&a.hasOwnProperty(e)){const t=smartMerger(n,s,{...r,parent:a});if(t.flag)t.mergeType?"Object"===t.mergeType&&(a[e]=t.result):a[e]=s;else{let t=o.useEnable?mergeEnableObject(n,s):s;n!==t&&null===t?"ignore"===o.nullBehavior||("delete"===o.nullBehavior?Reflect.deleteProperty(a,e):a[e]=t):n!==t&&void 0===t?"ignore"===o.undefinedBehavior||("delete"===o.undefinedBehavior?Reflect.deleteProperty(a,e):a[e]=s):a[e]=s}}else t.hasOwnProperty(e)&&!a.hasOwnProperty(e)&&o.inheritMissing&&(a[e]=s)}if(o.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)a[r]=t[r]}return a},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),s=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=s.length));e++){smartMerger(s[e],t[e],{...n,parent:s}).flag||(s[e]=t[e])}else"concat"===n.dataMode||(s.length=0),s.push(...t);return s},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=n.targetClone?new Map([...e]):e;for(const[e,o]of t.entries())if(s.has(e)){const t=s.get(e),r=o,a=smartMerger(t,r,n);a.flag?"Object"===a.mergeType&&s.set(e,a.result):s.set(e,r)}else r.inheritMissing&&s.set(e,o);return s},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...s],r=[...t],o=smartMerger(e,r,n);s.clear();for(let e of o.result)s.add(e)}else if("concat"===n.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,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:(e,t=document.body)=>{let r=getDataType(e),n=getEl(t),s=n&&n instanceof HTMLTemplateElement?n.content:n||document,o=[];return isEmpty(e)?o:(r.includes("HTML")?o.push(e):"String"===r?o=(e=e.trim()).split(",").map(e=>[...s.querySelectorAll(e)]).flat():"Array"===r&&(o=e.map(e=>getEl(e,n))),o.filter(Boolean))},createEl:createEl,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 n=new FileReader;n.onload=()=>{"string"==typeof n.result?t(n.result):r(new Error("FileReader result is not a string"))},n.onerror=()=>{r(n.error||new Error("Unknown error occurred during file reading"))},n.readAsDataURL(e)}),NAMESPACE:"ax",ALIAS:o,COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},addClasses:addClasses,removeClasses:(e,t,r)=>{const n=getEl(e),s=parseClasses(t);n&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.remove(e):"string"==typeof t&&t&&n.classList.remove(t)):n.classList.remove(e)})},createTools:e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?`<i ${o}="arrow"></i>`:"",n=(e.icon?`<i ${o}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${o}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${o}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${o}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${o}="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),n),e.iconEl=e.wrapEl.querySelector(`[${o}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${o}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${o}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${o}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${o}="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},typeWriter:(e,t)=>{const r=t.speed||100;return new Promise(n=>{t?.onBeforeType?.(e);let s=0;const o=setInterval(()=>{if(s<e.length){const r=e.charAt(s),n=e.substring(0,s+1);t?.onDuringType?.(r,n),s++}else clearInterval(o),n(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(),n=new TextDecoder("utf-8");let s="";const o={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:a}=await r.read();if(e)break;s+=n.decode(a,{stream:!0});let i=s.split("\n");s=i.pop()||"";for(const e of i){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const n=r.substring(6);if("[DONE]"!==n)try{const e=JSON.parse(n),r=e.choices?.[0],s=r?.delta?.content||"";s&&(o.fullText+=s,t?.(s)),r?.finish_reason&&(o.finishReason=r.finish_reason),e.usage&&(o.usage=e.usage)}catch(e){}else o.isCompleted=!0}}}catch(e){throw e}return o},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},escapeCharsMaps:t,escapeRegexMaps:r,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let n=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let s,o=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),a=o.start.split("").map(e=>"\\"+e).join(""),i=o.end.split("").map(e=>"\\"+e).join(""),l=new RegExp(`${a}([\\s\\S]+?)?${i}`,"g"),c='"use strict";let str=[];\n',p=0,u="",d=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(o.suffix)?c+=e.slice(0,-o.suffix.length)+"\n":c+=o.escape?`str.push(${d}(String(${e}), "${o.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=l.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(o.strict||"Array"===n)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},getBodyHTML:getBodyHTML,getUrlHash:getUrlHash,buildUrl:buildUrl,ajax:ajax,capitalize:capitalize,cleanQueryString:cleanQueryString,stringToEncodings:(e,t={})=>{const r=t.start??983040,n=t.end??1114109,s=BigInt(n-r+1),o=t.registryMap,formatResult=(e,t,r,n)=>{const s=t.toString(16).toUpperCase();return{name:e,unicode:`U+${s}`,htmlDec:`&#${t};`,htmlHex:`&#x${s};`,hex:s,codePoint:t,hash:r,collision:n}};let a=BigInt("0xcbf29ce484222325");const i=BigInt("0x100000001b3");for(const t of e)a^=BigInt(t.codePointAt(0)),a*=i;const l=a.toString(16).toUpperCase();if(!o){return formatResult(e,r+Number(a%s),l,!1)}if(o.has(e))return formatResult(e,o.get(e),l,!1);let c=Number(a%s),p=r+c,u=!1;const d=new Set(o.values());for(;d.has(p);)u=!0,c=(c+1)%Number(s),p=r+c;return o.set(e,p),formatResult(e,p,l,u)},unicodeToEncodings:e=>{let t;if("number"==typeof e)t=e;else{const r=e.trim().replace(/^U\+/i,"").replace(/^0x/i,"");t=/^[0-9A-F]+$/i.test(r)?parseInt(r,16):parseInt(r,10)}if(!Number.isFinite(t))throw new Error("Invalid Unicode input");const r=t.toString(16).toUpperCase();return{unicode:`U+${r}`,hex:r,codePoint:t,htmlDec:`&#${t};`,htmlHex:`&#x${r};`}}}});
|
package/dist.zip
CHANGED
|
Binary file
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>AJAX Download Progress Demo</title>
|
|
6
|
+
<style>
|
|
7
|
+
.download-card { border: 1px solid #e0e0e0; border-radius: 12px; padding: 20px; max-width: 500px; font-family: sans-serif; }
|
|
8
|
+
.progress-container { height: 10px; background: #eee; border-radius: 5px; margin: 15px 0; overflow: hidden; }
|
|
9
|
+
#progressBar { height: 100%; background: #2ecc71; width: 0%; transition: width 0.1s ease; }
|
|
10
|
+
.stats { display: flex; justify-content: space-between; font-size: 13px; color: #666; }
|
|
11
|
+
#statusText { font-weight: bold; margin-bottom: 5px; display: block; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h2>Demo 6: Large File Download</h2>
|
|
16
|
+
|
|
17
|
+
<div class="download-card">
|
|
18
|
+
<span id="statusText">Ready to download</span>
|
|
19
|
+
<div class="progress-container">
|
|
20
|
+
<div id="progressBar"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="stats">
|
|
23
|
+
<span id="percentText">0.00%</span>
|
|
24
|
+
<span id="sizeText">0 / 0 MB</span>
|
|
25
|
+
</div>
|
|
26
|
+
<hr>
|
|
27
|
+
<button id="btnDownload">Start 10MB Download</button>
|
|
28
|
+
<button id="btnAbort" disabled>Cancel</button>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<script src="../dist/utils.umd.js"></script>
|
|
32
|
+
<script>
|
|
33
|
+
let downloadCtrl = null;
|
|
34
|
+
const btnDownload = document.getElementById('btnDownload');
|
|
35
|
+
const btnAbort = document.getElementById('btnAbort');
|
|
36
|
+
const progressBar = document.getElementById('progressBar');
|
|
37
|
+
const percentText = document.getElementById('percentText');
|
|
38
|
+
const sizeText = document.getElementById('sizeText');
|
|
39
|
+
const statusText = document.getElementById('statusText');
|
|
40
|
+
|
|
41
|
+
btnDownload.onclick = () => {
|
|
42
|
+
// 重置 UI
|
|
43
|
+
progressBar.style.width = '0%';
|
|
44
|
+
btnDownload.disabled = true;
|
|
45
|
+
btnAbort.disabled = false;
|
|
46
|
+
statusText.innerText = "Connecting...";
|
|
47
|
+
|
|
48
|
+
downloadCtrl = utils.ajax({
|
|
49
|
+
// 使模拟 10 秒钟内持续吐出 1MB 的数据。
|
|
50
|
+
url: 'https://httpbin.org/drip?duration=10&numbytes=1000000&code=200',
|
|
51
|
+
method: 'GET',
|
|
52
|
+
precision: 2, // 演示你刚才要求的:保留两位小数
|
|
53
|
+
onCreated: (res) => {
|
|
54
|
+
downloadCtrl = res;
|
|
55
|
+
},
|
|
56
|
+
onDownload: (res) => {
|
|
57
|
+
const p = res.progress;
|
|
58
|
+
// 使用你建议的 text 字段(带补零)
|
|
59
|
+
progressBar.style.width = p.text + '%';
|
|
60
|
+
percentText.innerText = p.text + '%';
|
|
61
|
+
|
|
62
|
+
// 转换单位为 MB
|
|
63
|
+
const loadedMB = (p.loaded / 1024 / 1024).toFixed(2);
|
|
64
|
+
const totalMB = (p.total / 1024 / 1024).toFixed(2);
|
|
65
|
+
sizeText.innerText = `${loadedMB} / ${totalMB} MB`;
|
|
66
|
+
statusText.innerText = "Downloading...";
|
|
67
|
+
},
|
|
68
|
+
onSuccess: (res) => {
|
|
69
|
+
statusText.innerText = "Download Complete!";
|
|
70
|
+
statusText.style.color = "#2ecc71";
|
|
71
|
+
// 这里可以将 res.content (Blob) 转化为 URL 进行下载保存
|
|
72
|
+
// const url = window.URL.createObjectURL(res.content);
|
|
73
|
+
},
|
|
74
|
+
onAbort: () => {
|
|
75
|
+
statusText.innerText = "Download Canceled";
|
|
76
|
+
statusText.style.color = "#e67e22";
|
|
77
|
+
},
|
|
78
|
+
onFailure: (res) => {
|
|
79
|
+
statusText.innerText = "Download Failed";
|
|
80
|
+
statusText.style.color = "#e74c3c";
|
|
81
|
+
},
|
|
82
|
+
onFinish: () => {
|
|
83
|
+
btnDownload.disabled = false;
|
|
84
|
+
btnAbort.disabled = true;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
btnAbort.onclick = () => {
|
|
90
|
+
downloadCtrl && downloadCtrl.abort();
|
|
91
|
+
};
|
|
92
|
+
</script>
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<body>
|
|
4
|
+
<h2>Demo 1: GET / HEAD / TRACE</h2>
|
|
5
|
+
<button id="btnGet">GET Data (with params)</button>
|
|
6
|
+
<button id="btnSelector">GET with Selector (#main)</button>
|
|
7
|
+
<button id="btnSelector2">GET with Selector (#main)</button>
|
|
8
|
+
<button id="btnHead">HEAD (Headers Only)</button>
|
|
9
|
+
<div id="result" style="border:1px solid #ccc; padding:10px; margin-top:10px;">Results will appear here...</div>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<script src="../dist/utils.umd.js"></script>
|
|
13
|
+
<script >
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// 1. GET with automatic params conversion
|
|
17
|
+
document.getElementById('btnGet').onclick = () => {
|
|
18
|
+
utils.ajax({
|
|
19
|
+
url: 'https://jsonplaceholder.typicode.com/posts',
|
|
20
|
+
method: 'GET',
|
|
21
|
+
data: { userId: 1, _limit: 3 } // Automatically becomes ?userId=1&_limit=3
|
|
22
|
+
}).then(res => {
|
|
23
|
+
document.getElementById('result').innerText = JSON.stringify(res.content, null, 2);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// 2. Selector Filter: Extract specific part of a page
|
|
28
|
+
document.getElementById('btnSelector').onclick = () => {
|
|
29
|
+
utils.ajax({
|
|
30
|
+
url: 'https://req.axui.cn/v3/html/his01.html', // In real use, this would be your own page
|
|
31
|
+
method: 'GET',
|
|
32
|
+
selector: '.post' // Only get the <h1> content
|
|
33
|
+
}).then(res => {
|
|
34
|
+
document.getElementById('result').innerHTML = `Extracted .post: ${res.content}`;
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
document.getElementById('btnSelector2').onclick = () => {
|
|
39
|
+
utils.ajax({
|
|
40
|
+
url: 'https://req.axui.cn/v3/html/his01.html#post03', // user hash
|
|
41
|
+
method: 'GET',
|
|
42
|
+
}).then(res => {
|
|
43
|
+
document.getElementById('result').innerHTML = `Extracted #post03: ${res.content}`;
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 3. HEAD request: No body, just metadata
|
|
48
|
+
document.getElementById('btnHead').onclick = () => {
|
|
49
|
+
utils.ajax({
|
|
50
|
+
url: 'https://jsonplaceholder.typicode.com/posts/1',
|
|
51
|
+
method: 'HEAD'
|
|
52
|
+
}).then(res => {
|
|
53
|
+
const contentType = res.xhr.getResponseHeader('Content-Type');
|
|
54
|
+
document.getElementById('result').innerText = `Status: ${res.status}\nContent-Type: ${contentType}`;
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
</script>
|
|
58
|
+
</body>
|
|
59
|
+
</html>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<body>
|
|
5
|
+
<h2>Demo 3: Lifecycle & Progress</h2>
|
|
6
|
+
<progress id="prog" value="0" max="100" style="width:100%"></progress>
|
|
7
|
+
<div id="status">Ready</div>
|
|
8
|
+
<button id="btnUpload">Upload Sim</button>
|
|
9
|
+
<button id="btnAbort">Abort Request</button>
|
|
10
|
+
<ul id="logs" style="font-family:monospace; font-size:12px;"></ul>
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<script src="../dist/utils.umd.js"></script>
|
|
14
|
+
<script>
|
|
15
|
+
let currentReq = null;
|
|
16
|
+
|
|
17
|
+
document.getElementById('btnUpload').onclick = () => {
|
|
18
|
+
const logs = document.getElementById('logs');
|
|
19
|
+
logs.innerHTML = '';
|
|
20
|
+
const addLog = (txt) => logs.innerHTML += `<li>${txt}</li>`;
|
|
21
|
+
|
|
22
|
+
currentReq = utils.ajax({
|
|
23
|
+
url: 'https://httpbin.org/post',
|
|
24
|
+
method: 'POST',
|
|
25
|
+
data: new Array(100000).fill('data-chunk').join(''), // Large data for progress
|
|
26
|
+
onCreated: () => addLog('Lifecycle: Created'),
|
|
27
|
+
onHeadersReceived: () => addLog('Lifecycle: HeadersReceived'),
|
|
28
|
+
onLoading: () => addLog('Lifecycle: Loading'),
|
|
29
|
+
onBeforeSend: () => addLog('Lifecycle: BeforeSend'),
|
|
30
|
+
onOpened: () => addLog('Lifecycle: Opened'),
|
|
31
|
+
onUpload: (res) => {
|
|
32
|
+
document.getElementById('prog').value = res.progress.percent;
|
|
33
|
+
document.getElementById('status').innerText = `Uploading: ${res.progress.percent}%`;
|
|
34
|
+
console.log(res.progress.percent,res.progress.ratio,res.progress.text)
|
|
35
|
+
},
|
|
36
|
+
onSuccess: () => addLog('<b>Lifecycle: Success!</b>'),
|
|
37
|
+
onFinish: () => addLog('Lifecycle: Finished (Done)'),
|
|
38
|
+
onComplete: () => addLog('Lifecycle: Complete (100% Done)'),
|
|
39
|
+
onAbort: () => addLog('Lifecycle: Abort'),
|
|
40
|
+
onFailure: () => addLog('Lifecycle: Failure'),
|
|
41
|
+
onServerError: () => addLog('Lifecycle: ServerError'),
|
|
42
|
+
onClientError: () => addLog('Lifecycle: ClientError'),
|
|
43
|
+
onUnknownError: () => addLog('Lifecycle: UnknownError'),
|
|
44
|
+
onInformation: () => addLog('Lifecycle: Information'),
|
|
45
|
+
onRedirection: () => addLog('Lifecycle: Redirection'),
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
document.getElementById('btnAbort').onclick = () => {
|
|
50
|
+
currentReq && currentReq.abort();
|
|
51
|
+
};
|
|
52
|
+
</script>
|
|
53
|
+
</body>
|
|
54
|
+
|
|
55
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<body>
|
|
5
|
+
<h2>Demo 4: Static Methods & All</h2>
|
|
6
|
+
<button id="btnAll">Fetch All (3 APIs)</button>
|
|
7
|
+
<div id="result"></div>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<script src="../dist/utils.umd.js"></script>
|
|
11
|
+
<script>
|
|
12
|
+
let currentReq = null;
|
|
13
|
+
|
|
14
|
+
// Using static ajax.all
|
|
15
|
+
document.getElementById('btnAll').onclick = async () => {
|
|
16
|
+
let elem = document.getElementById('result');
|
|
17
|
+
elem.innerText = 'Loading multiple...';
|
|
18
|
+
|
|
19
|
+
await utils.ajax.all([
|
|
20
|
+
{ url: 'https://jsonplaceholder.typicode.com/posts/1', method: 'GET' },
|
|
21
|
+
{ url: 'https://jsonplaceholder.typicode.com/posts/2', method: 'GET' },
|
|
22
|
+
{ url: 'https://jsonplaceholder.typicode.com/posts/3', method: 'GET' }
|
|
23
|
+
]).then(responses => {
|
|
24
|
+
const titles = responses.map(r => r.content.title);
|
|
25
|
+
elem.innerHTML = `
|
|
26
|
+
<h3>All Fetched:</h3>
|
|
27
|
+
<ul>${titles.map(t => `<li>${t}</li>`).join('')}</ul>
|
|
28
|
+
`;
|
|
29
|
+
});
|
|
30
|
+
elem.innerHTML += `<h3>Finish</h3>`
|
|
31
|
+
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
35
|
+
|
|
36
|
+
</html>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<body>
|
|
4
|
+
<h2>Demo 2: POST / PUT / DELETE</h2>
|
|
5
|
+
<button id="btnPostJson">POST JSON</button>
|
|
6
|
+
<button id="btnDelete">DELETE (Silent Error)</button>
|
|
7
|
+
<div id="result">Submit data to see result...</div>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<script src="../dist/utils.umd.js"></script>
|
|
11
|
+
<script >
|
|
12
|
+
|
|
13
|
+
// POST as JSON
|
|
14
|
+
document.getElementById('btnPostJson').onclick = () => {
|
|
15
|
+
utils.ajax({
|
|
16
|
+
url: 'https://jsonplaceholder.typicode.com/posts',
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: { 'Content-Type': 'application/json' },
|
|
19
|
+
data: { title: 'Hello', body: 'World', userId: 1 }
|
|
20
|
+
}).then(res => {
|
|
21
|
+
document.getElementById('result').innerHTML = `<b>Success:</b> ${JSON.stringify(res.content)}`;
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// DELETE with catchError: false (No red error in console if 404)
|
|
26
|
+
document.getElementById('btnDelete').onclick = () => {
|
|
27
|
+
utils.ajax({
|
|
28
|
+
url: 'https://jsonplaceholder.typicode.com/invalid-url',
|
|
29
|
+
method: 'DELETE',
|
|
30
|
+
catchError: false
|
|
31
|
+
}).then(res => {
|
|
32
|
+
document.getElementById('result').innerHTML = `Caught logic error without console red: ${res.type}`;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
</script>
|
|
36
|
+
</body>
|
|
37
|
+
</html>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>AJAX AbortSignal Demo</title>
|
|
6
|
+
<style>
|
|
7
|
+
.box { border: 1px solid #ddd; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
|
|
8
|
+
.req-item { margin: 5px 0; font-family: monospace; }
|
|
9
|
+
.status { font-weight: bold; }
|
|
10
|
+
.status-cancel { color: #faad14; }
|
|
11
|
+
.status-success { color: #52c41a; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h2>Demo 7: Control via AbortSignal</h2>
|
|
16
|
+
|
|
17
|
+
<div class="box">
|
|
18
|
+
<button id="btnGroupStart">Start Group Requests (3 Requests)</button>
|
|
19
|
+
<button id="btnCancelAll" style="color: red;" disabled>Cancel All via Signal</button>
|
|
20
|
+
|
|
21
|
+
<div id="results">
|
|
22
|
+
<div class="req-item">Request 1: <span id="s1" class="status">-</span></div>
|
|
23
|
+
<div class="req-item">Request 2: <span id="s2" class="status">-</span></div>
|
|
24
|
+
<div class="req-item">Request 3: <span id="s3" class="status">-</span></div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<script src="../dist/utils.umd.js"></script>
|
|
29
|
+
<script>
|
|
30
|
+
const btnStart = document.getElementById('btnGroupStart');
|
|
31
|
+
const btnCancel = document.getElementById('btnCancelAll');
|
|
32
|
+
|
|
33
|
+
// 外部维护控制器
|
|
34
|
+
let controller = null;
|
|
35
|
+
|
|
36
|
+
btnStart.onclick = () => {
|
|
37
|
+
// 1. 创建新的控制器
|
|
38
|
+
controller = new AbortController();
|
|
39
|
+
const signal = controller.signal;
|
|
40
|
+
|
|
41
|
+
// UI 状态重置
|
|
42
|
+
[1, 2, 3].forEach(i => {
|
|
43
|
+
const el = document.getElementById('s' + i);
|
|
44
|
+
el.innerText = 'Pending...';
|
|
45
|
+
el.className = 'status';
|
|
46
|
+
});
|
|
47
|
+
btnStart.disabled = true;
|
|
48
|
+
btnCancel.disabled = false;
|
|
49
|
+
|
|
50
|
+
// 2. 同时发起 3 个请求,共享同一个 signal
|
|
51
|
+
[1, 2, 3].forEach(i => {
|
|
52
|
+
utils.ajax({
|
|
53
|
+
// 使用 delay 模拟长时间请求,方便我们有时间点取消
|
|
54
|
+
url: `https://httpbin.org/delay/${i + 2}`,
|
|
55
|
+
method: 'GET',
|
|
56
|
+
signal: signal, // <--- 关键参数:传入外部信号
|
|
57
|
+
onAbort: (data) => {
|
|
58
|
+
const el = document.getElementById('s' + i);
|
|
59
|
+
el.innerText = 'Canceled';
|
|
60
|
+
el.classList.add('status-cancel');
|
|
61
|
+
console.log('abort')
|
|
62
|
+
},
|
|
63
|
+
onSuccess: (data) => {
|
|
64
|
+
const el = document.getElementById('s' + i);
|
|
65
|
+
el.innerText = 'Success';
|
|
66
|
+
el.classList.add('status-success');
|
|
67
|
+
console.log('success')
|
|
68
|
+
},
|
|
69
|
+
onFinish: (data) => {
|
|
70
|
+
// 如果所有请求都结束了,重置按钮
|
|
71
|
+
if (i === 3) {
|
|
72
|
+
btnStart.disabled = false;
|
|
73
|
+
btnCancel.disabled = true;
|
|
74
|
+
}
|
|
75
|
+
console.log('finish')
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// 3. 外部一键取消
|
|
82
|
+
btnCancel.onclick = () => {
|
|
83
|
+
if (controller) {
|
|
84
|
+
// 只要这一个指令,所有绑定了该 signal 的 ajax 请求都会立即停止
|
|
85
|
+
controller.abort();
|
|
86
|
+
console.log('Signal sent: All associated requests aborted.');
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
</script>
|
|
90
|
+
</body>
|
|
91
|
+
</html>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<body>
|
|
4
|
+
<h2>Demo 5: Timeout & Manual Abort</h2>
|
|
5
|
+
|
|
6
|
+
<div class="control-panel">
|
|
7
|
+
<p>Target: <code>/delay/10</code> (Server waits 10s before responding)</p>
|
|
8
|
+
<button id="btnTimeout">Start (3s Timeout)</button>
|
|
9
|
+
|
|
10
|
+
<button id="btnStartManual">Start (Manual Cancel)</button>
|
|
11
|
+
<button id="btnAbort" disabled style="color: red;">Abort Now!</button>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<h4>Execution Logs:</h4>
|
|
15
|
+
<ul id="logs"></ul>
|
|
16
|
+
|
|
17
|
+
<script src="../dist/utils.umd.js"></script>
|
|
18
|
+
<script >
|
|
19
|
+
|
|
20
|
+
const logs = document.getElementById('logs');
|
|
21
|
+
const btnAbort = document.getElementById('btnAbort');
|
|
22
|
+
let currentXHR = null;
|
|
23
|
+
|
|
24
|
+
const addLog = (msg, color = '') => {
|
|
25
|
+
const time = new Date().toLocaleTimeString().split(' ')[0];
|
|
26
|
+
const li = document.createElement('li');
|
|
27
|
+
li.innerHTML = `<span class="log-time">[${time}]</span> <span style="color:${color}">${msg}</span>`;
|
|
28
|
+
logs.appendChild(li);
|
|
29
|
+
logs.scrollTop = logs.scrollHeight;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// --- 场景 1: 自动超时 ---
|
|
33
|
+
document.getElementById('btnTimeout').onclick = () => {
|
|
34
|
+
addLog('Request started: Expecting timeout in 3s...', '#569cd6');
|
|
35
|
+
|
|
36
|
+
utils.ajax({
|
|
37
|
+
url: 'https://httpbin.org/delay/10',
|
|
38
|
+
method: 'GET',
|
|
39
|
+
timeout: 3000, // 3秒超时
|
|
40
|
+
onTimeout: (res) => {
|
|
41
|
+
addLog('HOOK: onTimeout triggered!', '#faad14');
|
|
42
|
+
},
|
|
43
|
+
onFailure: (res) => {
|
|
44
|
+
if (res.type === 'timeout') {
|
|
45
|
+
addLog('RESULT: Promise caught timeout error.', '#ff4d4f');
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
onFinish: () => addLog('Lifecycle: Finished.')
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// --- 场景 2: 手动中止 ---
|
|
53
|
+
document.getElementById('btnStartManual').onclick = () => {
|
|
54
|
+
addLog('Request started: Use "Abort" button to cancel.', '#569cd6');
|
|
55
|
+
btnAbort.disabled = false;
|
|
56
|
+
|
|
57
|
+
utils.ajax({
|
|
58
|
+
url: 'https://httpbin.org/delay/10',
|
|
59
|
+
method: 'GET',
|
|
60
|
+
onCreated: (res) => {
|
|
61
|
+
// 获取内部的 abort 方法
|
|
62
|
+
currentXHR = res;
|
|
63
|
+
addLog('Lifecycle: Created (Abort function captured)');
|
|
64
|
+
},
|
|
65
|
+
onAbort: () => {
|
|
66
|
+
addLog('HOOK: onAbort triggered!', '#faad14');
|
|
67
|
+
},
|
|
68
|
+
onSuccess: () => addLog('Success! (If you see this, you were too slow to click abort)'),
|
|
69
|
+
onFinish: () => {
|
|
70
|
+
addLog('Lifecycle: Finished.');
|
|
71
|
+
btnAbort.disabled = true;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
document.getElementById('btnAbort').onclick = () => {
|
|
77
|
+
if (currentXHR) {
|
|
78
|
+
currentXHR.abort(); // 调用封装好的 abort 方法
|
|
79
|
+
addLog('Action: .abort() called manually.', '#ff4d4f');
|
|
80
|
+
currentXHR = null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
</script>
|
|
84
|
+
</body>
|
|
85
|
+
</html>
|