@codady/axui
Version:
The AXUI front-end framework is built on HTML5, CSS3, and JavaScript standards, with TypeScript used for type management. It has no library dependencies and is designed to meet diverse needs with a focus on design.
1,255 lines (1,203 loc) • 1.48 MB
JavaScript
/*!
* @since Last modified: 2025-3-29 21:6:38
* @name AXUI front-end framework.
* @version 3.0.35
* @author AXUI development team <3217728223@qq.com>
* @description The AXUI front-end framework is built on HTML5, CSS3, and JavaScript standards, with TypeScript used for type management.
* @see {@link https://www.axui.cn|Official website}
* @see {@link https://github.com/codady/axui/issues|github issues}
* @see {@link https://gitee.com/codady/axui/issues|Gitee issues}
* @see {@link https://www.npmjs.com/package/@codady/axui|NPM}
* @issue QQ Group No.1:952502085
* @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.
* @license MIT license
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ax = factory());
})(this, (function () { 'use strict';
const getComputedVar = (name) => getComputedStyle(document.documentElement).getPropertyValue(name).trim();
const prefix = getComputedVar(`--PREFIX`);
const alias = getComputedVar(`--ALIAS`);
const lang = {
name: 'zh-CN',
support: {
content: '由于AXUI使用了<code>:has</code>的css伪类选择器,而您的浏览器相对陈旧,请更新至<code>Chrome105</code>以上内核的浏览器!',
cancel: '下次再提醒我',
confirm: '我知道了'
},
privacy: {
content: '我们使用Cookie来确保您在我们的网站上获得最佳体验,并为您提供个性化服务。继续浏览即表示您同意我们的Cookie政策。',
cancel: '拒绝',
confirm: '接受'
},
ajax: {
abort: `<i class="${prefix}c-warn">中止了请求!</i>`,
timeout: `<i class="${prefix}c-error">请求超时了!</i>`,
error: `<i class="${prefix}c-error">错误状态:{{this.status}}</i>`,
submit: {
btn: '正在提交',
succ: '恭喜,提交成功!',
fail: '对不起,提交失败!',
}
},
more: {
unfold: '收起',
fold: '折叠',
},
button: {
default: '新按钮',
confirm: '确定',
cancel: '取消',
clear: '清除',
close: '关闭',
reset: '重置',
submit: '提交',
now: '现在',
prev: '上一个',
next: '下一个'
},
placehold: {
note: '请写上备注内容!',
fileName: '新文件',
downloadName: '下载文件',
},
form: {
placeholder: '请输入...',
fileLabel: '请选择文件...',
fileMulti: '{{this.data}}个文件:',
maxLength: '最多可输入{{this.total}}个字符,已输入{{this.value}}个,还可以输入{{this.remaining}}个。',
minLength: '至少输入{{this.min}}个字符,已输入{{this.value}}个,还要输入{{this.remaining}}个。',
limitLength: '至少输入{{this.min}}个字符,最多可输入{{this.max}}个字符,已输入{{this.value}}个。',
maxNumber: '最大取值{{this.max}}。',
minNumber: '最小取值{{this.min}}。',
limitNumber: '取值范围{{this.min}}~{{this.max}}。',
exceed: '已超限。',
range: '取值范围{{this.min}}~{{this.max}}。',
},
range: {
result: `结果:{{this.multiple?this.range[0]+'-'+this.range[1]:this.value}}`,
},
valid: {
regLocal: '\u4e00-\u9fa5',
types: {
'a': '小写字母',
'A': '大写字母',
'd': '数字',
'~': '特殊字符',
'@': '中文字符',
},
message: {
wrongRule: '校验规则错误,请修正!',
wrongFormat: '值格式错误,应该为文本格式!',
noValids: '表单没有任何校验字段!',
},
strFormat: '值格式错误,应该为文本格式!',
arrFormat: '参数格式错误,应该为数组格式!',
succ: '{{ this.label || "" }}通过校验!',
fail: '{{ this.label || "" }}校验失败!',
required: '{{ this.label }}是必填项!',
email: '{{ this.label }}请填写正确的邮箱!',
cellphone: '{{ this.label }}请填写11位手机号!',
landline: '{{ this.label }}请填写正确的座机号码!',
ip: '{{ this.label }}请填写正确的IP地址!',
id: '{{ this.label }}请填写正确的身份证号!',
zip: '{{ this.label }}只能填写6位数字邮编!',
url: '{{ this.label }}请填写正确的域名!',
plate: '{{ this.label }}请填写正确的车牌号!',
locale: '{{ this.label }}只能填写中文!',
letter: '{{ this.label }}只能填写大小写英文字母!',
string: '{{ this.label }}只能填写大小写英文字母和数字!',
password: '{{ this.label }}只能填写大小写英文字母、数字以及特殊字符!',
ymdhms: '{{ this.label }}只能填写类似2022-11-13 2:56:12的日期格式!',
ymd: '{{ this.label }}只能填写类似2022-11-13的日期格式!',
hms: '{{ this.label }}只能填写类似2:56:12的日期格式!',
ym: '{{ this.label }}只能填写类似2022-11的日期格式!',
y: '{{ this.label }}只能填写4位数字年份!',
m: '{{ this.label }}只能填写1~12月份!',
d: '{{ this.label }}只能填写1~31日!',
date: '{{ this.label }}请填写有效的日期!',
integer: '{{ this.label }}只能填写非0开头的正整数!',
number: '{{ this.label }}只能填写数字,包括正数、负数、整数、小数!',
'date=': '{{ this.label }}只能是{{ this.data }}!',
'date>': '{{ this.label }}需超过{{ this.data }}!',
'date>=': '{{ this.label }}不可早于{{ this.data }}!',
'date<': '{{ this.label }}不可超过{{ this.data }}!',
'date<=': '{{ this.label }}不可晚于{{ this.data }}!',
'date><': '{{ this.label }}需超过{{ this.data[0] }},且不可超过{{ this.data[1] }}!',
'date><=': '{{ this.label }}需超过{{ this.data[0] }},且不可超过或等于{{ this.data[1] }}!',
'date>=<': '{{ this.label }}需超过或等于{{ this.data[0] }},且不可超过{{ this.data[1] }}!',
'date>=<=': '{{ this.label }}不可早于{{ this.data[0] }},且不可晚于{{ this.data[1] }}!',
'than=': '{{ this.label }}需要等于{{ this.data }}!',
'than>': '{{ this.label }}需要大于{{ this.data }}!',
'than>=': '{{ this.label }}需要大于或等于{{ this.data }}!',
'than<': '{{ this.label }}需要小于{{ this.data }}!',
'than<=': '{{ this.label }}需要小于或等于{{ this.data }}!',
'than><': '{{ this.label }}需要大于{{ this.data[0] }},且小于{{ this.data[1] }}!',
'than><=': '{{ this.label }}需要大于{{ this.data[0] }}个,且小于等于{{ this.data[1] }}!',
'than>=<': '{{ this.label }}需要大于等于{{ this.data[0] }}个,且小于{{ this.data[1] }}!',
'than>=<=': '{{ this.label }}需要大于等于{{ this.data[0] }}个,且小于等于{{ this.data[1] }}!',
'length=': '{{ this.label }}已输入{{ this.value.length }}个字符,只能填写{{ this.data }}个字符!',
'length>': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量需多于{{ this.data }}个!',
'length>=': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量不可少于{{ this.data }}个!',
'length<': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量需少于{{ this.data }}个!',
'length<=': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量不可多于{{ this.data }}个!',
'length><': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量需多于{{ this.data[0] }}个,且少于{{ this.data[1] }}个!',
'length><=': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量需多于{{ this.data[0] }}个,且少于或等于{{ this.data[1] }}个!',
'length>=<': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量需多于或等于{{ this.data[0] }}个,且少于{{ this.data[1] }}个!',
'length>=<=': '{{ this.label }}已输入{{ this.value.length }}个字符,字符数量不可少于{{ this.data[0] }}个,且不可多于{{ this.data[1] }}个!',
'count=': '{{ this.label }}有{{ this.value }}项,必须且只能选择{{ this.data }}项!',
'count>': '{{ this.label }}有{{ this.value }}项,选择项需要多于{{ this.data }}!',
'count>=': '{{ this.label }}有{{ this.value }}项,至少选择{{ this.data }}项!',
'count<': '{{ this.label }}有{{ this.value }}项,选择项需要少于{{ this.data }}!',
'count<=': '{{ this.label }}有{{ this.value }}项,最多选择{{ this.data }}项!',
'count><': '{{ this.label }}有{{ this.value }}项,选择项需多于{{ this.data[0] }},且少于{{ this.data[1] }}!',
'count><=': '{{ this.label }}有{{ this.value }}项,选择项需多于{{ this.data[0] }},且少于或等于{{ this.data[1] }}!',
'count>=<': '{{ this.label }}有{{ this.value }}项,选择项需多于或等于{{ this.data[0] }},且少于{{ this.data[1] }}!',
'count>=<=': '{{ this.label }}有{{ this.value }}项,至少选择{{ this.data[0] }}项,且不能多于{{ this.data[1] }}项!',
include: '{{ this.label }}的值应该在"{{ this.data }}"之中!',
exclude: '{{ this.label }}的值不能在"{{ this.data }}"之中!',
same: '{{ this.label }}字段值与"{{ this.data[1] || this.data[0] }}"字段值不一致!',
different: '{{ this.label }}字段值不能与"{{ this.data[1] || this.data[0] }}"字段值一致!',
strength: '{{ this.label }}的当前强度为{{ this.value}},要求达到{{ this.data }}!',
specific: `{{ this.label }}要求{{ for(let k in this.data){/}}{{k+'至少'+this.data[k]+'个'}}{{ (Object.keys(this.data).slice(-1)[0] !== k)? ',':''}}{{}/}}!`,
combine: `{{ this.label }}要求{{ this.data.types.join('、') }}至少{{ this.data.total }}种!`,
},
status: {
warn: '有警告',
succ: '完成了',
error: '有报错',
issue: '有疑问',
info: '有消息',
confirm: '已确认',
cancel: '已取消',
forbid: '已禁用'
},
message: {
heading: {
warn: '操作警告!',
succ: '操作成功!',
error: '操作失败!',
issue: '操作疑问!',
info: '信息提示!',
},
content: {
warn: '警告!运行过程中可能存在故障,请注意排查!',
succ: '恭喜!运行顺利或者操作成功!',
error: '失败!运行过程中发生了错误或操作失败!',
issue: '有疑问!运行过程中遇到一些问题需要解决!',
info: '提示!运行中未出现状况,请继续!',
},
},
tree: {
label: '新分支',
title: {
folder: '新增枝干分支',
file: '新增叶子分支',
edit: '编辑分支',
remove: '删除分支',
arrow: '点击折叠或展开',
},
message: {
remove: '确定要删除"{{this.label}}"分支么',
},
paginated: {
more: '查看更多',
next: '下一页',
first: '返回首页',
info: '"{{this.label}}"还剩{{this.rest}}条信息',
main: '主分支',
},
result: `<i ${alias}="holder">还未选择...</i>`,
},
accordion: {
label: '新板块',
content: '新内容',
extra: '更多内容',
title: {
add: '新增板块',
edit: '编辑板块',
remove: '删除板块',
arrow: '点击折叠或展开',
},
message: {
remove: '确定要删除"{{this.label}}"板块么',
},
},
tab: {
label: '新标签',
content: '新内容',
title: {
add: '新增页签',
edit: '编辑页签',
close: '删除页签',
move: '移动页签',
update: '更新页签',
},
message: {
add: '确定要新增"{{this.label}}"页签么',
edit: '确定要编辑"{{this.label}}"页签么',
close: '确定要删除"{{this.label}}"页签么',
move: '确定要移动"{{this.label}}"页签么',
update: '确定要更新"{{this.label}}"页签么',
},
},
flat: {
label: '新项目'
},
spy: {
isObserved: `媒体文件{{ this.src }}已经处于监听状态,不需要添加监听操作!`,
isUnobserved: `媒体文件{{ this.src }}还未被监听,不需要取消监听操作!`
},
tags: {
emptyholder: '还没有创建标签!',
placeholder: '请输入...',
includePart: '包含了重复的标签!',
includeFull: '标签完全重复,添加失败!',
},
retrieval: {
status: `共有<u>{{this.value}}</u>个结果符合<s>{{this.keys}}</s>要求!`,
nullKeys: `没有检索词且没有检索结果!`,
},
drag: {
holderDrag: '转移中...',
holderDrop: '释放到这里...',
},
progress: {
complete: '已完成!',
tips: '当前进度',
},
infinite: {
finish: '没有更多内容了',
error: '请求终止,已停止加载',
next: '<ax-btn width="x5">查看更多</ax-btn>',
preload: '等待加载数据',
loading: '正在加载数据',
loaded: '单页数据加载完成!',
},
virtualize: {
preload: '等待加载数据',
},
pagination: {
first: '首页',
last: '尾页',
prev: '上一页',
next: '下一页',
ellipsis: '...',
tips: '{{this.current}}/{{this.pages}}',
total: '共有{{this.total}}条数据',
locate: '跳到',
count: '每页',
page: '页',
unit: '条',
},
datetime: {
month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
week: ['一', '二', '三', '四', '五', '六', '日'],
weeks: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
year: {
prev: '上一页',
next: '下一页',
placeholder: '输入年份',
},
range: {
hyphen: '至',
checkbox: '选择同一天'
},
unit: {
Y: '年',
M: '月',
D: '日',
W: '周',
h: '时',
m: '分',
s: '秒',
},
bc: '公元前',
daytime: {
select: '时间选择',
start: '开始时间',
end: '结束时间'
},
toolTip: {
restore: '还原初始值',
reset: '归零',
now: '设为当前时间',
close: '关闭时间选择器',
},
empty: `<i class="${prefix}c-ignore">还未选择日期!</i>`,
message: {
requireTwoValue: '区间模式至少需要选择两个日期!',
requireYearFormat: '请填入正确的年份格式!',
requireOneSelected: '请至少选择一个日期!',
},
noEvent: `<i class="${prefix}c-ignore">今天没有需要安排的事项!</i>`,
},
rate: {
title: {
dft: '暂无评星',
clear: '评星归零',
},
template: {
result: `{{this.stars}}星`,
tooltip: `{{this.stars}}星,总分:{{this.value}}`,
},
star: '星',
},
editor: {
defer: '点击加载内容',
placeholder: '请输入...',
path: '路径:',
chars: '文字:',
paras: '段落:',
fontsizeDft: '默认字号',
alignDft: '默认排列',
tagsDft: '特殊标签',
tips: {
bold: '加粗',
italic: '斜体',
through: '删除线',
underline: '下划线',
alignDft: '默认对齐',
alignLeft: '左对齐',
alignRight: '右对齐',
alignCenter: '居中对齐',
alignJustify: '两端对齐',
indentMore: '增加缩进',
indentLess: '减少缩进',
sub: '下标',
sup: '上标',
highlight: '高亮(MARK)',
em: '强调(EM)',
ruby: '拼音(RUBY)',
rt: '拼音(RT)',
address: '地址(ADDRESS)',
time: '时间(TIME)',
blockquote: '段落引用(BLOCKQUOTE)',
cite: '行内引用(CITE)',
codeInline: '行内代码(CODE)',
codeBlock: '代码块(PRE+CODE)',
source: '源码模式',
heading: '设置标题',
hr: '插入水平线(HR)',
br: '插入换行符(BR)',
p: '插入段落符(P)',
listOl: '有序列表(OL+LI)',
listUl: '无序列表(UL+LI)',
listCheck: '任务列表(CHECKBOX)',
paragraph: '插入段落(DIV+BR)',
fontSet: '文字设置',
fontSize: '字号大小',
fontColor: '文字颜色',
fontBg: '文字背景色',
h1: '一号标题',
h2: '二号标题',
h3: '三号标题',
h4: '四号标题',
h5: '五号标题',
h6: '六号标题',
text: '正文',
}
},
select: {
placeholder: '请选择...',
title: {
close: '清空'
},
search: {
fail: `没有找到符合"{{this.keys}}"的选项`,
succ: `找到了{{this.value}}项符合"{{this.keys}}"`,
start: '还没有输入检索关键字',
placeholder: '请输入关键字...',
},
check: {
ed: '未勾选,选择全部',
ing: '勾选了部分,选择全部',
none: '已勾选全部,取消全部'
},
stats: `已选择了{{this.value}}/{{this.total}}项`,
},
upload: {
paste: {
before: '点击这里粘贴上传',
ing: '请使用ctrl+v组合键',
after: '完成了粘贴!',
},
tips: {
suffix: `支持{{this.value}}格式`,
size: `单文件子节数不超过{{this.value}}MB`,
min: `至少上传{{this.value}}个文件`,
max: `最多上传{{this.value}}个文件`,
free: '上传文件未做限制',
},
progress: {
passed: '文件合格',
notPassed: '文件不合格',
rendered: '等待上传',
uploading: '上传中',
uploaded: '已上传',
received: '已接收',
getAuth: '获取授权中',
authorized: '已授权',
unauthorized: '未获得授权',
failed: '上传失败',
},
summary: `提交了{{this.total}}个文件,成功上传了{{this.count}}个,共{{this.size}}`,
message: {
single: {
passed: '通过校验!',
max: '文件数量太多,请删除!',
size: '文件体积太大,请删除!',
suffix: '文件格式错误,请删除!',
success: '上传成功!',
failed: '提交地址可能错误,请删除!',
},
global: {
passed: '所有文件通过校验!',
min: '请至少上传{{this.value}}个文件!',
max: '最多只能上传{{this.value}}个文件,可先删除再添加!',
}
},
button: {
choose: '选择文件',
upload: '批量上传',
clear: '批量删除',
gallery: '点击或拖拽上传',
picture: '选择文件',
},
thead: ['图示', '文件名', '文件体积', '上传进度', '实时消息', '上传状态', '操作'],
},
confirm: {
heading: '',
},
twilight: {
day: '白天',
night: '黑夜',
},
};
const config = {
initial: true,
support: false,
privacy: false,
lang,
attrs: {
ajaxSpin: `spinning`,
ajaxState: `ajax`,
},
debounce: 200,
throttle: 500,
rootStart: -1,
idStart: 0,
floorStart: 0,
pathHyphen: '~',
rangeHyphen: '~',
labelHyphen: '/',
splitHyphen: ',',
wordHyphen: ' ',
actClass: `${prefix}opened`,
reqProp: 'REQRETRY',
parser: 'new Function',
warn: {
init: 'The initialization process of the instance has been stopped. You will need to manually initialize it using the init() method later!',
emptyCont: 'Data was not obtained, but execution was not halted!',
},
error: {
parse: 'Getting data from HTML resulted in an error, an empty array was returned, but execution was not interrupted!',
},
message: {},
valid: {
regChars: '~!@#$%^&*',
lengthStr: 6,
},
popup: {},
alert: {},
more: {},
menu: {},
tree: {},
drawer: {},
};
const isNull = (data) => [undefined, null, 'undefined', 'null'].includes(data);
const augment = function (arg) {
if (isNull(arg) || !arg.name)
return;
let target;
if (!arg.target || arg.target === 'ax') {
target = this;
}
else {
for (let k in this) {
if (this[k].name === arg.target) {
target = this[k];
break;
}
}
if (!target)
throw new Error(`Cannot find the ${arg.target} property in the ax object!`);
}
if (arg.type === 'method') {
target[target.prototype ? 'prototype' : '__proto__'][arg.name] = arg.data;
}
else {
Reflect.set(target, arg.name, arg.data);
}
};
const getDataType = (obj) => {
let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
if (tmp === 'Function' && /^\s*class\s+/.test(obj.toString())) {
result = 'Class';
}
else if (tmp === 'Object' && Object.getPrototypeOf(obj) !== Object.prototype) {
result = 'Instance';
}
else {
result = tmp;
}
return result;
};
const isEmpty = (data) => {
let type = getDataType(data), flag;
if (!data) {
flag = true;
}
else {
flag = (type === 'Object') ? (Object.keys(data).length === 0) :
(type === 'Array') ? data.join('') === '' :
(type === 'Function') ? (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}') :
(type === 'Symbol') ? (data.toString().replace(/\s+/g, '').match(/\(.*\)/g)[0] === '()') : false;
}
return flag;
};
const getEl = (obj, wrap) => {
let objType = getDataType(obj), parType = getDataType(wrap), parent = parType.includes('HTML') ? wrap : document.querySelector(wrap), result = null;
if (obj) {
if (objType.includes('HTML')) {
result = obj;
}
else if (objType === 'String') {
try {
result = (parent || document).querySelector(obj.trim());
}
catch {
result = null;
}
}
}
return result;
};
const deepClone = (data) => {
let dataType = getDataType(data), result;
if (dataType === 'Object') {
let newObj = {}, symbols = Object.getOwnPropertySymbols(data);
for (let k in data) {
newObj[k] = deepClone(data[k]);
}
if (symbols.length > 0) {
for (let k of symbols) {
newObj[k] = deepClone(data[k]);
}
}
result = newObj;
}
else if (dataType === 'Array') {
result = data.map((k) => deepClone(k));
}
else if (dataType === 'Date') {
result = new Date(data);
}
else {
result = data;
}
return result;
};
const deepMerge = (target, source, opt) => {
let targetType = getDataType(target), sourceType = getDataType(source), options = Object.assign({ arrAppend: false, propAppend: true, targetClone: false, override: 'partial' }, opt), result = options.targetClone ? deepClone(target) : target;
if (targetType !== 'Object' || sourceType !== 'Object') {
return result;
}
for (let k in source) {
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
let _resultType = getDataType(result[k]), _sourceType = getDataType(source[k]);
if (_resultType !== _sourceType) {
if (options.override === 'partial' && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
result[k].enable = source[k];
}
else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
result = Object.assign({ enable: result[k] }, source[k]);
}
else {
result[k] = source[k];
}
}
else {
result[k] = source[k];
}
}
else {
if (_sourceType === 'Object') {
result[k] = deepMerge(result[k], source[k], options);
}
else if (_sourceType === 'Array' && options.arrAppend) {
result[k].push(...source[k]);
}
else {
result[k] = source[k];
}
}
}
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
result[k] = source[k];
}
}
let symbols = Object.getOwnPropertySymbols(source);
if (symbols.length > 0) {
for (let k of symbols) {
result[k] = source[k];
}
}
return result;
};
const requireTypes = (data, require, cb) => {
let type = getDataType(data).toLowerCase(), types = typeof require === 'string' ? [require] : require;
type.includes('html') ? type = 'element' : null;
types = types.map((k) => k.toLowerCase());
if (cb) {
try {
if (!types.includes(type)) {
throw new Error(`Wrong data type,Require types: "${'' + types}"!`);
}
}
catch (error) {
cb(error);
}
}
else {
if (!types.includes(type)) {
throw new Error(`Wrong data type,Require types: "${'' + types}"!`);
}
}
};
const parseStr = ({ content = '', type = 'object', method = config.parser, catchable = false, error }) => {
let dft = {
start: type === 'object' ? '{' : '[',
end: type === 'object' ? '}' : ']',
return: type === 'object' ? {} : type === 'array' ? [] : null,
}, result = dft.return;
if (!content)
return dft.return;
let trim = content.trim();
if (['object', 'array'].includes(type)) {
if (!trim.startsWith(dft.start) || !trim.endsWith(dft.end))
return result;
}
try {
let tmp = typeof method === 'function' ? method(trim) : method === 'JSON.parse' ? JSON.parse(trim) : new Function(`"use strict"; return ${trim}`)();
result = tmp;
}
catch (err) {
error && error(err);
if (catchable)
throw err;
}
return result;
};
const strToJson = (str, type = 'object') => {
let dft = type === 'array' ? [] : {};
if (typeof str !== 'string')
return dft;
str = str.trim();
if (!str)
return dft;
str = (str.startsWith('[') && str.endsWith(']')) || (str.startsWith('{') && str.endsWith('}')) ? str : `{${str}}`;
try {
return parseStr({
content: str,
type,
catchable: true,
});
}
catch {
return dft;
}
};
const attrToJson = (elem, attr) => {
requireTypes(attr, 'string');
let el = getEl(elem), elAttr = el.getAttribute(attr), result = {};
if (el && attr && elAttr) {
result = strToJson(elAttr);
}
return result;
};
const extend = ({ target = {}, source = {}, host = null, attr = '' }) => {
let targetType = getDataType(target), el = getEl(host);
if (targetType !== 'Object') {
return target;
}
else {
source && deepMerge(target, source);
el && attr && deepMerge(target, attrToJson(el, attr));
}
return target;
};
const ax = {
frame: 0,
ajaxStorage: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
prefix,
alias,
compSign: 'comp',
embedSign: 'embed',
namePfx: 'TMP_',
messages: [],
valids: [],
config,
augment,
tasks: [],
install(vue, options) {
!isEmpty(options) && extend({
target: this.config,
source: options,
});
vue.config.globalProperties.$ax = this;
}
};
const fieldTypes = ['input', 'file', 'textarea', 'range', 'number', 'datetime', 'upload', 'select', 'radio', 'checkbox', 'radios', 'checkboxes'];
const renderTpl = (html, data) => {
requireTypes(html, 'string');
requireTypes(data, ['array', 'object']);
if (!html || Object.keys(data).length === 0) {
return '';
}
let regStart = '\\{\\{', regEnd = '\\}\\}', exeEnd = '/', tplReg = new RegExp(`${regStart}([\\s\\S]+?)?${regEnd}`, 'g'), code = '"use strict";let str=[];\n', cursor = 0, match, result = '', add = (fragment, isJs) => {
isJs ? (code += (fragment.endsWith(exeEnd) ? fragment.replace('=>', '=>').slice(0, -1) + '\n' : 'str.push(' + fragment + ');\n'))
: (code += (fragment !== '' ? 'str.push("' + fragment.replace(/"/g, '\\"') + '");\n' : ''));
return add;
};
while (match = tplReg.exec(html)) {
add(html.slice(cursor, match.index))(match[1], true);
cursor = match.index + match[0].length;
}
add(html.slice(cursor));
code += `return str.join('');`;
try {
result = new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
}
catch (err) {
console.error(`'${err.message}'`, ' in \n', code, '\n');
}
return result;
};
const getScreenSize = () => getComputedVar(`--SCREEN`);
const startUpper = (str) => {
str = str.trim();
return str.slice(0, 1).toUpperCase() + str.slice(1);
};
const sliceStrEnd = ({ str = '', key = '#', type = 'afterend', contain = true }) => {
str = str.toString();
key = key.toString();
let result = '', indexKey = 0, lenKey = key.length, lenEnd = str.length, indexStart = 0;
if (!str || !key) {
return result;
}
str = str.trim();
if (str.includes(key)) {
if (type === 'beforebegin') {
indexKey = str.indexOf(key);
contain ? indexKey += lenKey : null;
lenEnd = indexKey;
}
else if (type === 'afterbegin') {
indexKey = str.indexOf(key);
!contain ? indexKey += lenKey : null;
indexStart = indexKey;
}
else if (type === 'beforeend') {
indexKey = str.lastIndexOf(key);
contain ? indexKey += lenKey : null;
lenEnd = indexKey;
}
else if (type === 'afterend') {
indexKey = str.lastIndexOf(key);
!contain ? indexKey += lenKey : null;
indexStart = indexKey;
}
result = str.substring(indexStart, lenEnd);
}
return result;
};
const delay = function ({ duration = 2000, todo, doing, done, frame = 0 }) {
if (duration < 0)
Promise.reject(new Error('Invalid duration'));
todo && todo(frame);
return new Promise((resolve, reject) => {
try {
if (!duration) {
done && done(frame);
resolve(frame);
}
let deadline = Date.now() + duration, listen = () => {
let newTime = Date.now();
if (newTime >= deadline) {
cancelAnimationFrame(frame);
done && done(frame);
resolve(frame);
frame = 0;
}
else {
frame = requestAnimationFrame(listen);
doing && doing(frame);
}
};
listen();
}
catch (e) {
reject(e);
}
});
};
const getPlaces = (data) => data.toString().split(".")[1]?.length || 0;
const toNumber = (data, opt) => {
let result = 0, number = Number(data), options = Object.assign({ places: 10, mode: 'round', zero: false, epsilon: true }, opt);
if (!data || !number) {
return 0;
}
if (options.places < 0) {
return number;
}
else {
let precise = number + (options.epsilon ? Number.EPSILON : 0), tail = Number(`1${'0'.repeat(options.places)}`), tempPrecise = precise * tail;
if (options.mode === 'floor') {
result = Math.floor(tempPrecise) / tail;
}
else if (options.mode === 'ceil') {
result = Math.ceil(tempPrecise) / tail;
}
else {
result = Math.round(tempPrecise) / tail;
}
if (options.zero) {
let decPlaces = getPlaces(result);
options.places > decPlaces ? result = result + (!decPlaces ? '.' : '') + ('0'.repeat(options.places - decPlaces)) : null;
}
return result;
}
};
const toPixel = (data, multiple) => {
let result = 0;
if (!data) {
return result;
}
multiple = multiple || parseInt(getComputedVar(`--${prefix}fs-base`)) || 10;
if (typeof data === 'string') {
data = data.trim();
if (data.endsWith('rem') || data.endsWith('REM')) {
result = ~~(toNumber(data.replace('rem', '').replace('REM', '')) * multiple);
}
else if (data.endsWith('px') || data.endsWith('PX')) {
result = ~~toNumber(data.replace('px', '').replace('PX', ''));
}
else {
result = ~~data;
}
}
else if (typeof data === 'number') {
result = ~~data;
}
return result;
};
const preventDft = (event, enhance = false) => {
event.cancelable && event.preventDefault();
enhance && event.stopPropagation();
};
const isMobi = ('ontouchstart' in document.documentElement);
const events = isMobi ? ['touchstart', 'touchmove', 'touchend', 'touchcancel'] : ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];
const icons = {
font: {
succ: `<i class="${prefix}icon-check-o"></i>`,
error: `<i class="${prefix}icon-close-o"></i>`,
warn: `<i class="${prefix}icon-warn-o"></i>`,
info: `<i class="${prefix}icon-info-o"></i>`,
issue: `<i class="${prefix}icon-issue-o"></i>`,
'succ-t': `<i class="${prefix}icon-check-o-t"></i>`,
'error-t': `<i class="${prefix}icon-close-o-t"></i>`,
'warn-t': `<i class="${prefix}icon-warn-o-t"></i>`,
'info-t': `<i class="${prefix}icon-info-o-t"></i>`,
'issue-t': `<i class="${prefix}icon-issue-o-t"></i>`,
'succ-f': `<i class="${prefix}icon-check-o-f"></i>`,
'error-f': `<i class="${prefix}icon-close-o-f"></i>`,
'warn-f': `<i class="${prefix}icon-warn-o-f"></i>`,
'info-f': `<i class="${prefix}icon-info-o-f"></i>`,
'issue-f': `<i class="${prefix}icon-issue-o-f"></i>`,
},
svg: {
succ: `<svg class="${prefix}svg-succ" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${prefix}line ${prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}in-1" d="M26.316,42.859L37.9984,54.5414L60.3826,32.1572"></path></svg>`,
error: `<svg class="${prefix}svg-error" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${prefix}line ${prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}in-1" d="M28.774,57.9246L57.9247,28.7739"></path><path class="${prefix}line ${prefix}in-2" d="M57.9246,57.9246L28.7739,28.7739"></path></svg>`,
warn: `<svg class="${prefix}svg-warn" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${prefix}line ${prefix}bg" d="M43.4611 7.24c2.8081,0.0924 4.39,1.7 5.3045,3.1159l17.4543 29.9414 17.3445 29.7538c0.5448,1.0193 1.596,4.0544 0.1109,6.4168 -1.4849,2.3626 -3.6815,2.9155 -5.3768,2.992l-34.9082 0.0002 -34.6892 -0.0002c-1.1636,-0.0421 -4.3433,-0.6583 -5.6666,-3.1131 -1.3232,-2.4549 -0.7085,-4.6157 0.0723,-6.1078l17.454 -29.9417 17.3449 -29.7537c0.6185,-0.977 2.7471,-3.396 5.5554,-3.3036z"></path><path class="${prefix}line ${prefix}out" d="M43.4611 7.24c2.8081,0.0924 4.39,1.7 5.3045,3.1159l17.4543 29.9414 17.3445 29.7538c0.5448,1.0193 1.596,4.0544 0.1109,6.4168 -1.4849,2.3626 -3.6815,2.9155 -5.3768,2.992l-34.9082 0.0002 -34.6892 -0.0002c-1.1636,-0.0421 -4.3433,-0.6583 -5.6666,-3.1131 -1.3232,-2.4549 -0.7085,-4.6157 0.0723,-6.1078l17.454 -29.9417 17.3449 -29.7537c0.6185,-0.977 2.7471,-3.396 5.5554,-3.3036z"></path><path class="${prefix}line ${prefix}in-1" d="M43.3493,27.8713L43.3493,57.2858"></path><circle class="${prefix}circle ${prefix}in-2" cx="43.3492" cy="64.3337" r="2.1166"></circle></svg>`,
info: `<svg class="${prefix}svg-info" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${prefix}line ${prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}in-1" d="M43.3493,65.0602L43.3493,30.9723"></path><circle class="${prefix}circle ${prefix}in-2" cx="43.3492" cy="23.5856" r="2.1166"></circle></svg>`,
issue: `<svg class="${prefix}svg-issue" xmlns="http://www.w3.org/2000/svg" width="86.6986mm" height="86.6986mm" viewBox="0 0 86.6986 86.6986"><path class="${prefix}line ${prefix}bg" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}out" d="M7.238500000000002,43.3493A36.1108,36.1108 0,1,1 79.4601,43.3493A36.1108,36.1108 0,1,1 7.238500000000002,43.3493"></path><path class="${prefix}line ${prefix}in-1" d="M32.3757 35.7255c-0.2203,-11.823 12.5789,-14.1087 18.4056,-9.4189 5.4663,4.3995 4.7426,12.804 -3.1088,17.9938 -3.0015,1.9839 -3.0003,3.8403 -3.0003,10.1707"></path><circle class="${prefix}circle ${prefix}in-2" cx="44.6612" cy="60.5502" r="2.1166"></circle></svg>`,
}
};
const getFullGap = () => getComputedVar(`--${prefix}g-full`);
const propsMap = {
x: { axis: 'x', position: 'left', overflow: 'overflowX', inner: 'clientWidth', outer: 'offsetWidth', scroll: 'scrollLeft', client: 'clientX', size: 'width', index: 4, offset: 'offsetLeft', gap: 'marginLeft' },
y: { axis: 'y', position: 'top', overflow: 'overflowY', inner: 'clientHeight', outer: 'offsetHeight', scroll: 'scrollTop', client: 'clientY', size: 'height', index: 5, offset: 'offsetTop', gap: 'marginTop' }
};
const instance = {
data: [],
destroyFun: (item) => {
if (!item) {
return false;
}
if ((!item.ins.hasOwnProperty('destroyed') || !item.ins.destroyed) && item.ins.__proto__.destroy) {
item.ins.destroy();
item.destTime = Date.now();
}
},
initFun: (item) => {
if (!item) {
return false;
}
if ((!item.ins.hasOwnProperty('destroyed') || item.ins.destroyed) && item.ins.__proto__.init) {
item.ins.init();
item.initTime = Date.now();
}
},
push: function (ins, name = '', type = '') {
if (!ins) {
return false;
}
let obj = { name, ins, type, pushTime: Date.now() };
if (!this.data.some((k) => k.ins === ins)) {
this.data.push(obj);
}
return this;
},
find: function (name, type = '', destroyed = false) {
if (!name) {
return null;
}
let item;
item = this.data.find((k) => {
let flag = type ? k.type === type : true;
return (k.ins.hasOwnProperty('destroyed')) ? (k.name === name && k.ins.destroyed === destroyed && flag) : (k.name === name && flag);
});
return item ? item.ins : null;
},
findAll: function (type = '', destroyed = false) {
let items = [];
if (!type) {
items = this.data.filter((i) => i.ins.destroyed === destroyed);
}
else {
items = this.data.filter((i) => {
return (i.ins.hasOwnProperty('destroyed')) ? (i.type === type && i.ins.destroyed === destroyed) : (i.type === type);
});
}
return items.length > 0 ? items.map((i) => i.ins) : [];
},
destroy: function (name, type) {
if (!name) {
return false;
}
let item = type ? (this.data.find((i) => i.name === name && i.type === type)) : (this.data.find((i) => i.name === name));
if (item) {
this.destroyFun(item);
}
return this;
},
destroyAll: function (type) {
let items = !type ? this.data : this.data.filter((i) => i.type === type);
items.forEach((i) => {
this.destroyFun(i);
});
return this;
},
clear: function () {
this.data.forEach((i) => {
this.destroyFun(i);
});
this.data.length = 0;
return this;
},
init: function (name, type) {
if (!name) {
return false;
}
let item = type ? (this.data.find((i) => i.name === name && i.type === type)) : (this.data.find((i) => i.name === name));
if (item) {
this.initFun(item);
}
return this;
},
initAll: function (type) {
let items = !type ? this.data : this.data.filter((i) => i.type === type);
items.forEach((i) => {
this.initFun(i);
});
return this;
}
};
const getEls = (data, parent) => {
let type = getDataType(data), parentEl = getEl(parent) || document, result = [];
if (isEmpty(data)) {
return result;
}
if (type.includes('HTML')) {
result.push(data);
}
else if (type === 'String') {
data = data.trim();
result = data.split(',').map((k) => {
return [...parentEl.querySelectorAll(k)];
}).flat();
}
else if (type === 'Array') {
result = data.map((k) => {
return getEl(k, parentEl);
});
}
return result.filter(Boolean);
};
const createEl = (name, attrs, content) => {
name = name || 'div';
let rootName = name.toUpperCase().trim(), rootEl = document.createElement(rootName), attrsType = getDataType(attrs), loop = (host, data) => {
if (data === '' || data === null || data === undefined) {
return false;
}
let dataType = getDataType(data);
if (rootName === 'TEMPLATE') {
host.innerHTML = data.toString();
}
else {
if (dataType === 'Array' && data.length > 0) {
for (let k of data) {
let childType = getDataType(k);
if (childType.includes('HTML')) {
host.appendChild(k);
}
else {
let child = createEl(k.name, k.attrs, k.content);
child && host.appendChild(child);
}
}
}
else if (dataType.includes('HTML')) {
host.appendChild(data);
}
else if (dataType === 'String' && data.trim().startsWith('#') && data.trim().length > 1) {
let el = getEl(data);
if (!el)
return;
el.nodeName === 'TEMPLATE' ? host.appendChild(el.content.cloneNode(true)) : host.insertAdjacentHTML('beforeEnd', el.innerHTML);
}
else {
host.insertAdjacentHTML('beforeEnd', data);
}
}
};
if (attrs && attrsType === 'Object') {
for (let k in attrs) {
attrs.hasOwnProperty(k) && rootEl.setAttribute(k, attrs[k]);
}
}
loop(rootEl, content);
return rootEl;
};
const trim = (str, placement) => {
requireTypes(str, 'string');
return placement === 'start' ? str.trimStart() :
placement === 'end' ? str.trimEnd() :
placement === 'both' ? str.trim() :
placement === 'global' ? str.replace(/[\s\r\n]+/g, '') : str.trim().replace(/[\s\r\n]+/g, ' ');
};
const allToEls = (data, parent) => {
if (isEmpty(data))
return [];
let result = [], type = getDataType(data);
if (type.includes('HTML')) {
result.push(data);
}
else if (type === 'String') {
let str = trim(data), separator = str.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen;
str.split(separator).forEach(k => {
let el = getEl(k, parent);
el && result.push(el);
});
}
else if (type === 'Array') {
data.forEach(k => {
let el = getEl(k, parent);
el && result.push(el);
});
}
else if (type === 'NodeList') {
result = [...data];
}
return result;
};
const ajax = (options) => {
if (isEmpty(options)) {
throw new Error(`There is no options!`);
}
let dft = {
target: '',
url: '',
type: 'post',
async: true,
data: null,
holdTime: 0,
stopTime: 3600000,
contType: '',
headers: {},
respType: '',
catchable: false,
spinStr: `<ax-spin></ax-spin>`,
spinSel: '',
xhrName: '',
repeat: {
index: 0,
max: 0,
keyword: '',
},
xhrFields: {},
abort: (resp) => { },
timeout: (resp) => { },
opened: (resp) => { },
before: (resp) => { },
downloading: (resp) => { },
uploading: (resp) => { },
complete: (resp) => { },
success: (resp) => { },
error: (resp) => { },
cb: (resp) => { },
};
extend({ target: dft, source: options });
!dft.type && (dft.type = 'post');
let label = createEl('span', { [alias]: 'message' }), target = getEl(dft.target);
target && (target.innerHTML = '', target.appendChild(label));
let dftAbort = () => {
target ? label.innerHTML = config.lang.ajax.abort : console.warn('The request has been suspended!');
}, dftTimeout = () => {
target ? label.innerHTML = config.lang.ajax.timeout : console.warn('The request is out of time!');
}, dftBefore = (res) => {
target && (label.innerHTML = res.content);
}, dftSuccess = (res) => {
target && (target.innerHTML = res.content);
}, dftError = (res) => {
target ? label.innerHTML = renderTpl(config.lang.ajax.error, { status: res.status }) : console.error(`The current error state is:${res.status}`);
};
let spinEls = allToEls(dft.spinSel), xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"), params;
if (!isEmpty(dft.data)) {
let dataType = getDataType(dft.data);
if (dataType === 'FormData') {
params = dft.data;
}
else if (dataType === 'Object') {
if (dft.contType?.includes('json')) {
params = JSON.stringify(dft.data);
}
else {
params = new URLSearchParams(dft.data).toString();
dft.contType = 'application/x-www-form-urlencoded';
}
}