@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.
41,848 lines • 1.66 MB
JavaScript
/*!
* @since Last modified: 2026-1-11 15:12:29
* @name AXUI front-end framework.
* @version 3.1.34
* @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 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 _style = getComputedStyle(document.documentElement), _getCssVar = (prop) => _style.getPropertyValue(prop).trim(), _prefix = _getCssVar(`--PREFIX`).trim();
const ax = {
frame: 0,
ajaxStor: [],
styles: _style,
cssVar: _getCssVar,
prefix: _prefix,
alias: _getCssVar(`--${_prefix}alias`),
screen: _getCssVar(`--${_prefix}screen`),
fullGap: _getCssVar(`--${_prefix}g-full`),
fsRoot: _getCssVar(`--${_prefix}fs-root`),
images: {
spin: _getCssVar(`--${_prefix}spin`).split('"')[1],
spinDk: _getCssVar(`--${_prefix}spin-dk`).split('"')[1],
blank: _getCssVar(`--${_prefix}blank`).split('"')[1],
avatar: _getCssVar(`--${_prefix}avatar`).split('"')[1],
empty: _getCssVar(`--${_prefix}empty`).split('"')[1],
none: _getCssVar(`--${_prefix}none`).split('"')[1],
},
curves: {
linear: _getCssVar(`--${_prefix}bez-linear`),
ease: _getCssVar(`--${_prefix}bez-ease`),
easeOut: _getCssVar(`--${_prefix}bez-eo`),
easeIn: _getCssVar(`--${_prefix}bez-ei`),
easeInOut: _getCssVar(`--${_prefix}bez-eio`),
easeOutIn: _getCssVar(`--${_prefix}bez-eoi`)
},
isNarrowScr: ~~(_getCssVar(`--${_prefix}isnarrow`)),
isTouchScr: ('ontouchstart' in document.documentElement),
dragNode: null,
compSign: 'comp',
embedSign: 'embed',
namePfx: 'TMP_',
messages: [],
valids: [],
augment,
tasks: [],
swatches: [
'#ff6b6b',
'#e83e8c',
'#f72585',
'#e64980',
'#ff922b',
'#feca57',
'#51cf66',
'#94d82d',
'#20c997',
'#0ca678',
'#4cc9f0',
'#228be6',
'#4263eb',
'#364fc7',
'#6d5dfc',
'#7209b7',
'#3a0ca3',
'#7950f2',
'#be4bdb',
'#343a40',
'#495057',
'#6c757d',
'#adb5bd',
'#e9ecef',
'#f8f9fa',
'#ffffff'
],
colorStor: 'CUSTOM_COLOR',
};
const fieldTypes = ['input', 'file', 'textarea', 'range', 'number', 'datetime', 'upload', 'select', 'radio', 'checkbox', 'radios', 'checkboxes', 'editor'];
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="${ax.prefix}c-warn">中止了请求!</i>`,
timeout: `<i class="${ax.prefix}c-error">请求超时了!</i>`,
error: `<i class="${ax.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}}。',
},
color: {
label: {
h: '色相 (H)',
s: '饱和度 (S)',
v: '明度 (V)',
l: '亮度 (L)',
a: '透明度 (A)',
hsv: 'HSV模式',
hsl: 'HSL模式',
},
btn: {
random: '随机位置',
change: '切换模式',
straw: '吸色',
restore: '重置',
clear: '清空',
save: '保存',
copy: '复制',
confirm: '确定',
add: '从拾色器自定义颜色',
},
message: {
preset: '是否存为所有拾色器实例共用的预设色值?',
copy: '复制成功!可Ctrl+V粘贴到文档中。',
},
regular: '常用颜色',
theme: '主题颜色',
history: '最近使用的颜色',
add: {
heading: '添加颜色',
content: '是否添加<code>{{this.value}}</code>颜色到调色盘?',
}
},
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: '提示!运行中未出现状况,请继续!',
},
},
toast: {
content: {
warn: '系统异常!',
succ: '操作成功!',
error: '操作失败!',
issue: '操作存疑?',
info: '系统提示!'
}
},
viewer: {
close: '关闭查看器',
play: '已暂停,点击播放',
pause: '播放中,点击暂停',
fullscrOn: '非全屏,点击展开',
fullscrOff: '全屏中,点击退出',
rotatel: '逆时针旋转90°',
rotater: '顺时针旋转90°',
flipv: '垂直翻转',
fliph: '水平翻转',
download: '下载媒体文件',
thumb: '切换缩略图',
zoom: '切换缩放模式',
zoomin: '放大',
zoomout: '缩小',
expand: '侧边栏已收起,点击展开',
collapse: '侧边栏已展开,点击收起'
},
tree: {
empty: '没有树形数据',
label: '新分支',
title: {
folder: '新增枝干分支',
file: '新增叶子分支',
edit: '编辑分支',
remove: '删除分支',
arrow: '点击折叠或展开',
},
message: {
remove: '确定要删除"{{this.label}}"分支么',
},
paginated: {
more: '查看更多',
next: '下一页',
first: '返回首页',
info: '"{{this.label}}"还剩{{this.rest}}条信息',
main: '主分支',
},
result: `<i ${ax.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: '释放到这里...',
holderEmpty: '可拖入这里',
},
progress: {
complete: '已完成!',
tips: '当前进度',
},
infinite: {
finish: '没有更多内容了',
error: '请求终止,已停止加载',
next: '<ax-btn width="5">查看更多</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="${ax.prefix}c-caption">还未选择日期!</i>`,
message: {
requireTwoValue: '区间模式至少需要选择两个日期!',
requireYearFormat: '请填入正确的年份格式!',
requireOneSelected: '请至少选择一个日期!',
},
noEvent: `<i class="${ax.prefix}c-caption">今天没有需要安排的事项!</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: {
empty: '没有可选择的数据',
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 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 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 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: `${ax.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!',
parse: 'Getting data from HTML resulted in an error, an empty array was returned, but execution was not interrupted!',
},
error: {},
message: {},
valid: {
regChars: '~!@#$%^&*',
lengthStr: 6,
},
popup: {},
alert: {},
more: {},
menu: {},
tree: {},
drawer: {},
};
ax.config = config;
ax.install = (vue, options) => {
!isEmpty(options) && deepMerge(config, options);
vue.config.globalProperties.$ax = ax;
};
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 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 getComputedVar = (name) => getComputedStyle(document.documentElement).getPropertyValue(name).trim();
const getScreenSize = () => getComputedVar(`--${ax.prefix}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(ax.fsRoot) || 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 if (data.startsWith('var(')) {
let tmp = ax.getCssVar(data);
result = toPixel(tmp);
}
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 events = ax.isTouchScr ? ['touchstart', 'touchmove', 'touchend', 'touchcancel'] : ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];
const icons = {
font: {
succ: `<i class="${ax.prefix}icon-check-o"></i>`,
error: `<i class="${ax.prefix}icon-close-o"></i>`,
warn: `<i class="${ax.prefix}icon-warn-o"></i>`,
info: `<i class="${ax.prefix}icon-info-o"></i>`,
issue: `<i class="${ax.prefix}icon-issue-o"></i>`,
'succ-t': `<i class="${ax.prefix}icon-check-o-t"></i>`,
'error-t': `<i class="${ax.prefix}icon-close-o-t"></i>`,
'warn-t': `<i class="${ax.prefix}icon-warn-o-t"></i>`,
'info-t': `<i class="${ax.prefix}icon-info-o-t"></i>`,
'issue-t': `<i class="${ax.prefix}icon-issue-o-t"></i>`,
'succ-f': `<i class="${ax.prefix}icon-check-o-f"></i>`,
'error-f': `<i class="${ax.prefix}icon-close-o-f"></i>`,
'warn-f': `<i class="${ax.prefix}icon-warn-o-f"></i>`,
'info-f': `<i class="${ax.prefix}icon-info-o-f"></i>`,
'issue-f': `<i class="${ax.prefix}icon-issue-o-f"></i>`,
},
svg: {
succ: `<svg class="${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.prefix}in-1" d="M26.316,42.859L37.9984,54.5414L60.3826,32.1572"></path></svg>`,
error: `<svg class="${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.prefix}in-1" d="M28.774,57.9246L57.9247,28.7739"></path><path class="${ax.prefix}line ${ax.prefix}in-2" d="M57.9246,57.9246L28.7739,28.7739"></path></svg>`,
warn: `<svg class="${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.prefix}in-1" d="M43.3493,27.8713L43.3493,57.2858"></path><circle class="${ax.prefix}circle ${ax.prefix}in-2" cx="43.3492" cy="64.3337" r="2.1166"></circle></svg>`,
info: `<svg class="${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.prefix}in-1" d="M43.3493,65.0602L43.3493,30.9723"></path><circle class="${ax.prefix}circle ${ax.prefix}in-2" cx="43.3492" cy="23.5856" r="2.1166"></circle></svg>`,
issue: `<svg class="${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}line ${ax.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="${ax.prefix}circle ${ax.prefix}in-2" cx="44.6612" cy="60.5502" r="2.1166"></circle></svg>`,
}
};
const propsMap = {
x: { axis: 'x', position: 'left', start: 'insetInlineStart', startAlt: 'inset-inline-start', overflow: 'overflowX', inner: 'clientWidth', outer: 'offsetWidth', scroll: 'scrollLeft', client: 'clientX', size: 'width', index: 4, offset: 'offsetLeft', gap: 'marginInlineStart' },
y: { axis: 'y', position: 'top', start: 'insetBlockStart', startAlt: 'inset-block-start', overflow: 'overflowY', inner: 'clientHeight', outer: 'offsetHeight', scroll: 'scrollTop', client: 'clientY', size: 'height', index: 5, offset: 'offsetTop', gap: 'marginBlockStart' }
};
const getEl = (obj, wrap) => {
let objType = getDataType(obj), parType = getDataType(wrap), parent = parType.includes('HTML') ? wrap : document.querySelector(wrap), root = parent && parent instanceof HTMLTemplateElement ? parent.content : parent, result = null;
if (obj) {
if (objType.includes('HTML')) {
result = obj;
}
else if (objType === 'String') {
try {
result = (root || document).querySelector(obj.trim());
}
catch {
result = null;
}
}
}
return result;
};
const instance = {
data: [],
destroyFn: (item) => {
if (!item) {
return false;
}
if ((!item.ins.hasOwnProperty('destroyed') || !item.ins.destroyed) && item.ins.__proto__.destroy) {
item.ins.destroy();
item.destTime = Date.now();
}
},
initFn: (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.destroyFn(item);
}
return this;
},
destroyAll: function (type) {
let items = !type ? this.data : this.data.filter((i) => i.type === type);
items.forEach((i) => {
this.destroyFn(i);
});
return this;
},
clear: function () {
this.data.forEach((i) => {
this.destroyFn(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.initFn(item);
}
return this;
},
initAll: function (type) {
let items = !type ? this.data : this.data.filter((i) => i.type === type);
items.forEach((i) => {
this.initFn(i);
});
return this;
}
};
const getEls = (data, parent) => {
let type = getDataType(data), parentEl = getEl(parent), root = parentEl && parentEl instanceof HTMLTemplateElement ? parentEl.content : (parentEl || 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 [...root.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, typeof attrs[k] === 'string' ? attrs[k] : JSON.stringify(attrs[k]));
}
}
loop(rootEl, content);
return rootEl;
};
const parseStr = ({ content = '', type = 'object', method = config.parser, catchable = false, error }) => {
let result = type === 'object' ? {} : type === 'array' ? [] : null;
if (!content)
return result;
let trim = content.trim();
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 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: '',
signal: null,
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', { [ax.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') || dft.headers['Content-Type']?.includes('json')) {
params = JSON.stringify(dft.data);
}
else {
params = new URLSearchParams(dft.data).toString();
dft.contType = 'application/x-www-form-urlencoded';
}
}
else {
dft.data = dft.data.trim();
params = dft.data.startsWith('&') || dft.data.startsWith('?') ? dft.data.slice(1) : dft.data;
dft.contType = 'application/x-www-form-urlencoded';
}
}
if (dft.contType) {
dft.headers['Content-Type'] = dft.contType;
if (!dft.contType.includes('urlencoded') && dft.type.toLowerCase() === 'get') {
throw new Error(`Please request data with post!`);
}
}
xhr.timeout = dft.stopTime;
xhr.responseType = dft.respType;
let dftResp = { target, label, xhr, spins: spinEls }, timeoutFun, errorFun, successFun, abortFun = () => {
timeoutFun && xhr.removeEventListener('timeout', timeoutFun);
xhr.abort();
target && target.setAttribute(config.attrs.ajaxState, 'abort');
!isEmpty(dft.abort) ? dft.abort(Object.assign({ status: xhr.status, content: xhr.response }, dftResp)) : dftAbort();
};
return new Promise((resolve, reject) => {
let progress = (e, cb) => {
let current = e.loaded, total = e.total, ratio = 0, percent = 0, result = '0%', time = (new Date(e.timeStamp)).getTime();
if (e.lengthComputable) {
ratio = current / total;
percent = Math.round(ratio * 100);
result = percent + '%';
let data = Object.assign({ result, percent, current, total, ratio, time, status: xhr.status, abort: abortFun }, dftResp);
cb && cb(data);
percent >= 100 && dft.complete && dft.complete(data);
}
}, abortHandler = null;
if (dft.signal) {
abortHandler = () => {
xhr.abort();
reject({ ...dftResp, status: xhr.status });
};
if (dft.signal?.aborted) {
return reject({ ...dftResp, status: xhr.status });
}
dft.signal.addEventListener('abort', abortHandler);
}
xhr.upload.onprogress = (e) => {
progress(e, (data) => {
!isEmpty(dft.uploading) && dft.uploading(data);
});
};
xhr.onprogress = (e) => {
progress(e, (data) => {
!isEmpty(dft.downloading) && dft.downloading(data);
});
};
timeoutFun = () => {
let resp = Object.assign({ status: xhr.status, content: xhr.response }, dftResp);
target && target.setAttribute(config.attrs.ajaxState, 'timeout');
!isEmpty(dft.timeout) ? dft.timeout(resp) : dftTimeout();
dft.catchable && reject(resp);
dft.cb && dft.cb(resp);
};
errorFun = (resp) => {
target && target.setAttribute(config.attrs.ajaxState, 'error');
!isEmpty(dft.error) ? dft.error(resp) : dftError(resp);
dft.catchable && reject(resp);
dft.cb && dft.cb(resp);
};
successFun = (resp) => {
if (dft.repeat.max && dft.repeat.keyword && typeof resp.content === 'string') {
if (ax.ajaxStor[dft.repeat.index] < dft.repeat.max &&
resp.content.includes(dft.repeat.keyword)) {
if (isNull(ax.ajaxStor[dft.repeat.index])) {
ax.ajaxStor.push(0);
dft.repeat.index = ax.ajaxStor.length - 1;
}
else {
ax.ajaxStor[dft.repeat.index]++;
}
ajax(dft);
return;
}
else {
ax.ajaxStor[dft.repeat.index] = 0;
}
}
if (spinEls.length > 0) {
for (let k of spinEls)
k.removeAttribute(config.attrs.ajaxSpin);
}
target && target.setAttribute(config.attrs.ajaxState, 'success');
!isEmpty(dft.success) ? dft.success(resp) : dftSuccess(resp);
resolve(resp);
dft.cb && dft.cb(resp);
};
xhr.addEventListener('timeout', timeoutFun);
xhr.onreadystatechange = function () {
if (xhr.readyState < 4) {
let resp = Object.assign({ status: xhr.status, content: dft.spinStr, abort: abortFun }, dftResp);
if (xhr.readyState === 1) {
dft.xhrName && (this[dft.xhrName] = xhr);
!isEmpty(dft.opened) && dft.opened(resp);
}
if (spinEls.length > 0) {
for (let k of spinEls)
k.toggleAttribute(config.attrs.ajaxSpin, true);
}
target && target.setAttribute(config.attrs.ajaxState, 'before');
!isEmpty(dft.before) ? dft.before(resp) : dftBefore(resp);
}
else {
dft.signal && dft.signal.removeEventListener('abort', abortHandler);
let resp = Object.assign({ status: xhr.status }, dftResp);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
if (!dft.respType || xhr.responseType === 'text') {
let trim = xhr.responseText.trim(), content = '';
if ((trim.startsWith('[') && trim.endsWith(']')) || (trim.startsWith('{') && trim.endsWith('}'))) {
try {
content = JSON.parse(trim);
}
catch {
console.warn('Failed to parse JSON data. Defaulting to default string.');
content = xhr.responseText;
}
}
else if (trim.endsWith('</html>')) {
let reg = /(<head\b[^<]*(?:(?!<\/head>)<[^<]*)*<\/head>)|(<\/?html.*?>)|(<\!DOCTYPE.*?html.*?>)|(<\/?body.*?>)/gi, strEnd = sliceStrEnd({ str: dft.url }), childSel = (typeof dft.data === 'string' ? dft.data : strEnd);
if (childSel) {
let div = createEl('div', '', trim), childDom = getEl(childSel, div);
if (childDom) {
content = childDom.innerHTML;
}
else {
console.warn(`Target node "${childSel}" does not exist, returning full HTML content instead.`);
content = trim.replace(reg, '').trim();
}
}
else {
content = trim.replace(reg, '').trim();
}
}
else {
content = xhr.responseText;
}
resp.content = content;
}
else {
resp.content = xhr.response;
}
if (dft.holdTime) {
delay({
duration: dft.holdTime,
done: () => {
successFun(resp);
}
});
}
else {
successFun(resp);
}
}
else {
resp.content = xhr.response;
if (dft.holdTime) {
delay({
duration: dft.holdTime,
done: () => {
errorFun(resp);
}
});
}
else {
errorFun(resp);
}
}
}
};
let openParams = [], sendParams = null;
if (dft.type.toLowerCase() === 'get') {
openParams = ['get', dft.url + '?now=' + Date.now() + '&' + params, dft.async];
}
else if (dft.type.toLowerCase() === 'post') {
openParams = ['post', dft.url, dft.async];
sendParams = params;
}
for (let k in dft.xhrFields) {
dft.xhrFields.hasOwnProperty(k) && (xhr[k] = dft.xhrFields[k]);
}
xhr.open(...openParams);
for (let k in dft.headers) {
dft.headers.hasOwnProperty(k) && xhr.setRequestHeader(k, dft.headers[k]);
}
xhr.send(sendParams);
});
};
const valToArr = (data, hyphen, toNum = true) => {
let dataType = getDataType(data), arr = [];
if ([undefined, null, 'undefined', 'null', ''].includes(data)) {
return arr;
}
if (dataType === 'Array') {
arr = data.filter((k) => !isNull(k));
}
else if (dataType === 'String') {
arr = data.trim().split(hyphen || config.splitHyphen);
arr = arr.filter((k) => {
k = k.trim();
return k !== '' && !isNull(k);
});
toNum && (arr = arr.map((k) => isNaN(+k) ? k : +k));
}
else {
arr.push(data);
}
return [...new Set(arr)];
};
const getValsFromAttrs = (el) => {
let elem = getEl(el), obj = {};
if (elem) {
obj.label = elem.textContent.trim();
let attrs = [...elem.attributes];
attrs.forEach(k => {
obj[k.name] = (['selected', 'disabled', 'readonly', 'active', 'checked', 'expanded', 'draggable'].includes(k.name)) ? true : k.value.trim();
});
!obj.hasOwnProperty('value') && (obj.value = obj.label);
obj.value && !obj.label && (obj.label = obj.value);
}
return obj;
};
const select2Tree = (el) => {
let elem = getEl(el), result = [];
if (!elem) {
console.warn(`No node, no access to data!`);
return result;
}
let getChild = () => {
let data = [];
[...elem.children].forEach(k => {
data.push(getJson(k));
});
return data;
}, getJson = (elem) => {
let obj = { node: elem, ...getValsFromAttrs(elem) };
if (elem.nodeName == 'OPTGROUP') {
obj.children = [];
[...elem.children].forEach(k => {
obj.children.push(getJson(k));
});
}
return obj;
};
result = getChild();
return result;
};
const ul2Tree = (el, type = 'tree') => {
let elem = getEl(el), result = [];
if (!elem) {
console.warn(`No node, no access to data!`);
return result;
}
let getChild = () => {
let data = [];
[...elem.children].forEach(k => {
data.push(getJson(k));
});
return data;
}, getJson = (elem) => {
let obj = { node: elem.firstElementChild }, tmpLabel = obj.node.querySelector(`:scope> [${ax.alias}="label"]`), tmpBadge = obj.node.querySelector(`:scope> [${ax.alias}="badge"]`) || obj.node.querySelector(`:scope> AX-BADGE`), tmpTips = obj.node.querySelector(`:scope> [${ax.alias}="tips"]`), tmpIcon = obj.node.querySelector(`:scope> [${ax.alias}="icon"]`), tmpDisk = obj.node.querySelector(`:scope> [${ax.alias}="disk"]`), tmpCube = obj.node.querySelector(`:scope> [${ax.alias}="cube"]`), tmpCustom = obj.node.querySelector(`:scope> [${ax.alias}="custom"]`), tmpBrief = elem.querySelector(`:scope> .${ax.prefix}${type}-brief`), tmpCont = elem.querySelector(`:scope> .${ax.prefix}${type}-cont`), tmpExtra = elem.querySelector(`:scope> .${ax.prefix}${type}-extra`);
obj.node.classList.contains(`${ax.prefix}${type}-head`) && (obj.headEl = obj.node);
tmpLabel && (obj.labelEl = tmpLabel);
tmpBadge && (obj.badgeEl = tmpBadge);
tmpTips && (obj.tipsEl = tmpTips);
tmpCustom && (obj.customEl = tmpCustom);
tmpIcon && (obj.iconEl = tmpIcon);
tmpDisk && (obj.diskEl = tmpDisk);
tmpCube && (obj.cubeEl = tmpCube);
tmpBrief && (obj.briefEl = tmpBrief);
tmpCont && (obj.contEl = tmpCont);
tmpExtra && (obj.extraEl = tmpExtra);
Object.assign(obj, { ...getValsFromAttrs(obj.wrapEl), ...getValsFromAttrs(obj.node), ...getValsFromAttrs(obj.labelEl) });
obj.headEl && !obj.labelEl && (obj.headEl.innerHTML = '');
let parent = elem.querySelector(':scope> ul,:scope> ol');
if (parent) {
obj.children = [];
[...parent.children].forEach(k => {
obj.children.push(getJson(k));
});
}
return obj;
};
result = getChild();
return result;
};
const getContent = async function (opts) {
let dataType = getDataType(opts.content), getListArr = (data) => {
let el = getEl(data, opts.parent) || createEl('div', {}, data), nodeName = el.nodeName, target, result;
if (el) {
if (['SELECT', 'DATALIST', 'UL', 'OL'].includes(nodeName)) {
target = el;
}
else if (nodeName === 'TEMPLATE') {
target = el.content.cloneNode(true).querySelector('ul,ol,select,datalist');
}
else {
target = el.querySelector('ul,ol,select,datalist');
}
}
if (target) {
let tgtName = target.nodeName;
result = (['SELECT', 'DATALIST',].includes(tgtName)) ? select2Tree(target) :
(['UL', 'OL'].includes(tgtName)) ? ul2Tree(target) : [];
}
else {
result = [];
}
return result;
}, getIframe = (src) => {
let dft = { src }, iframe = createEl('iframe', Object.assign(dft, opts.contData)), media = createEl('div', { [ax.alias]: 'media' }, iframe);
return createEl('div', { class: `${ax.prefix}box-iframe` }, media);
}, getImage = (src) => {
let dft = { src }, image = createEl('img', Object.assign(dft, opts.contData)), media = createEl('div', { [ax.alias]: 'media' }, image);
return createEl('div', { class: `${ax.prefix}box-image` }, media);
}, getVideo = (src) => {
let dft = { src, controls: 'controls' }, video = createEl('video', Object.assign(dft, opts.contData)), media = createEl('div', { [ax.alias]: 'media' }, video);
return createEl('div', { class: `${ax.prefix}box-video` }, media);
}, getAudio = (src) => {
let dft = { src, controls: 'controls' }, audio = createEl('audio', Object.assign(dft, opts.contData)), media = createEl('div', { [ax.alias]: 'media' }, audio);
return createEl('div', { class: `${ax.prefix}box-audio` }, media);
}, getMedias = (type) => {
let map = {
iframe: getIframe,
audio: getAudio,
video: getVideo,
image: getImage,
}, vals = valToArr(opts.content, opts.hyphen || config.splitHyphen).map((k) => k.trim()), arr = [];
for (let k of vals) {
arr.push(map[type](k));
}
return arr;
}, getAsync = async (url) => {
let data, options = Object.assign({
url,
data: opts.contData,
success: (resp) => {
data = resp.content;
},
cb: (resp) => {
opts.request && opts.request(resp);
}
}, opts.ajax);
await ajax.call(this, options);
return data;
}, getAsyncs = async () => {
let vals = valToArr(opts.content, opts.hyphen || config.splitHyphen), arr = [];
for (let k of vals) {
await getAsync(k).then((resp) => {
arr.push(resp);
});
}
return arr;
}, result;
if (dataType === 'Number') {
result = opts.content + '';
}
else if (dataType === 'String') {
opts.content = opts.content.trim();
if (opts.contType === 'text') {
result = opts.content;
}
else if (opts.contType === 'html') {
result = getEl(opts.content, opts.parent) ? getEl(opts.content, opts.parent).innerHTML : '';
}
else if (opts.contType === 'node') {
result = getEl(opts.content, opts.parent);
}
else if (opts.contType === 'list') {
result = getListArr(opts.content);
}
else if (opts.contType === 'form') {
let tmp = getEl(opts.content, opts.parent), elem = tmp?.nodeName === 'TEMPLATE' ? tmp.content.cloneNode(true) : tmp;
result = elem?.querySelector('form') || '';
}
else if (opts.contType === 'iframe') {
result = getIframe(opts.content);
}
else if (opts.contType === 'iframes') {
result = getMedias('iframe');
}
else if (opts.contType === 'image') {
result = getImage(opts.content);
}
else if (opts.contType === 'images') {
result = getMedias('image');
}
else if (opts.contType === 'video') {
result = getVideo(opts.content);
}
else if (opts.contType === 'videos') {
result = getMedias('video');
}
else if (opts.contType === 'audio') {
result = getAudio(opts.content);
}
else if (opts.contType === 'audios') {
result = getMedias('audio');
}
else if (opts.contType === 'async') {
await getAsync(opts.content).then((resp) => {
result = resp;
});
}
else if (opts.contType === 'asyncs') {
await getAsyncs().then((resp) => {
result = resp;
});
}
else if (fieldTypes.includes(opts.contType)) {
let attrs = opts.contType === 'select' ? { popup: { multiple: true } } : opts.contType === 'datetime' ? { feature: 'flat', full: true } : opts.contType === 'upload' ? { 'feature': 'gallery' } : ['radios', 'checkboxes', 'checkbox'].includes(opts.contType) ? { type: 'text' } : { full: true }, valProp = ['checkboxes', 'radios', 'select'].includes(opts.contType) ? 'content' :
['checkbox', 'radio'].includes(opts.contType) ? 'label' :
opts.contType === 'upload' ? 'url' :
opts.contType === 'file' ? 'placeholder' : 'value', dft = { [valProp]: opts.content, ...attrs, ...Object.assign({ name: ax.namePfx + Date.now() }, opts.contData) };
result = createEl(`ax-${opts.contType}`, dft);
}
else {
result = opts.content;
}
}
else if (dataType === 'Promise') {
await opts.content.then((resp) => {
result = resp;
});
}
else if (dataType === 'AsyncFunction') {
await opts.content.call(this).then((resp) => {
result = resp;
});
}
else if (dataType === 'Function') {
result = opts.content.call(this);
}
else if (dataType === 'Object' || dataType === 'Array') {
if (dataType === 'Object' && opts.content[config.reqProp]) {
await getContent(opts.content).then((resp) => {
result = resp;
});
}
else {
result = deepClone(opts.content);
}
}
else if (dataType.includes('HTML') && opts.contType === 'list') {
result = getListArr(opts.content);
}
else {
result = opts.content;
}
opts.cb && opts.cb.call(this, result);
return result;
};
const style = (elem, pseudo) => {
let el = getEl(elem), result = el ? document.defaultView.getComputedStyle(el, pseudo) : {};
return result;
};
const getClasses = (data) => {
let dataType = getDataType(data), separator, result = [];
if (dataType === 'Array') {
result = data.filter((k) => k && typeof k === 'string');
}
else {
data = trim(data);
separator = data.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen;
result = data.split(separator);
}
return result.map((k) => trim(k, 'global')).filter(Boolean);
};
const classes = (target) => {
let el = getEl(target);
return {
get: () => el ? getClasses(el.getAttrubute('class')) : [],
add: function (classes, intercept) {
let arr = getClasses(classes);
if (!el || arr.length === 0) {
return this;
}
arr.forEach((k) => {
let tmp;
if (intercept) {
tmp = intercept(k);
tmp === true ? el.classList.add(k) :
(typeof tmp === 'string' && tmp) ? el.classList.add(tmp) : null;
}
else {
el.classList.add(k);
}
});
return this;
},
remove: function (classes, intercept) {
let arr = getClasses(classes);
if (!el || arr.length === 0)
return this;
arr.forEach((k) => {
let tmp;
if (intercept) {
tmp = intercept(k);
tmp === true ? el.classList.remove(k) :
(typeof tmp === 'string' && tmp) ? el.classList.remove(tmp) : null;
}
else {
el.classList.remove(k);
}
});
return this;
},
replace: function (oldClass, newClass) {
if (!el || !oldClass)
return this;
if (el && newClass && oldClass) {
el.classList.remove(oldClass);
el.classList.add(newClass);
}
return this;
},
has: function (classes) {
if (!el || isEmpty(classes))
return this;
let arr = getClasses(classes);
for (let k of arr) {
if (!el.classList.contains(k)) {
return false;
}
}
return true;
}
};
};
const elState = (elem) => {
let dom = getEl(elem), isExist = dom ? true : false;
if (!dom) {
return { isExist, isCalc: false, isUncalc: true };
}
else {
if (!dom.isConnected) {
return { isExist, isVirtual: true, isHidden: true, isVisible: false, isCalc: false, isUncalc: true };
}
if (dom.style.display === 'none') {
return { isExist, isVirtual: false, isHidden: true, isVisible: false, isCalc: false, isUncalc: true };
}
let style = getComputedStyle(dom), isVirtual = !style.display, isHidden = (style.display === 'none' || style.visibility === 'hidden'), isCalc = !!(style.display && style.display !== 'none'), isVisible = !!(isCalc && style.visibility === 'visible');
return { isExist, isVirtual, isHidden, isVisible, isCalc, isUncalc: isVirtual || isHidden };
}
};
const optBase = [
{
attr: 'ins-name',
prop: 'insName',
value: '',
},
{
attr: 'stor-name',
prop: 'storName',
value: '',
},
{
attr: 'stor-keys',
prop: 'storKeys',
value: [],
},
{
attr: 'breakpoints',
prop: 'breakpoints',
value: {},
},
{
attr: 'rtl',
prop: 'rtl',
value: false,
},
{
attr: 'lang',
prop: 'lang',
value: {},
},
{
attr: 'b4-init',
prop: 'b4Init',
value: null,
},
{
attr: 'on-constructed',
prop: 'onConstructed',
value: null,
},
{
attr: 'on-initiate',
prop: 'onInitiate',
value: null,
},
{
attr: 'on-initiated',
prop: 'onInitiated',
value: null,
},
{
attr: 'on-destroyed',
prop: 'onDestroyed',
value: null,
},
{
attr: 'on-error',
prop: 'onError',
value: null,
},
{
attr: 'on-reset',
prop: 'onReset',
value: null,
},
{
attr: 'on-updated',
prop: 'onUpdated',
value: null,
},
{
attr: 'on-saved',
prop: 'onSaved',
value: null,
},
{
attr: 'on-clearedcache',
prop: 'onClearedCache',
value: null,
},
{
attr: 'on-updatedcache',
prop: 'onUpdatedCache',
value: null,
},
];
let AXTMP_actClass = config.actClass;
const optBubble = [
{
attr: 'heading',
prop: 'heading',
value: '',
},
{
attr: 'divider',
prop: 'divider',
value: false,
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'auto-dur',
prop: 'autoDur',
value: false,
},
{
attr: 'asleep',
prop: 'asleep',
value: false,
},
{
attr: 'dead-show',
prop: 'deadShow',
value: false,
},
{
attr: 'keep-show',
prop: 'keepShow',
value: false,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'padding',
prop: 'padding',
value: {
enable: true,
body: true,
foot: true,
}
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'act-class',
prop: 'actClass',
value: AXTMP_actClass,
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'z-index',
prop: 'zIndex',
value: 0,
},
{
attr: 'dedicated',
prop: 'dedicated',
value: false,
},
{
attr: 'can-click',
prop: 'canClick',
value: null,
},
{
attr: 'media',
prop: 'media',
value: {
title: '',
brief: '',
},
},
{
attr: 'auto-fill',
prop: 'autoFill',
value: {
enable: false,
inputSel: '',
childSel: '',
detectable: false,
attr: '',
},
},
{
attr: 'bullet',
prop: 'bullet',
value: {
enable: false,
type: 'custom',
parentNode: 'ul',
childNode: 'li',
unpadded: false,
hoverable: false,
divisible: false,
multiline: false,
cols: 0,
lines: '',
action: null,
},
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: true,
placement: 'inside',
children: ['close']
},
},
{
attr: 'footer',
prop: 'footer',
value: {
enable: true,
layout: 'plain',
note: false,
divider: false,
padding: false,
children: ['cancel', 'confirm']
}
},
{
attr: 'b4-show',
prop: 'b4Show',
value: null,
},
{
attr: 'b4-hide',
prop: 'b4Hide',
value: null,
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'b4-confirm',
prop: 'b4Confirm',
value: null,
},
{
attr: 'b4-cancel',
prop: 'b4Cancel',
value: null,
},
{
attr: 'on-show',
prop: 'onShow',
value: null,
},
{
attr: 'on-hide',
prop: 'onHide',
value: null,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-hidden',
prop: 'onHidden',
value: null,
},
{
attr: 'on-invalidated',
prop: 'onInvalidated',
value: null,
},
{
attr: 'on-validated',
prop: 'onValidated',
value: null,
},
{
attr: 'on-sended',
prop: 'onSended',
value: null,
},
{
attr: 'on-render',
prop: 'onRender',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null,
},
{
attr: 'on-transferred',
prop: 'onTransferred',
value: null,
},
{
attr: 'on-confirmed',
prop: 'onConfirmed',
value: null,
},
{
attr: 'on-canceled',
prop: 'onCanceled',
value: null,
}, {
attr: 'on-closed',
prop: 'onClosed',
value: null,
}, {
attr: 'on-cleared',
prop: 'onCleared',
value: null,
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-bulletschecked',
prop: 'onBulletsChecked',
value: null
},
{
attr: 'on-bulletsselected',
prop: 'onBulletsSelected',
value: null
},
{
attr: 'on-targetset',
prop: 'onTargetSet',
value: null
},
...optBase
];
const optDrawer = [
{
attr: 'placement',
prop: 'placement',
value: 'right',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'click',
},
{
attr: 'offset',
prop: 'offset',
value: '100px',
},
{
attr: 'size',
prop: 'size',
value: 'sm',
},
{
attr: 'multiple',
prop: 'multiple',
value: true,
},
{
attr: 'parent',
prop: 'parent',
value: '',
},
{
attr: 'wing',
prop: 'wing',
value: {
selector: '',
actClass: '',
},
},
{
attr: 'mask',
prop: 'mask',
value: {
enable: true,
closable: true,
},
},
...optBubble
];
const getEvtTarget = (evt) => {
if (!evt.targetTouches) {
return evt.target;
}
else {
let tmp = evt.targetTouches[0] || evt.changedTouches[0];
return document.elementFromPoint(tmp.clientX, tmp.clientY);
}
};
const removeStyle = (el, prop) => {
let target = getEl(el);
if (!target || !prop)
return;
target.style.cssText = target.style.cssText.replace(`${prop}:`, '');
};
const addStyle = (el, key, value) => {
let target = getEl(el);
key = (key + '').toLowerCase();
value = value + '';
if (!target || !key || !value)
return;
let prop = key.replace(/-([a-z])/g, (match, k) => k.toUpperCase());
target.style[prop] = value;
};
const isDateStr = (str) => (typeof str === 'string' && !isNaN(Date.parse(str)));
const getUTCTimestamp = (value) => {
let date, offset, dateTamp, valType = getDataType(value);
if (valType === 'Date') {
date = value;
}
else if (valType === 'String') {
if (isDateStr(value)) {
date = new Date(value);
}
else {
date = new Date();
}
}
else if (valType === 'Number') {
date = new Date(value);
}
else {
date = new Date();
}
dateTamp = date.getTime();
offset = date.getTimezoneOffset() * 60000;
return dateTamp + offset;
};
const getExpiration = (type = 'd', value = 365, output = 'locale') => {
let dateExp;
if (isDateStr(value)) {
dateExp = new Date(value);
}
else {
dateExp = new Date();
switch (type) {
case 's':
dateExp.setSeconds(dateExp.getSeconds() + ~~value);
break;
case 'm':
dateExp.setMinutes(dateExp.getMinutes() + ~~value);
break;
case 'h':
dateExp.setHours(dateExp.getHours() + ~~value);
break;
default:
dateExp.setDate(dateExp.getDate() + ~~value);
}
}
return output === 'utc' ? getUTCTimestamp(dateExp) : dateExp.getTime();
};
const storage = {
set: function (key, value, opts) {
if (isEmpty(key) && typeof key !== 'string')
return;
let options = Object.assign({ unit: 'd', expires: 0, override: true, type: 'local' }, opts), newValue = deepClone(value), valType = getDataType(value), stor = options.type === 'session' ? window.sessionStorage : window.localStorage, filterProps = (obj) => {
Object.keys(obj).forEach(k => {
let val = obj[k], type = getDataType(val);
['Array', 'Object'].includes(type) && filterProps(val);
(type.includes('HTML') || type.includes('Function') || ['Promise', 'Symbol', 'Instance'].includes(type)) && delete obj[k];
});
return obj;
};
if (['Array', 'Object'].includes(valType) && !isEmpty(newValue)) {
filterProps(newValue);
}
let expires = options.expires !== 0 ? getExpiration(options.unit, options.expires) : 0, oldValue = this.get(key, options.type), valueExp = {
data: (!options.override && this.get(key, options.type)) ? extend({ target: oldValue, source: newValue }) : newValue,
expires,
};
if (((typeof options.expires === 'number' && options.expires < 0) || newValue === null) && this.get(key, options.type)) {
this.remove(key, options.type);
}
else {
stor.setItem(key, JSON.stringify(valueExp));
}
return this;
},
get: function (key, type = 'local') {
if (isEmpty(key) || typeof key !== 'string') {
return false;
}
let now = Date.now(), stor = type === 'session' ? window.sessionStorage : window.localStorage, valueStr = stor.getItem(key);
if (valueStr) {
let valueExp = (new Function('"use strict";return ' + valueStr))();
if (valueExp.expires === 0 || now <= valueExp.expires) {
return valueExp.data;
}
else {
stor.removeItem(key);
return null;
}
}
else {
return null;
}
},
remove: function (key, type = 'local') {
if (isEmpty(key) || typeof key !== 'string') {
return false;
}
let stor = type === 'session' ? window.sessionStorage : window.localStorage;
stor.removeItem(key);
return this;
},
clear: function (type = 'local') {
let stor = type === 'session' ? window.sessionStorage : window.localStorage;
stor.clear();
return this;
}
};
const optObserve = [
{
attr: 'deep',
prop: 'deep',
value: {
enable: false,
include: [],
exclude: [],
},
},
{
attr: 'filter',
prop: 'filter',
value: null,
},
{
attr: 'tpyes',
prop: 'tpyes',
value: ['Object', 'Array', 'Function'],
},
{
attr: 'accept',
prop: 'accept',
value: true,
},
{
attr: 'lenient',
prop: 'lenient',
value: true,
},
{
attr: 'once',
prop: 'once',
value: false,
},
{
attr: 'methods',
prop: 'methods',
value: ['set', 'delete'],
},
{
attr: 'on-added',
prop: 'onAdded',
value: null,
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null,
},
{
attr: 'on-set',
prop: 'onSet',
value: null,
},
{
attr: 'on-deleted',
prop: 'onDeleted',
value: null,
},
{
attr: 'on-crud',
prop: 'onCrud',
value: null,
},
{
attr: 'on-new',
prop: 'onNew',
value: null,
},
{
attr: 'on-applied',
prop: 'onApplied',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null,
},
{
attr: 'on-completed',
prop: 'onCompleted',
value: null,
},
...optBase
];
const deepEqual = (a, b) => {
if (a === b)
return true;
let typeA = getDataType(a), typeB = getDataType(b);
if (typeA === typeB && typeA === 'Object') {
let getStr = (data) => {
let cache = new Set();
return JSON.stringify(data, (key, val) => {
if (typeof val === 'object' && val !== null) {
if (cache.has(val))
return;
cache.add(val);
}
return val;
});
};
return getStr(a) === getStr(b);
}
else {
return false;
}
};
const isProxy = (obj) => obj?._isProxy === true;
const unique = (data, prop) => {
let result;
if (!isEmpty(data)) {
result = [...new Set(data)];
if (typeof result[0] === 'object' && prop) {
let map = new Map();
for (let k of result) {
!map.has(k[prop]) && map.set(k[prop], k);
}
result = [...map.values()];
}
}
else {
result = [...data];
}
return result;
};
const plan = {
handle: (name, type, cb) => {
let nameArr = [];
if (type === 'String') {
name = trim(name);
nameArr = name.includes(',') ? name.split(',') : name.split(' ');
}
else if (type === 'Array') {
nameArr = name.map((k) => trim(k));
}
if (nameArr.length > 0) {
for (let k of nameArr) {
cb(k);
}
}
},
add: function (name, instance, content) {
let nameType = getDataType(name), handle = (str) => {
if (!instance.plans.hasOwnProperty(str)) {
instance.plans[str] = [];
}
let newValue = content.toString().replace(/\s/g, '').replace(/\;/g, '').match(/{(\S*)}/), oldValue = instance.plans[str].toString().replace(/\s/g, '').replace(/\;/g, '');
newValue && !oldValue.includes(newValue[1]) ? instance.plans[str].push(content) : null;
};
this.handle(name, nameType, (item) => handle(item));
return this;
},
remove: function (name, instance, content) {
let nameType = getDataType(name), handle = (str) => {
if (!instance.plans.hasOwnProperty(str)) {
return console.warn(`The ${str} event is invalid or unusable!`);
}
if (!content) {
delete instance.plans[str];
}
else {
let index = instance.plans[str].findIndex((k) => k === content);
if (index < 0) {
return console.warn(`The ${str} event is not bound!`);
}
instance.plans[str].splice(index, 1);
instance.plans[str].length === 0 ? delete instance.plans[str] : null;
}
};
this.handle(name, nameType, (item) => handle(item));
return this;
},
do: function (name, instance, ...params) {
let nameType = getDataType(name), handle = (str) => {
if (!instance.plans.hasOwnProperty(str)) {
return console.warn(`The ${str} event is unregistered or unusable!`);
}
instance.plans[str].forEach((k) => {
k.call(instance, ...params);
});
};
this.handle(name, nameType, (item) => handle(item));
return this;
}
};
const attrJoinVal = (attr, value, map) => {
let item = map ? map.find((k) => k.attr === attr) : null, isFn = () => {
let tmp = attr.trim(), condition = item ? typeof item?.value === 'function' : false;
return (tmp.startsWith('on-') || tmp.startsWith('b4-')) || condition;
}, addFnShell = (str) => {
let tmp = str.trim(), result = (!(tmp.startsWith('function') || tmp.startsWith('(')) && !tmp.endsWith('}')) ? `function(){${str}}` : str;
return result;
}, fnVal = isFn() ? addFnShell(value) : value;
try {
if (item) {
if (value === null) {
return { [item.prop]: item.value };
}
else {
let valType = getDataType(item.value), trim = value.trim(), trueVals = ['', '1', 'true', true], falseVals = [null, 'null', 'undefined', '0', 'false', 'NaN'];
return item.type === 'ignore' ? { [item.prop]: value } :
(valType === 'String') ? { [item.prop]: value } :
(valType === 'Number') ? { [item.prop]: parseFloat(value) } :
(valType === 'Boolean' && trueVals.includes(trim)) ? { [item.prop]: true } :
(valType === 'Boolean' && falseVals.includes(trim)) ? { [item.prop]: false } :
(valType === 'Object' && item.value.hasOwnProperty('enable') && trueVals.includes(trim)) ? { [item.prop]: true } :
(valType === 'Object' && item.value.hasOwnProperty('enable') && item.value.hasOwnProperty('children') && trim.startsWith('[') && trim.endsWith(']')) ? { [item.prop]: { enable: true, children: parseStr({ content: `${value}`, type: 'array', catchable: true }) } } :
(valType === 'Object' && value.includes(':')) ? { [item.prop]: strToJson(value) } :
parseStr({ content: `{"${item.prop}":${fnVal}}`, type: 'object', catchable: true });
}
}
else {
return value === '' ? { [attr]: '' } : parseStr({ content: `{"${attr}":${fnVal}}`, type: 'object', catchable: true });
}
}
catch (e) {
return { [attr]: value };
}
};
const breakpoints = (obj, points) => {
if (isEmpty(obj) || isEmpty(points))
return;
let valids = [], assign = {}, width = document.body.clientWidth, validFun = (key, value) => {
let _key = ~~key;
if (_key === 0) {
let tmp = key.split('-')[1];
if (key.startsWith('screen')) {
let cond = (ax.screen === tmp) ||
(tmp === 'dt' && ['lg', 'xl', 'xxl', 'dt'].includes(ax.screen)) ||
(tmp === 'hh' && ['xxs', 'xs', 'sm', 'md', 'hh'].includes(ax.screen)) ||
(tmp === 'tb' && ['xs', 'sm', 'md', 'tb'].includes(ax.screen)) ? true : false;
cond && valids.push(value);
}
else if (key.startsWith('width')) {
~~tmp <= width && valids.push(value);
}
else if (key.startsWith('destop')) {
JSON.parse(tmp) !== ax.isTouchScr && valids.push(value);
}
}
else {
_key <= width && valids.push(value);
}
};
for (let k in points) {
if (points.hasOwnProperty(k)) {
Reflect.deleteProperty(points[k], 'breakpoints');
validFun(k, points[k]);
}
}
if (!valids.length)
return;
assign = Object.assign({}, ...valids);
extend({ target: obj, source: assign });
};
const storeNode = (el) => {
let target = getEl(el), result = null;
if (target) {
!target.hasOwnProperty('ax') && (target.ax = {});
result = {
addModule: (key) => {
if (!key)
return;
if (!target.ax.hasOwnProperty('modules')) {
target.ax.modules = {};
}
if (target.ax.modules[key])
return;
target.ax.modules[key] = true;
return target;
},
removeModule: (key) => {
if (!key)
return;
delete target.ax.modules[key];
return target;
},
addData: (key, value) => {
if (!key)
return;
target.ax[key] = value;
return target;
},
removeData: (key) => {
if (!key)
return;
delete target.ax[key];
return target;
}
};
}
return result;
};
const keyCond = (key) => {
return !/^(stor-keys|ins-name|stor-name|storKeys|insName|storName|on-|b4-|on[A-Z]|b4[A-Z])/.test(key);
};
const spreadBool = (host, params) => {
let result = host, hostType = getDataType(host), paramsType = getDataType(params);
if (paramsType === 'Object') {
if (hostType === 'Boolean') {
Reflect.deleteProperty(params, 'enable');
result = { enable: host, ...params };
}
else if (hostType === 'Object') {
if (host.hasOwnProperty('enable')) {
host = Object.assign({}, params, host);
}
else {
for (let k in params) {
if (params.hasOwnProperty(k) && host.hasOwnProperty(k)) {
host[k] = spreadBool(host[k], params[k]);
}
}
}
}
}
return result;
};
const contains = (child, parent) => {
let childEl = getEl(child), result = false;
if (!childEl)
return result;
if (Array.isArray(parent)) {
for (let k of parent) {
let parentEl = getEl(k);
if (!parentEl)
continue;
if (parentEl.contains(childEl)) {
result = true;
break;
}
}
}
else {
let parentEl = getEl(parent);
result = parentEl && parentEl.contains(childEl) ? true : false;
}
return result;
};
const getRtl = () => {
if (!ax.hasOwnProperty(ax.rtl)) {
let tmp = getComputedVar(`--${ax.prefix}dir-coef`);
ax.rtl = tmp == '-1' ? true : false;
}
return ax.rtl;
};
class ModBase {
targetEl;
targetData;
options;
destroyed;
timestamp;
renderCount;
respSource;
initialized;
moduleName;
dftOpts;
rawOpts;
rawHtml;
rawEl;
tplStr;
tplEng;
initCount;
handleEls;
isRtl;
constructor() {
this.timestamp = Date.now();
this.respSource = null;
this.initialized = false;
this.initCount = 0;
this.renderCount = 0;
this.handleEls = [];
this.targetEl = null;
this.targetData = null;
this.rawOpts = {};
this.dftOpts = {};
this.options = {};
this.rawHtml = '';
this.rawEl = null;
this.destroyed = false;
this.moduleName = this.constructor.name.toLowerCase();
this.tplStr = '';
this.tplEng = null;
}
getOptsFromMap(map) {
let options = {};
for (let k of map) {
options[k.prop] = k.value;
}
return options;
}
isComp(elem) {
return elem.getAttribute(ax.alias) === 'slot-host';
}
getElOptsMap(elem) {
if (isEmpty(elem)) {
return { el: null, attr: {} };
}
else {
let isComp = this.isComp(elem), el = isComp ? elem.parentNode : elem, attr = isComp ? 'initiated' : `ax-${this.moduleName}`;
return { el, attr };
}
}
mergeOpts({ source = {}, map = [], el = null, component = false }) {
let target = getEl(el), elMap = this.getElOptsMap(target), options = deepClone(this.getOptsFromMap(map));
this.rawOpts = deepClone(options);
!isEmpty(config.lang[this.moduleName]) && (options.lang = extend({ target: deepClone(config.lang[this.moduleName]), source: options.lang }));
extend({ target: options, source: config[this.moduleName] || {} });
extend({ target: options, source, host: elMap.el, attr: elMap.attr });
component ? extend({ target: options, source: this.mergeCompAttrs(target, map) }) : null;
this.dftOpts = deepClone(options);
return options;
}
mergeCompAttrs(elem, map) {
let options = {};
if (this.isComp(elem)) {
let target = elem.parentNode, attributes = target?.attributes;
if (!target || target.nodeName.toLowerCase() !== `ax-${this.moduleName}` || !attributes)
return {};
for (let k of attributes) {
let item = map.find((i) => i.attr === k.name);
if (item) {
let keyVal = attrJoinVal(item.attr, k.value, [item]);
Object.assign(options, keyVal);
}
}
}
return options;
}
getOptsAttr(elem) {
return elem.nodeName === `AX-${this.moduleName.toUpperCase()}` ? 'options' : `ax-${this.moduleName}`;
}
getStrFromContent(str) {
let el = getEl(str);
return el ? el.innerHTML : str;
}
revertHtml(elem) {
this.rawHtml ? elem.innerHTML = this.rawHtml : '';
elem.children.length === 1 && (this.rawEl = elem.children[0]);
}
replaceMult(str = '', arr, opts = {}) {
let options = Object.assign({ ignore: true, nodename: 'i' }, opts), regx = new RegExp(`(${arr.join('|')})`, `g${options.ignore ? 'i' : ''}`), tmp = `<${options.nodename} ${ax.alias}="mark"${options.classes ? ' class="' + options.classes + '"' : ''}>$1</${options.nodename}>`;
return (str + '').replace(regx, tmp);
}
parseLayout(host = this.targetEl, template = '', map = {}) {
let target = getEl(host), holder = createEl('i', { [ax.alias]: 'holder' }), gap = createEl('i', { [ax.alias]: 'gap' }), condition = (key) => key === 'holder' ? holder.cloneNode(true) : key === 'gap' ? gap.cloneNode(true) : map[key], getNodes = (str) => str.split('|').map(condition).filter(Boolean);
if (!target || !template || isEmpty(map))
return;
if (template.includes('(') && template.includes(')')) {
let startIdx = template.indexOf('('), endIdx = template.indexOf(')'), strL = template.slice(0, startIdx), strC = template.slice(startIdx + 1, endIdx), strR = template.slice(endIdx + 1), nodesL = getNodes(strL), nodesC = getNodes(strC), nodesR = getNodes(strR);
nodesL.length && target.append(...nodesL);
if (map.group) {
target.appendChild(map.group);
nodesC.length && map.group.append(...nodesC);
}
nodesR.length && target.append(...nodesR);
}
else {
let nodes = getNodes(template);
target.append(...nodes);
}
}
updateOpts(spread) {
this.optsMergeStorage && this.optsMergeStorage();
!isEmpty(this.options.breakpoints) ? breakpoints(this.options, this.options.breakpoints) : null;
if (Array.isArray(spread) && spread.length > 0) {
let obj = {};
for (let k of spread) {
obj[k] = this.rawOpts[k];
}
spreadBool(this.options, obj);
}
}
getStorageKeys() {
let result = [];
if (Array.isArray(this.options.storKeys) && this.options.storKeys.length > 0) {
result = this.options.storKeys;
}
else {
result = Object.keys(this.options).filter((k) => keyCond(k));
}
return result;
}
single2Els(data, parent) {
let result = [];
if (data) {
let dataType = getDataType(data);
if (dataType === 'Array') {
result = data;
}
else if (dataType.includes('HTML')) {
result.push(data);
}
else {
result = getEls(data, parent);
}
}
return result.filter(Boolean);
}
useTpl() {
let tplEl = getEl(this.options.tplStr);
this.tplEng = this.options.tplEng || renderTpl;
this.tplStr = tplEl?.innerHTML || this.options.tplStr;
}
getTplcont(data, str = this.tplStr, eng = this.tplEng) {
let tmp = eng || renderTpl;
return tmp.name === 'template' ? tmp(this.tplStr)(data) : tmp(str, data);
}
useHandle(target) {
return this.handleEls.length && contains(target, this.handleEls);
}
ready({ type = 'node', options = {}, maps = [], host, component = false, spread = [], }) {
getDataType(host); let moreParams = {};
this.propsMap = maps;
if (type === 'node') {
this.targetEl = getEl(host);
if (this.targetEl) {
storeNode(this.targetEl)?.addModule(this.moduleName);
moreParams = {
el: this.targetEl,
component,
};
this.rawHtml = this.targetEl.innerHTML;
this.targetEl.children.length === 1 && (this.rawEl = this.targetEl.children[0]);
this.compAttrs = [];
}
}
else {
type === 'data' && (this.targetData = host);
}
this.options = this.mergeOpts({
source: options,
map: this.propsMap,
...moreParams,
});
this.storKeys = this.getStorageKeys();
this.createProxy && this.createProxy();
this.plans = {};
instance.push(this, this.options.insName, this.moduleName);
this.on('initiate', () => {
this.destroyed = false;
this.updateOpts(spread);
this.targetEl && this.targetEl.classList.add(`${ax.prefix}initiated`);
this.options.hasOwnProperty('tplStr') && this.useTpl();
});
this.on('initiated', () => {
this.initialized = true;
this.initCount++;
});
this.on('destroyed', () => {
this.clearCache && this.clearCache();
this.destroyed = true;
});
}
moreExceed({ data, source, sliced = true, min = this.options.min, max = this.options.max }) {
return new Promise((resolve, reject) => {
let curLen = source.length, newLen = data.length, totalLen = curLen + newLen, param = { min, max, cur: curLen, val: newLen };
if (max && totalLen > max) {
this.listen({ name: 'tooMany', params: [param] });
let tmp = max - curLen;
if (!tmp) {
reject();
console.warn(`The maximum quantity (${max}) has been reached, no more new data can be added!`);
}
else {
if (sliced) {
resolve(data.slice(0, tmp));
console.warn('The amount of newly added data is too much, only part of it has been added!');
}
else {
reject();
console.warn('The amount of newly added data is too much, further additions have been prevented!');
}
}
}
else if (totalLen < min) {
console.warn('The amount of newly added data is too little, please continue adding!');
this.listen({ name: 'tooFew', params: [param] });
resolve(null);
}
else {
resolve(null);
}
});
}
lessExceed({ data, source, sliced = true, min = this.options.min, max = this.options.max }) {
return new Promise((resolve, reject) => {
let curLen = source.length, newLen = data.length, totalLen = curLen - newLen, param = { min, max, cur: curLen, val: newLen };
if (max && totalLen > max) {
console.warn('The current data is still too much, please continue deleting!');
this.listen({ name: 'tooMany', params: [param] });
resolve(null);
}
else if (totalLen < min) {
this.listen({ name: 'tooFew', params: [param] });
let tmp = curLen - min;
if (!tmp) {
reject();
console.warn(`The minimum quantity (${min}) has been reached, no more data can be deleted!`);
}
else {
if (sliced) {
resolve(data.slice(0, tmp));
console.warn('The amount of deleted data is too much, only part of it has been deleted!');
}
else {
reject();
console.warn('The amount of deleted data is too much, further deletion has been prevented!');
}
}
}
else {
resolve(null);
}
});
}
getDirRtl() {
if (this.options.rtl) {
this.isRtl = true;
return;
}
if (!this.targetEl)
return;
let rtlAttr = this.targetEl.getAttribute('dir');
if (rtlAttr === 'rtl') {
this.isRtl = true;
return;
}
this.isRtl = getRtl();
}
getRtlCoef() {
return (this.options.axis === 'x' && this.isRtl ? -1 : 1);
}
lock(cb) {
if (this.destroyed || !this.targetEl)
return;
this.targetEl.toggleAttribute('inert', true);
this.destroyed = true;
this.listen({ name: 'locked', cb });
return this;
}
unlock(cb) {
if (!this.targetEl)
return;
this.targetEl.toggleAttribute('inert', false);
this.destroyed = false;
this.listen({ name: 'unlocked', cb });
return this;
}
async reset(cb) {
this.options = deepClone(this.dftOpts);
this.revertHtml && this.targetEl && this.revertHtml(this.targetEl);
await this.init();
this.clearCache && this.clearCache();
this.listen && this.listen({ name: 'reset', cb });
return this;
}
async update(settings, cb) {
if (this.destroyed)
return this;
if (!isEmpty(settings)) {
this.updateCache && this.updateCache(settings);
extend({ target: this.options, source: settings });
await this.init();
}
this.listen && this.listen({ name: 'updated', cb, params: [settings] });
return this;
}
async updateCont(data, cb) {
if (this.destroyed)
return this;
if (this.options.hasOwnProperty('content') && !isNull(data)) {
this.options.content = data;
await this.init();
this.updateCache({ content: data });
this.listen({ name: 'updatedCont', cb, params: [data] });
return this;
}
}
async init(cb) { }
destroy(cb) { }
}
class ModBaseListen extends ModBase {
plans = {};
listen({ name, params = [], cb } = {}) {
name && this.plans.hasOwnProperty(name) ? this.emit(name, ...params) : null;
name && this.options[`on${startUpper(name)}`] && this.options[`on${startUpper(name)}`].call(this, ...params);
cb && cb.call(this, ...params);
}
on(type, handler) {
plan.add(type, this, handler);
return this;
}
emit(type, ...params) {
plan.do(type, this, ...params);
return this;
}
off(type, handler) {
plan.remove(type, this, handler);
return this;
}
}
class Observe extends ModBaseListen {
options = {};
dataType;
completedCount;
reactCount;
proxys;
fullMethods;
methods;
output;
canProxy;
hasProp;
canDeep;
canRun;
keys;
types;
proxy;
hostProxy;
static hostType = 'data';
static optMaps = optObserve;
constructor(data, options = {}, initial = true) {
super();
super.ready({
type: Observe.hostType,
options,
maps: Observe.optMaps,
host: data,
spread: ['deep'],
});
this.proxys = [];
this.targetData && initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.completedCount = 0;
this.reactCount = 0;
this.canProxy = (type, value) => (this.types.includes(type) && !isProxy(value));
this.hasProp = (key) => (isEmpty(this.options.deep.include) || this.options.deep.include.includes(key)) && (isEmpty(this.options.deep.exclude) || !this.options.deep.exclude.includes(key));
this.canDeep = (type, value) => this.canProxy(type, value) && this.options.deep.enable;
this.canRun = (key) => this.options.filter ? this.options.filter(key) : true;
this.keys = { got: [], set: [], deleted: [] };
this.fullMethods = {
get: (target, key, proxy) => {
if (!this.canRun(key))
return;
if (key === '_isProxy')
return true;
let value = target[key], baseProps = { target, key, value, raw: value, proxy };
!this.keys.got.includes(key) && this.keys.got.push(key);
super.listen({ name: 'got', params: [{ ...baseProps, type: 'got' }] });
super.listen({ name: 'crud', params: [{ ...baseProps, type: 'got' }] });
super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'got' }] });
return Reflect.get(target, key, proxy);
},
set: (target, key, value, proxy) => {
if (!this.canRun(key))
return true;
if (deepEqual(target[key], value) || (this.options.lenient && target[key] === value) || (!this.options.lenient && target[key] == value))
return true;
let raw = target[key], baseProps = { target, key, value, raw, proxy }, handleType = target[key] === undefined ? 'added' : 'edited';
value = this.deepProxy(value);
if (this.options.accept) {
Reflect.set(target, key, value);
}
!this.keys.set.includes(key) && this.keys.set.push(key);
super.listen({ name: 'crud', params: [{ ...baseProps, type: 'set' }] });
super.listen({ name: 'set', params: [{ ...baseProps, type: 'set' }] });
super.listen({ name: handleType, params: [{ ...baseProps, type: handleType }] });
super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'set' }] });
this.reactCount++;
this.complete(this.reactCount);
return true;
},
delete: (target, key) => {
if (!this.canRun(key))
return true;
let value = target[key], baseProps = { target, key, value, raw: value };
if (this.options.accept) {
Reflect.deleteProperty(target, key);
}
!this.keys.deleted.includes(key) && this.keys.deleted.push(key);
super.listen({ name: 'deleted', params: [{ ...baseProps, type: 'deleted' }] });
super.listen({ name: 'crud', params: [{ ...baseProps, type: 'deleted' }] });
super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'deleted' }] });
this.reactCount++;
this.complete(this.reactCount);
return true;
},
construct: (target, args, proxy) => {
let baseProps = { target, args, proxy };
super.listen({ name: 'constructed', params: [{ ...baseProps, type: 'constructed' }] });
super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'constructed' }] });
this.reactCount++;
this.complete(this.reactCount);
return Reflect.construct(target, args, proxy);
},
apply: (target, pointer, args) => {
let baseProps = { target, pointer, args };
super.listen({ name: 'applied', params: [{ ...baseProps, type: 'applied' }] });
super.listen({ name: 'trigger', params: [{ ...baseProps, type: 'applied' }] });
this.reactCount++;
this.complete(this.reactCount);
return Reflect.apply(target, pointer, args);
}
};
this.methods = {};
for (let k in this.fullMethods) {
let key = k === 'delete' ? 'deleteProperty' : k;
this.methods[key] = this.fullMethods[k];
}
this.types = isEmpty(this.options.types) ? ['Object', 'Array', 'Function', 'Class'] : this.options.types;
this.dataType = getDataType(this.targetData);
if (!this.types.includes(this.dataType)) {
console.warn(`The target data type should be an ${this.types.join('/')}, but failed to proxy the data!`);
this.proxy = this.targetData;
}
else {
this.hostProxy = this.options.deep.enable ? this.deepProxy(this.targetData) : this.addProxy(this.targetData);
this.proxy = this.hostProxy;
}
super.listen({ name: 'initiated', cb });
return this;
}
deepProxy(data) {
let dateType = getDataType(data);
if (this.canDeep(dateType, data)) {
for (let k in data) {
if (!this.hasProp(k))
continue;
let val = data[k], valType = getDataType(val);
if (data.hasOwnProperty(k) && this.canDeep(valType, val)) {
data[k] = this.deepProxy(val);
}
}
return this.addProxy(data);
}
return data;
}
addProxy(obj) {
if (obj['_isProxy']) {
this.proxys.push(obj);
return obj;
}
else {
let revProxy = Proxy.revocable(obj, this.methods);
this.proxys.push(revProxy);
return revProxy.proxy;
}
}
complete(nowReact) {
setTimeout(() => {
if (nowReact === this.reactCount) {
if (this.options.once && this.completedCount !== 0)
return;
for (let i in this.keys) {
this.keys[i] = unique(this.keys[i].filter((k) => typeof k !== 'symbol'));
}
super.listen({ name: 'completed', params: [{ count: this.completedCount, target: this.targetData, proxy: this.hostProxy, keys: this.keys, type: 'completed' }] });
this.completedCount++;
this.keys = { got: [], set: [], deleted: [] };
}
}, 0);
}
destroy() {
this.proxys.forEach((k) => {
k.revoke();
});
}
}
class ModBaseListenCache extends ModBaseListen {
storKeys = [];
storObs;
storTmp;
createProxy() {
this.storTmp = {};
this.storObs = new Observe(this.storTmp);
}
clearCache(cb) {
if (this.options.storName) {
for (let k in this.storObs.proxy) {
Reflect.deleteProperty(this.storObs.proxy, k);
}
this.listen && this.listen({ name: 'clearedCache', cb });
this.save();
}
return this;
}
updateCache(value, cb) {
if (this.options.storName && !isEmpty(value)) {
let temp = {};
for (let k in value) {
value.hasOwnProperty(k) && this.storKeys.includes(k) && (temp[k] = value[k]);
}
deepMerge(this.storObs.proxy, temp, {});
this.listen && this.listen({ name: 'updatedCache', cb });
this.save();
}
return this;
}
optsMergeStorage() {
if (this.options.storName) {
let storageVal = storage.get(this.options.storName);
if (!isEmpty(storageVal)) {
this.updateCache(storageVal);
extend({ target: this.options, source: storageVal });
}
else {
this.clearCache();
}
}
}
save(cb) {
if (this.destroyed || !this.options.storName)
return;
let value = !isEmpty(this.storTmp) ? deepClone(this.storTmp) : {};
storage.set(this.options.storName, value);
this.listen && this.listen({ name: 'saved', cb, params: [value] });
return this;
}
}
const bulletTools = {
getIBulletTpl: (global = {}) => {
return `
{{let value = this.value?'value="'+ this.value +'"':this.label?'value="'+ this.label +'"':'',
custom =this.custom?'<span ${ax.alias}="custom">'+this.custom+'</span>':'',
badge = this.badge?'<ax-badge>'+this.badge+'</ax-badge>':'',
tips =this.tips?'<i ${ax.alias}="tips">'+this.tips+'</i>':'',
arrow=this.arrow?'<i class="'+this.arrow+'" ${ax.alias}="arrow"></i>':'',
type = this.type || "${global.type}",
check = this.checked && !['checkboxes','radios'].includes(type) ?'checked':'',
name = this.name?'name="'+this.name+'"':'name="${ax.namePfx}${Date.now()}"',
icon = this.icon?'<i ${ax.alias}="icon" class="'+this.icon+'"></i>':'',
disk = this.disk?'<span ${ax.alias}="disk"><img src="'+this.disk+'"></span>':'',
cube = this.cube?'<span ${ax.alias}="cube"><img src="'+this.cube+'"></span>':'',
selected=this.selected?'selected':'',
active=this.active?'active':'',
disabled=this.disabled?'disabled':'';
/}}
<${global.childNode}>
<div class="${ax.prefix}bullet" ${global.unpadded ? 'unpadded' : ''} ${global.hoverable ? 'hoverable' : ''} ${global.multiline ? 'multiline' : ''} {{value}} {{selected}} {{active}} {{check}} {{disabled}}>
{{icon}}
{{disk}}
{{cube}}
<div class="${ax.prefix}bullet-body">
{{if(type ==='checkboxes'){/}}
<ax-checkbox {{name}} {{this.checked?'check="ed"':''}} {{value}}>{{this.label}}</ax-checkbox>
{{}else if (type ==='radios'){/}}
<ax-radio {{name}} {{this.checked?'check="ed"':''}} {{value}}>{{this.label}}</ax-radio>
{{}else if(this.href){/}}
<a ${ax.alias}="label" href="{{this.href}}" {{this.target?'target="'+ this.target +'"':''}} {{this.rel?'rel="'+ this.rel +'"':''}}>{{this.label}}</a>
{{}else{/}}
<span ${ax.alias}="label">{{this.label}}</span>
{{}/}}
</div>
{{custom}}
{{badge}}
{{tips}}
{{arrow}}
</div>
${global.divisible ? '<hr>' : ''}
</${global.childNode}>
`;
},
getBulletsTpl: function (global = {}) {
let grid = '';
if (global.cols > 0) {
grid = `${ax.prefix}grid ${ax.prefix}avg-${global.cols}`;
grid += global.lines === 'fence' ? ` ${ax.prefix}fence` : global.lines === 'fluid' ? ` ${ax.prefix}fluid` : '';
}
return `
<${global.parentNode} class="${ax.prefix}reset ${grid}">
{{for(let k of this){/}}
${this.getIBulletTpl(global).replaceAll('this.', 'k.')}
{{}/}}
</${global.parentNode}>`;
},
getChildNodes: (parent) => {
let target = getEl(parent);
if (isEmpty(target)) {
return [];
}
return getEls(`.${ax.prefix}bullet`, target);
},
getChecked: function (nodes) {
let result = [];
if (isEmpty(nodes))
return '';
if (nodes.length > 0) {
if (nodes[0].querySelector('input')) {
for (let k of nodes) {
let input = k.querySelector('input');
input.checked && result.push(input.value);
}
}
else {
for (let k of nodes)
k.hasAttribute('checked') && result.push(k.getAttribute('value'));
}
}
return result.filter(Boolean).join(',');
},
setChecked: function (vals, nodes) {
let dataType = getDataType(vals), values = [];
if (dataType === 'Array') {
values = vals;
}
else if (dataType === 'String') {
values = vals.split(',').filter(Boolean);
}
if (nodes.length === 0)
return;
if (values.length === 0) {
for (let k of nodes) {
let input = k.querySelector('AX-CHECKBOX,AX-RADIO');
input ? input.removeAttribute('check') : k.removeAttribute('checked');
}
}
else {
let checkedItems = values.map((k) => nodes.find((i) => i?.querySelector('input')?.value == k || i.getAttribute('value') == k)).filter(Boolean);
for (let k of nodes) {
let input = k.querySelector('AX-CHECKBOX,AX-RADIO');
if (checkedItems.includes(k)) {
input ? input.setAttribute('check', 'ed') : k.toggleAttribute('checked', true);
}
else {
input ? input.removeAttribute('check') : k.removeAttribute('checked');
}
}
}
},
toggleChecked: (item, els, type = 'select-single') => {
if (!item || !type.includes('select') || isEmpty(els))
return;
let checked = item.hasAttribute('checked');
type = type || 'select-single';
if (type === 'select-single') {
if (checked) {
return;
}
else {
item.toggleAttribute('checked', true);
els.filter((k) => k !== item && item.hasAttribute('checked')).forEach((k) => {
k.removeAttribute('checked');
});
}
}
else {
checked ? item.removeAttribute('checked') : item.toggleAttribute('checked', true);
}
},
clearChecked: (els) => {
if (isEmpty(els))
return;
for (let k of els) {
let input = k.querySelector('AX-CHECKBOX,AX-RADIO');
input ? input.removeAttribute('check') : k.removeAttribute('checked');
}
},
toggleSelected(item, els) {
if (!item || isEmpty(els))
return;
let selected = item.hasAttribute('selected');
if (!selected) {
item.toggleAttribute('selected', true);
let other = els.find((k) => k !== item && k.hasAttribute('selected'));
other && other.toggleAttribute('selected', false);
}
},
setSelected(value, els) {
if (!value || isEmpty(els))
return;
let item = els.find((k) => k.getAttribute('value') === value);
item && this.toggleSelected(item, els);
},
getSelected(els) {
if (isEmpty(els))
return;
let item = els.find((k) => k.hasAttribute('selected'));
return item && item.getAttribute('value') || '';
},
clearSelected(els) {
let item = els.find((k) => k.hasAttribute('selected'));
item && item.removeAttribute('selected');
}
};
const createBtns = (data, parent, settings = {}, refer) => {
let target = getEl(parent), wrapEl = createEl('div', { class: `${ax.prefix}box-btns` }), map = {
submit: {
name: 'submit',
label: config.lang.button.submit,
},
reset: {
name: 'reset',
label: config.lang.button.reset,
},
prev: {
name: 'prev',
label: config.lang.button.prev,
},
next: {
name: 'next',
label: config.lang.button.next,
},
now: {
name: 'now',
label: config.lang.button.now,
},
close: {
name: 'close',
label: config.lang.button.close,
},
cancel: {
name: 'cancel',
label: config.lang.button.cancel,
},
clear: {
name: 'clear',
label: config.lang.button.clear,
},
confirm: {
name: 'confirm',
label: config.lang.button.confirm,
},
}, keys = Object.keys(map), render = (props) => {
let dft = {
label: Object.keys(config.lang.button).includes(props.name) && !props.label ? config.lang.button[props.name] : (props.label || config.lang.button.default)
}, setProp = (type) => { type && !isNull(props[type]) && (dft[type] = props[type]); }, propArr = ['type', 'theme', 'size', 'width', 'shape', 'check', 'icon', 'tail', 'disk', 'cube', 'tips', 'mean', 'disabled', 'shaded', 'grad'];
for (let k of propArr)
setProp(k);
props.name && (dft[ax.alias] = props.name);
props.hasOwnProperty('badge') && (dft.badge = props.badge);
!isNull(props.href) && (dft.href = props.href);
props.target && !isNull(props.href) && (dft.target = props.target);
props.rel && !isNull(props.href) && (dft.rel = props.rel);
props.el = createEl('ax-btn', Object.assign({ ...settings }, dft, props.attrs));
!isEmpty(props.classes) && (classes(props.el).add(props.classes));
!isEmpty(props.styles) && (props.el.style.cssText += props.styles);
};
data.forEach((k, i) => {
let type = k?.name || k, result = keys.includes(type) ? extend({ target: { ...map[type] }, source: k.hasOwnProperty('name') ? k : {} }) : k;
render(result);
wrapEl.appendChild(result.el);
result.action && (refer ? result.action.call(refer, result) : result.action(result));
data[i] = result;
});
if (target) {
let tmp = target.querySelector(`.${ax.prefix}box-btns`);
tmp && tmp.remove();
target.appendChild(wrapEl);
}
return wrapEl;
};
const createFooter = ({ nodeName = 'div', layout = 'center', attrs, tips = false, divider = false, padding = false, children = [] }, parent, refer) => {
divider = spreadBool(divider, {});
padding = spreadBool(padding, {});
tips = spreadBool(tips, { html: config.lang.placehold.tips });
let target = getEl(parent), outer, footerEl = createEl(nodeName, Object.assign({ class: `${ax.prefix}bubble-footer`, layout }, attrs)), dividerEl = divider.enable ? createEl(divider.nodeName || 'ax-line', Object.assign({ [ax.alias]: 'divider' }, divider.attrs)) : null, paddingEl = padding.enable ? createEl(padding.nodeName || 'div', Object.assign({ class: `${ax.prefix}p`, [ax.alias]: 'padding' }, padding.attrs)) : null, tipsEl = tips.enable ? createEl(tips.nodeName || 'div', Object.assign({ [ax.alias]: 'tips' }, tips.attrs), tips.html) : null, wrapEl = createEl('div', { class: `${ax.prefix}bubble-footer-wrap` });
footerEl.setAttribute('layout', layout);
dividerEl && footerEl.appendChild(dividerEl);
paddingEl ? (footerEl.appendChild(paddingEl), outer = paddingEl) : (outer = footerEl);
outer.appendChild(wrapEl);
if (children.length > 0) {
createBtns(children, wrapEl, layout === 'plain' ? { type: 'plain' } : {}, refer);
}
tipsEl && wrapEl.appendChild(tipsEl);
if (target) {
let tmp = target.querySelector(`.${ax.prefix}bubble-footer`);
tmp && tmp.remove();
target.appendChild(footerEl);
}
return footerEl;
};
const createTools = (data, parent, refer) => {
let target = getEl(parent), toolsEl = createEl('span', { class: `${ax.prefix}box-tools` }), tipsIns, map = {
add: {
name: 'add',
icon: `${ax.prefix}icon-plus`,
},
close: {
name: 'close',
icon: `${ax.prefix}icon-close`,
},
remove: {
name: 'remove',
icon: `${ax.prefix}icon-trash`,
},
edit: {
name: 'edit',
icon: `${ax.prefix}icon-edit`,
},
copy: {
name: 'copy',
icon: `${ax.prefix}icon-copy`,
},
update: {
name: 'update',
icon: `${ax.prefix}icon-refresh`,
},
move: {
name: 'move',
icon: `${ax.prefix}icon-drag`,
},
file: {
name: 'file',
icon: `${ax.prefix}icon-file`,
},
folder: {
name: 'folder',
icon: `${ax.prefix}icon-folder`,
},
toggle: {
name: 'toggle',
icon: `${ax.prefix}icon-max`,
swap: `${ax.prefix}icon-min`,
},
enlarge: {
name: 'enlarge',
icon: `${ax.prefix}icon-expand`,
swap: `${ax.prefix}icon-collapse`,
},
widen: {
name: 'widen',
icon: `${ax.prefix}icon-expand-h`,
swap: `${ax.prefix}icon-collapse-h`,
},
heighten: {
name: 'heighten',
icon: `${ax.prefix}icon-expand-v`,
swap: `${ax.prefix}icon-collapse-v`,
},
play: {
name: 'play',
icon: `${ax.prefix}icon-play-o`,
swap: `${ax.prefix}icon-pause-o`,
},
zoomin: {
name: 'zoomin',
icon: `${ax.prefix}icon-zoomin`,
},
zoomout: {
name: 'zoomout',
icon: `${ax.prefix}icon-zoomout`,
},
zoom: {
name: 'zoom',
icon: `${ax.prefix}icon-zoom`,
},
fullscr: {
name: 'fullscr',
icon: `${ax.prefix}icon-bigger`,
swap: `${ax.prefix}icon-smaller`,
},
flipv: {
name: 'flipv',
icon: `${ax.prefix}icon-flip-v`,
},
fliph: {
name: 'fliph',
icon: `${ax.prefix}icon-flip-h`,
},
rotatel: {
name: 'rotatel',
icon: `${ax.prefix}icon-rotate-left`,
},
rotater: {
name: 'rotater',
icon: `${ax.prefix}icon-rotate-right`,
},
download: {
name: 'download',
icon: `${ax.prefix}icon-download`,
},
share: {
name: 'share',
icon: `${ax.prefix}icon-share`,
},
thumb: {
name: 'thumb',
icon: `${ax.prefix}icon-thumb`,
},
more: {
name: 'more',
icon: `${ax.prefix}icon-plus-s`,
swap: `${ax.prefix}icon-minus-s`,
},
}, keys = Object.keys(map), renderFn = (props) => {
let dft = {}, arrow = props.extendable ? `<i ${ax.alias}="arrow"></i>` : '', iconStr = props.icon ? `<i class="${props.icon}" ${ax.alias}="icon"></i>` : '', diskStr = props.disk ? `<i ${ax.alias}="disk"><img src="${props.disk}"/></i>` : '', cubeStr = props.cube ? `<i ${ax.alias}="cube"><img src="${props.cube}"/></i>` : '', imageStr = props.image ? `<i ${ax.alias}="image"><img src="${props.image}"/></i>` : '', label = props.label ? `<i ${ax.alias}="label">${props.label}</i>` : '', html = iconStr + diskStr + cubeStr + imageStr + label + arrow;
props.name && (dft[ax.alias] = props.name);
props.title && (dft.title = props.title);
props.focusable && (dft.tabindex = 1);
props.wrapEl = createEl(props.nodeName || 'span', Object.assign(dft, props.attrs), html);
props.iconEl = props.wrapEl.querySelector(`[${ax.alias}="icon"]`);
props.cubeEl = props.wrapEl.querySelector(`[${ax.alias}="cube"]`);
props.diskEl = props.wrapEl.querySelector(`[${ax.alias}="disk"]`);
props.imageEl = props.wrapEl.querySelector(`[${ax.alias}="image"]`);
props.labelEl = props.wrapEl.querySelector(`[${ax.alias}="label"]`);
!isEmpty(props.classes) && classes(props.wrapEl).add(props.classes);
!isEmpty(props.styles) && (props.wrapEl.style.cssText += props.styles);
};
data.forEach((k, i) => {
let type = k?.name || k, result = keys.includes(type) ? Object.assign(map[type], k.name ? k : {}) : k;
renderFn(result);
toolsEl.appendChild(result.wrapEl);
result.action && (refer ? result.action.call(refer, result) : result.action(result));
data[i] = result;
});
if (target) {
let tmp = target.querySelector(`.${ax.prefix}box-tools`);
tmp && tmp.remove();
target.appendChild(toolsEl);
}
let needTooltip = data.find((k) => k.tips);
if (needTooltip) {
toolsEl.tooltipTgr = 'pointermove';
toolsEl.tooltipEvt = function () {
let item = data.find((k) => k.wrapEl === this);
if (item) {
tipsIns.replaceCont(item.tips);
tipsIns.transfer(this);
}
};
let loadModule = async () => {
let Mod = await Promise.resolve().then(function () { return Tooltip$1; });
tipsIns = new Mod.default(needTooltip.wrapEl, {
content: '',
size: '',
placement: 'top',
});
for (let k of data) {
if (!k.tips)
continue;
k.wrapEl.addEventListener(toolsEl.tooltipTgr, toolsEl.tooltipEvt, false);
}
};
loadModule();
}
return toolsEl;
};
const clampVal = ({ val = 0, min = 0, max = 100 }) => {
let tmpVal = toNumber(val), tmpMin = toNumber(min), tmpMax = toNumber(max), result = (!['', null, undefined].includes(min) && tmpVal < tmpMin) ? tmpMin :
(!['', null, undefined].includes(max) && tmpVal > tmpMax) ? tmpMax : tmpVal;
return result;
};
const isCompField = (type) => !type || typeof type !== 'string' ? false : fieldTypes.includes(type.toLowerCase().replace('ax-', ''));
const fieldTools = {
getType: (target) => {
let targetEl = getEl(target), result = '';
if (!targetEl) {
return result;
}
result = (['TEXTAREA', 'SELECT', 'INPUT'].includes(targetEl.nodeName)) ? 'native' :
isCompField(targetEl.nodeName) && targetEl[ax.compSign] ? 'comp' : 'other';
return result;
},
getVals: function ({ target, format = '', parent, separator = ',', child, key }) {
let targetEl = getEl(target), targetType = this.getType(targetEl), values = [], none = format === 'array' ? [] : format === 'string' ? '' : null, result;
try {
if (targetEl) {
let nodeName = targetEl.nodeName, fieldType = targetEl.type, fields = [], parentEl = getEl(parent) || targetEl.closest('form') || document.body;
if (targetType === 'comp') {
if (['AX-CHECKBOX', 'AX-RADIO'].includes(nodeName)) {
fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k[ax.compSign]);
for (let k of fields)
k.checked && k.value && values.push(k.value);
result = format === 'array' ? values : values.join(separator);
}
else {
let tmp = targetEl.value;
result = format === 'array' ? tmp.split(separator) : tmp;
}
}
else if (targetType === 'native') {
if (nodeName === 'SELECT') {
for (let k of [...targetEl.options]) {
k.selected && values.push(k.value || k.getAttribute('label') || '');
}
}
else if (fieldType === 'file') {
values = [...targetEl.files];
}
else if (['checkbox', 'radio'].includes(fieldType)) {
fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)];
for (let k of fields)
k.checked && k.value && values.push(k.value);
}
else {
values = targetEl.value ? [targetEl.value] : [];
}
if (format === 'string') {
result = (fieldType === 'file') ? values.map((k) => k.name.trim()).join(separator) : values.join(separator);
}
else if (format === 'array') {
result = values;
}
else {
result = (nodeName === 'SELECT' && targetEl.multiple) || (fieldType === 'checkbox' && fields.length > 1) || (fieldType === 'file' && targetEl.multiple) ? values : (values[0] || '');
}
}
else {
let childEl = getEl(child, targetEl), hostEl = childEl || targetEl, tmp = key ? hostEl.getAttribute(key) : hostEl.textContent;
result = format === 'array' ? tmp.split(separator) : tmp;
}
return result;
}
}
catch (err) {
console.warn(err);
return none;
}
},
setVals: function ({ target, value, parent, separator = ',', child, key = '' }) {
let targetEl = getEl(target), values = isEmpty(value) ? [] : valToArr(value, separator).map((k) => k + ''), parentEl = getEl(parent) || targetEl?.closest('form') || document.body, fields = [];
if (targetEl) {
let targetType = this.getType(targetEl);
if (targetType === 'comp') {
let value = values.join(separator);
if (['AX-CHECKBOXES', 'AX-RADIOS'].includes(targetEl.nodeName)) {
targetEl.setAttribute('checked', value);
}
else if (['AX-CHECKBOX', 'AX-RADIO'].includes(targetEl.nodeName)) {
let fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k[ax.compSign] && k.getAttribute('value'));
for (let k of fields) {
values.includes(k.value) ? k.setAttribute('check', 'ed') : k.removeAttribute('check');
}
}
else {
targetEl.setAttribute('value', value);
}
}
else if (targetType === 'native') {
let nodeName = targetEl.nodeName, fieldType = targetEl.type;
if (nodeName === 'SELECT') {
let options = [...targetEl.options], tmp = values.map((k) => k.toString());
options.forEach((k) => {
let value = k.value || k.getAttribute('label') || '';
k.selected = tmp.includes(value) ? true : false;
});
fields = [targetEl];
}
else if (['checkbox', 'radio'].includes(fieldType)) {
fields = [...parentEl.querySelectorAll(`[name="${targetEl.name}"]`)].filter((k) => k.getAttribute('value'));
let tmp = values.map((k) => k.toString());
fields.forEach((k) => {
k.checked = tmp.includes(k.value) ? true : false;
});
}
else if (fieldType === 'file') {
targetEl.value = '';
console.warn('The field.files property cannot be changed through scripts,this operation is performed by resetting!');
}
else if (fieldType === 'number') {
targetEl.value = clampVal({
val: values[0] || 0,
min: targetEl.min,
max: targetEl.max
});
}
else if (fieldType === 'range') {
targetEl.value = values[0] || targetEl.min || 0;
}
else {
targetEl.value = values.filter(Boolean).join();
}
}
else {
let childEl = getEl(child, targetEl), hostEl = childEl || targetEl;
key ? hostEl.setAttribute(key, value) : hostEl.innerHTML = value;
}
}
},
reset: function ({ target, parent, zero = false }) {
let fieldEl = getEl(target);
if (!fieldEl) {
return;
}
let fielType = this.getType(fieldEl), type = fieldEl.type;
if (fielType === 'native') {
if (type?.includes('select')) {
[...fieldEl?.options].forEach((i) => i.selected = !zero ? i.defaultSelected : false);
}
else if (type === 'checkbox' || type === 'radio') {
let parentEl = getEl(parent) || fieldEl?.closest('form') || document.body, fields = [...parentEl.querySelectorAll(`[name="${fieldEl?.name}"]`)];
fields.forEach((k) => {
k.checked = !zero ? k.defaultChecked : false;
});
}
else if (['number', 'range'].includes(type)) {
fieldEl.value = !zero ? fieldEl?.defaultValue : (fieldEl?.min || 0);
}
else {
fieldEl.value = !zero ? fieldEl?.defaultValue : '';
}
}
else if (fielType === 'comp') {
zero ? fieldEl.clear() : fieldEl.reset();
}
else {
if (zero && fieldEl.clear) {
fieldEl.clear();
}
else if (!zero && fieldEl.reset) {
fieldEl.reset();
}
}
}
};
const tplToEl = (tpl) => {
tpl = tpl.trim().replaceAll('<', '<').replaceAll('>', '>');
if (!tpl)
return null;
let node = '';
if (tpl.startsWith('<tr') || tpl.startsWith('<TR')) {
node = 'tr';
tpl = `<table><tbody>${tpl}</tbody></table>`;
}
else if (tpl.startsWith('<td') || tpl.startsWith('<TD')) {
node = 'td';
tpl = `<table><tbody><tr>${tpl}</tr></tbody></table>`;
}
let tplNode = createEl('TEMPLATE', '', tpl), clone = tplNode.content.cloneNode(true), elem = node ? clone.querySelector(node) : clone.firstElementChild;
return elem || null;
};
const optMessage = [
{
attr: 'heading',
prop: 'heading',
value: '',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'placement',
prop: 'placement',
value: 'center-top',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'status',
prop: 'status',
value: 'info',
},
{
attr: 'delay',
prop: 'delay',
value: 3000,
},
{
attr: 'progress',
prop: 'progress',
value: true,
},
{
attr: 'closable',
prop: 'closable',
value: true,
},
{
attr: 'manual',
prop: 'manual',
value: false,
},
{
attr: 'eager',
prop: 'eager',
value: false,
},
{
attr: 'icon-show',
prop: 'iconShow',
value: false,
},
{
attr: 'notable',
prop: 'notable',
value: false,
},
{
attr: 'z-index',
prop: 'zIndex',
value: 0,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-hidden',
prop: 'onHidden',
value: null,
},
...optBase
];
const getHeights = (elem) => {
let target = getEl(elem);
if (!target) {
throw new Error('The target node does not exist!');
}
let styles = style(target);
return {
height: parseInt(styles.height),
paddingTop: parseInt(styles.paddingTop),
paddingBottom: parseInt(styles.paddingBottom),
marginTop: parseInt(styles.marginTop),
marginBottom: parseInt(styles.marginBottom),
borderTopWidth: parseInt(styles.borderTopWidth),
borderBottomWidth: parseInt(styles.borderBottomWidth),
};
};
const curveFns = {
linear: (t) => t,
ease: (t) => ((1 - t) ** 2) * t * 3 * 0.3 + (t ** 2) * (1 - t) * 3 * 1 + t ** 3,
easeIn: (t) => (t ** 2) * (1 - t) * 3 * 0.2 + t ** 3,
easeOut: (t) => ((1 - t) ** 2) * t * 3 * 0.8 + (t ** 2) * (1 - t) * 3 * 1 + t ** 3,
easeInOut: (t) => t < 0.5 ? Math.sqrt(0.5 * t) : -Math.sqrt(0.5 * (-t + 1)) + 1,
easeOutIn: (t) => t < 0.5 ? 2 * t ** 2 : -2 * (t - 1) ** 2 + 1,
};
let ease = ({ from, to, before, doing, done, progress, duration, curve }) => {
if (!from || !to)
throw new Error('from and to are required!');
let initTime = Date.now(), result = { step: 0, value: { ...from }, frame: 0, remaining: 0 }, repeat = () => {
let dftTime = duration || 500, newTime = Date.now() - initTime, ratio = newTime / dftTime, step = curveFns[curve || 'easeOut'](ratio), value = { ...from }, remaining = dftTime - newTime, frame = requestAnimationFrame(repeat);
for (let k in from) {
from.hasOwnProperty(k) && from[k] !== to[k] ? value[k] = from[k] + (to[k] - from[k]) * step : null;
}
result = { step, frame, value, remaining };
ax.frame = frame;
if (ratio < 1) {
progress && progress(result);
doing && doing(result);
}
else {
cancelAnimationFrame(frame);
result.step = 1;
result.value = { ...to };
result.remaining = 0;
progress && progress(result);
done && done(result);
}
};
before && before(result);
repeat();
return result;
};
const getAutoDur = (val) => isNull(val) ? 200 : ~~(parseFloat(val) / 3 + 250);
let slideDown = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
let state = elState(target);
if (state.isHidden) {
let rawStyle = target.style.cssText, dftCss = `${rawStyle}display: ${display};`, startCss = `${dftCss}${cut ? 'overflow:hidden;' : ''}`;
target.style.cssText = startCss;
let { height, paddingTop, paddingBottom, marginTop, marginBottom } = getHeights(target), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(height);
target.style.cssText += `padding-top: 0; padding-bottom: 0;margin-top: 0; margin-bottom: 0;`;
ease({
from: { height: 0, paddingTop: 0, paddingBottom: 0, marginTop: 0, marginBottom: 0 },
to: { height, paddingTop, paddingBottom, marginTop, marginBottom },
duration: time,
curve,
before: (e) => {
before && before.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'show' });
},
doing: (e) => {
target.style.cssText = `
${startCss}
padding-top: ${e.value.paddingTop}px;
padding-bottom: ${e.value.paddingBottom}px;
margin-top: ${e.value.marginTop}px;
margin-bottom: ${e.value.marginBottom}px;
height: ${e.value.height}px
`;
doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step, target, for: 'show' });
}, done: (e) => {
target.style.cssText = dftCss;
done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step, target, for: 'show' });
}
});
}
else if (state.isVirtual) {
target.style.display = display;
done && done.call(target);
}
return target;
};
let slideUp = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
let state = elState(target);
if (state.isCalc) {
let rawStyle = target.style.cssText, { height, paddingTop, paddingBottom, marginTop, marginBottom } = getHeights(target), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(height), dftCss = `${rawStyle}display: ${display};`, startCss = `${dftCss}${cut ? 'overflow:hidden;' : ''}`;
target.style.cssText = `${startCss}padding-top: 0; padding-bottom: 0;margin-top: 0; margin-bottom: 0;`;
ease({
from: { height, paddingTop, paddingBottom, marginTop, marginBottom },
to: { height: 0, paddingTop: 0, paddingBottom: 0, marginTop: 0, marginBottom: 0 },
duration: time,
curve,
before: (e) => {
before && before.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
},
doing: (e) => {
target.style.cssText = `
${startCss}
padding-top: ${e.value.paddingTop}px;
padding-bottom: ${e.value.paddingBottom}px;
margin-top: ${e.value.marginTop}px;
margin-bottom: ${e.value.marginBottom}px;
height: ${e.value.height}px
`;
doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
}, done: (e) => {
target.style.cssText = `${rawStyle}display: none`;
done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step, for: 'hide' });
}
});
}
else if (state.isVirtual) {
target.style.display = 'none';
done && done.call(target);
}
return target;
};
const setAttr = (el, key, value) => {
let elem = getEl(el), valType = getDataType(value), result;
if (!elem || !key)
return;
if (isNull(value) || value === false) {
elem.removeAttribute(key);
result = { key, value: isNull(value) ? null : false };
}
else {
if (valType === 'Boolean' && value === true) {
elem.toggleAttribute(key, true);
result = { key, value: true };
}
else if (valType === 'String') {
elem.setAttribute(key, value);
result = { key, value };
}
else {
elem.setAttribute(key, JSON.stringify(value));
result = { key, value: elem.getAttribute(key) };
}
}
return result;
};
const setAttrs = (el, data, cb) => {
let elem = getEl(el), result = [];
if (!elem || isEmpty(data))
return;
if (!Array.isArray(data) && !data.hasOwnProperty('key') && !data.hasOwnProperty('value')) {
for (let k in data)
result.push(setAttr(elem, k, data[k]));
}
else {
let tmp = Array.isArray(data) ? data : [data];
for (let k of tmp)
result.push(setAttr(elem, k.key, k.value));
}
cb && cb(result.filter(Boolean));
};
const getAttrBool = (val) => {
return (val === 'true' || val === '') ? true : false;
};
const getAttrArr = (val, dft = '') => {
let result = [];
if (val !== null) {
let tmp = val.trim();
try {
if (tmp === '' || tmp === 'true') {
dft && (result = dft.split(',').filter(Boolean));
}
else {
let val = parseStr({
content: tmp,
type: 'array',
catchable: true,
});
result = Array.isArray(val) ? val : [tmp];
}
}
catch (err) {
result = tmp.split(',');
}
}
return result;
};
class CompBase extends HTMLElement {
shadowEl;
slotEl;
propsRaw;
properties;
propsProxy;
propsObs;
custAttrs;
boolAttrs;
reset;
clear;
wrapEl;
plans;
connected;
set;
timestamp;
connCount;
rawHtml;
canListen;
sourceEl;
ins;
constructor() {
super();
this.properties = {};
this.propsRaw = {};
this[ax.compSign] = true;
this.plans = {};
this.timestamp = Date.now();
this.connCount = 0;
this.createPropsObs();
this.canListen = true;
this.getRawCont();
}
connectedCallback() {
this.connectedRender();
}
disconnectedCallback() {
this.listen({ name: 'disconnected' });
}
adoptedCallback() {
this.listen({ name: 'adopted' });
}
static lazyAttrs = ['stor-name', 'class'];
static baseAttrs = ['on-connected', 'on-disconnected', 'on-adopted', 'on-reset', 'on-set'];
static jsonAttrs = ['lang'];
static boolAttrs = [];
createShadow() {
this.shadowEl = this.attachShadow({ mode: "open" });
this.slotEl = createEl('slot');
this.shadowEl.appendChild(this.slotEl);
}
saveProps(name, newVal, comp) {
this.propsProxy[name] = comp.boolAttrs.includes(name) ? getAttrBool(newVal) : comp.jsonAttrs.includes(name) ? strToJson(newVal) : newVal;
}
savePropsToListen(name, oldVal, newVal, comp, other) {
if (other && Object.keys(other).includes(name)) {
this.propsProxy[name] = other[name];
}
else {
this.saveProps(name, newVal, comp);
}
this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
}
getRawProps(comp, opts) {
for (let k of [...comp.custAttrs, ...comp.lazyAttrs])
this.propsRaw[k] = this.getAttribute(k);
for (let k of comp.boolAttrs)
this.propsRaw[k] = getAttrBool(this.getAttribute(k));
for (let k of comp.jsonAttrs)
this.propsRaw[k] = strToJson(this.getAttribute(k));
}
getProxyProps() {
for (let k in this.propsRaw)
this.propsProxy[k] = this.propsRaw[k];
}
restoreAttrs() {
for (let k in this.propsProxy) {
let valProxy = this.propsProxy[k], valRaw = this.propsRaw[k];
if (valProxy !== valRaw) {
if (isNull(valRaw)) {
this.removeAttribute(k);
}
else if (valRaw === true) {
this.setAttribute(k, '');
}
else if (valRaw === false) {
this.removeAttribute(k);
}
else {
this.setAttribute(k, valRaw);
}
}
}
}
getHtmlVal(name = 'label', unformatted = true) {
let val = unformatted ? this.textContent?.trim() : this.innerHTML;
return val || this.getAttribute(name);
}
connectedRender(data) {
this.render(data);
this.connected = true;
this.listen({ name: 'connected', params: [this.ins] });
this.connCount++;
}
getConnCont(format = 'html') {
let tmp = createEl('div', null, this.rawHtml);
return format === 'text' ? tmp.textContent : this.rawHtml;
}
getRawCont() {
if (!this.connCount) {
let tmp = this.querySelector(`:scope>[${ax.alias}="source"]`);
if (tmp) {
this.rawHtml = tmp.innerHTML;
}
else {
this.sourceEl = createEl('template', { [ax.alias]: 'source' });
this.sourceEl.innerHTML = this.rawHtml = this.innerHTML;
}
}
}
insertSource() {
let tmpSourceEl = this.sourceEl || this.querySelector(`:scope>[${ax.alias}="source"]`);
this.innerHTML = tmpSourceEl?.outerHTML || '';
}
createPropsObs() {
this.propsObs = new Observe(this.properties, { deep: true });
this.propsProxy = this.propsObs.proxy;
}
updateProxy(name, newVal, map) {
let value;
if (newVal === null) {
this.propsProxy[name] = this.ins.rawOpts[name];
}
else {
if (name === 'options') {
value = strToJson(newVal);
}
else if (name === 'async') {
value = getAttrBool(newVal);
}
else {
if (!map)
throw new Error(`Setting ${name} is invalid , Please use a module and set the map for options!`);
value = attrJoinVal(name, newVal, map);
}
deepMerge(this.propsProxy, value, {});
}
}
getAttrHtmlData(data) {
let arr, getStr = (str) => {
let tmp = createEl('div', null, str), script = tmp.querySelector('script[type="content"]');
return (script?.innerHTML || str).replace(/\n/g, '').trim();
};
if (isEmpty(data)) {
let attrCont = this.getAttribute('content');
arr = attrCont ? getAttrArr(attrCont) : getAttrArr(getStr(this.rawHtml));
}
else {
arr = Array.isArray(data) ? data : getAttrArr(getStr(data));
}
return arr;
}
changedMaps = {};
}
class CompBaseComm extends CompBase {
constructor() {
super();
this.reset = function () {
this.innerHTML = '';
this.fillWrap(this.propsRaw);
this.restoreAttrs();
this.render(this.propsRaw);
this.listen({ name: 'reset' });
};
this.clear = (attr = 'value') => {
this.removeAttribute(attr);
this.listen({ name: 'cleared', params: [attr] });
};
this.set = (data) => {
if (isEmpty(data))
return;
let tmp = (typeof data === 'string') ? strToJson(data) : data;
setAttrs(this, tmp, (resp) => {
this.listen({ name: 'set', params: [resp] });
});
};
this.on('disconnected', () => {
this.connCount = 0;
this.innerHTML = this.rawHtml;
});
this.on('adopted', () => {
this.connCount = 0;
this.innerHTML = this.rawHtml;
});
this.on('connected', () => {
this.setAttribute(ax.compSign, '');
this.setCache();
});
this.on('reset', () => {
this.clearCache();
});
this.propsObs.on('set', (data) => {
this.connected && this.updateCache({ [data.key]: data.value });
});
}
completedEvt(data) {
this.ins.update(this.properties);
this.listen({ name: 'updated', params: [this.properties] });
}
listen({ name, params = [], cb } = {}) {
name && this.plans.hasOwnProperty(name) ? this.emit(name, ...params) : null;
if (name && this.propsProxy[`on-${name.toLowerCase()}`]) {
let value = this.propsProxy[`on-${name.toLowerCase()}`], addFnShell = (str) => {
let tmp = str.trim(), result = (!(tmp.startsWith('function') || tmp.startsWith('(')) && !tmp.endsWith('}')) ? `function(){${str}}` : str;
return result;
}, fn = parseStr({
content: addFnShell(value),
type: 'other',
method: 'new Function'
});
fn && fn.call(this, ...params);
}
cb && cb.call(this, ...params);
}
on(type, handler) {
plan.add(type, this, handler);
return this;
}
emit(type, ...params) {
plan.do(type, this, ...params);
return this;
}
off(type, handler) {
plan.remove(type, this, handler);
return this;
}
setCache() {
let storName = this.propsProxy['stor-name'], cache = storage.get(storName);
if (!storName || !cache)
return;
let copyCache = deepClone(cache), dataCache = copyCache['data'], hasData = copyCache.hasOwnProperty('data');
if (hasData) {
dataCache ? setAttr(this, 'data', dataCache) : this.removeAttribute('data');
Reflect.deleteProperty(copyCache, 'data');
}
for (let k in copyCache) {
setAttr(this, k, copyCache[k]);
}
}
updateCache(data) {
let storName = this.propsProxy['stor-name'];
if (!storName)
return;
let cache = storage.get(storName) || {};
Object.assign(cache, data);
storage.set(storName, cache);
}
clearCache() {
let storName = this.propsProxy['stor-name'];
if (!storName)
return;
storage.clear(storName);
}
}
class ResultElem extends CompBaseComm {
iconEl;
labelEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['to', 'shape', 'type', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, ResultElem);
}
getRawData() {
this.getRawProps(ResultElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('span', { [ax.alias]: 'wrap' });
this.iconEl = createEl('i', { [ax.alias]: 'icon' }, icons.svg.info);
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label || '');
this.wrapEl.appendChild(this.iconEl);
data.label && this.wrapEl.appendChild(this.labelEl);
}
getIcon(data) {
let result = '';
if (!data.to) {
result = icons.svg.info;
}
else {
if (!data.type || data.type === 'svg') {
result = icons.svg[data.to];
}
else if (data.type === 'font') {
let icon = data.to + (data.shape === 'thick' ? '-t' : data.shape === 'fill' ? '-f' : '');
result = icons.font[icon];
}
}
return result;
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
type: this.changedIcon,
to: this.changedIcon,
shape: this.changedIcon,
};
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal || '';
elState(this.labelEl).isVirtual && this.wrapEl.appendChild(this.labelEl);
}
else {
this.labelEl.remove();
}
}
changedIcon(opt) {
let content = this.getIcon(this.propsProxy);
content && (this.iconEl.innerHTML = content);
}
}
const optProgress = [
{
attr: 'type',
prop: 'type',
value: 'line',
},
{
attr: 'theme',
prop: 'theme',
value: '',
},
{
attr: 'gradient',
prop: 'gradient',
value: false
},
{
attr: 'linecap',
prop: 'linecap',
value: 'round',
},
{
attr: 'size',
prop: 'size',
value: '',
},
{
attr: 'thk',
prop: 'thk',
value: '',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'range',
prop: 'range',
value: [0, 100],
},
{
attr: 'value',
prop: 'value',
value: 0,
},
{
attr: 'curve',
prop: 'curve',
value: 'easeOut',
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'rotate',
prop: 'rotate',
value: false,
},
{
attr: 'simple',
prop: 'simple',
value: false,
},
{
attr: 'control',
prop: 'control',
value: false,
},
{
attr: 'steps',
prop: 'steps',
value: [],
},
{
attr: 'label',
prop: 'label',
value: {
enable: true,
template: '',
placement: '',
unit: '%',
tips: false,
},
},
{
attr: 'number',
prop: 'number',
value: {
type: 'percent',
trunc: true,
emphatic: false,
},
},
{
attr: 'b4-set',
prop: 'b4Set',
value: null,
},
{
attr: 'on-start',
prop: 'onStart',
value: null,
},
{
attr: 'on-move',
prop: 'onMove',
value: null,
},
{
attr: 'on-end',
prop: 'onEnd',
value: null,
},
{
attr: 'on-zero',
prop: 'onZero',
value: null,
},
{
attr: 'on-completed',
prop: 'onCompleted',
value: null,
},
{
attr: 'on-set',
prop: 'onSet',
value: null,
},
{
attr: 'on-pause',
prop: 'onPause',
value: null,
},
{
attr: 'on-continue',
prop: 'onContinue',
value: null,
},
{
attr: 'on-restored',
prop: 'onRestored',
value: null,
},
...optBase
];
const splitNum = (value) => {
let num = value.toString().split('.'), str = `<s>${num[0]}</s>`;
!isNull(num[1]) && (str += `<u>.${num[1]}</u>`);
return `<span class="${ax.prefix}splitnum">${str}</span>`;
};
class Progress extends ModBaseListenCache {
options = {};
vals;
valNow;
barNow;
range;
barSize;
steps;
completeEl;
textEl;
controlEl;
obsIns;
obs;
labelTpl;
trackEl;
wrapEl;
barEl;
labelEl;
numEl;
unitEl;
tipsEl;
animFrame;
durRest;
initVals;
startVals;
endVals;
toggleCtrl;
static hostType = 'node';
static optMaps = optProgress;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Progress.optMaps,
host: elem,
component: true,
spread: ['label']
});
this.vals = {};
this.valNow = 0;
this.barNow = 0;
this.toggleCtrl = () => {
this.controlEl.classList.contains(`${ax.prefix}icon-pause`) ? this.pause() : this.continue();
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.range = [...this.options.range].sort((a, b) => a - b);
this.barSize = this.options.type === 'circle' ? 251.2 : this.options.type === 'semicircle' ? 125.6 : this.options.type === 'gapcircle' ? 167.6 : this.range[1];
this.steps = this.options.steps.length ? [...this.options.steps].sort((a, b) => b.value - a.value) : [];
this.getInitVals();
this.completeEl = createEl('span', { [ax.alias]: 'complete' }, this.options.lang.complete);
this.textEl = createEl('div', { [ax.alias]: 'text' });
this.controlEl = createEl('i', { [ax.alias]: 'control', class: `${ax.prefix}icon-pause`, disabled: '' });
this.controlEl.addEventListener('click', this.toggleCtrl, false);
this.setObs();
this.render();
this.setAttrs();
this.watchEnds();
this.watchSteps();
super.listen({ name: 'initiated', cb });
return this;
}
setObs() {
this.obsIns = new Observe({ paused: false, completed: false }, {
onSet: (resp) => {
if (resp.key === 'paused') ;
else if (resp.key === 'completed') {
if (resp.value) {
this.targetEl.setAttribute('completed', '');
this.labelEl ? this.labelEl.appendChild(this.completeEl) : null;
}
else {
this.completeEl.remove();
this.targetEl.removeAttribute('completed');
}
}
}
});
this.obs = this.obsIns.proxy;
}
setControl(pause, disabled) {
if (pause) {
classes(this.controlEl).replace(`${ax.prefix}icon-pause`, `${ax.prefix}icon-play`);
}
else {
classes(this.controlEl).replace(`${ax.prefix}icon-play`, `${ax.prefix}icon-pause`);
}
if (disabled) {
this.controlEl.setAttribute('disabled', '');
}
else {
this.controlEl.removeAttribute('disabled');
}
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}progress`);
this.targetEl.setAttribute('linecap', this.options.linecap);
this.targetEl.setAttribute('type', this.options.type);
this.options.thk ? this.targetEl.setAttribute('thk', this.options.thk) : this.targetEl.removeAttribute('thk');
this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
this.options.theme ? this.targetEl.setAttribute('theme', this.options.theme) : this.targetEl.removeAttribute('theme');
this.targetEl.toggleAttribute('gradient', this.options.gradient);
this.targetEl.toggleAttribute('simple', this.options.simple);
this.options.classes && classes(this.targetEl).add(this.options.classes);
let tmp = [`${ax.prefix}rotate360`, `${ax.prefix}loop-inf`];
(this.options.rotate && this.options.type === 'circle') ? this.wrapEl.classList.add(...tmp) : this.wrapEl.classList.remove(...tmp);
}
getInitVals() {
this.vals = this.getVals();
this.valNow = this.vals.val;
this.barNow = this.vals.bar;
this.initVals = { ...this.vals };
this.startVals = {
val: this.range[0],
bar: this.barSize,
ratio: 0,
percent: 0,
number: this.getNumber(this.range[0], 0),
};
this.endVals = {
val: this.range[1],
bar: 0,
ratio: 1,
percent: 100,
number: this.getNumber(this.range[1], 100),
};
}
getVal(val = this.vals.val) {
return isNull(val) ? this.range[0] : clampVal({ val, min: this.range[0], max: this.range[1] });
}
getBarVal(val) {
let result;
if (val == this.range[0]) {
result = this.barSize;
}
else if (val == this.range[1]) {
result = 0;
}
else {
let value, ratio, tmp;
if (isNull(val)) {
value = this.vals.val;
ratio = this.vals.ratio;
}
else {
value = clampVal({ val: val, min: this.range[0], max: this.range[1] });
ratio = this.getRatio(value);
}
tmp = (this.options.type == 'line') ? (value - this.range[0]) : (this.barSize * (1 - ratio));
result = toNumber(tmp, { mode: 'floor' });
}
return result;
}
getRatio(val = this.vals.val) {
let result;
if (val == this.range[1]) {
result = 1;
}
else if (val == this.range[0]) {
result = 0;
}
else {
result = toNumber((val - this.range[0]) / (this.range[1] - this.range[0]), { places: 4, mode: 'floor' });
}
return result;
}
getNumber(value, percent) {
let tmp = this.options.number.type === 'value' ? value : percent, val = this.options.number.trunc ? ~~tmp : toNumber(tmp, { places: 2, mode: 'floor', zero: true }), result = this.options.number.emphatic ? splitNum(val) : val;
return result;
}
getVals(val = this.options.value) {
let value = this.getVal(val), ratio = this.getRatio(value), percent = ratio * 100, barVal = this.getBarVal(value), number = this.getNumber(value, percent);
return {
val: value,
bar: barVal,
ratio,
percent,
number,
};
}
render() {
this.targetEl.innerHTML = '';
this.labelTpl = this.options.label.template || `<div ${ax.alias}=label><div ${ax.alias}=result><i ${ax.alias}=number></i><i ${ax.alias}=unit></i></div></div>`;
if (this.options.type == 'line') {
this.trackEl = createEl('div', { [ax.alias]: 'track' });
this.wrapEl = this.trackEl;
this.barEl = createEl('div', { [ax.alias]: 'bar', 'style': `width:${this.vals.percent}%` });
this.wrapEl.appendChild(this.barEl);
}
else {
let gradient = '', svg = '';
if (this.options.gradient) {
if (this.options.theme == 'prim') {
gradient = `
<linearGradient id="svgbar-prim" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-prim);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-prim-aj);" ></stop>
</linearGradient>
`;
}
else if (this.options.theme == 'error') {
gradient = `
<linearGradient id="svgbar-error" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-error);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-error-aj);" ></stop>
</linearGradient>
`;
}
else if (this.options.theme == 'succ') {
gradient = `
<linearGradient id="svgbar-succ" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-succ);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-succ-aj);" ></stop>
</linearGradient>
`;
}
else if (this.options.theme == 'warn') {
gradient = `
<linearGradient id="svgbar-warn" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-warn);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-warn-aj);" ></stop>
</linearGradient>
`;
}
else if (this.options.theme == 'info') {
gradient = `
<linearGradient id="svgbar-info" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-info);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-info-aj);" ></stop>
</linearGradient>
`;
}
else if (this.options.theme == 'issue') {
gradient = `
<linearGradient id="svgbar-issue" >
<stop offset="0%" style="stop-color:var(--${ax.prefix}c-issue);" ></stop>
<stop offset="100%" style="stop-color:var(--${ax.prefix}c-issue-aj);"></stop>
</linearGradient>
`;
}
}
if (this.options.type == 'circle') {
svg = `<svg viewBox="0 0 100 100">
${gradient}
${!this.options.simple ? `<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0 a 40 40 0 1 1 -80 0" ${ax.alias}="track"></path>` : ''}
<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0 a 40 40 0 1 1 -80 0" ${ax.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap} stroke-dashoffset=${this.vals.bar}></path>
</svg>
`;
}
else if (this.options.type == 'semicircle') {
svg = `<svg viewBox="0 0 100 60">
${gradient}
${!this.options.simple ? `<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0" ${ax.alias}="track" stroke-linecap=${this.options.linecap}></path>` : ''}
<path d="M 50 50 m -40 0 a 40 40 0 1 1 80 0" ${ax.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap} stroke-dashoffset=${this.vals.bar}></path>
</svg>
`;
}
else if (this.options.type == 'gapcircle') {
svg = `<svg viewBox="0 0 100 80">
${gradient}
${!this.options.simple ? `<path d="M15.367,70.026C11.954,64.137,10,57.296,10,49.999 C10,27.909,27.909,10,50,10c22.092,0,40,17.909,40,39.999c0,7.295-1.952,14.134-5.363,20.022" ${ax.alias}="track" stroke-linecap=${this.options.linecap}></path>` : ''}
<path d="M15.367,70.026C11.954,64.137,10,57.296,10,49.999 C10,27.909,27.909,10,50,10c22.092,0,40,17.909,40,39.999c0,7.295-1.952,14.134-5.363,20.022" ${ax.alias}="bar" stroke-dasharray=${this.barSize} stroke-linecap=${this.options.linecap} stroke-dashoffset=${this.vals.bar}></path>
</svg>
`;
}
this.wrapEl = tplToEl(svg);
this.barEl = this.wrapEl.querySelector(`[${ax.alias}="bar"]`);
this.trackEl = this.wrapEl.querySelector(`[${ax.alias}="track"]`);
}
this.targetEl.appendChild(this.wrapEl);
this.targetEl.appendChild(this.textEl);
if (this.options.label.enable) {
if (!this.options.label.placement) {
this.textEl.insertAdjacentHTML('beforeEnd', this.labelTpl);
this.labelEl = this.targetEl.querySelector(`[${ax.alias}="label"]`);
}
else {
let place = getEl(this.options.label.placement);
if (place) {
place.insertAdjacentHTML('beforeEnd', this.labelTpl);
this.labelEl = place.querySelector(`[${ax.alias}="label"]`);
}
}
this.numEl = this.labelEl.querySelector(`[${ax.alias}="number"]`);
this.unitEl = this.labelEl.querySelector(`[${ax.alias}="unit"]`);
this.numEl && (this.numEl.innerHTML = this.vals.number);
this.unitEl && (this.unitEl.innerHTML = this.options.label.unit);
if (this.options.label.tips) {
if (!this.labelEl.querySelector(`[${ax.alias}="tips"]`)) {
this.tipsEl = createEl('span', { [ax.alias]: 'tips' }, this.options.lang.tips);
this.labelEl.insertAdjacentElement('afterbegin', this.tipsEl);
}
else {
this.tipsEl = this.labelEl.querySelector(`[${ax.alias}="tips"]`);
this.tipsEl.innerHTML = this.options.lang.tips;
}
}
}
this.options.control && this.textEl.appendChild(this.controlEl);
}
setAnim(val = this.vals.val, duration) {
if (this.obs.paused)
return false;
if (val === this.valNow)
return false;
this.animFrame && cancelAnimationFrame(this.animFrame);
let vals = this.vals, dftTime = (size) => size * 3 + 200, barDiff = vals.bar - this.barNow, time = duration || dftTime(Math.abs(barDiff));
this.setControl(false, false);
ease({
from: { val: this.valNow },
to: { val },
duration: time,
curve: this.options.curve,
before: (resp) => {
super.listen({ name: 'start', params: [{ ...vals }] });
},
progress: (resp) => {
vals = this.getVals(resp.value.val);
this.durRest = resp.remaining;
this.valNow = vals.val;
this.barNow = vals.bar;
if (this.options.type == 'line') {
this.barEl.style.width = vals.percent + '%';
}
else {
this.barEl.setAttribute('stroke-dashoffset', this.barNow);
}
this.numEl && (this.numEl.innerHTML = vals.number);
this.animFrame = resp.frame;
this.watchEnds();
this.watchSteps();
},
doing: (resp) => {
super.listen({ name: 'move', params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
},
done: (resp) => {
this.setControl(false, true);
super.listen({ name: 'end', params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
},
});
}
watchEnds() {
if (this.valNow >= this.range[1]) {
this.obs.completed = true;
super.listen({ name: 'completed' });
}
else {
this.obs.completed = false;
(this.valNow <= this.range[0]) && super.listen({ name: 'zero' });
}
}
watchSteps(val = this.valNow) {
if (!this.steps.length)
return;
let step = this.steps.find((k) => k.value <= val);
if (step) {
if (step.color) {
if (['prim', 'succ', 'error', 'info', 'warn', 'issue', 'text'].includes(step.color)) {
this.targetEl.setAttribute('theme', step.color);
}
else {
if (this.options.type === 'line') {
this.barEl.style.background = step.color;
}
else {
this.barEl.style.stroke = step.color;
}
}
}
step.text && (this.textEl.innerHTML = step.text);
step.action && step.action.call(this, step.value, this.valNow);
}
}
getStepVals(val) {
let result;
if (typeof val === 'string') {
if (val === 'zero') {
result = this.startVals;
}
else if (val === 'completed') {
result = this.endVals;
}
else if (val.includes('/')) {
let splits = val.split('/'), num = ~~splits[0], demom = ~~splits[1], ratio = num / demom, value = (this.range[1] - this.range[0]) * ratio + this.range[0];
result = this.getVals(value);
}
else {
result = this.getVals();
}
}
else if (typeof val === 'number') {
result = this.getVals(val);
}
return result;
}
async animateTo(val, opts = { duration: this.options.duration }) {
if (this.destroyed)
return this;
this.barEl.style.transitionDuration = null;
this.obs.paused = false;
this.vals = typeof val === 'string' ? this.getStepVals(val) : this.getVals(val);
this.options.b4Set && await this.options.b4Set.call(this, this.vals);
if (this.vals.val === this.valNow)
return false;
this.setAnim(this.vals.val, opts?.duration);
super.listen({ name: 'set', cb: opts?.cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
return this;
}
async locateTo(val, opts) {
this.vals = typeof val === 'string' ? this.getStepVals(val) : this.getVals(val);
this.options.b4Set && await this.options.b4Set.call(this, this.vals);
this.animFrame && cancelAnimationFrame(this.animFrame);
this.obs.paused = false;
this.valNow = this.vals.val;
this.barNow = this.vals.bar;
this.numEl && (this.numEl.innerHTML = this.vals.number);
this.barEl.style.transitionDuration = '0ms';
if (this.options.type === 'line') {
this.barEl.style.width = this.vals.percent + '%';
}
else {
this.barEl.setAttribute('stroke-dashoffset', this.barNow);
}
this.watchEnds();
this.watchSteps();
super.listen({ name: 'set', cb: opts?.cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
return this;
}
restore(cb) {
if (this.destroyed)
return this;
this.locateTo('restore');
super.listen({ name: 'restored', cb });
return this;
}
setCompleted(cb) {
if (this.destroyed)
return this;
this.locateTo('completed');
cb && cb.call(this);
return this;
}
setZero(cb) {
if (this.destroyed)
return this;
this.locateTo('zero');
cb && cb.call(this);
return this;
}
continue(duration, cb) {
if (this.destroyed || this.valNow === this.vals.val)
return this;
if (!this.obs.paused)
return false;
this.obs.paused = false;
this.setControl(false, false);
this.setAnim(this.vals.val, duration || this.durRest);
super.listen({ name: 'continue', cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow, durRest: duration || this.durRest }] });
return this;
}
pause(cb) {
if (this.destroyed || this.valNow === this.vals.val)
return this;
if (this.animFrame) {
cancelAnimationFrame(this.animFrame);
this.obs.paused = true;
this.setControl(true, false);
}
super.listen({ name: 'pause', cb, params: [{ ...this.vals, valNow: this.valNow, barNow: this.barNow }] });
return this;
}
get() {
return {
...this.vals,
valNow: this.valNow,
barNow: this.barNow,
completed: this.obs.completed,
paused: this.obs.paused,
durRest: this.durRest || 0,
};
}
destroy(cb) {
if (this.destroyed)
return this;
this.restore();
this.controlEl.removeEventListener('click', this.toggleCtrl);
this.obsIns.ins.destroy();
super.listen({ name: 'destroyed', cb });
return this;
}
}
class ProgressElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optProgress.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'value' || name === 'duration') {
if (!this.connected || !this.ins)
return;
let duration = this.getAttribute('duration'), value = this.getVal(newVal);
duration && (this.ins.options.duration = ~~duration);
if (duration == 0) {
this.ins.locateTo(value);
}
else {
!duration ? this.ins.animateTo(value) : this.ins.animateTo(value, { duration });
}
}
else {
super.updateProxy(name, newVal, optProgress);
}
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new Progress(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
getVal(val) {
return val == 0 ? 0 : ~~val === 0 ? val : parseFloat(val);
}
}
class CalloutElem extends CompBaseComm {
resultEl;
iconEl;
diskEl;
cubeEl;
imageEl;
closeEl;
linkEl;
maskEl;
toolsEl;
captEl;
contEl;
bodyEl;
progEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-result', comp: ResultElem }, { tag: 'ax-progress', comp: ProgressElem }];
static custAttrs = ['theme', 'label', 'icon', 'disk', 'cube', 'image', 'href', 'target', 'rel', 'feature', 'autoclose', 'size', ...this.baseAttrs];
static boolAttrs = ['closable', 'square', 'opaque', 'notable', 'hidden', 'result'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, CalloutElem);
}
getRawData() {
this.getRawProps(CalloutElem);
this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.resultEl = createEl('ax-result');
this.iconEl = createEl('i', { [ax.alias]: 'icon' });
this.diskEl = createEl('i', { [ax.alias]: 'disk' });
this.cubeEl = createEl('i', { [ax.alias]: 'cube' });
this.imageEl = createEl('i', { [ax.alias]: 'image' });
this.closeEl = createEl('span', { [ax.alias]: 'close' }, `<i class="${ax.prefix}icon-close"></i>`);
this.linkEl = createEl('a', { [ax.alias]: 'link' }, `<i class="${ax.prefix}icon-right-up"></i>`);
this.maskEl = createEl('a', { [ax.alias]: 'mask' });
this.toolsEl = createEl('span', { [ax.alias]: 'tools', class: `${ax.prefix}box-tools` });
this.captEl = createEl('div', { [ax.alias]: 'title' });
this.contEl = createEl('div', { [ax.alias]: 'content' }, this.propsProxy.content);
this.bodyEl = createEl('div', { [ax.alias]: 'body' }, this.contEl);
this.progEl = createEl('ax-progress', { [ax.alias]: 'prog', linecap: 'square', thk: 'xs', theme: 'warn', value: '100', label: false });
this.wrapEl.append(this.bodyEl, this.toolsEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.autoclose && this.progEl.setAttribute('value', 0);
this.closeEl.onclick = () => {
this.toggleAttribute('hidden', true);
};
}
changedMaps = {
theme: this.changedTheme,
label: this.changedLabel,
content: this.changedCont,
icon: this.changedIcon,
disk: this.changedDisk,
cube: this.changedDisk,
image: this.changedDisk,
result: this.changedResult,
href: this.changedHref,
ref: this.changedRel,
target: this.changedRel,
closable: this.changedClose,
feature: this.changedFeature,
hidden: this.changedHidden,
autoclose: this.changedAuto,
};
changedTheme(opt) {
this.progEl.setAttribute('theme', opt.newVal || 'warn');
}
changedHidden(opt) {
if (this.propsProxy.hidden) {
slideUp({
el: this,
done: () => {
this.listen({ name: 'hidden' });
}
});
}
else {
slideDown({
el: this,
done: () => {
this.listen({ name: 'shown' });
}
});
}
}
changedLabel(opt) {
if (opt.newVal) {
this.captEl.innerHTML = opt.newVal;
elState(this.captEl).isVirtual && this.contEl.insertAdjacentElement('beforebegin', this.captEl);
}
else {
this.captEl.remove();
}
}
changedCont(opt) {
this.contEl.innerHTML = opt.newVal || '';
}
changedIcon(opt) {
if (opt.newVal) {
this.iconEl.setAttribute('class', opt.newVal);
elState(this.iconEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.iconEl);
}
else {
this.iconEl.remove();
}
}
changedDisk(opt) {
let target = this[opt.name + 'El'];
if (opt.newVal) {
target.innerHTML = `<img src="${opt.newVal}"/>`;
elState(target).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', target);
}
else {
target.remove();
}
}
changedResult(opt) {
if (this.propsProxy.result) {
elState(this.resultEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.resultEl);
this.resultEl.setAttribute('to', this.propsProxy.theme || 'warn');
}
else {
this.resultEl.remove();
}
}
changedHref(opt) {
if (opt.newVal) {
this.maskEl.setAttribute('href', opt.newVal);
this.linkEl.setAttribute('href', opt.newVal);
elState(this.maskEl).isVirtual && this.wrapEl.appendChild(this.maskEl);
elState(this.linkEl).isVirtual && this.toolsEl.insertAdjacentElement('afterbegin', this.linkEl);
}
else {
this.maskEl.remove();
this.linkEl.remove();
}
}
changedRel(opt) {
if (opt.newVal) {
this.maskEl.setAttribute(opt.name, opt.newVal);
this.linkEl.setAttribute(opt.name, opt.newVal);
}
else {
this.maskEl.removeAttribute(opt.name);
this.linkEl.removeAttribute(opt.name);
}
}
changedClose(opt) {
if (this.propsProxy.closable) {
this.toolsEl.appendChild(this.closeEl);
}
else {
this.closeEl.remove();
}
}
changedFeature(opt) {
if (opt.newVal === 'alert') {
this.setAttribute('icon', `${ax.prefix}icon-warn-o-f`);
this.setAttribute('theme', 'warn');
this.toggleAttribute('notable', true);
}
else if (opt.newVal === 'note') {
this.setAttribute('icon', `${ax.prefix}icon-info-o-f`);
this.setAttribute('theme', 'info');
this.toggleAttribute('notable', true);
}
}
changedAuto(opt) {
if (opt.newVal !== null) {
this.progEl.setAttribute('duration', opt.newVal || 3000);
elState(this.progEl).isVirtual && this.wrapEl.appendChild(this.progEl);
this.progEl?.ins?.on('zero', () => {
if (this.progEl.ins.vals.val === 0) {
this.toggleAttribute('hidden', true);
}
}).on('updated', () => {
this.progEl.ins.vals.val = 0;
});
this.onmouseenter = () => {
this.progEl.ins.pause();
};
this.onmouseleave = () => {
this.progEl.ins.continue();
};
this.progEl.setAttribute('value', 0);
}
else {
this.progEl.remove();
}
}
}
class Message extends ModBaseListen {
options = {};
parentEl;
template;
shown;
static hostType = 'none';
static optMaps = optMessage;
static dependencies = [CalloutElem];
constructor(options, initial = true) {
super();
super.ready({
options,
type: Message.hostType,
maps: Message.optMaps,
});
this.parentEl = null;
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.createParent(this.options.placement || 'center-top');
this.createSection();
this.shown = false;
elState(this.parentEl).isVirtual && document.body.appendChild(this.parentEl);
super.listen({ name: 'initiated', cb });
this.options.eager && this.show();
return this;
}
createParent = (placement) => {
let parent = ax.messages.find((k) => k.placement === placement);
if (!parent) {
this.parentEl = createEl('div', { class: `${ax.prefix}message`, placement });
this.options.classes && classes(this.parentEl).add(this.options.classes);
ax.messages.push({ placement, el: this.parentEl });
}
else {
this.parentEl = parent.el;
}
this.options.zIndex && (this.parentEl.style.zIndex = this.options.zIndex);
};
createSection() {
this.template = `
<ax-callout
size="lg"
opaque
hidden
${this.options.notable ? 'notable' : ''}
${this.options.iconShow ? 'result' : ''}
${this.options.closable ? 'closable' : ''}
${this.options.status ? 'theme="' + (this.options.status || 'info') + '"' : ''}
${this.options.heading ? 'label="' + (this.options.heading === true ? this.options.lang.heading[this.options.status] : this.options.heading) + '"' : ''}
${!this.options.progress ? 'noprogress' : ''}
>
${this.options.content === true || this.options.content === '' ? this.options.lang.content[this.options.status] : this.options.content}
</ax-callout>
`;
this.targetEl = tplToEl(this.template);
}
getCloseBtns() {
for (let k of getEls(`[${ax.alias}="closebubble"]`, this.targetEl))
k.onclick = () => this.hide();
}
show(cb) {
if (this.destroyed || this.shown)
return this;
this.parentEl.appendChild(this.targetEl);
this.targetEl.toggleAttribute('hidden', false);
this.getCloseBtns();
this.targetEl.on('hidden', () => {
this.targetEl.remove();
this.shown = false;
super.listen({ name: 'hidden' });
});
this.targetEl.on('shown', () => {
this.shown = true;
super.listen({ name: 'shown' });
});
!this.options.manual && this.targetEl.setAttribute('autoclose', this.options.delay);
return this;
}
hide(cb) {
if (this.destroyed || !this.shown)
return this;
this.targetEl.toggleAttribute('hidden', true);
return this;
}
updateCont(content, cb) {
if (this.destroyed)
return this;
this.targetEl.setAttribute('content', content);
this.getCloseBtns();
super.listen({ name: 'updatedCont', cb, params: [content] });
return this;
}
async update(settings, cb) {
if (this.destroyed)
return this;
this.targetEl.remove();
this.options = extend({ target: this.options, source: settings });
await this.init();
super.listen({ name: 'updated', cb, params: [settings] });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.targetEl.remove();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const combineArr = ({ origin, length = 2, start = 0, splice = [], result = [] }) => {
let arrayLen = origin.length;
if (start + length > arrayLen) {
return [];
}
for (let i = start; i < arrayLen; i++) {
if (length === 1) {
result.push([...splice, origin[i]]);
i + 1 < arrayLen && combineArr({ origin, length, start: i + 1, splice, result });
break;
}
combineArr({ origin, length: length - 1, start: i + 1, splice: [...splice, origin[i]], result });
}
return result || [];
};
const sliceFrags = ({ str = '', start = '{', end = '}', contain = true }) => {
let reg = new RegExp(`\\${start}([^\\${end}]+)\\${end}`, 'g'), arr = str.match(reg) || [];
return (!contain && arr.length > 0) ? arr.map((k) => k.replace(start, '').replace(end, '')) : arr;
};
const toLocalTime = (date) => {
let dateStr, localDate, flag, loacalTime;
if (date) {
date = date.trim();
localDate = new Date(date);
flag = localDate instanceof Date && !isNaN(localDate.getTime());
if (!flag) {
throw new Error('Date format must be "YYYY-MM-DD" or "YYYY/MM/DD"!');
}
dateStr = date.replace(/-/g, "/");
loacalTime = new Date(dateStr).getTime();
}
else {
loacalTime = Date.now();
}
return loacalTime;
};
const validTools = {
test: (value, pattern) => {
if (isEmpty(value) || isEmpty(pattern)) {
return false;
}
return (typeof pattern === 'string' ? new RegExp(pattern) : pattern).test(value);
},
expired: (value, data) => {
let getTime = (v) => typeof v === 'string' ? toLocalTime(v) : v.getTime(), valueTime = getTime(value), dataType = getDataType(data), result = [-2, -2], compare = (a, b) => {
return a < b ? -1 :
a === b ? 0 :
a > b ? 1 : -2;
};
if (isEmpty(value) || isEmpty(data)) {
return result;
}
if (dataType === 'Array' && data.length === 2) {
let dates = data.map((k) => getTime(k)).sort();
result[0] = compare(valueTime, dates[0]);
result[1] = compare(valueTime, dates[1]);
}
else {
let dataTime = getTime(data);
result[0] = compare(valueTime, dataTime);
}
return result;
},
than: (value, data) => {
let result = [-2, -2], dataType = getDataType(data), valueParse = parseFloat(value), dataParse, compare = (a, b) => {
return a < b ? -1 :
a === b ? 0 :
a > b ? 1 : -2;
};
if (dataType === 'Array') {
if (data.length === 2) {
dataParse = data.map((k) => parseFloat(k)).sort();
result[0] = compare(valueParse, dataParse[0]);
result[1] = compare(valueParse, dataParse[1]);
}
}
else {
dataParse = parseFloat(data);
result[0] = compare(valueParse, dataParse);
}
return result;
},
getStrength: (value, data) => {
let datas = Object.assign({ lowerCase: '[a-z]', upperCase: '[A-Z]', digital: '[0-9]', chars: `[${config.valid.regChars}]`, local: `[${config.lang.valid.regLocal}]`, length: config.valid.lengthStr }, data), strength = 0;
if (isEmpty(value) || typeof value !== 'string') {
return strength;
}
for (let k in datas) {
if (k === 'length') {
value.trim().length >= datas[k] ? strength++ : null;
}
else {
if (datas.hasOwnProperty(k) && datas[k]) {
value.match(new RegExp(datas[k])) ? strength++ : null;
}
}
}
return strength;
},
parseLength: (value, raw = '', label = '') => {
let regex = '', text = '', param = { value: raw, label: '' };
if (value) {
let arr = value.replace('{', '').replace('}', '').split(',').map((k) => ~~k);
if (arr.length === 2) {
regex = (arr[1] && arr[1] > arr[0]) ? `{${arr[0]},${arr[1]}}` :
(arr[1] && arr[1] === arr[0]) ? `{${arr[0]}}` : `{${arr[0]},}`;
if (arr[1]) {
if (arr[0] === 0) {
text = renderTpl(config.lang.valid['length<='], { ...param, data: arr[1] });
}
else {
text = renderTpl(config.lang.valid['length>=<='], { ...param, data: arr });
}
}
else {
text = renderTpl(config.lang.valid['length>='], { ...param, data: arr[0] });
}
}
else {
regex = `{${arr[0]}}`;
text = renderTpl(config.lang.valid['length='], { ...param, data: arr[0] });
}
}
return { regex, text };
},
parseSpecific: function (value, data) {
value = trim(value, 'global');
let regex = '', typeStr = value, rangeStr = '', text = '', strData = {}, regTypes = Object.assign({ ...config.lang.valid.types }, data?.types), tplStr = data?.tpl || config.lang.valid.specific, tplData = {};
if (value) {
let rangeTemp = sliceFrags({ str: value });
if (rangeTemp.length > 0) {
rangeStr = rangeTemp[0];
typeStr = value.replace(rangeStr, '');
}
regex = '^';
let arr = typeStr.split('&');
arr.forEach((k) => {
let val = k.split('='), reg = '';
reg = (val[0] === 'a') ? `.*?[a-z]` :
(val[0] === 'A') ? `.*?[A-Z]` :
(val[0] === 'd') ? `.*?[0-9]` :
(val[0] === '~') ? `.*?[${data?.regChars || config.valid.regChars}]` :
(val[0] === '@') ? `.*?[${data?.regLocal || config.lang.valid.regLocal}]` : '';
regex += (reg ? '(?=' + Array((val[1] ? ~~val[1] : 1) + 1).join(reg) + ')' : '');
strData[regTypes[val[0]]] = val[1] || 1;
});
tplData = { label: data?.label || '', name: data?.name || '', value: data?.value || '', data: strData };
regex += `.${this.parseLength(rangeStr, tplData.value).regex || '{0,}'}$`;
text = renderTpl(tplStr, tplData) + (rangeStr ? this.parseLength(rangeStr, tplData.value).text : '');
}
return { regex, text };
},
parseCombine: function (value, data) {
value = trim(value, 'global');
let regChars = data?.regChars || config.valid.regChars, regLocal = data?.regLocal || config.lang.valid.regLocal, regex = '', typeStr = value, rangeStr = '', text = '', strData = { types: [], total: 0 }, regTypes = Object.assign({ ...config.lang.valid.types }, data?.types), tplStr = data?.tpl || config.lang.valid.combine, tplData = {};
if (value) {
let rangeTemp = sliceFrags({ str: value });
if (rangeTemp.length > 0) {
rangeStr = rangeTemp[0];
typeStr = value.replace(rangeStr, '');
}
let arr = typeStr.split(':'), types = ~~arr[1] ? ~~arr[1] : 2, regs = [];
arr[0].includes('a') ? (regs.push('a-z'), strData.types.push(regTypes['a'])) : null;
arr[0].includes('A') ? (regs.push('A-Z'), strData.types.push(regTypes['A'])) : null;
arr[0].includes('d') ? (regs.push('0-9'), strData.types.push(regTypes['d'])) : null;
arr[0].includes('~') ? (regs.push(regChars), strData.types.push(regTypes['~'])) : null;
arr[0].includes('@') ? (regs.push(regLocal), strData.types.push(regTypes['@'])) : null;
types = Math.min(types, regs.length);
if (types === 1) {
regex = `^[${regs.join('')}]`;
}
else {
regex += '^';
combineArr({ origin: regs, length: types - 1 }).forEach((k) => {
regex += `(?![${k.join('')}]+$)`;
});
regex += `[${regs.join('')}]`;
}
strData.total = types;
tplData = { label: data?.label || '', name: data?.name || '', value: data?.value || '', data: strData };
regex += `${this.parseLength(rangeStr, tplData.value).regex || '{0,}'}$`;
text = renderTpl(tplStr, tplData) + (rangeStr ? this.parseLength(rangeStr, tplData.value).text : '');
}
return { regex, text };
},
validForm: async ({ el, fail, succ, intvl = 100 }) => {
let parentEl = getEl(el) || document.body, validItem = ax.valids.find((k) => k.parent === parentEl), children = validItem?.children || [], passed = true, fails = [], loopValid = async () => {
for (let i = 0; i < children.length; i++) {
let v = children[i];
await delay({
duration: intvl * i
}).then(async () => {
await v.ins.do().then((res) => {
!res.passed ? (passed = res.passed, fails.push(v)) : null;
});
});
}
};
if (ax.valids.length === 0 || !validItem) {
new Message({
content: config.lang.valid.message.noValids,
iconShow: true,
status: 'info',
}).show();
return { passed: true, fails: [] };
}
await loopValid().then(() => {
!passed ? (fail && fail(fails)) : (succ && succ());
});
return { passed, fails };
},
listenSubmit: async function ({ item, fail, succ, cb }) {
let allItems = ax.valids, getItems = () => {
let itemType = getDataType(item), result = [];
if (isEmpty(item)) {
result = allItems;
}
else {
if (itemType === 'Array') {
result = item;
}
else {
if (itemType.includes('HTML')) {
result = [allItems.find((k) => k.parent === item)];
}
else if (itemType === 'String') {
let temp = getEl(item);
temp ? result = [allItems.find((k) => k.parent === temp)] : null;
}
else {
result = [item];
}
}
}
return result;
}, usableItems = getItems().filter((k) => k?.parent?.nodeName === 'FORM'), result = { passed: true, fails: [] };
if (usableItems.length > 0) {
for (let k of usableItems) {
if (k.parent?.ax?.hasSubmitListener)
continue;
k.parent.addEventListener('submit', (e) => {
preventDft(e);
this.validForm({
el: k.parent,
fail: (fails) => {
fail && fail(k, fails);
},
succ: (fails) => {
if (succ) {
succ(k, fails);
}
else {
k.parent.submit();
}
}
}).then((resp) => {
result = resp;
cb && cb(k, resp);
});
}, false);
storeNode(k.parent).addData('hasSubmitListener', true);
}
}
return result;
},
factory: async (data) => {
let textSucc = data?.text?.succ || config.lang.valid.succ, textFail = data?.text?.fail || config.lang.valid.fail, result = { passed: true, succ: renderTpl(textSucc, { label: data.label, name: data.name }), fail: renderTpl(textFail, { label: data.label, name: data.name }) };
if (data.rules.length === 0) {
return result;
}
try {
for (let k in data.rules) {
if (data.rules.hasOwnProperty(k)) {
let item = data.rules[k], param = { value: data.value, name: data.name, label: data.label, type: k, ins: data.ins, data: data.ins.types[k] }, output = await item(param), dataType = getDataType(output);
if (dataType === 'Object') {
Object.assign(result, output?.content?.hasOwnProperty('passed') ? output.content : output);
if (!result.passed)
break;
}
else {
throw new Error('Return value is not a standard object : {passed,succ,fail}!');
}
}
}
}
catch (err) {
result.passed = false;
new Message({
status: 'info',
content: config.lang.valid.message.wrongRule,
}).show();
console.error(err);
}
data.cb && data.cb(result);
return result;
}
};
const formTools = {
getName: (item) => {
let field = getEl(item), types = ['file', 'select-multiple', 'checkbox'];
return (types.includes(field.type) && !field.name.endsWith('[]')) ? `${field.name}[]` : field.name;
},
getHosts: (el) => {
let form = getEl(el), condition = (k) => k.name && !k.name.includes(ax.namePfx) && !k.hasAttribute(ax.embedSign);
if (!form)
return [];
return unique([...form.querySelectorAll(`${fieldTypes.map((k) => 'ax-' + k).join()},input:not([type="submit"],[type="reset"]),select,textarea`)].filter(condition), 'name');
},
reset: function (el, zero = false) {
let parentEl = getEl(el), fields = this.getHosts(parentEl);
if (fields.length > 0) {
for (let k of fields) {
fieldTools.reset({ target: k, parent: parentEl, zero });
}
}
},
setVals: function (el, data = {}) {
let parentEl = getEl(el), fields = this.getHosts(parentEl);
if (!parent || fields.length === 0) {
return;
}
if (isEmpty(data))
this.reset(parent, true);
for (let [k, value] of Object.entries(data)) {
let item = fields.find((i) => i.name === k);
item && fieldTools.setVals({ target: item, value, parent });
}
},
getVals: function (el, format = 'array') {
let parentEl = getEl(el), none = format === 'string' ? '' : format === 'json' ? {} : format === 'formdata' ? new FormData() : [], fields = [], items = [], output;
try {
if (parentEl) {
fields = this.getHosts(parentEl);
items = fields.map((k) => {
let value = fieldTools.getVals({ target: k, parent: parentEl }), fullName = k.name + (Array.isArray(value) && !k.name.endsWith('[]') ? '[]' : '');
return { type: k.type, name: k.name, fullName, value };
});
if (format === 'string') {
output = '';
items.forEach((k, i) => {
let symbol = i === 0 ? '' : '&';
if (Array.isArray(k.value)) {
if (k.value.length > 0) {
for (let x of k.value)
output += symbol + k.fullName + '=' + (getDataType(k) === 'File' ? x.name : x);
}
else {
output += symbol + k.fullName + '=';
}
}
else {
output += symbol + k.name + '=' + (getDataType(k.value) === 'File' ? k.value.name : k.value);
}
});
}
else if (format === 'formdata') {
output = new FormData();
for (let k of items) {
if (Array.isArray(k.value)) {
if (k.value.length > 0) {
for (let x of k.value)
output.append(k.fullName, x);
}
}
else {
output.append(k.name, k.value);
}
}
;
}
else if (format === 'json') {
output = {};
for (let k of items)
output[k.name] = k.value;
}
else {
output = items;
}
return output;
}
else {
return none;
}
}
catch {
console.warn('Failed to retrieve data from the form, and empty content has been output!');
return none;
}
},
submit: async function (el, options) {
let formEl = getEl(el);
if (!formEl)
throw new Error('The form node is required!');
let opt = extend({
target: {
type: 'post',
delay: 0,
},
source: options
}), ajaxSubmit = async () => {
if (!opt.url)
throw new Error('The request url is required!');
let btnEl = getEl(opt.button?.selector), btnText = btnEl ? btnEl.innerHTML : '', resume = () => {
formEl?.classList.remove(`${ax.prefix}ajax-mask`);
if (btnEl) {
if (opt?.button?.replace) {
btnEl.removeAttribute('inert');
btnEl.innerHTML = btnText;
}
else {
opt?.button?.attr && btnEl.removeAttribute(opt.button.attr.key);
}
}
};
if (formEl?.classList.contains(`${ax.prefix}ajax-mask`))
return;
await ajax({
url: opt.url,
data: this.getVals(formEl, opt.type === 'get' ? 'string' : 'formdata'),
type: opt.type,
opened: (response) => {
opt.opened && opt.opened(response);
},
before: (response) => {
formEl?.classList.add(`${ax.prefix}ajax-mask`);
if (btnEl) {
if (opt?.button?.replace === 'loading') {
btnEl.innerHTML = response.content;
btnEl.toggleAttribute('inert', true);
}
else if (opt.button?.replace === 'text') {
btnEl.innerHTML = config.lang.ajax.submit.btn;
btnEl.toggleAttribute('inert', true);
}
else {
opt?.button?.attr && btnEl.setAttribute(opt.button.attr.key, opt.button.attr.value);
}
}
opt.before && opt.before(response);
},
success: (response) => {
setTimeout(() => {
resume();
opt.success && opt.success(response);
}, opt.delay);
},
error: (response) => {
resume();
opt.error && opt.error(response);
}
});
}, submitForm = async () => {
if (opt.url) {
ajaxSubmit();
}
else {
formEl?.nodeName === 'FORM' && formEl.submit();
}
}, awaitValid = async () => {
if (opt.valid) {
let resp = await opt.valid();
resp && submitForm();
}
else {
submitForm();
}
}, validItem = ax.valids.find((k) => k.parent === formEl);
if (validItem) {
await validTools.validForm({
el: formEl,
fail: () => {
opt.invalid && opt.invalid();
},
succ: async () => {
await awaitValid();
}
});
}
else {
await awaitValid();
}
}
};
const setContent = ({ content, target, position = 'override', engine, template, prevent }) => {
let contType = getDataType(content), el = getEl(target), result = '';
if (isNull(content))
return;
if (contType.includes('HTML') || contType === 'String' || contType === 'Number') {
result = content;
}
else if (contType === 'Array' || contType === 'Object') {
let tplDom = getEl(template), tplStr = tplDom?.innerHTML || template, tplEng = engine || renderTpl;
if (tplStr && tplEng) {
try {
result = tplEng.name === 'template' ? tplEng(tplStr)(content) : tplEng(tplStr, content);
}
catch (err) {
console.error(err);
}
}
else {
console.warn('Be sure to fill in the template content and template engine!');
}
}
if (!isEmpty(prevent)) {
prevent(result);
}
else {
if (!el)
return;
let valType = getDataType(result);
if (valType.includes('HTML')) {
(position === 'override') ? (el.innerHTML = '', el.appendChild(content)) : el.insertAdjacentElement(position, content);
}
else {
(position === 'override') ? el.innerHTML = result : el.insertAdjacentHTML(position, result);
}
}
};
const createEvt = ({ target, name, cb, options }) => {
let el = getEl(target);
if (!el || !name)
return;
let dft = { cancelable: true, composed: false, bubbles: false }, evt = new CustomEvent(name, Object.assign(dft, options)), fn = function (e) {
cb.call(this, e);
};
cb && el.addEventListener(name, fn);
return {
event: evt,
remove: () => {
cb && el.removeEventListener(name, fn);
}
};
};
class CompBaseCommField extends CompBaseComm {
name;
value;
disabled;
readOnly;
checked;
multiple;
events;
inputEl;
zeroEvt;
evtsArr;
toolsEl;
mediaEl;
constructor() {
super();
this.focus = () => {
this.inputEl.focus();
};
this.blur = () => {
this.inputEl.blur();
};
this.zeroEvt = new Event('input');
this.reset = (cb) => {
for (let k in this.propsRaw) {
(this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
}
this.inputEl && this.inputEl.dispatchEvent(this.zeroEvt);
this.listen({ name: 'reset', cb });
};
this.clear = (cb) => {
if (this.inputEl) {
this.inputEl.value = '';
this.inputEl.dispatchEvent(this.zeroEvt);
}
this.mediaEl && (this.mediaEl.innerHTML = '');
this.listen({ name: 'cleared', cb });
};
this.on('connected', () => {
this.setAttribute(ax.compSign, '');
this.setCache();
});
this.on('reset', () => {
this.clearCache();
});
}
static evtsArr = [...this.baseAttrs, 'on-cleared', 'on-changed',];
connectedCallback() {
if (this.inputEl) {
this.addEvts(['blur', 'focus']);
for (let k in this.events) {
this.inputEl.addEventListener(k, () => {
this.dispatchEvent(this.events[k].event);
});
}
}
this.connectedRender();
}
addEvts(evts) {
this.events = {};
if (isEmpty(evts))
return;
for (let k of evts) {
this.events[k] = createEvt({ target: this, name: k });
}
}
getToolsEl(data) {
if (!isEmpty(data)) {
this.toolsEl = createTools(data, null, this);
this.toolsEl.setAttribute(ax.alias, 'tools');
}
}
setFieldProps(props) {
for (let k of props) {
k === 'name' ? this.name = this.propsProxy.name || '' :
k === 'value' ? this.value = this.propsProxy.value || '' :
k === 'disabled' ? this.disabled = this.propsProxy.disabled || false :
k === 'readOnly' ? this.readOnly = this.propsProxy.readonly || false :
k === 'multiple' ? this.multiple = this.propsProxy.multiple || false :
k === 'check' ? this.checked = (this.propsProxy.check === 'ed' ? true : false) : null;
}
}
getItemsData(data) {
let arr = super.getAttrHtmlData(data);
return this.formatData(arr);
}
formatData(data) {
let itemType = typeof data[0];
if (itemType === 'string') {
return data.map((k) => {
return { label: k, value: k, disabled: false, checked: false };
});
}
else {
return data;
}
}
addScrollable(input) {
let scrolled = input.scrollHeight > input.clientHeight;
this.wrapEl.toggleAttribute('scrollable', scrolled);
}
setValAttr(data, el) {
if (!isNull(data.value)) {
el.value = data.value;
}
else if (isNull(data.value) && data.label) {
el.value = data.label;
}
this.propsProxy.value = this.value = (el.value || data.value);
}
changedMultiDisable(opt) {
let tmp = getAttrArr(opt.newVal);
for (let k of this.inputs) {
if (tmp.includes(k.propsProxy.value)) {
k.setAttribute('disabled', '');
}
else {
k.removeAttribute('disabled');
}
}
}
changedMultiDisabled(opt) {
this.toggleAttribute('disabled', this.propsProxy['disabled']);
this.disabled = this.propsProxy['disabled'];
}
changedMultiName(opt) {
for (let k of this.inputs)
opt.newVal ? k.setAttribute(opt.name, opt.newVal) : k.removeAttribute(opt.name);
if (opt.name === 'name') {
opt.newVal ? this.name = opt.newVal : this.removeAttribute('name');
}
}
changedMultiCont(opt) {
this.updateInputs(opt.newVal);
}
changedSingleDisabled(opt) {
this.inputEl.toggleAttribute('disabled', this.propsProxy.disabled);
this.disabled = this.propsProxy.disabled;
}
changedSingleName(opt) {
opt.newVal ? this.inputEl.name = opt.newVal : this.inputEl.removeAttribute('name');
this.name = this.inputEl.name;
}
changedSingleValue(opt) {
if (opt.newVal === null && !this.propsProxy.label) {
this.propsProxy.value = undefined;
this.value = '';
this.inputEl.removeAttribute('value');
}
else {
this.propsProxy.value = this.value = opt.newVal;
this.inputEl.value = this.value;
}
}
changedSingleLabel(opt) {
this.labelEl.innerHTML = opt.newVal;
if (opt.newVal && isNull(this.propsProxy.value)) {
this.propsProxy.value = this.value = opt.newVal;
this.inputEl.value = this.value;
}
}
changedSingleCheck(opt) {
let oldChecked = opt.oldVal === 'ed' ? true : false;
this.checked = opt.newVal === 'ed' ? true : false;
this.inputEl.checked = this.checked;
this.listen({ name: 'check', params: [{ value: opt.newVal, checked: this.checked }] });
oldChecked !== this.checked && this.listen({ name: 'changed', params: [{ newVal: this.checked, oldVal: !this.checked }] });
}
changedAttrs(opt) {
opt.newVal && (this.inputEl || this.ins?.inputEl) && setAttrs(this.inputEl, strToJson(opt.newVal));
}
}
class RadioElem extends CompBaseCommField {
labelEl;
legendEl;
check;
type;
constructor() {
super();
this.type = 'radio-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.clear = () => {
this.removeAttribute('check');
this.listen({ name: 'cleared' });
};
this.check = (val) => {
this.setAttribute('check', val);
};
}
static custAttrs = ['size', 'value', 'name', 'type', 'check', 'attrs', ...this.evtsArr];
static boolAttrs = ['disabled'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, RadioElem);
}
getRawData() {
this.getRawProps(RadioElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled', 'check']);
}
fillWrap(data) {
this.wrapEl = createEl('label', { [ax.alias]: 'wrap' });
this.inputEl = createEl('input', { type: 'radio', [ax.embedSign]: '' });
this.setValAttr(data, this.inputEl);
data.name && (this.inputEl.name = data.name || '');
this.legendEl = createEl('u');
this.labelEl = createEl('i', '', data.label);
this.wrapEl.append(this.inputEl, this.legendEl, this.labelEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.inputEl.addEventListener('change', (e) => {
this.setAttribute('check', 'ed');
let others = getEls(`ax-radio[name=${this.propsProxy.name}]`, this.closest('form')).filter((k) => k !== this);
others.forEach((k) => {
k.setAttribute('check', '');
});
}, false);
}
changedMaps = {
disabled: this.changedSingleDisabled,
name: this.changedSingleName,
value: this.changedSingleValue,
label: this.changedSingleLabel,
check: this.changedSingleCheck,
attrs: this.changedAttrs,
};
}
class CheckboxElem extends CompBaseCommField {
labelEl;
legendEl;
check;
type;
constructor() {
super();
this.type = 'checkbox-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.clear = () => {
this.removeAttribute('check');
this.listen({ name: 'cleared' });
};
this.check = (val) => {
this.setAttribute('check', val);
};
}
static custAttrs = ['size', 'value', 'type', 'name', 'check', 'attrs', ...this.evtsArr];
static boolAttrs = ['disabled'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, CheckboxElem);
}
getRawData() {
[...CheckboxElem.custAttrs, ...CheckboxElem.lazyAttrs].forEach((k) => {
this.propsRaw[k] = this.getAttribute(k);
});
CheckboxElem.boolAttrs.forEach((k) => {
this.propsRaw[k] = getAttrBool(this.getAttribute(k));
});
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled', 'check']);
}
fillWrap(data) {
this.wrapEl = createEl('label', { [ax.alias]: 'wrap' });
this.inputEl = createEl('input', { type: 'checkbox', [ax.embedSign]: '' });
this.setValAttr(data, this.inputEl);
data.name && (this.inputEl.name = data.name || '');
this.legendEl = createEl('u');
this.labelEl = createEl('i', '', data.label);
this.wrapEl.append(this.inputEl, this.legendEl, this.labelEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.inputEl.addEventListener('change', (e) => {
let val = e.target.checked ? 'ed' : '';
this.setAttribute('check', val);
}, false);
}
changedMaps = {
disabled: this.changedSingleDisabled,
name: this.changedSingleName,
value: this.changedSingleValue,
label: this.changedSingleLabel,
check: this.changedSingleCheck,
lang: this.changedLang,
attrs: this.changedAttrs,
};
changedLang(opt) {
if (this.propsProxy.type !== 'switch')
return;
let trackEl = getEl(':scope > u', this.wrapEl);
this.propsProxy.lang.on ? trackEl.setAttribute('on', this.propsProxy.lang.on) : trackEl.removeAttribute('on');
this.propsProxy.lang.off ? trackEl.setAttribute('off', this.propsProxy.lang.off) : trackEl.removeAttribute('off');
}
}
class BadgeElem extends CompBaseComm {
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['theme', 'type', 'shape', ...this.baseAttrs];
static boolAttrs = ['glassy'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, BadgeElem);
}
getRawData() {
this.getRawProps(BadgeElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, data.label);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
};
changedLabel(opt) {
if (opt.newVal === null) {
this.wrapEl.innerHTML = '';
}
else {
this.wrapEl.innerHTML = opt.newVal;
}
}
}
class ModBaseListenCacheBubble extends ModBaseListenCache {
bubbleType;
positionIns;
hoverIns;
mainEl;
state;
footEl;
data;
submitXhr;
contEl;
template;
wrapEl;
bodyEl;
headEl;
maskEl;
clickOutHideEvt;
triggerClose;
contXhr;
triggerShow;
wings;
cssDur;
duration;
wrapHeight;
leaveTrigger;
static hostType = 'node';
static dependencies = [RadioElem, CheckboxElem, BadgeElem];
formEl = null;
canTrigger = false;
lastShowTime = 0;
bullets = { nodes: [], value: '' };
setEmpty() {
if (this.bubbleType === 'popup') {
this.positionIns && this.positionIns.destroy();
this.hoverIns && this.hoverIns.destroy();
}
this.mainEl && this.mainEl.remove();
this.state = 'hidden';
}
async hide(param) { }
handleFooter() {
if (this.footEl) {
let isBullets = this.options.bullet.enable && ['checkboxes', 'radios', 'select-single', 'select-multi'].includes(this.options.bullet.type);
this.options.footer.children.forEach((k) => {
if (k.name === 'confirm') {
if (k.action) {
k.action.call(this, k);
}
else {
if (!k?.attrs?.href) {
k.el.onclick = async (e) => {
this.options.b4Confirm && await this.options.b4Confirm.call(this, k);
let inputEl = getEl(this.options.autoFill.inputSel) || this.targetEl, childEl = getEl(this.options.autoFill.childSel, inputEl), vals;
if (isCompField(this.options.contType)) {
let value = ['checkbox', 'radio'].includes(this.options.contType) && !this.data.checked ? '' : this.data.value;
this.options.autoFill.enable && inputEl && this.setTargetVals(value, inputEl, childEl);
!this.options.keepShow && this.hide();
vals = value;
}
else if (isBullets) {
if (this.targetEl) {
this.bullets.value = this.getBulletsChecked();
this.setTargetVals(this.bullets.value, this.targetEl, childEl);
}
!this.options.keepShow && this.hide();
vals = this.bullets.value;
}
else {
if (k.event === 'submit') {
if (this.formEl) {
formTools.submit(this.formEl, {
url: k.url,
invalid: () => {
this.listen({ name: 'invalidated' });
},
valid: () => {
this.listen({ name: 'validated' });
return true;
}
});
}
else {
throw new Error('Form node is required!');
}
}
else if (k.event === 'async') {
if (this.formEl && k.url) {
formTools.submit(this.formEl, {
url: k.url,
button: {
selector: k.el,
attr: { key: 'check', value: 'ing' },
},
opened: (resp) => {
this.submitXhr = resp.xhr;
},
invalid: () => {
this.listen({ name: 'invalidated' });
},
valid: () => {
this.listen({ name: 'validated' });
return true;
},
success: (resp) => {
this.listen({ name: 'sended', params: [resp.content] });
}
});
}
else {
throw new Error('The request url and form node are required!');
}
}
else if (k.event === 'prevent') {
preventDft(e);
}
else {
!this.options.keepShow && this.hide();
}
}
this.listen({ name: 'confirmed', cb: k.cb, params: [k, vals] });
};
}
}
}
else if (k.name === 'cancel') {
if (k.action) {
k.action.call(this, k);
}
else {
if (!k?.attrs?.href) {
k.el.onclick = async (e) => {
this.options.b4Cancel && await this.options.b4Cancel.call(this, k);
if (k.event === 'zero') {
this.formEl && formTools.reset(this.formEl, true);
}
else if (k.event === 'reset') {
this.formEl && formTools.reset(this.formEl, false);
}
else if (k.event === 'prevent') {
preventDft(e);
}
else {
!this.options.keepShow && this.hide();
}
this.listen({ name: 'canceled', cb: k.cb, params: [k] });
};
}
}
}
else if (k.name === 'close') {
if (k.action) {
k.action.call(this, k);
}
else {
k.el.onclick = () => {
this.hide();
};
}
this.listen({ name: 'closed', cb: k.cb, params: [k] });
}
else if (k.name === 'clear') {
if (k.action) {
k.action.call(this, k);
}
else {
k.el.onclick = () => {
if (isCompField(this.options.contType)) {
fieldTools.reset({ target: this.data, zero: true });
}
else if (isBullets) {
this.clearBulletsChecked();
}
this.listen({ name: 'cleared', cb: k.cb, params: [k] });
};
}
}
else {
k.action && k.action.call(this, k);
}
});
}
}
getBulletsTpl() {
return !this.options.tplStr && this.options.bullet.enable ? bulletTools.getBulletsTpl(this.options.bullet) : '';
}
handleData(data) {
let result = data;
if (!this.options.bullet.enable)
return result;
if (Array.isArray(data) && typeof data[0] === 'string') {
result = data.map((k) => { return { label: k }; });
}
else if (typeof data === 'string' && !data.includes(`${ax.prefix}bullet-body`)) {
result = data.split(',').filter(Boolean).map((k) => { return { label: k }; });
}
return result;
}
async renderContent(data) {
isEmpty(data) && console.info('No content to insert, proceeding without blocking.');
this.data = this.handleData(data);
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, this.data, this.contEl);
resp && (this.data = resp);
}
this.listen({ name: 'render', params: [this.data] });
let dataType = getDataType(this.data), tplEl = getEl(this.options.tplStr), template = tplEl?.innerHTML || this.options.tplStr || this.getBulletsTpl();
if (dataType.includes('HTML') && ['image', 'iframe', 'audio', 'video'].includes(this.options.contType)) {
this.options.media.title && this.data.insertAdjacentHTML('afterbegin', `<div ${ax.alias}="title">${this.options.media.title}</div>`);
this.options.media.brief && this.data.insertAdjacentHTML('beforeend', `<div ${ax.alias}="brief">${this.options.media.brief}</div>`);
}
setContent({
content: this.data,
target: this.contEl,
engine: this.options.tplEng,
template,
});
this.formEl = this.contEl.querySelector('form');
this.listen({ name: 'rendered', params: [this.data] });
}
renderBubble(name = 'popup') {
this.template = renderTpl(this.getTpl(name), this.options);
this.mainEl = tplToEl(this.template);
this.wrapEl = this.mainEl.querySelector(`.${ax.prefix}${name}-wrap`);
this.contEl = this.mainEl.querySelector(`.${ax.prefix}${name}-cont`);
this.bodyEl = this.mainEl.querySelector(`.${ax.prefix}${name}-body`);
this.headEl = this.mainEl.querySelector(`.${ax.prefix}${name}-head`);
this.footEl = this.mainEl.querySelector(`.${ax.prefix}${name}-foot`);
this.maskEl = this.mainEl.querySelector(`.${ax.prefix}${name}-mask`);
if (this.options.tools.enable) {
createTools(this.options.tools.children, this.wrapEl, this);
}
if (this.footEl) {
if (this.options.footer.layout !== 'plain') {
this.options.footer.children = this.options.footer.children.map((k) => {
if (k === 'confirm') {
return { name: 'confirm', attrs: { theme: 'prim' } };
}
else if (k?.name === 'confirm') {
if (k.attrs) {
!k.attrs.theme && (k.attrs.theme = 'prim');
}
else {
k.attrs = { theme: 'prim' };
}
return k;
}
else {
return k;
}
});
}
createFooter(this.options.footer, this.footEl, this);
}
}
getTpl(name = 'popup') {
return `
{{let noPadding = (this.padding.enable && !this.bullet.enable) || (this.padding.enable && this.bullet.enable && this.bullet.cols>0 && this.bullet.lines==='fluid');/}}
<div class="${ax.prefix}${name}">
{{ if(this?.mask?.enable){ /}}<div class="${ax.prefix}${name}-mask"></div>{{ } /}}
<div class="${ax.prefix}${name}-wrap">
{{ if(this.heading){ /}}
<div class="${ax.prefix}${name}-head">{{ this.heading }}</div>
{{ } /}}
{{ if(this.divider){ /}}
<ax-line></ax-line>
{{ } /}}
<div class="${ax.prefix}${name}-body">
{{ if(this.padding.enable){ /}}
<div class="${ax.prefix}${name}-padding {{ this.padding.value || '${ax.prefix}p' }} ">
{{ }else if(noPadding){ /}}
<div class="${ax.prefix}${name}-padding">
{{ } /}}
<div class="${ax.prefix}${name}-cont"></div>
{{ if(noPadding || this.padding.enable){ /}}
</div>
{{ } /}}
</div>
{{ if((!this.bullet.enable && this.footer.enable) || (this.bullet.enable && ['custom','checkboxes','select-multi'].includes(this.bullet.type) && this.footer.enable)){ /}}
<div class="${ax.prefix}${name}-foot {{ this.footer.layout !=='plain'? this.padding.value || '${ax.prefix}p':'' }} "></div>
{{ } /}}
</div>
</div>
`;
}
initBullets() {
this.on('show', () => {
this.options.autoFill.enable && this.options.autoFill.detectable && this.presetFromTarget();
});
if (!this.options.bullet.enable)
return;
if (this.targetEl) {
isNull(this.targetEl.readOnly) ? this.targetEl.toggleAttribute('readonly', true) : this.targetEl.readOnly = true;
}
this.bullets.nodes = bulletTools.getChildNodes(this.contEl);
if (this.options.autoFill.enable) {
let vals = this.getTargetVals();
bulletTools.setChecked(vals, this.bullets.nodes);
}
let childEl = getEl(this.options.autoFill.childSel, this.targetEl), fill2Hide = () => {
if (this.targetEl) {
this.bullets.value = this.getBulletsChecked();
this.setTargetVals(this.bullets.value, this.targetEl, childEl);
}
this.hide();
};
for (let [i, k] of this.bullets.nodes.entries()) {
if (this.options.bullet.type.includes('select')) {
k.onclick = () => {
bulletTools.toggleChecked(k, this.bullets.nodes, this.options.bullet.type);
(this.options.bullet.type === 'select-single') && fill2Hide();
};
}
else if (this.options.bullet.type === 'radios') {
k.onclick = () => fill2Hide();
}
this.options.bullet.action && this.options.bullet.action.call(this, { el: k, data: Array.isArray(this.data) ? this.data[i] : null });
}
}
presetFromTarget() {
if (!this.options.autoFill.enable)
return;
let vals = this.getTargetVals();
if (isCompField(this.options.contType)) {
let isComp = this.data?.nodeName && this.data.nodeName.startsWith('AX-'), isEqual = vals === this.data.value;
isComp && !isEqual && fieldTools.setVals({ target: this.data, value: vals, key: this.options.autoFill.key });
}
else {
(vals !== this.bullets.value) && bulletTools.setChecked(vals, this.bullets.nodes);
}
}
setBulletsChecked(vals) {
if (!this.options.bullet.enable)
return;
bulletTools.setChecked(vals, this.bullets.nodes);
if (this.options.autoFill.enable && ['radios', 'select-single'].includes(this.options.bullet.type)) {
this.setTargetVals(this.getBulletsChecked());
}
this.listen({ name: 'bulletsChecked', params: [vals] });
}
getBulletsChecked() {
if (!this.options.bullet.enable)
return '';
return bulletTools.getChecked(this.bullets.nodes);
}
toggleBulletsChecked(el, type = 'select-single') {
let target = getEl(el);
if (!target)
return;
bulletTools.toggleChecked(target, this.bullets.nodes, type);
}
clearBulletsChecked() {
bulletTools.clearChecked(this.bullets.nodes);
}
checkedBulletsAll() {
if (['radios', 'select-single'].includes(this.options.bullet.type))
return;
for (let k of this.bullets.nodes) {
let input = k.querySelector('AX-CHECKBOX');
if (input) {
(!k.hasAttribute('disabled') && !input.hasAttribute('disabled')) && input.setAttribute('check', 'ed');
}
else {
!k.hasAttribute('disabled') && k.setAttribute('checked', '');
}
}
}
setBulletsSelected(value) {
bulletTools.setSelected(value, this.bullets.nodes);
this.listen({ name: 'bulletsSelected', params: [value] });
}
getBulletsSelected() {
return bulletTools.getSelected(this.bullets.nodes);
}
clearBulletsSelected() {
bulletTools.clearSelected(this.bullets.nodes);
}
toggleBulletsSelected(el) {
let target = getEl(el);
target && bulletTools.toggleSelected(target, this.bullets.nodes);
}
getTargetVals() {
if (!this.targetEl)
return '';
return fieldTools.getVals({ target: this.targetEl, child: getEl(this.options.autoFill.childSel, this.targetEl), key: this.options.autoFill.key });
}
setTargetVals(value = this.getBulletsChecked(), target = this.targetEl, child = getEl(this.options.autoFill.childSel, this.targetEl)) {
if (!target)
return;
fieldTools.setVals({ target, value, child, key: this.options.autoFill.key });
this.listen({ name: 'targetSet', params: [value] });
}
getDuration() {
let tmp = parseFloat(style(this.bubbleType === 'popup' ? this.mainEl : this.wrapEl).animationDuration) * 1000 || 0;
this.duration = this.options.duration || (this.options.autoDur ? getAutoDur(this.wrapHeight) : tmp);
}
async reset(cb) {
this.options = deepClone(this.dftOpts);
await this.init();
this.clearCache();
this.listen && this.listen({ name: 'reset', cb });
return this;
}
async update(settings, cb) {
if (this.destroyed || isEmpty(settings)) {
return this;
}
if (!isEmpty(settings)) {
this.updateCache(settings);
extend({ target: this.options, source: settings });
if (this.state !== 'ing') {
let tmp = this.state;
await this.init().then((res) => {
tmp === 'shown' && res.show();
});
}
}
this.listen({ name: 'updated', cb, params: [settings] });
return this;
}
async updateCont(content, cb) {
if (this.destroyed || content === this.options.content)
return this;
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.contEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
this.data = this.handleData(data);
this.renderContent(data);
this.updateCache({ content });
this.listen({ name: 'updatedCont', cb, params: [data] });
}
});
return this;
}
replaceCont(content, cb) {
if (this.destroyed)
return this;
let contType = getDataType(content);
contType.includes('HTML') ? (this.contEl.innerHTML = '', this.contEl.appendChild(content)) : (this.contEl.innerHTML = content);
this.listen({ name: 'replacedCont', cb, params: [content] });
}
unbindTrigger(str) {
}
bindTrigger(str) {
}
async transfer(el, cb) {
if (this.destroyed)
return this;
let host = getEl(el);
if (host && host !== this.targetEl) {
let initialized = this.initialized;
if (!initialized) {
this.targetEl = host;
await this.init();
}
else {
this.unbindTrigger('host');
this.targetEl = host;
this.bindTrigger();
}
if (this.bubbleType === 'popup' && initialized) {
this.positionIns.transfer(host, (target) => {
this.listen({ name: 'transferred', cb, params: [target] });
});
}
else {
this.listen({ name: 'transferred', cb, params: [host] });
}
}
return this;
}
addPulseEvt() {
}
removePulseEvt() {
}
destroy(cb) {
if (this.destroyed)
return this;
this.mainEl.remove();
if (this.bubbleType === 'popup') {
this.positionIns && this.positionIns.destroy();
this.hoverIns && this.hoverIns.destroy();
this.clickOutHideEvt && document.removeEventListener('click', this.clickOutHideEvt);
}
if (this.options.trigger === 'click' || this.options.trigger === 'input') {
this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
this.wings.forEach((i) => {
i.removeEventListener(this.options.wing.trigger || this.options.trigger, this.triggerShow);
});
}
if (this.maskEl && this.options.mask.closable) {
this.maskEl.removeEventListener('click', this.triggerShow);
}
this.contEl.querySelectorAll(`[${ax.alias}="closebubble"]`).forEach((k) => {
k.removeEventListener('click', this.triggerClose);
});
if (this.bubbleType === 'dialog' && ['confirm', 'alert'].includes(this.options.feature)) {
this.removePulseEvt();
this.addPulseEvt();
}
this.canTrigger = false;
this.contXhr && this.contXhr.abort();
this.submitXhr && this.submitXhr.abort();
this.leaveTrigger && this.leaveTrigger.cancel();
this.destroyed = true;
this.listen({ name: 'destroyed', cb });
return this;
}
}
class Drawer extends ModBaseListenCacheBubble {
options = {};
parentEl;
sizeProp;
lastSize;
lastPlace;
bubbleType;
timestamp;
lastShowTime;
confirmEl;
cancelEl;
closeEl;
triggerShow;
content;
wrapSize;
sequenceShow;
sequenceHide;
sequenceToggle;
static optMaps = optDrawer;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Drawer.optMaps,
component: true,
spread: ['mask', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
});
this.bubbleType = 'drawer';
this.timestamp = Date.now();
this.lastShowTime = 0;
let _this = this;
this.triggerShow = function (evt) {
if (this === _this.targetEl && _this.options.canClick) {
let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
if (!tmp)
return;
}
if (_this.state === 'hidden') {
_this.show();
(_this.options.wing.actClass && _this.wings.includes(this)) && this.classList.add(_this.options.wing.actClass);
}
else if (_this.state === 'shown') {
!_this.options.keepShow && _this.hide();
}
};
this.triggerClose = () => {
!this.options.keepShow && this.hide();
};
this.sequenceToggle = () => {
this.mainEl.toggleAttribute('show', true);
for (let k of this.getToggleItems())
k.ins.hide();
};
this.sequenceShow = (el, placement) => {
let size = (!el.style[placement]) ? this.options.offset : (parseInt(el.style[placement]) * 0.6 + parseInt(this.options.offset) + 'px');
el.style[placement] = size;
};
this.sequenceHide = (el, placement) => {
if (el.style[placement] == this.options.offset) {
el.style.cssText = el.style.cssText.replace(placement, '');
}
else {
el.style[placement] = (parseInt(el.style[placement]) - parseInt(this.options.offset)) / 0.6 + 'px';
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.options.placement = this.options.placement || 'right';
this.parentEl = getEl(this.options.parent) || document.body;
this.sizeProp = (this.options.placement === 'left' || this.options.placement === 'right') ? 'width' : 'height';
this.wings = getEls(this.options.wing.selector);
this.renderBubble('drawer');
this.setAttrs();
await getContent.call(this, {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.contEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
this.renderContent(data);
}
});
this.lastPlace = '';
this.handleFooter();
this.handleTools();
this.bindTrigger();
this.contEl.querySelectorAll(`[${ax.alias}="closebubble"]`).forEach((k) => {
k.removeEventListener('click', this.triggerClose);
k.addEventListener('click', this.triggerClose, false);
});
this.initBullets();
super.listen({ name: 'initiated', cb });
return this;
}
handleTools() {
if (this.options.tools.enable) {
this.options.tools.children.forEach((k) => {
if (k.name === 'close') {
k.wrapEl.onclick = () => this.hide();
}
else if (['widen', 'heighten', 'enlarge'].includes(k.name)) {
k.wrapEl.onclick = () => {
if (this.lastSize === 'max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.mainEl.setAttribute('size', this.options.size);
this.lastSize = this.options.size;
}
else {
classes(k.iconEl).replace(k.swap, k.icon);
this.mainEl.setAttribute('size', 'max');
this.lastSize = 'max';
}
};
}
else {
k.action && k.action.call(this, k);
}
});
}
}
setAttrs() {
this.options.classes && classes(this.mainEl).add(this.options.classes);
this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
this.contEl.toggleAttribute('dedicated', this.options.dedicated);
this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
if (this.parentEl !== document.body) {
let pStyle = style(this.parentEl);
pStyle.position === 'static' && addStyle(this.parentEl, 'position', 'relative');
pStyle.overflow !== 'hidden' && addStyle(this.parentEl, 'overflow', 'hidden');
this.mainEl.toggleAttribute('restrict', true);
}
else {
this.mainEl.removeAttribute('restrict');
}
}
getBeforeItems() {
return instance.data.filter((k) => k.ins !== this &&
k.type === 'drawer' &&
!k.ins.destroyed &&
k.ins.state === 'shown' &&
k.ins.parentEl === this.parentEl &&
k.ins.options.placement === this.options.placement &&
k.ins.lastShowTime < this.lastShowTime);
}
getToggleItems() {
return instance.data.filter((k) => k.ins !== this &&
k.type === 'drawer' &&
!k.ins.destroyed &&
k.ins.state === 'shown' &&
k.ins.parentEl === this.parentEl);
}
getIngItems() {
return instance.data.filter((k) => k.ins !== this &&
k.type === 'drawer' &&
!k.ins.destroyed &&
k.ins.state === 'ing' &&
k.ins.parentEl === this.parentEl &&
k.ins.options.placement === this.options.placement);
}
bindTrigger() {
if (this.options.trigger === 'click') {
if (this.targetEl && !this.canTrigger) {
this.targetEl.removeEventListener('click', this.triggerShow);
this.targetEl.addEventListener('click', this.triggerShow, false);
}
if (this.wings.length > 0 && !this.canTrigger) {
this.wings.forEach((k) => {
k.removeEventListener('click', this.triggerShow);
k.addEventListener('click', this.triggerShow, false);
});
}
}
else if (this.options.trigger === 'sticky') {
this.show();
}
if (this.maskEl && this.options.mask.closable) {
this.maskEl.removeEventListener('click', this.triggerShow);
this.maskEl.addEventListener('click', this.triggerShow, false);
}
this.canTrigger = true;
}
unbindTrigger(mode = 'host') {
this.canTrigger = false;
if (this.options.trigger === 'click') {
this.targetEl.removeEventListener('click', this.triggerShow);
if (this.wings.length > 0 && mode === 'all') {
this.wings.forEach((item) => {
item.removeEventListener('click', this.triggerShow);
});
}
}
if (this.maskEl && this.options.mask.closable && mode === 'all') {
this.maskEl.removeEventListener('click', this.triggerShow);
}
}
async show(cb) {
if (this.destroyed || this.state !== 'hidden' || this.options.asleep)
return;
if (this.options.multiple && this.getIngItems().length)
return this;
this.state = 'ing';
this.options.b4Show && await this.options.b4Show.call(this);
elState(this.mainEl).isVirtual && this.parentEl.appendChild(this.mainEl);
super.listen({ name: 'show', cb });
this.wrapSize = parseInt(style(this.wrapEl)[this.sizeProp]);
requestAnimationFrame(async () => {
super.getDuration();
this.wrapEl.style.transitionDuration = `${this.duration}ms`;
this.targetEl && this.targetEl.classList.add(this.options.actClass);
this.lastShowTime = Date.now();
if (this.options.multiple) {
for (let k of this.getBeforeItems()) {
this.sequenceShow(k.ins.wrapEl, this.options.placement);
}
}
else {
this.sequenceToggle();
}
this.mainEl.toggleAttribute('show', true);
await delay({
duration: this.duration,
done: () => {
this.state = 'shown';
super.listen({ name: 'shown', cb });
}
});
});
return this;
}
async hide(cb) {
if (this.destroyed || this.state !== 'shown')
return this;
if (this.options.multiple && this.getIngItems().length)
return this;
this.state = 'ing';
if (!this.options.deadShow) {
this.options.b4Hide && await this.options.b4Hide.call(this);
super.listen({ name: 'hide', cb });
this.targetEl && this.targetEl.classList.remove(this.options.actClass);
this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
this.maskEl && (this.maskEl.style.opacity = 0);
this.wrapEl.style[this.options.placement] = '-' + style(this.wrapEl)[this.sizeProp];
for (let k of this.getBeforeItems())
this.sequenceHide(k.ins.wrapEl, this.options.placement);
for (let k of getEls('video,audio', this.mainEl))
k.pause();
await delay({
duration: this.duration,
done: () => {
this.state = 'hidden';
this.mainEl.removeAttribute('show');
this.maskEl && this.maskEl.removeAttribute("style");
this.wrapEl.removeAttribute("style");
this.mainEl.remove();
super.listen({ name: 'hidden', cb });
}
});
}
return this;
}
}
const privacy = ({ content = config.lang.privacy.content, contType, contData, cb }) => {
if (!storage.get('AXUI_GOT_PRIVACY')) {
new Drawer(undefined, {
content,
contType,
contData,
footer: {
children: [
{
name: 'canceled',
label: config.lang.privacy.cancel,
},
{
name: 'confirmed',
label: config.lang.privacy.confirm,
},
]
},
onConfirmed: () => {
storage.set('AXUI_GOT_PRIVACY', true);
cb && cb();
}
}).show();
}
};
const support = (useCont = false, cb) => {
try {
createEl('div').querySelector(':has');
}
catch (e) {
if (useCont && !storage.get('AXUI_GOT_SUPPORT')) {
new Drawer(undefined, {
content: config.lang.support.content,
footer: {
children: [
{
name: 'canceled',
label: config.lang.support.cancel,
},
{
name: 'confirmed',
label: config.lang.support.confirm,
},
]
},
onConfirmed: () => {
storage.set('AXUI_GOT_SUPPORT', true);
cb && cb();
}
}).show();
}
return false;
}
return true;
};
const getSelectorType = (str) => {
requireTypes(str, 'string');
str = str.trim();
let type = '', isUpperCase = (letter) => (letter >= 'A' && letter <= 'Z') ? true : false;
if (str) {
if (str.includes(' ')) {
type = 'nesting';
}
else {
type = (str.startsWith('#') ? 'id' :
str.startsWith('.') ? 'class' :
(str.startsWith('[') && str.endsWith(']')) ? 'attr' :
([...str].every(i => isUpperCase(i))) ? 'node' : '');
}
}
return type;
};
const purifyHtml = (str) => trim(str.replace(/<[^>]+>/g, ''));
const offset = (elem) => {
let totalLeft, totalTop, scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft, scrollTop = document.documentElement.scrollTop || document.body.scrollTop, targetEl = getEl(elem);
if (!targetEl) {
throw new Error(`The target node does not exist!`);
}
totalLeft = targetEl.getBoundingClientRect().left + scrollLeft;
totalTop = targetEl.getBoundingClientRect().top + scrollTop;
return {
left: totalLeft,
top: totalTop
};
};
const tplToEls = (tpl) => {
tpl = tpl.trim().replaceAll('<', '<').replaceAll('>', '>');
if (!tpl)
return [];
let tplNode = createEl('TEMPLATE', '', tpl), clone = tplNode.content.cloneNode(true), firstEl = clone.firstElementChild, result;
if (!firstEl)
return [];
if (firstEl.nodeName === 'TR') {
let trs = [...clone.querySelectorAll('TR')], tmp = tplNode.innerHTML.split('</tr>').map(k => k.replace(/<\/?tr[^>]*>/g, ''));
tmp.shift();
trs.forEach((k, i) => {
k.innerHTML = tmp[i];
});
result = trs;
}
else {
result = [...clone.children];
}
return result;
};
const getWidths = (elem) => {
let target = getEl(elem);
if (!target) {
throw new Error('The target node does not exist!');
}
let styles = style(target);
return {
width: parseInt(styles.width),
paddingLeft: parseInt(styles.paddingLeft),
paddingRight: parseInt(styles.paddingRight),
marginLeft: parseInt(styles.marginLeft),
marginRight: parseInt(styles.marginRight),
borderLeftWidth: parseInt(styles.borderLeftWidth),
borderRightWidth: parseInt(styles.borderRightWidth),
};
};
const getElSpace = (target, axis = 'y') => {
let el = getEl(target), tmp;
if (!el)
return 0;
if (axis === 'x') {
tmp = getWidths(el);
return el.offsetWidth + tmp.marginLeft + tmp.marginRight;
}
else {
tmp = getHeights(el);
return el.offsetHeight + tmp.marginTop + tmp.marginBottom;
}
};
let slideToggle = ({ el, display = 'block', before, doing, done, duration, curve = 'easeOut', cut = true }) => {
let target = getEl(el);
if (!target)
throw new Error('The target node does not exist!');
if (elState(target).isHidden) {
slideDown({ el: target, display, duration, curve, cut, before, doing: doing?.down, done: done?.down });
}
else if (elState(target).isCalc) {
slideUp({ el: target, display, duration, curve, cut, before, doing: doing?.up, done: done?.up });
}
return target;
};
let easeHeight = ({ el, height, type = 'down', doing, done, duration, curve = 'easeOut', cut = true, unaware = true }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
let canDo = !unaware || (unaware && elState(target).isCalc);
if (canDo) {
let origHeight = ~~height, styleHeight, _height = origHeight && height !== 0 ? origHeight : (styleHeight = getHeights(target).height), time = ~~duration && duration !== 0 ? ~~duration : getAutoDur(_height), dftCss = `${target.style.cssText} ${cut ? 'overflow:hidden;' : ''};`, from = {}, to = {};
target.style.cssText = `${dftCss}`;
if (type === 'to' && origHeight) {
from = { height: isNull(styleHeight) ? styleHeight : getHeights(target).height };
to = { height: origHeight };
}
else if (type === 'up') {
from = { height: _height };
to = { height: 0 };
}
else {
from = { height: 0 };
to = { height: _height };
}
ease({
from,
to,
duration: time,
curve,
doing: (e) => {
target.style.cssText = `
${dftCss}
height: ${e.value.height}px
`;
doing && doing.call(target, { frame: e.frame, value: e.value.height, step: e.step });
}, done: (e) => {
done && done.call(target, { frame: e.frame, value: e.value.height, step: e.step });
}
});
}
return target;
};
let fadeIn = ({ el, display = 'block', doing, done, duration = 200, curve = 'easeOut' }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
let state = elState(target), opacity = parseFloat(style(target).opacity), from = { opacity: 0 };
if (opacity === 1) {
return target;
}
if (state.isHidden) {
from.opacity = 0;
target.style.display = display;
target.style.opacity = 0;
}
else if (state.isCalc && opacity !== 1) {
from.opacity = opacity;
}
ease({
from,
to: { opacity: 1 },
duration,
curve,
doing: (e) => {
target.style.opacity = e.value.opacity;
doing && doing.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'show' });
}, done: (e) => {
target.style.opacity = 1;
done && done.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'show' });
}
});
return target;
};
let fadeOut = ({ el, display, doing, done, duration = 200, curve = 'easeOut' }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
let opacity = parseFloat(style(target).opacity);
if (opacity === 0) {
return target;
}
display ? target.style.display = display : null;
if (elState(target).isCalc) {
ease({
from: { opacity },
to: { opacity: 0 },
duration,
curve,
doing: (e) => {
target.style.opacity = e.value.opacity;
doing && doing.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'hide' });
}, done: (e) => {
target.style.opacity = 0;
done && done.call(target, { frame: e.frame, value: e.value.opacity, step: e.step, target, for: 'hide' });
}
});
}
return target;
};
let fadeToggle = ({ el, display = 'block', doing, done, duration = 200, curve = 'easeOut' }) => {
let target = getEl(el);
if (!target)
throw new Error('The target node does not exist!');
let state = elState(target), opacity = parseFloat(style(target).opacity);
if (state.isHidden) {
fadeIn({ el: target, display, duration, curve, doing: doing?.in, done: done?.in });
}
else if (state.isCalc) {
if (opacity <= 0.5) {
fadeIn({ el: target, display, duration, curve, doing: doing?.in, done: done?.in });
}
else {
fadeOut({ el: target, display, duration, curve, doing: doing?.out, done: done?.out });
}
}
return target;
};
let show = ({ el, display = 'block', done }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
if (display == 'visible') {
target.style.visibility = 'visible';
}
else {
target.style.display = display;
}
done && done.call(target, { target, for: 'show' });
return target;
};
let hide = ({ el, display = 'none', done }) => {
let target = getEl(el);
if (!target) {
throw new Error('The target node does not exist!');
}
if (display === 'hidden') {
target.style.visibility = 'hidden';
}
else {
target.style.display = 'none';
}
done && done.call(target, { target, for: 'hide' });
return target;
};
let toggle = ({ el, display = { show: 'block', hide: 'none' }, done }) => {
let target = getEl(el);
if (!target)
throw new Error('The target node does not exist!');
elState(target).isVisible ? hide({ el: target, display: display.hide, done: done?.hide }) : show({ el: target, display: display.show, done: done?.show });
return target;
};
const regExps = {
email: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/,
ip: /^\d+\.\d+\.\d+\.\d+$/,
url: /^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/,
locale: /^[\u0391-\uFFE5]+$/,
letter: /^[a-zA-Z]+$/,
string: /^[a-zA-Z0-9]+$/,
password: `^[a-zA-Z0-9${ax.config.valid.regChars}]+$`,
ymdhms: /^(\d{4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/,
ymd: /^(\d{4})(-|\/)(\d{1,2})\2(\d{1,2})$/,
hms: /^((20|21|22|23|[0-1]\d)\:[0-5][0-9])(\:[0-5][0-9])?$/,
ym: /^(\d{4})(-|\/)(\d{1,2})$/,
y: /^(\d{4})$/,
m: /^(0?[1-9]|1[0-2])$/,
d: /^((0?[1-9])|((1|2)[0-9])|30|31)$/,
integer: /^[1-9]\d*$/,
number: /^(-?\d+)\.?(\d*)$/,
cellphone: /^[1][3456789][0-9]{9}$/,
landline: /^([0-9]{3,4}-)?[0-9]{7,8}$/,
plate: {
nev: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/,
oil: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/,
},
id: /^(([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([5][0-4])|([6][1-5])|([7][1])|([8][1-2]))\d{4}(([1][9]\d{2})|([2]\d{3}))(([0][1-9])|([1][0-2]))(([0][1-9])|([1-2][0-9])|([3][0-1]))\d{3}[0-9xX]$/,
zip: /^\d{6}$/,
};
const replaceFrag = ({ origin, text, start, stop, length }) => {
typeof origin !== 'string' ? origin = JSON.stringify(origin) : null;
typeof text !== 'string' ? text = JSON.stringify(text) : null;
let result = '';
if (start === undefined && stop === undefined) {
result = text;
}
else if (start !== undefined && stop === undefined) {
result = length !== undefined ? origin.substring(0, start) + text + origin.substring(start + length) : origin.substring(0, start) + text;
}
else if (start === undefined && stop !== undefined) {
result = length !== undefined ? origin.substring(stop - length) + text + origin.substring(0, start) : text + origin.substring(stop);
}
else {
result = origin.substring(0, start) + text + origin.substring(stop);
}
return result;
};
const paramToJson = (str) => {
let result;
if (str) {
str = str.trim();
let objStr = sliceFrags({ str }).join(''), arrStr = sliceFrags({ str, start: '[', end: ']' }).join(''), excludeStr = objStr + arrStr, std = str.split(',').filter(Boolean).map((k) => {
return (!k.includes(':') && !excludeStr.includes(k)) ? `${k}:true` : k;
}).join(',');
try {
result = parseStr({
content: `{${std}}`,
type: 'object',
catchable: true,
});
}
catch {
result = {};
console.warn('Data parsing error, an empty object "{}" has been returned!');
}
}
return result;
};
const getLast = (data) => {
let dataType = getDataType(data), last = null;
if (dataType === 'Array' && data.length > 0) {
last = data.slice(-1)[0];
}
else if (dataType === 'Object' && Object.keys(data).length > 0) {
last = Object.keys(data).slice(-1)[0];
}
return last;
};
const isSubset = (child, parent) => (Array.isArray(child)) ? child.length <= parent.length && child.every(k => parent.includes(k)) : parent.includes(child);
const stdParam = (val, dft = {}, prop) => {
let result = (getDataType(dft) === 'Object') ? { ...dft } : {};
if (getDataType(val) === 'Object') {
extend({
target: result,
source: val,
});
}
else {
if (prop && !isNull(val)) {
Reflect.set(result, prop, val);
}
}
return result;
};
const throttle = (fn, options) => {
let dft = { intvl: config.throttle, prevent: false }, opts = stdParam(options, dft, 'intvl');
let last = 0, timer = null, handler = function (e) {
let now = Date.now();
if (now - last > opts.intvl) {
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(this, arguments);
last = now;
}
else {
opts.prevent ? (e.stopPropagation(), e.preventDefault()) : null;
}
};
handler.cancel = () => {
clearTimeout(timer);
timer = null;
return handler;
};
return handler;
};
const debounce = (fn, options) => {
let dft = { delay: config.debounce, prevent: false, auto: false }, opts = stdParam(options, dft, 'delay');
if (ax.isTouchScr && opts.auto) {
return throttle(fn, { intvl: opts.delay, prevent: opts.prevent });
}
else {
let timer = null, handler = function (e) {
opts.prevent ? (e.stopPropagation(), e.preventDefault()) : null;
timer ? clearTimeout(timer) : null;
opts.instant && opts.instant();
timer = setTimeout(() => {
fn.apply(this, arguments);
}, opts.delay);
};
handler.cancel = () => {
timer && clearTimeout(timer);
return handler;
};
return handler;
}
};
const convertByte = ({ val, to = '', places = 2, outer = 'span', inner = 'i', units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] }) => {
val = clampVal({ val, min: 0, max: '' });
let lvs = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'], unit = '', lv = 0, base = val / 1024, getVal = (i) => i === 0 ? val : toNumber(val / (1024 ** i), { places });
if (lvs.includes(to)) {
lv = lvs.findIndex(k => k === to);
}
else {
lv = (base >= 1024 ** 4) ? 5 :
(base >= 1024 ** 3) ? 4 :
(base >= 1024 ** 2) ? 3 :
(base >= 1024) ? 2 :
(base >= 1) ? 1 : 0;
}
val = getVal(lv);
unit = units[lv];
return { val, unit, str: `<${outer}><${inner}>${val}</${inner}>${unit}</${outer}>` };
};
const fileTools = {
download: (url, name) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
let url = window.URL.createObjectURL(xhr.response), dom = createEl('a');
dom.src = url || 'javascript:void(0);';
dom.download = name || config.lang.placeholder.downloadName + Date.now();
dom.click();
};
xhr.send();
},
getBase64: (file, cb) => {
return new Promise((resolve, reject) => {
try {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
cb && cb(e?.target?.result);
resolve(e?.target?.result);
};
}
catch (e) {
reject(e);
}
});
},
getSuffix: (file) => {
if (file.name.includes('.')) {
return file.name.split('.').pop();
}
else {
return '';
}
},
getFileName: (url) => {
try {
return url.split('/').pop()?.trim() || '';
}
catch {
return '';
}
},
urlToFile: function (url, name = '', cb) {
name = name || this.getFileName(url) || config.lang.placeholder.fileName + Date.now();
return new Promise((resolve, reject) => {
ajax({
url,
respType: 'blob',
type: 'get',
error: (res) => {
reject(res.content);
},
success: (res) => {
let file = new File([res.content], name, { type: res.content.type });
cb && cb(file);
resolve(file);
}
});
});
}
};
const increaseId = (data, hasId = true) => {
let ids = new Set(), newId = 0;
if (!data.length)
return newId;
if (hasId) {
for (let k of data)
ids.add(~~k.id);
newId = Math.max(...ids) + 1;
}
else {
newId = data.length;
}
return newId;
};
const findItem = (val, source, key, prio) => {
let valType = getDataType(val);
if (!source)
return val;
let result, first = source[0], firstId = first?.id, idType = getDataType(firstId);
if (isNull(firstId) && valType === 'Number') {
result = source[val];
}
else {
if (key) {
result = source.find((k) => k[key] === val);
}
else {
if (valType.includes('HTML')) {
let hasPrio = (item) => prio?.node ? item[prio.node] === val : false, condition = (item) => hasPrio(item) || item.headEl === val || item.wrapEl === val;
result = source.find((k) => condition(k));
}
else {
let prop = (valType === 'Number') ? (prio?.number || 'id') :
(valType === 'String') ? prio?.string || (idType === 'String' ? 'id' : 'label') : '';
if (valType === 'Object') {
result = source.find((k) => k === val);
}
else {
result = prop ? source.find((k) => k[prop] === val || k[prio?.guard || 'value'] === val) : undefined;
}
}
}
}
return result;
};
const splice = ({ host = [], source, intent = 'end+', index = 0, cb }) => {
if (isNull(host) || !Array.isArray(host))
return [];
let tmp = source !== undefined ? (Array.isArray(source) ? source : [source]) : null, data = Array.isArray(tmp) ? tmp : [tmp], idx = isNull(index) ? 0 : clampVal({ min: 0, max: host.length - 1, val: index }), items = [];
if (intent === 'clear') {
items = [...host];
host.splice(0);
}
else if (intent === 'add') {
if (!tmp)
return host;
let start = (idx >= host.length) ? (host.length - 1) : idx;
host.splice(start, 0, ...data);
items = host.slice(start, start + data.length);
}
else if (intent === 'remove') {
let _tmp = source !== undefined ? host.indexOf(source) : idx;
if (_tmp < 0) {
return host;
}
else {
items = host.slice(_tmp, _tmp + 1);
host.splice(_tmp, 1);
}
}
else if (intent === 'replace') {
if (!tmp)
return host;
host.splice(idx, 1, ...data);
items = host.slice(idx, idx + data.length);
}
else if (intent === 'start-') {
items = host.slice(0, 1);
host.shift();
}
else if (intent === 'end-') {
items = host.slice(-1);
host.pop();
}
else if (intent === 'start+') {
if (!tmp)
return host;
host.unshift(...data);
items = host.slice(0, data.length);
}
else {
if (!tmp)
return host;
host.push(...data);
items = host.slice(-data.length);
}
cb && cb(items);
return host;
};
const dl2Tree = (el) => {
let elem = getEl(el), result = [];
if (!elem) {
console.warn(`No node, no access to data!`);
return result;
}
let heads = [...elem.querySelectorAll('dt')], bodys = [...elem.querySelectorAll('dd')];
if (heads.length !== bodys.length) {
console.warn('Inconsistent number of "dt" and "dd" tags!');
return result;
}
if (heads.length === 0) {
console.warn('No "dt" and "dd" tags!');
return result;
}
result = heads.map((k, i) => {
return { content: bodys[i].innerHTML, ...getValsFromAttrs(k) };
});
return result;
};
const attrValBool = (value) => ![false, 0, null, undefined, 'false', '0'].includes(value);
const treeTools = {
find: function (arr, val, key) {
let tmp = findItem(arr, val, key);
if (tmp)
return tmp;
for (let k of arr) {
k.children && this.find(k.children, val, key);
}
return null;
},
getBoolItems: (data, prop, negative = false) => {
return data.filter((k) => {
let tmp = attrValBool(k[prop]);
return negative ? !tmp : tmp;
});
},
toFlat: function (data) {
let result = [];
data.forEach(k => {
if (k.children && !data.includes(k.children[0])) {
result = [...result, k, ...this.toFlat(k.children)];
}
else {
result.push(k);
}
});
return result;
},
toTree: (data) => {
if (!data || data.length === 0 || !data[0].hasOwnProperty('pId')) {
return data;
}
let root = data[0].pId;
data.forEach(k => {
let children = data.filter(i => k.id == i.pId);
if (children.length) {
k.children = children;
}
});
return data.filter(k => k.pId == root);
},
addIdPath: ({ source, rootStart = config.rootStart, idStart = config.idStart, floorStart = config.floorStart, pathHyphen = config.pathHyphen, lbl2Val = true }) => {
if (!Array.isArray(source) || source.length === 0 || source[0].hasOwnProperty('path')) {
return source;
}
let hasId = source[0].hasOwnProperty('id') ? true : false, index = idStart, each = (data, floor, path = rootStart) => {
data.forEach(item => {
if (!hasId) {
item.id = index;
index++;
}
item.floor = floor;
item.pId = item.pId || item.pId === 0 ? item.pId : rootStart;
item.path = path + pathHyphen + item.id;
(!item.hasOwnProperty('value') && item.hasOwnProperty('label') && lbl2Val) ? item.value = item.label : null;
if (item.children && item.children.length > 0) {
item.children.forEach((k) => {
k.pId = item.id;
});
each(item.children, floor + 1, item.path);
}
if (!item.path) {
item.path = item.pId + pathHyphen + item.id;
}
});
};
each(source, floorStart);
return source;
},
fromInput: (el, hyphen = config.splitHyphen) => {
let elem = getEl(el), result = [];
if (!elem) {
console.warn(`No node, no access to data!`);
return result;
}
let tmp = elem.value.trim();
return !tmp ? [] : elem.value.trim().split(hyphen).map((k) => { return { label: k, value: k }; });
},
createBranchObj: function ({ source, flatData, target, isChild = true, isLeaf = true, rootStart = config.rootStart, idStart = config.idStart, floorStart = config.floorStart, pathHyphen = config.pathHyphen }) {
let obj = {}, targetObj = findItem(target, flatData), emptyArr = flatData.length === 0, sourceType = getDataType(source), setIdLabelVal = (data, id) => {
!data.hasOwnProperty('id') ? data.id = id : null;
!data.hasOwnProperty('value') ? (data.hasOwnProperty('label') ? data.value = data.label : data.value = '') : null;
!data.hasOwnProperty('label') ? data.label = config.lang.tree.label + id : null;
}, setRootChild = (data, id) => {
let base = {
pId: rootStart,
path: rootStart + pathHyphen + id,
floor: floorStart
};
setIdLabelVal(data, id);
Object.assign(data, base);
};
if (isNull(flatData)) {
return obj;
}
if (sourceType === 'String' || sourceType === 'Number') {
obj.value = obj.label = source;
}
else if (sourceType === 'Object') {
obj = { ...source };
}
if (emptyArr) {
setRootChild(obj, idStart);
}
else {
let newId = increaseId(flatData);
if (!targetObj) {
obj.hasOwnProperty('id') ? newId = obj.id : null;
setRootChild(obj, newId);
}
else {
!targetObj.hasOwnProperty('children') && isChild && (targetObj.children = []);
let props = {};
setIdLabelVal(obj, newId);
props = isChild ? {
pId: targetObj.id,
path: targetObj.path + pathHyphen + obj.id,
floor: targetObj.floor + 1
} : {
pId: targetObj.pId,
path: targetObj.path.replace(new RegExp('(.*)' + targetObj.id), '$1' + obj.id),
floor: targetObj.floor
};
Object.assign(obj, props);
}
}
!isLeaf && (obj.children = []);
return obj;
},
childToParent: (source, arrowEnd = true) => {
if (!source.children) {
return;
}
if (!source.childrenEl) {
source.childrenEl = createEl('ul');
source.headEl.insertAdjacentElement('afterEnd', source.childrenEl);
}
if (!source.arrowEl) {
source.arrowEl = createEl('i', { [ax.alias]: 'arrow' });
source.headEl.insertAdjacentElement(arrowEnd ? 'beforeEnd' : 'afterBegin', source.arrowEl);
}
},
parentToChild: (source) => {
if (source.children) {
return;
}
source.target.childrenEl.remove();
source.target.childrenEl = null;
source.target.arrowEl.remove();
source.target.arrowEl = null;
source.target.expanded = false;
},
addBranch: function ({ source, rootEl, flatData, treeData, brother, isFront = true, repeat = true, autoFill = true, cb }) {
if (!flatData || !source) {
return;
}
let existing = flatData.find((k) => k.pId === source.pId && k.label === source.label), brotherObj = findItem(brother, flatData), parentObj = findItem(source.pId, flatData), result;
if (!repeat && existing) {
console.warn(`A branch with the same label (${source.label}) and pId (${source.pId}) already exists. Duplicate addition is not allowed!`);
return;
}
if (parentObj) {
if (brotherObj && parentObj.children.includes(brotherObj)) {
let index = flatData.indexOf(brotherObj);
if (isFront) {
splice({ host: parentObj.children, source, index, intent: 'add', cb: (resp) => result = resp[0] });
autoFill && brotherObj.wrapEl.insertAdjacentElement('beforeBegin', source.wrapEl);
}
else {
splice({ host: parentObj.children, source, index: index + 1, intent: 'add', cb: (resp) => result = resp[0] });
autoFill && brotherObj.wrapEl.insertAdjacentElement('afterEnd', source.wrapEl);
}
}
else {
if (isFront) {
splice({ host: parentObj.children, source, intent: 'start+', cb: (resp) => result = resp[0] });
autoFill && parentObj.childrenEl.insertAdjacentElement('afterBegin', source.wrapEl);
}
else {
splice({ host: parentObj.children, source, intent: 'end+', cb: (resp) => result = resp[0] });
autoFill && parentObj.childrenEl.insertAdjacentElement('beforeEnd', source.wrapEl);
}
}
}
else {
if (brotherObj && brotherObj.pId === source.pId) {
let index = treeData.indexOf(brotherObj);
if (isFront) {
splice({ host: treeData, source, index, intent: 'add', cb: (resp) => result = resp[0] });
autoFill && brotherObj.wrapEl.insertAdjacentElement('beforeBegin', source.wrapEl);
}
else {
splice({ host: treeData, source, index: index + 1, intent: 'add', cb: (resp) => result = resp[0] });
autoFill && brotherObj.wrapEl.insertAdjacentElement('afterEnd', source.wrapEl);
}
}
else {
if (!rootEl) {
return;
}
if (isFront) {
splice({ host: treeData, source, intent: 'start+', cb: (resp) => result = resp[0] });
autoFill && rootEl.insertAdjacentElement('afterBegin', source.wrapEl);
}
else {
splice({ host: treeData, source, intent: 'end+', cb: (resp) => result = resp[0] });
autoFill && rootEl.insertAdjacentElement('beforeEnd', source.wrapEl);
}
}
}
cb && cb(result, treeData);
},
removeBranch: function ({ source, flatData, treeData, cb, }) {
if (isNull(source) || !flatData || flatData.length === 0) {
return;
}
let obj = findItem(source, flatData), floorStart = treeData[0].floor;
if (!obj) {
return;
}
if (obj.floor === floorStart) {
splice({ host: treeData, source: obj, intent: 'remove' });
}
else {
let parent = findItem(obj.pId, flatData);
if (!parent) {
return;
}
let children = parent.children;
splice({ host: children, source: obj, intent: 'remove' });
if (children.length === 0) {
this.parentToChild(parent);
}
}
obj?.wrapEl && obj.wrapEl.remove();
cb && cb(obj);
},
getParentsFromPath({ path, flatData, labelHyphen = config.labelHyphen, field = 'label', pathHyphen = config.pathHyphen, shift = false, pop = false }) {
let paths = path.split(pathHyphen), parents = paths.map((k) => flatData.find((i) => i.id.toString() == k)).filter(Boolean), text = '';
shift && parents.shift();
pop && parents.pop();
text = parents.map((k) => k[field]).join(labelHyphen);
return { parents, text };
},
allToTree: async function ({ content, idStart = config.idStart, rootStart = config.rootStart, floorStart = config.rootStart, pathHyphen = config.pathHyphen, splitHyphen = config.splitHyphen, contType = '', contData = {}, ajax = {}, fill = true, ins, nodeType = 'tree', cb }) {
if (isEmpty(content)) {
return [];
}
let treeData = [], result = [], getFromNode = (node) => {
let nodeName = node.nodeName, arr = [];
if (nodeName === 'SELECT' || nodeName === 'DATALIST') {
arr = select2Tree(node);
}
else if (nodeName === 'UL' || nodeName === 'OL') {
arr = ul2Tree(node, nodeType);
}
else if (nodeName === 'DL') {
arr = dl2Tree(node);
}
else if (nodeName === 'SCRIPT' && node.getAttribute('type') === 'content') {
arr = this.toTree(parseStr({
content: node.textContent,
type: 'array',
error: (err) => {
console.info(config.warn.parse);
}
}));
}
else if (nodeName === 'INPUT') {
arr = this.fromInput(node, splitHyphen);
}
return arr;
}, getFromArray = (data) => {
let copyData = deepClone(data);
return this.toTree(copyData);
}, strArr2ObjArr = (arr) => {
let firstType = getDataType(arr[0]), tmp = (firstType === 'String' || firstType === 'Number') ? arr.map((k) => { return { label: k, value: k }; }) : arr;
return tmp;
};
await getContent.call(ins, {
content,
contType,
contData,
ajax,
cb: (resp) => {
let dataType = getDataType(resp);
if (dataType === 'Object' && resp.hasOwnProperty('data') && Array.isArray(resp.data)) {
treeData = getFromArray(resp.data);
resp.data = treeData;
result = resp;
}
else {
if (dataType === 'Array') {
treeData = getFromArray(strArr2ObjArr(resp));
}
else if (dataType.includes('HTML')) {
if (['UL', 'OL', 'DATALIST', 'DL', 'SELECT', 'SCRIPT'].includes(resp.nodeName)) {
treeData = strArr2ObjArr(getFromNode(resp));
}
else if (resp.nodeName.includes('INPUT')) {
treeData = this.fromInput(resp, splitHyphen);
}
}
else if (dataType === 'String') {
let tmp = createEl('div', '', resp), node = tmp.querySelector(':scope > ul,:scope > ol,:scope > datalist,:scope > dl,:scope > select,:scope > script,:scope > input');
if (node) {
treeData = strArr2ObjArr(getFromNode(node));
tmp.remove();
}
else {
let str = resp.trim(), type = (str.startsWith('{') && str.endsWith('}')) ? 'object' : (str.startsWith('[') && str.endsWith(']')) ? 'array' : '';
if (type) {
treeData = this.toTree(strArr2ObjArr(parseStr({
content: resp,
type,
error: (err) => {
console.info(config.warn.parse);
}
})));
}
else {
treeData = strArr2ObjArr(resp.split(splitHyphen).filter(Boolean));
}
}
}
result = treeData;
}
}
});
fill && this.addIdPath({ source: treeData, rootStart, idStart, floorStart, pathHyphen });
cb && cb(result);
return result;
},
getPathHyphen: (treeData) => {
let item = treeData[0], id = item.id, floor = item.floor, pId = item.pId, path = item.path, hyphen = item.path.replace(pId, '').replace(id, '');
return { id, floor, pId, path, hyphen };
},
graftBranch: function ({ source, target, flatData, treeData, rootEl, isFront = true, isChild = true, cb }) {
if (isNull(source) || isEmpty(treeData)) {
return;
}
let sourceObj = findItem(source, flatData), targetObj = findItem(target, flatData), firstData = this.getPathHyphen(treeData), floorStart = firstData.floor, rootStart = firstData.pId, pathHyphen = firstData.hyphen;
if (!sourceObj) {
return;
}
let sourceParent = findItem(sourceObj.pId, flatData);
if (!sourceParent) {
splice({ host: treeData, source: sourceObj, intent: 'remove' });
}
else {
splice({ host: sourceParent.children, source: sourceObj, intent: 'remove' });
}
if (!targetObj) {
if (isFront) {
rootEl?.insertAdjacentElement('afterBegin', sourceObj.wrapEl);
treeData.unshift(sourceObj);
}
else {
rootEl?.insertAdjacentElement('beforeEnd', sourceObj.wrapEl);
treeData.push(sourceObj);
}
sourceObj.pId = rootStart;
sourceObj.floor = floorStart;
sourceObj.path = rootStart + pathHyphen + sourceObj.id;
}
else {
if (isChild) {
!targetObj.hasOwnProperty('children') && (targetObj.children = []);
if (isFront) {
targetObj.childrenEl.insertAdjacentElement('afterBegin', sourceObj.wrapEl);
targetObj.children.unshift(sourceObj);
}
else {
targetObj.childrenEl.insertAdjacentElement('beforeEnd', sourceObj.wrapEl);
targetObj.children.push(sourceObj);
}
sourceObj.pId = targetObj.id;
sourceObj.floor = targetObj.floor + 1;
sourceObj.path = targetObj.path + pathHyphen + sourceObj.id;
}
else {
if (targetObj.floor === floorStart) {
let index = treeData.indexOf(targetObj), id = isFront ? index : index + 1;
splice({ host: treeData, source: sourceObj, index: id, intent: 'add' });
}
else {
let targetParent = findItem(targetObj.pId, flatData), index = targetParent.children.indexOf(targetObj), id = isFront ? index : index + 1;
splice({ host: targetParent.children, source: sourceObj, index: id, intent: 'add' });
}
sourceObj.pId = targetObj.pId;
sourceObj.floor = targetObj.floor;
sourceObj.path = targetObj.path.replace(new RegExp('(.*)' + targetObj.id), '$1' + sourceObj.id);
let position = isFront ? 'beforeBegin' : 'afterEnd';
targetObj.wrapEl.insertAdjacentElement(position, sourceObj.wrapEl);
}
}
cb && cb(sourceObj, targetObj);
}
};
const moveItem = ({ source, target, data, isFront = true }) => {
let sourceType = getDataType(source), targetType = getDataType(target), from = (sourceType === 'Number') ? source : data.indexOf(source), to = (targetType === 'Number') ? target : data.indexOf(target), sourceObj = sourceType === 'Number' ? data[source] : source, offset = isFront ? 0 : 1;
if (isNull(from) || isEmpty(data)) {
throw new Error('Cannot get the index of the moving item!');
}
if (from > data.length || from < 0) {
throw new Error('Exceeded array length!');
}
if (to < 0 || to > data.length) {
to = isFront ? 0 : data.length - 1;
}
if (from === to) {
console.warn('Source and target are the same, not moved!');
return;
}
data.splice(from, 1);
from < to ? to-- : null;
data.splice(to + offset, 0, sourceObj);
};
const findItems = (vals, source, key, pio) => {
let valsType = getDataType(vals), result = [], tmp = (valsType === 'String') ? vals.split(pio?.separator || config.splitHyphen) :
(valsType === 'Array') ? vals : [vals];
result = tmp.map((k) => findItem(k, source, key, pio)).filter(Boolean);
return result;
};
let theme = {
set: function (value, name = '') {
if (isEmpty(value)) {
return;
}
let hexToRgbArr = (val) => {
val = val.trim();
let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/, colorStr = val.toLowerCase(), result = [];
if (reg.test(colorStr)) {
if (colorStr.length === 4) {
let temp = '#';
for (let k = 1; k < 4; k += 1) {
temp += colorStr.slice(k, k + 1).concat(colorStr.slice(k, k + 1));
}
colorStr = temp;
}
for (let k = 1; k < 7; k += 2) {
result.push(parseInt("0x" + colorStr.slice(k, k + 2)));
}
}
return result;
}, rgbToHsl = (arr) => {
let r = arr[0] / 255, g = arr[1] / 255, b = arr[2] / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h = 0, s, l = (min + max) / 2, diff = max - min;
if (max === min) {
h = 0;
s = 0;
}
else {
s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
switch (max) {
case r:
h = (g - b) / diff + (g < b ? 6 : 0);
break;
case g:
h = 2 + (b - r) / diff;
break;
case b:
h = 4 + (r - g) / diff;
break;
}
h = Math.round(h * 60);
}
s = Math.round(s * 100);
l = Math.round(l * 100);
return arr.length === 4 ? [h, s, l, arr[3]] : [h, s, l, 1];
}, getHslaArr = (val) => {
let valType = getDataType(val), result = [];
if (!isEmpty(val)) {
if (valType === 'String') {
val = val.trim().toLowerCase();
if (val.startsWith('hsl')) {
result = val.replace(/^(hsl|hsla)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',');
}
else {
let temp = [];
if (val.startsWith('#')) {
temp = hexToRgbArr(val);
}
else if (val.startsWith('rgb')) {
temp = val.replace(/^(rgb|rgba)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',').map(Number);
}
result = rgbToHsl(temp);
}
}
else if (valType === 'Array') {
result = val;
}
}
result.length === 3 ? result.push(1) : null;
return result;
}, valueType = getDataType(value);
let hslaObj = { prim: [], text: [], error: [], succ: [], info: [], warn: [], issue: [] };
if (valueType === 'Object') {
for (let k in value) {
if (value.hasOwnProperty(k) && value[k].length > 2) {
hslaObj[k] = getHslaArr(value[k]);
}
}
}
else {
hslaObj.prim = getHslaArr(value);
}
if (isEmpty(storage.get('AxThemeRaw'))) {
storage.set('AxThemeRaw', this.get());
}
let rootDom = document.querySelector(":root");
for (let k in hslaObj) {
if (hslaObj.hasOwnProperty(k) && hslaObj[k].length > 2) {
rootDom.style.setProperty(`--${ax.prefix}h-${k}`, hslaObj[k][0]);
rootDom.style.setProperty(`--${ax.prefix}s-${k}`, typeof hslaObj[k][1] === 'string' && hslaObj[k][1].includes('%') ? hslaObj[k][1] : hslaObj[k][1] + '%');
rootDom.style.setProperty(`--${ax.prefix}l-${k}`, typeof hslaObj[k][2] === 'string' && hslaObj[k][2].includes('%') ? hslaObj[k][2] : hslaObj[k][2] + '%');
rootDom.style.setProperty(`--${ax.prefix}a-${k}`, hslaObj[k][3]);
}
}
name ? storage.set(name, hslaObj) : null;
},
get: function () {
let getValue = (type) => {
return [
getComputedVar(`--${ax.prefix}h-${type}`),
getComputedVar(`--${ax.prefix}s-${type}`),
getComputedVar(`--${ax.prefix}l-${type}`),
getComputedVar(`--${ax.prefix}a-${type}`),
].map(k => {
let val = k.trim();
return val.includes('%') ? val : Number(val);
});
};
return {
prim: getValue('prim'),
text: getValue('text'),
succ: getValue('succ'),
error: getValue('error'),
info: getValue('info'),
warn: getValue('warn'),
issue: getValue('issue'),
};
},
reset: function () {
let themeRaw = storage.get('AxThemeRaw');
this.set(themeRaw);
}
};
const getBetweenEls = ({ selector, start, end, root, exclude }) => {
let rootEl = getEl(root) || document.body, startEl = getEl(start, rootEl), endEl = getEl(end, rootEl), excEls = getEls(exclude, rootEl), els = getEls(selector, rootEl), result = [];
if (els.length === 0) {
return result;
}
if (startEl && !endEl) {
result = els.filter((k) => {
return startEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_FOLLOWING;
});
}
else if (!startEl && endEl) {
result = els.filter((k) => {
return endEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_PRECEDING;
});
}
else if (startEl && endEl) {
result = els.filter((k) => {
return (startEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_FOLLOWING) && endEl.compareDocumentPosition(k) & Node.DOCUMENT_POSITION_PRECEDING;
});
}
if (excEls.length) {
return result.filter((k) => {
return !excEls.find((i) => i.contains(k));
});
}
else {
return result;
}
};
const scrollTo = (elem, options) => {
let opts = Object.assign({
curve: 'easeOut',
offset: 0,
duration: 0,
}, options), rootDom = getEl(options?.root), scrollParent = rootDom || window, scrollOffset = toPixel(opts.offset), anchorDom = getEl(elem), bodyScrollTop = document.documentElement.scrollTop || document.body.scrollTop, offsetScrolled = rootDom ? rootDom.scrollTop : bodyScrollTop, initTime = Date.now(), offsetClient = 0;
if (rootDom && style(rootDom).position === 'static') {
rootDom.style.position = 'relative';
}
if (anchorDom) {
offsetClient = rootDom ? anchorDom.offsetTop - rootDom.scrollTop : anchorDom.getBoundingClientRect().top;
}
else {
offsetClient = typeof elem === 'number' ? elem - offsetScrolled : -offsetScrolled;
}
let duration = !opts.duration || typeof opts.duration !== 'number' ? Math.abs(offsetClient) / 4 + 1000 : opts.duration, repeat = () => {
let newTime = Date.now() - initTime, timestep = newTime / duration, step = offsetScrolled + (offsetClient - scrollOffset) * curveFns[opts.curve](timestep);
scrollParent.scrollTo(0, step);
repeat.timer = requestAnimationFrame(repeat);
if (newTime >= duration) {
scrollParent.scrollTo(0, step);
cancelAnimationFrame(repeat.timer);
}
};
repeat();
return elem;
};
const getScrollObj = () => navigator.userAgent.indexOf("Firefox") > 0 ? { event: 'DOMMouseScroll', detail: 'detail' } : { event: 'mousewheel', detail: 'wheelDelta' };
const transformTools = {
get: (elem, props, instead = false) => {
let dom = getEl(elem), styles = style(dom), value = dom?.style?.transform, result = {
rotate: 0,
scale: { x: 1, y: 1 },
translate: { x: 0, y: 0 },
skew: { x: 0, y: 0 }
};
isEmpty(props) && (props = ['translate', 'scale', 'rotate', 'skew']);
if (value) {
let getReg = (type) => new RegExp(`${type}\\(([^\\)]+)\\)`), getText = (type) => value.match(getReg(type));
if (props.includes('translate') && value.includes('translate') && getText('translate')) {
if (getText('translate')[1].includes(',')) {
let arr = getText('translate')[1].split(',').map((k) => parseInt(k));
result.translate = { x: arr[0], y: arr[1] };
}
else {
result.translate = { x: parseInt(getText('translate')[1]), y: 0 };
}
}
if (props.includes('scale') && value.includes('scale') && getText('scale')) {
if (getText('scale')[1].includes(',')) {
let arr = getText('scale')[1].split(',').map((k) => parseFloat(k));
result.scale = { x: arr[0], y: arr[1] };
}
else {
result.scale = { x: parseFloat(getText('scale')[1]), y: parseFloat(getText('scale')[1]) };
}
}
if (props.includes('rotate') && value.includes('rotate') && getText('rotate')) {
result.rotate = parseFloat(getText('rotate')[1]);
}
if (props.includes('skew') && value.includes('skew') && getText('skew')) {
if (getText('skew')[1].includes(',')) {
let arr = getText('skew')[1].split(',').map((k) => parseFloat(k));
result.skew = { x: arr[0], y: arr[1] };
}
else {
result.skew = { x: parseFloat(getText('skew')[1]), y: 0 };
}
}
}
if (instead) {
result.translate = { x: parseInt(styles.left), y: parseInt(styles.top) };
}
return result;
},
set: function ({ el, data, instead = false, cb }) {
let dom = getEl(el), now = this.get(dom, ['translate', 'scale', 'rotate', 'skew'], instead), transformTxt = dom?.style.transform || '', getReg = (type) => { return new RegExp(`${type}\\(([^\\)]+)\\)`, 'gmi'); }, re = (val, label, prop) => isNull(val[prop]) ? now[label][prop] : val[prop];
if (!dom && isEmpty(data))
return;
for (let k in data) {
if (data.hasOwnProperty(k)) {
let value = '';
if (k === 'translate') {
if (instead) {
!isNaN(data[k]) ?
(dom.style.left = `${data[k]}px`) :
(dom.style.left = `${re(data[k], 'translate', 'x')}px`, dom.style.top = `${re(data[k], 'translate', 'y')}px`);
}
else {
value = !isNaN(data[k]) ? `${k}(${data[k]}px)` : `${k}(${re(data[k], 'translate', 'x')}px,${re(data[k], 'translate', 'y')}px)`;
if (transformTxt.includes(k)) {
if (transformTxt.startsWith('translate')) {
transformTxt = transformTxt.replace(getReg(k), value);
}
else {
transformTxt = transformTxt.replace(getReg(k), '');
transformTxt = `${value} ${transformTxt}`;
}
}
else {
transformTxt = `${value} ${transformTxt}`;
}
}
}
else {
if (k === 'scale') {
value = !isNaN(data[k]) ? `${k}(${data[k]})` : `${k}(${re(data[k], 'scale', 'x')},${re(data[k], 'scale', 'y')})`;
}
else if (k === 'rotate') {
value = `${k}(${data[k]}deg)`;
}
else if (k === 'skew') {
value = !isNaN(data[k]) ? `${k}(${data[k]}deg)` : `${k}(${re(data[k], 'skew', 'x')}deg,${re(data[k], 'skew', 'y')}deg)`;
}
if (transformTxt.includes(k)) {
transformTxt = transformTxt.replace(getReg(k), value);
}
else {
transformTxt += ` ${value}`;
}
}
}
}
dom.style.transform = transformTxt;
cb && cb(transformTxt);
},
remove: ({ el, prop }) => {
let dom = getEl(el), tmp = dom?.style?.transform;
if (!dom || !tmp)
return;
dom.style.transform = prop ? tmp.replace(new RegExp(`${prop}\\([^)]+\\)\\s*`, 'g'), '') : 'none';
},
disable: (el) => {
let dom = getEl(el);
if (!dom)
return;
dom.style.transitionDuration = `0ms`;
},
enable: (el, duration = 200) => {
let dom = getEl(el);
if (!dom)
return;
dom.style.transitionDuration = `${duration}ms`;
},
clear: (el) => {
let dom = getEl(el);
if (!dom)
return;
dom.style.transition = `none`;
},
matrix: (elem) => {
let el = getEl(elem);
if (!el)
return [];
let value = style(el).transform;
return (value === 'none') ? [1, 0, 0, 1, 0, 0] : value.replace(/[^0-9.\-,]/g, '').split(',').map(k => Number(k));
},
};
const isScrollUp = (event, detailName = getScrollObj().detail) => {
let mouseDetail = event[detailName], isUp;
if (navigator.userAgent.indexOf("Firefox") > 0) {
isUp = mouseDetail > 0 ? true : false;
}
else {
isUp = mouseDetail < 0 ? true : false;
}
return isUp;
};
const eventMap = ax.isTouchScr ? ['touchstart', 'touchmove', 'touchend', 'touchcancel'] : ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];
const getClientObj = (event) => {
let tmp = ax.isTouchScr ? event.targetTouches[0] : event;
return tmp ? { x: tmp.clientX, y: tmp.clientY } : null;
};
const getNestProp = (data, path) => {
if (!path)
return data;
return path.replace(/['"\s]/g, '').split('.').reduce((prev, cur) => {
if (prev && prev[cur] !== undefined)
return prev[cur];
if (cur.endsWith(']')) {
let tmp = [];
if (cur.startsWith('[')) {
tmp = cur.split(']').map((k) => k.replace('[', '')).filter(Boolean);
}
else {
tmp = cur.split('[').map((k) => k.replace(']', ''));
}
return tmp.reduce((a, b) => a && a[b], prev);
}
return undefined;
}, data);
};
const arrSort = (source, basis) => {
if (isEmpty(source))
return;
let basisType = getDataType(basis), _basis = [], basisFn = (keys) => {
if (keys.length === 0)
return (a, b) => (a + '').localeCompare(b + '', config.lang.name);
return (a, b) => {
for (let k of keys) {
let key = '', dir = 0, result = 0;
if (k.hasOwnProperty('key')) {
key = k.key;
}
else {
key = 'label';
}
if (k.hasOwnProperty('dir')) {
dir = k.dir === 'asc' ? 1 : k.dir === 'desc' ? -1 : 0;
}
else {
dir = 1;
}
result = (getNestProp(a, key) + '').localeCompare(getNestProp(b, key) + '', k.locale || config.lang.name, k.opt || {});
if (result !== 0)
return result * dir;
}
return 0;
};
};
if (basisType === 'Object') {
_basis = [basis];
}
else if (basisType === 'Array') {
_basis = basis;
}
source.sort(basisFn(_basis));
};
const clearRegx = (data) => (data + '').replace(/[.*+?^${}()|[\]\\]/g, '');
const arrSearch = ({ keys, props = 'label', source = [], fuzzy = true, limit = 0, order = '', ignore = true, hyphen = config.splitHyphen }) => {
if (isEmpty(keys) || isEmpty(props) || isEmpty(source)) {
return [];
}
let keysArr = valToArr(keys, hyphen).map((k) => clearRegx(k)).filter(Boolean), propsArr = valToArr(props, hyphen), crudeArr = [], regStr = '(' + keysArr.join('|') + ')', regExp = new RegExp(regStr, `${ignore ? 'i' : ''}g`), lowerSet = (arr) => [...new Set(arr.map((k) => k.toLowerCase()))];
for (let v of source) {
let valueStr = propsArr.map(k => v[k]).join('■'), valueMatch = valueStr.match(regExp), valueObj = {}, keysMatch = [];
if (valueMatch) {
keysMatch = [...new Set(valueMatch)];
valueObj = { source: v, weight: valueMatch.length, keys: keysMatch };
if (!fuzzy) {
if (ignore) {
(lowerSet(keysArr).length === lowerSet(keysMatch).length) && crudeArr.push(valueObj);
}
else {
(keysArr.length === keysMatch.length) && crudeArr.push(valueObj);
}
}
else {
crudeArr.push(valueObj);
}
}
}
if (order) {
let orderType = getDataType(order), basis;
if (orderType === 'String') {
basis = order === 'desc' ? { key: 'weight', dir: 'desc' } : order === 'asc' ? { key: 'weight', dir: 'asc' } : '';
}
else if (orderType === 'Boolean' && order === true) {
basis = { key: 'weight', dir: 'desc' };
}
else {
basis = order;
}
arrSort(crudeArr, basis);
}
(limit && crudeArr.length > limit) && crudeArr.splice(limit);
return crudeArr;
};
const getIntArr = (data, hyphen = config.splitHyphen) => {
let arrs = data.map((k) => {
return typeof k === 'string' ? valToArr(k, hyphen) : k;
});
return arrs.reduce((prev, cur) => prev.filter((k) => cur.includes(k)));
};
const isOutside = (ev, elem) => {
let el = getEl(elem);
if (!el || !ev)
return true;
let point = ax.isTouchScr ? { x: ev.targetTouches[0].clientX, y: ev.targetTouches[0].clientY } : { x: ev.clientX, y: ev.clientY }, lt = { x: el.getBoundingClientRect().left, y: el.getBoundingClientRect().top }, rb = { x: lt.x + el.offsetWidth, y: lt.y + el.offsetHeight };
return (point.x < lt.x || point.x > rb.x || point.y < lt.y || point.y > rb.y) ? true : false;
};
const getEvtClient = (evt, axis) => {
let data = evt.targetTouches && evt.targetTouches[0] ? evt.targetTouches[0] : evt.changedTouches ? evt.changedTouches[0] : evt, prop = axis === 'x' ? 'clientX' : axis === 'y' ? 'clientY' : '';
return prop ? data[prop] : { x: data.clientX, y: data.clientY };
};
const getRectPoints = (evt, elem) => {
let el = getEl(elem), result = [];
if (!el || !evt)
return result;
let point = getEvtClient(evt), x = point.x, y = point.y, size = { w: el.offsetWidth, h: el.offsetHeight }, lt = { x: el.getBoundingClientRect().left, y: el.getBoundingClientRect().top }, rb = { x: lt.x + size.w, y: lt.y + size.h }, range = { 'h1/3': lt.y + size.h / 3, 'h1/2': lt.y + size.h / 2, 'h2/3': lt.y + size.h * 2 / 3, 'w1/3': lt.x + size.w / 3, 'w1/2': lt.x + size.w / 2, 'w2/3': lt.x + size.w * 2 / 3 };
if (x >= lt.x && x <= rb.x && y >= lt.y && y <= rb.y) {
result.push('inside');
if (y < range['h1/3']) {
result.push('t/3');
}
else if (y >= range['h1/3'] && y < range['h1/2']) {
result.push('t/2');
}
else if (y >= range['h2/3']) {
result.push('b/3');
}
else if (y >= range['h1/2']) {
result.push('b/2');
}
if (x < range['w1/3']) {
result.push('l/3');
}
else if (x >= range['w1/3'] && x < range['w1/2']) {
result.push('l/2');
}
else if (x >= range['w2/3']) {
result.push('r/3');
}
else if (x >= range['w1/2']) {
result.push('r/2');
}
}
else {
result = ['outside'];
}
return result;
};
const elsSort = (data, reverse = false) => {
let tmp = data.map((k) => getEl(k)).filter(Boolean), els = unique(tmp);
els.sort((a, b) => {
if (a.contains(b))
return 1;
if (b.contains(a))
return -1;
return 0;
});
return reverse ? els.reverse() : els;
};
const getStrFromTpl = function (data, tplStr, tplEng) {
let str = tplStr || this.tplStr, eng = tplEng || this.tplEng;
return eng.name === 'template' ? eng(str)(data) : eng(str, data);
};
const setSingleSel = (target, sel) => {
let arr = Array.isArray(target) ? target : [target], els = arr.map((k) => getEls(k)).flat().filter(Boolean), setFn = (el) => {
if (sel.trim().startsWith('#')) {
el.id = sel.slice(1);
}
else if (sel.trim().startsWith('.')) {
el.classList.add(sel.slice(1));
}
else if (sel.trim().startsWith('[') && sel.trim().endsWith(']')) {
let tmp = sel.slice(1, -1).replace('"', '').replace("'", '').split('=');
el.setAttribute(tmp[0], tmp[1] || '');
}
};
if (els.length === 0 || !sel || typeof sel !== 'string')
return;
for (let k of els) {
setFn(k);
}
};
const parseUrlArr = (url, opts = {}) => {
if (!url)
return [];
let options = Object.assign({ start: '{', end: '}', max: 20 }, opts), result = [], reg = new RegExp(`\\${options.start}(\\S*)\\${options.end}`), match = url.match(reg);
if (!match)
return [];
let tmp = match[1], pageRange = tmp.split('-').map((k) => ~~k), pageCount = tmp.split(',').map((k) => ~~k), pageStart = pageRange[0], pageEnd = pageRange[1], pageMax = pageEnd || pageStart + options.max, holder = `${options.start}${tmp}${options.end}`;
if (url.includes(',')) {
result = pageCount.map((k) => url.replace(holder, k));
}
else {
for (let i = pageStart; i <= pageMax; i++) {
result.push(url.replace(holder, i));
}
}
return result;
};
const dateTools = {
toSlash: (data) => {
return data.replaceAll('-', '/');
},
getTimeObj: function (str) {
let tmp = str.replaceAll(' ', '').split(':'), result = { hh: 0, mm: 0, ss: 0 };
if (str) {
if (tmp.length < 2) {
result.hh = ~~str || 0;
}
else {
result.hh = ~~tmp[0] || 0;
result.mm = ~~tmp[1] || 0;
result.ss = ~~tmp[2] || 0;
}
}
return result;
},
int2Date: (value, type = 'datetime') => {
value = ~~value;
let prop = (type === 'daytime') ? 'hh' : (type === 'month') ? 'MM' : 'YYYY';
return { value, prop };
},
getDate: function (data, type = 'datetime', lang = config.lang.datetime) {
let dateType = getDataType(data), result;
if (isEmpty(data)) {
result = new Date();
}
else {
if (dateType === 'Date') {
result = new Date(data.valueOf());
}
else if (dateType === 'String') {
let isBc = data.includes(lang.bc);
data = this.toSlash(trim(data).replace(lang.bc, ''));
if (data.includes(' ')) {
result = new Date(data);
if (!data.includes('/')) {
console.warn('Invalid date format, current date used instead!');
result = new Date();
}
else {
let tmp = data.split(' '), tmpStart = tmp[0].split('/'), tmpEnd = tmp[1].split(':'), tmpFlat, tmpDate;
tmpStart[1] = tmpStart[1] ? tmpStart[1] - 1 : 0;
tmpStart[2] = tmpStart[2] || 0;
tmpEnd[1] = tmpEnd[1] || 0;
tmpEnd[2] = tmpEnd[2] || 0;
tmpFlat = [...tmpStart, ...tmpEnd].map((k) => ~~k);
isBc && (tmpFlat[0] = tmpFlat[0] * -1);
tmpDate = new Date(...tmpFlat);
tmpDate.setFullYear(tmpFlat[0]);
result = tmpDate;
}
}
else {
if (data.includes(':')) {
result = new Date('1970/1/1 ' + data);
}
else if (data.includes('/')) {
let tmp = data.split('/').map((k) => ~~k);
tmp[1] && tmp[1]--;
isBc && (tmp[0] = tmp[0] * -1);
result = new Date(...tmp);
}
else {
result = new Date('1970/1/1 00:00:00');
let tmp = this.int2Date(data, type);
tmp.prop === 'hh' ? result.setHours(tmp.value) : tmp.prop === 'MM' ? result.setMonth(tmp.value - 1) : result.setFullYear(isBc ? tmp.value * -1 : tmp.value);
}
}
}
else if (dateType === 'Object') {
result = new Date('1970/1/1 00:00:00');
data.hasOwnProperty('YYYY') && result.setFullYear(data.YYYY);
data.hasOwnProperty('MM') && result.setMonth(data.MM);
data.hasOwnProperty('DD') && result.setDate(data.DD);
data.hasOwnProperty('hh') && result.setHours(data.hh);
data.hasOwnProperty('mm') && result.setMinutes(data.mm);
data.hasOwnProperty('ss') && result.setSeconds(data.ss);
}
else {
result = new Date();
}
}
if (['date', 'year', 'month'].includes(type)) {
result.setHours(0);
result.setMinutes(0);
result.setSeconds(0);
['year', 'month'].includes(type) && result.setDate(1);
type === 'year' && result.setMonth(0);
}
else if (type === 'daytime') {
result.setFullYear(1970);
result.setMonth(0);
result.setDate(1);
}
return result;
},
getDateObj: function (data, type = 'datetime') {
let dataType = getDataType(data), date, result;
if (dataType === 'Object') {
result = { ...data };
}
else {
date = this.getDate(data, type);
result = { YYYY: date.getFullYear(), MM: date.getMonth(), DD: date.getDate(), hh: date.getHours(), mm: date.getMinutes(), ss: date.getSeconds() };
}
if (['date', 'year', 'month'].includes(type)) {
Reflect.deleteProperty(result, 'hh');
Reflect.deleteProperty(result, 'mm');
Reflect.deleteProperty(result, 'ss');
['year', 'month'].includes(type) && Reflect.deleteProperty(result, 'DD');
type === 'year' && Reflect.deleteProperty(result, 'MM');
}
else if (type === 'daytime') {
Reflect.deleteProperty(result, 'YYYY');
Reflect.deleteProperty(result, 'MM');
Reflect.deleteProperty(result, 'DD');
}
return result;
},
getCurDays: function (data) {
let curDate = this.getDate(data), curYear = curDate.getFullYear(), curMonth = curDate.getMonth();
return new Date(curYear, curMonth + 1, 0).getDate();
},
getOffsetDate: function (data, options = { YYYY: 0, MM: 0, DD: 0, hh: 0, mm: 0, ss: 0 }) {
let curDate = this.getDate(data);
options.hasOwnProperty('ss') && curDate.setDate(curDate.getSeconds() + options.ss);
options.hasOwnProperty('mm') && curDate.setDate(curDate.getMinutes() + options.mm);
options.hasOwnProperty('hh') && curDate.setDate(curDate.getHours() + options.hh);
options.hasOwnProperty('DD') && curDate.setDate(curDate.getDate() + options.DD);
options.hasOwnProperty('MM') && curDate.setMonth(curDate.getMonth() + options.MM);
options.hasOwnProperty('YYYY') && curDate.setFullYear(curDate.getFullYear() + options.YYYY);
return curDate;
},
fillZero: (data, places = 2) => data.toString().padStart(places, '0'),
fillFormat: function (date, format, lang = config.lang.datetime) {
let YYYY, MM, DD, hh, mm, ss, WW, weeks = lang.weeks, tmp = this.getDate(date);
YYYY = tmp.getFullYear();
MM = tmp.getMonth() + 1;
DD = tmp.getDate();
WW = tmp.getDay();
hh = tmp.getHours();
mm = tmp.getMinutes();
ss = tmp.getSeconds();
if (format.includes('YYYY')) {
let tmp = Math.abs(YYYY) + '';
if (YYYY < 0) {
if (format.includes('BC')) {
format = format.replace('BC', lang.bc);
}
else {
tmp = lang.bc + tmp;
}
}
else {
format.includes('BC') && (format = format.replace('BC', ''));
}
format = format.replace('YYYY', tmp);
}
format.includes('MM') && (format = format.replace('MM', this.fillZero(MM)));
format.includes('DD') && (format = format.replace('DD', this.fillZero(DD)));
format.includes('hh') && (format = format.replace('hh', this.fillZero(hh)));
format.includes('mm') && (format = format.replace('mm', this.fillZero(mm)));
format.includes('ss') && (format = format.replace('ss', this.fillZero(ss)));
format.includes('WW') && (format = format.replace('WW', weeks[WW]));
return format;
},
sort: function (data, order = 'asc') {
return data.sort((a, b) => order === 'asc' ? this.getDate(a) - this.getDate(b) : this.getDate(b) - this.getDate(a));
},
getDateType: (format) => {
return RegExp(/^(?=.*YYYY)(?=.*MM)(?=.*DD)(?=.*hh).*$/).test(format) ? 'datetime' :
RegExp(/^(?=.*YYYY)(?=.*MM)(?=.*DD).*$/).test(format) ? 'date' :
RegExp(/^(?=.*YYYY)(?=.*MM).*$/).test(format) ? 'month' :
RegExp(/^(?=.*YYYY).*$/).test(format) ? 'year' :
RegExp(/^(?=.*hh).*$/).test(format) ? 'daytime' : '';
},
isSameDay: (a, b) => {
return a.YYYY == b.YYYY && a.MM == b.MM && a.DD == b.DD;
}
};
const repeatStr = (tpl, num = 1, data) => {
let result = '';
for (let i = 1; i <= num; i++) {
result += renderTpl(tpl, { index: i, data });
}
return result;
};
const createModule = (options) => {
let opts = Object.assign({ type: 'none', optMaps: [], component: false, spread: [], methods: {}, ready: null, init: null, augment: false, initial: true }, options), modName = opts.name || 'Module' + Date.now(), hasHost = ['node', 'data'].includes(opts.type), hostType = hasHost ? opts.type : 'none', str = `"use strict";
return class ${modName} extends ModBaseListenCache {
static hostType = "${hostType}";
static optMaps = optMaps;
constructor(${hasHost ? 'host,' : ''}options, eager = initial) {
super();
super.ready({ type:"${hostType}",${hasHost ? 'host,' : ''} options, optMaps:${modName}.optMaps, component, spread });
constructed && constructed.call(this);
super.listen({ name: 'constructed' });
eager && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try{
this.options.b4Init && await this.options.b4Init.call(this);
}catch{
console.warn(config.warn.init);
return this;
}
initiated && await initiated.call(this);
super.listen({ name: 'initiated', cb });
return this;
}
}
`, module = new Function('optMaps', 'component', 'spread', 'constructed', 'initiated', 'initial', 'ModBaseListenCache', 'config', str)(opts.optMaps, opts.component, opts.spread, opts.constructed, opts.initiated, opts.initial, ModBaseListenCache, config);
for (let k in opts.methods) {
module.prototype[k] = opts.methods[k];
}
opts.augment && (ax[modName] = module);
return module;
};
const createComp = (options) => {
let opts = Object.assign({ attrs: [], methods: {}, excludeAttrs: [], modOpts: {}, augment: false, autoUpdate: true, autoIns: true, register: true }, options), elem = window.customElements.get(opts.tagName);
if (elem) {
console.warn(`${opts.tagName} is already defined!`);
return elem;
}
let compName = opts.compName || 'Comp' + Date.now(), hostName = opts.hostName || 'div', optMaps = opts.module ? opts.module.optMaps : [], attrs = opts.module ? [...optMaps.map((k) => k.attr), ...opts.attrs] : opts.attrs, str = `"use strict";
return class ${compName} extends CompBaseComm {
constructor() {
super();
this.createShadow();
this.createPropsObs();
this.optMaps = optMaps;
this.canUpdate = true;
for (let k of [...attrs, 'options']) this.propsRaw[k] = this.getAttribute(k);
this.on('connected',()=>{
connected && connected.call(this);
});
this.reset = () => {
this.restoreAttrs();
this.listen({ name: 'reset' });
}
for (let k in methods) this[k] = methods[k].bind(this);
constructed && constructed.call(this);
this.listen({ name: 'constructed'});
}
static get observedAttributes() {
return [...attrs, 'options'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen) return;
!excludeAttrs.includes(name) && this.updateProxy(name, newVal,this.optMaps);
changed && changed.call(this,{name, oldVal, newVal});
this.listen({ name: 'changed', params: [{name, oldVal, newVal}] });
}
render() {
this.insertSource();
this.wrapEl = createEl('${hostName}',{${ax.alias}:'slot-host'}, this.rawHtml);
this.appendChild(this.wrapEl);
autoIns && module && (this.ins = new module(this.wrapEl,modOpts));
this.propsObs.on('completed', (data) => {
if(this.connCount > 1){
autoUpdate && this?.ins?.update && this.ins.update(this.properties);
updated && updated.call(this,data);
this.listen({ name: 'updated',params:[data]});
}
this.listen({ name: 'completed',params:[data]});
});
}
}
`, component = new Function('constructed', 'connected', 'changed', 'updated', 'autoUpdate', 'autoIns', 'excludeAttrs', 'module', 'modOpts', 'CompBaseComm', 'createEl', 'attrs', 'optMaps', 'methods', str)(opts.constructed, opts.connected, opts.changed, opts.updated, opts.autoUpdate, opts.autoIns, opts.excludeAttrs, opts.module, opts.modOpts, CompBaseComm, createEl, attrs, optMaps, opts.methods);
opts.register && window.customElements.define(opts.tagName, component);
opts.augment && (ax[compName] = component);
return component;
};
const getArrMap = (data, key) => {
if (!Array.isArray(data) || !data.length)
return null;
let map = new Map();
for (let k of data) {
let prop = key ? k[key] : k;
!map.has(k[prop]) && map.set(prop, k);
}
return map;
};
const includes = (data, value) => {
if (!Array.isArray(data) || !data.length)
return false;
let set = new Set(data), result = set.has(value);
set.clear();
return result;
};
const capStart = (str) => {
let idx = str.search(/[a-zA-Z]/);
if (idx > -1) {
let char = str.charAt(idx);
return str.replace(char, char.toUpperCase());
}
else {
return str;
}
};
const removeItem = (data, item) => {
if (!Array.isArray(data) || !data.length || !item)
return;
for (let i = 0; i < data.length; i++) {
if (data[i] === item) {
data.splice(i, 1);
break;
}
}
};
const appendEls = ({ parent, nodes, reverse = false, target, prepend = false }) => {
let fragment = document.createDocumentFragment(), tmp = Array.isArray(nodes) ? nodes : [nodes], data = tmp.filter((k) => k && k.nodeType && (k.nodeType === k.ELEMENT_NODE)), host = getEl(parent), targetEl = getEl(target, host), refer;
if (!host || !data.length)
return;
for (let k of data)
reverse ? fragment.prepend(k) : fragment.appendChild(k);
if (targetEl) {
refer = prepend ? targetEl : targetEl.nextElementSibling;
}
else {
refer = prepend ? host.firstElementChild : null;
}
host.insertBefore(fragment, refer);
};
const decompTask = ({ tasks: initTasks, run, count = 4, doing, done, type = 'idle', delay = 0 }) => {
if (!Array.isArray(initTasks) || !initTasks.length)
return;
if (typeof run !== 'function')
throw new Error('run must be a function!');
let tasks = [...initTasks], idx = 0, isAborted = false, next = () => {
if (isAborted)
return;
if (type === 'timeout')
setTimeout(handler, delay);
else if (type === 'idle')
requestIdleCallback(handler);
else
requestAnimationFrame(handler);
}, handler = () => {
if (isAborted)
return;
let end = Math.min(idx + count, tasks.length);
for (; idx < end; idx++) {
let task = tasks[idx], progress = tasks.length <= 1 ? 1 : idx / (tasks.length - 1);
try {
run && run(task);
}
catch (err) {
console.error('Task error:', err);
}
doing?.(task, progress);
}
idx >= (tasks.length) ? done?.() : next();
};
next();
return {
abort: () => { isAborted = true; },
add: (newTasks) => {
if (!newTasks)
return;
let tmp = Array.isArray(newTasks) ? newTasks : [newTasks];
tasks.push(...tmp);
(idx >= tasks.length - tmp.length && !isAborted) && next();
}
};
};
const filterPrims = (data) => {
let filter = (obj) => {
return Object.entries(obj).reduce((start, [key, value]) => {
if (['number', 'string', 'boolean', 'undefined', 'bigint', 'symbol'].includes(typeof value)) {
start[key] = value;
}
return start;
}, {});
};
if (Array.isArray(data)) {
return data.map((k) => {
let dataType = getDataType(k);
return dataType === 'Object' ? filter(k) : k;
});
}
else {
let dataType = getDataType(data);
return dataType === 'Object' ? filter(data) : data;
}
};
const optPopup$1 = [
{
attr: 'placement',
prop: 'placement',
value: 'center',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'click',
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'in',
prop: 'in',
value: 'fadeIn',
},
{
attr: 'out',
prop: 'out',
value: 'fadeOut',
},
{
attr: 'multiple',
prop: 'multiple',
value: true,
},
{
attr: 'draggable',
prop: 'draggable',
value: true,
},
{
attr: 'feature',
prop: 'feature',
value: '',
},
{
attr: 'height',
prop: 'height',
value: '',
},
{
attr: 'adaptive',
prop: 'adaptive',
value: true,
},
{
attr: 'draggable',
prop: 'draggable',
value: true,
},
{
attr: 'gesture',
prop: 'gesture',
value: {},
},
{
attr: 'parent',
prop: 'parent',
value: '',
},
{
attr: 'wing',
prop: 'wing',
value: {
selector: '',
actClass: '',
},
},
{
attr: 'mask',
prop: 'mask',
value: {
enable: true,
closable: true,
},
},
...optBubble
];
const optGesture = [
{
attr: 'parent',
prop: 'parent',
value: ''
},
{
attr: 'viewport',
prop: 'viewport',
value: {
enable: false,
selector: '',
dmpRatio: 0.8,
bouncy: true,
duration: 0,
},
},
{
attr: 'jitter-click',
prop: 'jitterClick',
value: 10,
},
{
attr: 'jitter-trans',
prop: 'jitterTrans',
value: 1,
},
{
attr: 'origin',
prop: 'origin',
value: null,
},
{
attr: 'unbound',
prop: 'unbound',
value: '[unbound]',
},
{
attr: 'spy',
prop: 'spy',
value: {
enable: false,
},
},
{
attr: 'click',
prop: 'click',
value: {
timeThr: 200,
delay: 200,
dblclickable: true,
holdDelay: 1000,
hold2Menu: false,
},
},
{
attr: 'step',
prop: 'step',
value: {
mode: 'translate',
axis: 'y',
value: 0,
duration: 500,
intvl: 200,
linkage: true,
reverse: false,
curve: 'easeOut',
},
},
{
attr: 'wheel',
prop: 'wheel',
value: false,
},
{
attr: 'keyboard',
prop: 'keyboard',
value: {
enable: false,
prev: 'ArrowUp',
next: 'ArrowDown',
intvl: 200,
target: null,
},
},
{
attr: 'translate',
prop: 'translate',
value: {
enable: true,
max: 10000000,
min: -10000000,
instead: false,
target: '',
},
},
{
attr: 'drift',
prop: 'drift',
value: {
enable: false,
timeThr: 300,
distThr: 20,
coef: 0.5,
duration: 500,
curve: 'easeOut',
auto: true,
},
},
{
attr: 'swipe',
prop: 'swipe',
value: {
enable: false,
timeThr: 100,
distThr: 20,
coef: 0.5,
duration: 500,
curve: 'easeOut',
auto: true,
},
},
{
attr: 'scale',
prop: 'scale',
value: {
enable: false,
centered: true,
max: 100,
min: 0,
},
},
{
attr: 'rotate',
prop: 'rotate',
value: {
enable: false,
max: 3600,
min: -3600,
},
},
{
attr: 'initial-val',
prop: 'initialVal',
value: null,
},
{
attr: 'b4-trigger',
prop: 'b4Trigger',
value: null,
},
{
attr: 'on-start',
prop: 'onStart',
value: null,
},
{
attr: 'on-move',
prop: 'onMove',
value: null,
},
{
attr: 'on-enter',
prop: 'onEnter',
value: null,
},
{
attr: 'on-leave',
prop: 'onLeave',
value: null,
},
{
attr: 'on-end',
prop: 'onEnd',
value: null,
},
{
attr: 'on-click',
prop: 'onClick',
value: null,
},
{
attr: 'on-dblclick',
prop: 'onDblclick',
value: null,
},
{
attr: 'on-hold',
prop: 'onHold',
value: null,
},
{
attr: 'on-scale',
prop: 'onScale',
value: null,
},
{
attr: 'on-scaling',
prop: 'onScaling',
value: null,
},
{
attr: 'on-scaled',
prop: 'onScaled',
value: null,
},
{
attr: 'on-rotate',
prop: 'onRotate',
value: null,
},
{
attr: 'on-rotating',
prop: 'onRotating',
value: null,
},
{
attr: 'on-rotated',
prop: 'onRotated',
value: null,
},
{
attr: 'on-translate',
prop: 'onTranslate',
value: null,
},
{
attr: 'on-translating',
prop: 'onTranslating',
value: null,
},
{
attr: 'on-translated',
prop: 'onTranslated',
value: null,
},
{
attr: 'on-drift',
prop: 'onDrift',
value: null,
},
{
attr: 'on-drifting',
prop: 'onDrifting',
value: null,
},
{
attr: 'on-drifted',
prop: 'onDrifted',
value: null,
},
{
attr: 'on-canceled',
prop: 'onCanceled',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null,
},
{
attr: 'on-finished',
prop: 'onFinished',
value: null,
},
...optBase
];
const optSpy = [
{
attr: 'margin',
prop: 'margin',
value: '0px',
},
{
attr: 'threshold',
prop: 'threshold',
value: [0, 1]
},
{
attr: 'root',
prop: 'root',
value: null
},
{
attr: 'spy-sel',
prop: 'spySel',
value: '',
},
{
attr: 'nav-sel',
prop: 'navSel',
value: '',
},
{
attr: 'sub-sel',
prop: 'subSel',
value: '',
},
{
attr: 'intvl',
prop: 'intvl',
value: 500,
},
{
attr: 'repeat',
prop: 'repeat',
value: true,
},
{
attr: 'active',
prop: 'active',
value: '',
},
{
attr: 'in',
prop: 'in',
value: '',
},
{
attr: 'out',
prop: 'out',
value: '',
},
{
attr: 'visible',
prop: 'visible',
value: true,
},
{
attr: 'manual',
prop: 'manual',
value: false,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'wing',
prop: 'wing',
value: {
selector: '',
offset: 0,
duration: 0,
},
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'on-show',
prop: 'onShow',
value: null,
},
{
attr: 'on-showing',
prop: 'onShowing',
value: null,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-in',
prop: 'onIn',
value: null,
},
{
attr: 'on-out',
prop: 'onOut',
value: null,
},
{
attr: 'on-added',
prop: 'onAdded',
value: null,
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null,
},
...optBase
];
class Spy extends ModBaseListen {
options = {};
storObs;
storTmp;
navEl;
subEls;
items;
interactIns;
rootEl;
actIsAttr;
active;
hide2Debounce;
static hostType = 'node';
static optMaps = optSpy;
constructor(elem, options = {}) {
super();
super.ready({
options,
maps: Spy.optMaps,
host: elem,
component: false,
});
this.navEl = this.options.navSel ? getEl(this.options.navSel) : null;
this.subEls = this.navEl && this.options.subSel ? this.navEl.querySelectorAll(this.options.subSel) : [];
this.hide2Debounce = debounce((el) => {
if (el.ax.spy.state === 'hidden') {
if (el.ax.spy?.out) {
classes(el).add(el.ax.spy?.out);
}
if (el.ax.spy?.in) {
classes(el).remove(el.ax.spy?.in);
!this.options.visible && classes(el).add(`${ax.prefix}o`);
}
if (this.active) {
el.ax.spy.wing.forEach((k) => {
this.actIsAttr ? k.removeAttribute(this.active[0]) : classes(k).remove(this.active);
});
}
}
}, this.options.intvl);
this.rootEl = getEl(this.options.root);
this.getActive();
super.listen({ name: 'constructed' });
this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.items = [];
this.interactIns && this.interactIns.disconnect();
this.interactIns = new IntersectionObserver(entries => {
entries.forEach(i => {
let args = { target: i.target, ratio: i.intersectionRatio, ins: this.interactIns, entry: i };
if (i.isIntersecting) {
args.intersecting = true;
if (i.intersectionRatio === 0) {
i.target.ax.spy.state = 'show';
super.listen({ name: 'shown', params: [args] });
}
else if (i.intersectionRatio === 1) {
i.target.ax.spy.state = 'shown';
super.listen({ name: 'shown', params: [args] });
this.setActiveOnly(i.target);
}
else {
i.target.ax.spy.state = 'showing';
super.listen({ name: 'showing', params: [args] });
}
if (i.target.ax.spy.ratio < i.intersectionRatio) {
super.listen({ name: 'in', params: [args] });
!this.options.visible && classes(i.target).remove(`${ax.prefix}o`);
if (i.target.ax.spy.state = 'showing') {
if (i.target.ax.spy?.in) {
classes(i.target).add(i.target.ax.spy?.in, (name) => i.target.classList.contains(name) ? false : true);
}
}
!this.options.repeat && this.interactIns.unobserve(i.target);
}
i.target.ax.spy.ratio = i.intersectionRatio;
}
else {
args.intersecting = false;
i.target.ax.spy.state = 'hidden';
if (this.options.repeat) {
this.hide2Debounce.cancel()(i.target);
}
super.listen({ name: 'out', params: [args] });
i.target.ax.spy.ratio = 0;
}
});
}, {
root: this.rootEl,
rootMargin: this.options.margin,
threshold: this.options.threshold,
});
if (this.options.spySel) {
this.items = [...this.targetEl.querySelectorAll(this.options.spySel)];
}
else {
this.targetEl && this.items.push(this.targetEl);
}
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, this.items);
resp && (this.items = resp);
}
if (!this.options.manual && this.items.length) {
this.items.forEach((k) => {
this.setSpyAttr(k);
this.interactIns.observe(k);
});
}
super.listen({ name: 'initiated', cb });
return this;
}
getActive() {
let activeTrim = this.options.active.trim();
if (activeTrim.startsWith('[') && activeTrim.endsWith(']')) {
this.actIsAttr = true;
this.active = activeTrim.replace('[', '').replace(']', '').replace(' ', '').split('=');
}
else {
this.actIsAttr = false;
this.active = this.options.active;
}
}
setActiveOnly(el) {
if (!isEmpty(this.active)) {
el.ax.spy.wing.forEach((k) => {
if (this.actIsAttr) {
if (this.active.length > 0) {
k.setAttribute(this.active[0], this.active[1] || '');
}
}
else {
classes(k).add(this.active, (name) => {
return k.classList.contains(name) ? false : true;
});
}
});
let other = this.items.filter((k) => k !== el && k.ax.spy), otherWings = other.map((k) => k.ax.spy.wing).flat(Infinity);
otherWings.forEach((k) => {
this.actIsAttr ? k.removeAttribute(this.active[0]) : classes(k).remove(this.active);
});
}
}
setSpyAttr(el) {
if (!getDataType(el).includes('HTML'))
return;
let attrs = attrToJson(el, 'spy'), props = {
observed: true,
wing: this.getWings(el),
in: attrs.in || this.options.in,
out: attrs.out || this.options.out,
ratio: 0,
};
if (!el.ax) {
el.ax = { spy: props };
}
else {
el.ax.spy = props;
}
this.options.classes && classes(el).add(this.options.classes);
!this.options.visible && classes(el).add(`${ax.prefix}o`);
}
getWings(el) {
let arrFromId = [], arrFromSpy = [], arrFromOpt = [], wingArr = [];
if (el.id) {
if (this.subEls.length > 0 && this.subEls[0].hasAttribute('href')) {
let navWing = this.subEls.find((k) => k.getAttribute('href') === `#${k.id}`);
navWing && arrFromId.push(navWing);
}
else {
arrFromId = [...document.querySelectorAll(`[href='#${el.id}']`)];
}
}
else {
let index = this.items.findIndex((k) => k == el);
index !== -1 && this.subEls[index] ? arrFromId.push(this.subEls[index]) : null;
}
if (el.hasAttribute('spy')) {
let attrs = attrToJson(el, 'spy');
if (attrs.wing) {
arrFromSpy = allToEls(attrs.wing);
}
}
if (this.options.wing.selector) {
arrFromOpt = allToEls(this.options.wing.selector);
}
wingArr = [...arrFromId, ...arrFromSpy, ...arrFromOpt].filter(Boolean);
wingArr.forEach(k => {
k.onclick = (e) => {
preventDft(e);
scrollTo(el, { root: this.rootEl, duration: this.options.wing.duration, offset: this.options.wing.offset });
};
});
return wingArr;
}
getEls(data) {
let dataType = getDataType(data), els = [];
if (dataType === 'Array') {
els = data.map((k) => getEl(k)).filter(Boolean);
}
else if (dataType === 'String') {
els = allToEls(data).filter(Boolean);
}
return els;
}
async add(data, cb) {
if (this.destroyed)
return;
let els = this.getEls(data);
if (!els.length)
return this;
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, els);
resp && (els = resp);
}
els.forEach((i) => {
if (!i?.ax?.spy) {
this.setSpyAttr(i);
this.interactIns.observe(i);
!this.items.includes(i) && this.items.push(i);
}
else {
new Message({
content: renderTpl(this.options.lang.isObserved, { src: i.dataset.src || i.src }),
iconShow: true,
status: 'info',
}).show();
}
});
super.listen({ name: 'add', cb, params: [els] });
return this;
}
async remove(data, cb) {
if (this.destroyed)
return;
let els = this.getEls(data);
this.options.b4Remove && await this.options.b4Remove.call(this, els);
els.forEach((i) => {
if (this.items.includes(i)) {
if (i.ax.spy) {
Reflect.deleteProperty(i, 'spy');
this.interactIns.unobserve(i);
}
else {
new Message({
content: renderTpl(this.options.lang.isUnobserved, { src: i.dataset.src || i.src }),
iconShow: true,
status: 'info',
}).show();
}
}
});
super.listen({ name: 'remove', cb, params: [els] });
return this;
}
destroy(cb) {
if (this.destroyed)
return;
this.interactIns.disconnect();
this.items.forEach((k) => {
k.ax.spy.wing.forEach((i) => {
i.onclick = null;
});
});
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const getHypotenuse = (x = 0, y = 0) => Math.sqrt(x * x + y * y);
class Gesture extends ModBaseListen {
options = {};
started;
eventState;
scrollObj;
evtTarget;
startTime;
diffTime;
jitterClick;
jitterTrans;
clickCount;
preventEase;
holdHandler;
canTrans;
transType;
stepVal;
moveVals;
diffVals;
startCoord;
triangleVals;
moveCount;
touchesMoveCount;
paramsFormat;
params;
endParams;
driftListen;
sizes;
viewRange;
viewportEl;
parentEl;
initialVals;
spyIns;
lastVals;
nowVals;
startVals;
totalTrans;
startFn;
moveFn;
endFn;
stepFn;
wheelFn;
keyboardFn;
cancelFn;
menuFn;
triggerFn;
transitionendFn;
preventDft;
lastTarget;
finishFn;
static hostType = 'node';
static optMaps = optGesture;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Gesture.optMaps,
spread: ['translate', 'drift', 'scale', 'swipe', 'rotate', 'viewport', 'keyboard', 'spy']
});
let _this = this;
this.started = false;
this.eventState = 'end';
this.scrollObj = getScrollObj();
this.evtTarget = null;
this.startTime = 0;
this.diffTime = 0;
this.nowVals = {
translate: { x: 0, y: 0 },
scale: { x: 1, y: 1 },
rotate: 0
};
this.jitterClick = _this.options.jitterClick + (ax.isTouchScr ? 10 : 0);
this.jitterTrans = _this.options.jitterTrans + (ax.isTouchScr ? 4 : 0);
this.clickCount = 0;
this.preventEase = false;
this.holdHandler = null;
this.handleEls = getEls(this.options.translate.target);
for (let k of this.handleEls)
k.setAttribute('handle', '');
this.canTrans = true;
this.transType = 'translate';
this.getStepVal();
this.moveVals = {
h: 0,
x: 0,
y: 0,
c: { id: 0, x: 0, y: 0 },
d: { x: '', y: '' }
};
this.diffVals = { scale: 0, rotate: 0, translate: { x: 0, y: 0, h: 0 } };
this.startCoord = { x: 0, y: 0 };
this.triangleVals = { start: { x: 0, y: 0, h: 0 }, last: { x: 0, y: 0, h: 0 }, now: { x: 0, y: 0, h: 0 } };
this.moveCount = 0;
this.touchesMoveCount = 0;
this.paramsFormat = {
orgEvt: null,
pointer: ax.isTouchScr ? 'finger' : 'mouse',
scale: {
direction: 0,
diff: 0,
value: { x: 1, y: 1 },
translate: { x: 0, y: 0 }
},
rotate: {
direction: 0,
diff: 0,
value: 0
},
translate: {
direction: { x: 0, y: 0 },
diff: { x: 0, y: 0, h: 0 },
value: { x: 0, y: 0 },
canDrift: false,
canSwipe: false,
},
drift: {
duration: 0,
direction: { x: 0, y: 0 },
diff: { x: 0, y: 0, h: 0 },
value: { x: 0, y: 0 }
},
swipe: {
duration: 0,
direction: { x: 0, y: 0 },
diff: { x: 0, y: 0, h: 0 },
value: { x: 0, y: 0 }
},
step: {
direction: { x: 0, y: 0 },
},
coord: { x: 0, y: 0 },
target: this.targetEl,
name: '',
moveStart: false,
touchesStart: false,
moveEnd: false,
moveTime: 0,
};
this.params = null;
this.endParams = {
moveStart: false,
touchesStart: false,
moveEnd: true,
};
this.startFn = function (e) {
_this.evtTarget = getEvtTarget(e);
_this.prevEvtDft(e);
_this.params = { ...deepClone(_this.paramsFormat), evtTarget: _this.evtTarget, relatedTarget: null };
_this.params.orgEvt = e;
if ((ax.isTouchScr && e.targetTouches.length > 2 && e.changedTouches.length === 0) || !contains(_this.evtTarget, _this.targetEl)) {
_this.started = false;
return;
}
_this.lastTarget = null;
_this.getStartVals();
_this.targetEl.setAttribute('gesture', 'start');
let changedVals = _this.getTouchCoords(e, 'targetTouches'), targetVals = _this.getTouchCoords(e, 'targetTouches'), paramsHold = { ..._this.params }, paramsTranslate = { ..._this.params }, paramsScale = { ..._this.params }, paramsRotate = { ..._this.params }, paramsStart = { ..._this.params };
_this.startCoord = _this.getCenterCoord(changedVals);
_this.startTime = Date.now();
if (!ax.isTouchScr || e.targetTouches.length === 1) {
_this.holdHandler = setTimeout(() => {
paramsHold.coord = { ..._this.startCoord };
paramsHold.name = 'hold';
_this.listen({ name: 'hold', params: [paramsHold] });
clearTimeout(_this.holdHandler);
}, _this.options.click.holdDelay);
}
else {
_this.holdHandler && clearTimeout(_this.holdHandler);
}
if (ax.isTouchScr && e.targetTouches.length > 1) {
if (_this.options.scale.enable) {
_this.startCoord = _this.getCenterCoord(targetVals);
paramsScale.coord = { ..._this.startCoord };
paramsScale.scale.value = _this.lastVals.scale;
paramsScale.name = 'scale';
_this.listen({ name: 'scale', params: [paramsScale] });
}
if (_this.options.rotate.enable) {
paramsRotate.coord = { ..._this.startCoord };
paramsRotate.rotate.value = _this.lastVals.rotate;
paramsRotate.name = 'rotate';
_this.listen({ name: 'rotate', params: [paramsRotate] });
}
}
if (_this.options.translate.enable) {
paramsTranslate.coord = { ..._this.startCoord };
paramsTranslate.translate.value = { ..._this.lastVals.translate };
paramsTranslate.name = 'translate';
if (_this.handleEls.length === 0 || _this.useHandle(_this.evtTarget)) {
_this.listen({ name: 'translate', params: [paramsTranslate] });
}
else {
_this.canTrans = false;
}
}
paramsStart.coord = { ..._this.startCoord };
paramsStart.scale.value = _this.lastVals.scale;
paramsStart.rotate.value = _this.lastVals.rotate;
paramsStart.translate.value = { ..._this.lastVals.translate };
paramsStart.totalTrans = _this.totalTrans;
paramsStart.name = 'start';
_this.listen({ name: 'start', params: [paramsStart] });
_this.getViewportSizeDiff(_this.lastVals.translate);
_this.started = true;
_this.eventState = 'start';
};
this.moveFn = function (e) {
_this.evtTarget = getEvtTarget(e);
if (!_this.started)
return;
_this.prevEvtDft(e);
_this.driftListen && cancelAnimationFrame(_this.driftListen.frame);
_this.diffTime = Date.now() - _this.startTime;
_this.moveCount++;
_this.params.orgEvt = e;
let targetVals = _this.getTouchCoords(e, 'targetTouches'), moveStart = _this.moveCount === 1 ? true : false;
_this.moveVals = _this.getMoveVals(targetVals, _this.startCoord);
if (_this.moveVals.h <= _this.jitterTrans) {
return;
}
else {
_this.targetEl.style.transitionDuration = `0ms`;
}
let paramsTouches = { ..._this.params, coord: _this.moveVals.c, moveStart, evtTarget: _this.evtTarget, relatedTarget: null }, paramsTranslate = { ...paramsTouches }, paramsScale = { ...paramsTouches }, paramsRotate = { ...paramsTouches }, paramsMove = { ...paramsTouches };
if (_this.options.translate.enable) {
_this.diffVals.translate = { x: ~~_this.moveVals.x, y: ~~_this.moveVals.y, h: ~~_this.moveVals.h };
_this.updateNowTrans();
_this.options.viewport.enable && (_this.nowVals.translate = _this.getBounceVals(_this.nowVals.translate));
_this.moveVals.h > _this.jitterClick && _this.holdHandler && clearTimeout(_this.holdHandler);
paramsTranslate = extend({
target: paramsTouches,
source: {
translate: {
diff: { ..._this.diffVals.translate },
value: { ..._this.nowVals.translate },
direction: _this.moveVals.d
},
name: 'translating'
}
});
_this.totalTrans = _this.nowVals.translate;
if (_this.parentEl && isOutside(e, _this.parentEl))
_this.canTrans = false;
if (_this.canTrans) {
if (_this.options.swipe.enable && _this.diffTime < _this.options.swipe.timeThr && _this.diffVals.translate.h > _this.options.swipe.distThr) {
_this.transType = 'swipe';
}
else {
_this.transType = 'translate';
_this.targetEl.setAttribute('gesture', 'move');
_this.listen({ name: 'translating', params: [paramsTranslate] });
}
}
}
if (ax.isTouchScr && e.targetTouches.length > 1) {
_this.touchesMoveCount++;
_this.triangleVals.now = _this.getTriangleVals(targetVals[0], targetVals[1]);
if (_this.touchesMoveCount === 1) {
_this.triangleVals.start = { ..._this.triangleVals.now };
_this.diffVals.scale = 0;
_this.diffVals.rotate = 0;
paramsTouches.touchesStart = true;
}
else {
_this.diffVals.scale = (_this.triangleVals.now.h / _this.triangleVals.last.h) - 1;
_this.diffVals.rotate = _this.triangleVals.now.a - _this.triangleVals.last.a;
_this.correctDiffRotate();
}
_this.correctRangeScale();
_this.correctRangeRotate();
if (_this.options.scale.enable) {
paramsScale = extend({
target: paramsTouches,
source: {
scale: {
diff: toNumber(_this.diffVals.scale),
value: { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) },
direction: _this.diffVals.scale > 0 ? 1 : _this.diffVals.scale < 0 ? -1 : 0
},
name: 'scaling'
}
});
if (!_this.options.scale.centered) {
paramsScale.scale.translate = _this.getScaleTrans({
coord: paramsScale.coord,
diff: paramsScale.scale.diff,
});
_this.totalTrans = _this.getScaleTrans({
initVal: _this.totalTrans,
coord: paramsScale.coord,
diff: paramsScale.scale.diff,
});
}
_this.listen({ name: 'scaling', params: [paramsScale] });
}
if (_this.options.rotate.enable) {
paramsRotate = extend({
target: paramsTouches,
source: {
rotate: {
diff: toNumber(_this.diffVals.rotate),
value: toNumber(_this.nowVals.rotate),
direction: _this.diffVals.rotate > 0 ? 1 : _this.diffVals.rotate < 0 ? -1 : 0
},
name: 'rotating'
}
});
_this.listen({ name: 'rotating', params: [paramsRotate] });
}
}
paramsMove = extend({
target: paramsTouches,
source: {
rotate: paramsRotate.rotate,
scale: paramsScale.scale,
translate: paramsTranslate.translate,
totalTrans: _this.totalTrans,
name: 'move'
}
});
_this.listen({ name: 'move', params: [paramsMove] });
_this.triangleVals.last = { ..._this.triangleVals.now };
_this.eventState = 'move';
if (_this.lastTarget !== _this.evtTarget) {
if (_this.lastTarget) {
_this.listen({ name: 'leave', params: [{ ...paramsMove, evtTarget: _this.lastTarget, relatedTarget: _this.evtTarget }] });
}
if (_this.evtTarget) {
_this.listen({ name: 'enter', params: [paramsMove] });
}
_this.lastTarget = _this.evtTarget;
}
};
this.endFn = function (e) {
if (!_this.started)
return;
_this.prevEvtDft(e);
_this.moveCount = _this.touchesMoveCount = 0;
_this.params.orgEvt = e;
_this.params.evtTarget = _this.evtTarget;
_this.params.relatedTarget = null;
_this.params.moveTime = _this.diffTime = Date.now() - _this.startTime;
_this.holdHandler && clearTimeout(_this.holdHandler);
let paramsTranslate = {
..._this.params,
coord: { ..._this.moveVals.c },
translate: {
diff: { ..._this.diffVals.translate },
value: { ..._this.nowVals.translate },
direction: { ..._this.moveVals.d },
},
..._this.endParams,
}, paramsClick = { ..._this.params, ..._this.endParams }, paramsScale = { ...paramsClick }, paramsRotate = { ...paramsClick }, paramsEnd = { ...paramsClick };
if (_this.diffVals.translate.h < _this.jitterClick) {
if (_this.diffTime < _this.options.click.timeThr && (!ax.isTouchScr && e.button === 0 || ax.isTouchScr)) {
let coords = _this.getTouchCoords(e, 'changedTouches'), endCoord = _this.getCenterCoord(coords);
paramsClick.coord = endCoord;
paramsClick.name = 'click';
if (_this.options.click.dblclickable) {
_this.clickCount++;
if (_this.clickCount === 1) {
setTimeout(() => {
if (_this.clickCount === 1) {
_this.listen({ name: 'click', params: [paramsClick] });
}
else if (_this.clickCount > 1) {
paramsClick.name = 'dblclick';
_this.listen({ name: 'dblclick', params: [paramsClick] });
}
_this.clickCount = 0;
}, _this.options.click.delay);
}
}
else {
_this.listen({ name: 'click', params: [paramsClick] });
}
}
}
if (_this.canTrans && _this.options.translate.enable) {
let canDrift = _this.diffVals.translate.h > (_this.options.drift.distThr * (ax.isTouchScr ? 2 : 1)) && _this.diffTime < (_this.options.drift.timeThr / (ax.isTouchScr ? 2 : 1));
paramsTranslate.translate.canSwipe = _this.transType === 'swipe' ? true : false;
paramsTranslate.translate.canDrift = paramsTranslate.translate.canSwipe ? false : canDrift;
paramsTranslate.name = 'translated';
_this.listen({ name: 'translated', params: [paramsTranslate] });
if (!_this.preventEase) {
if (_this.transType === 'swipe') {
_this.updateEaseParamsListen(paramsTranslate, 'swipe');
}
else {
(_this.options.drift.enable && canDrift) && _this.updateEaseParamsListen(paramsTranslate);
}
}
_this.options.viewport.enable && _this.moveVals.h > 1 && _this.rebound();
}
if (ax.isTouchScr) {
if (_this.options.scale.enable) {
paramsScale.scale.diff = toNumber(_this.diffVals.scale);
paramsScale.scale.value = { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) };
paramsScale.name = 'scaled';
_this.listen({ name: 'scaled', params: [paramsScale] });
}
if (_this.options.rotate.enable) {
paramsRotate.rotate.diff = toNumber(_this.diffVals.rotate);
paramsRotate.rotate.value = toNumber(_this.nowVals.rotate);
paramsRotate.name = 'rotated';
_this.listen({ name: 'rotated', params: [paramsRotate] });
}
_this.moveVals.h > 1 && _this.getViewportSizeDiff();
_this.lastVals.rotate = _this.nowVals.rotate;
_this.lastVals.scale = { ..._this.nowVals.scale };
}
paramsEnd.translate = paramsTranslate.translate;
paramsEnd.drift = paramsTranslate.drift;
paramsEnd.scale = paramsScale.scale;
paramsEnd.rotate = paramsRotate.rotate;
paramsEnd.totalTrans = _this.totalTrans;
paramsEnd.name = 'end';
_this.listen({ name: 'end', params: [paramsEnd] });
_this.lastVals.translate = { ..._this.nowVals.translate };
_this.setCompleted();
_this.removeSecondEvents();
};
this.stepFn = (e, dirValue, type = 'wheel') => {
if (!_this.options.scale.enable && !_this.options.rotate.enable && !_this.options.translate.enable)
return;
_this.getViewportSizeDiff();
_this.getStartVals();
_this.options.step.duration ? _this.targetEl.style.transitionDuration = `${_this.options.step.duration}ms` : null;
_this.targetEl.style.transitionTimingFunction = ax.curves[_this.options.step.curve];
_this.params = {
...deepClone(_this.paramsFormat),
relatedTarget: null,
evtTarget: (type === 'keyboard' ? this.targetEl : getEvtTarget(e))
};
_this.params = extend({
target: _this.params,
source: {
pointer: type,
orgEvt: e,
coord: type === 'keyboard' ? { x: 0, y: 0 } : { x: e.clientX, y: e.clientY },
step: {
direction: { x: dirValue, y: dirValue }
},
translate: { value: { ..._this.nowVals.translate } },
scale: {
value: { ..._this.nowVals.scale },
direction: dirValue
},
rotate: {
value: _this.nowVals.rotate,
direction: dirValue
},
moveTime: parseFloat(style(_this.targetEl).transitionDuration) * 1000
}
});
_this.listen({ name: 'step', params: [{ ..._this.params, name: 'step' }] });
let paramsAction = { ..._this.params };
if (_this.options.step.mode === 'scale') {
if (!_this.options.scale.enable)
return;
_this.diffVals.scale = (dirValue === 1 ? _this.stepVal : -_this.stepVal);
_this.correctRangeScale();
paramsAction.scale.diff = toNumber(_this.diffVals.scale);
paramsAction.scale.value = { x: toNumber(_this.nowVals.scale.x), y: toNumber(_this.nowVals.scale.y) };
if (!_this.options.scale.centered) {
paramsAction.scale.translate = _this.getScaleTrans({
coord: paramsAction.coord,
diff: paramsAction.scale.diff,
});
_this.totalTrans = _this.getScaleTrans({
initVal: _this.totalTrans,
coord: paramsAction.coord,
diff: paramsAction.scale.diff,
});
}
_this.options.step.linkage && _this.listen({ name: 'scaling', params: [{ ...paramsAction, name: 'scaling' }] });
}
else if (_this.options.step.mode === 'rotate') {
if (!_this.options.rotate.enable)
return;
_this.diffVals.rotate = (dirValue === 1 ? _this.stepVal : -_this.stepVal);
_this.correctRangeRotate();
paramsAction.rotate.diff = toNumber(_this.diffVals.rotate);
paramsAction.rotate.value = toNumber(_this.nowVals.rotate);
_this.options.step.linkage && _this.listen({ name: 'rotating', params: [{ ...paramsAction, name: 'rotating' }] });
}
else if (_this.options.step.mode === 'translate') {
if (!_this.options.translate.enable)
return;
let direction = _this.options.step.axis === 'y' ? { x: 0, y: -dirValue, } : { x: -dirValue, y: 0 }, axisDist = -dirValue * _this.stepVal, x = _this.options.step.axis === 'y' ? 0 : axisDist, y = _this.options.step.axis === 'x' ? 0 : axisDist;
_this.diffVals.translate = { x, y, h: _this.stepVal };
_this.updateNowTrans();
_this.options.viewport.enable && (_this.nowVals.translate = _this.getViewLimitVals(_this.nowVals.translate));
paramsAction.translate.diff = _this.diffVals.translate;
paramsAction.translate.value = _this.nowVals.translate;
paramsAction.translate.direction = direction;
_this.options.step.linkage && _this.listen({ name: 'translating', params: [{ ...paramsAction, name: 'translating' }] });
}
_this.listen({ name: 'stepped', params: [{ ...paramsAction, name: 'stepped' }] });
_this.listen({ name: 'move', params: [{ ...paramsAction, totalTrans: _this.totalTrans, name: 'move' }] });
_this.lastVals[_this.options.step.mode] = { ..._this.nowVals[_this.options.step.mode] };
};
this.wheelFn = throttle(function (e) {
e.stopPropagation();
e.preventDefault();
let isUp = _this.correctWheelDirection(isScrollUp(e, _this.scrollObj.detail)), dirValue = isUp ? 1 : -1;
_this.stepFn(e, dirValue, 'wheel');
}, { intvl: _this.options.step.intvl, prevent: true });
this.keyboardFn = throttle((e) => {
e.stopPropagation();
e.preventDefault();
let dirValue = (e.code === this.options.keyboard.prev) ? -1 : (e.code === this.options.keyboard.next) ? 1 : 0;
if (!dirValue)
return;
_this.stepFn(e, dirValue, 'keyboard');
}, { intvl: _this.options.step.intvl, prevent: true });
this.cancelFn = function (e) {
_this.setCompleted();
_this.removeSecondEvents();
let paramsCancel = Object.assign(deepClone(_this.paramsFormat), {
orgEvt: e,
relatedTarget: null,
evtTarget: getEvtTarget(e),
coord: { x: e.clientX, y: e.clientY },
..._this.endParams,
name: 'canceled'
});
_this.listen({ name: 'canceled', params: [paramsCancel] });
};
this.menuFn = function (e) {
if (_this.isUnbound(e.target))
return;
e.stopPropagation();
e.preventDefault();
let paramsClick = Object.assign(deepClone(_this.paramsFormat), {
orgEvt: e,
relatedTarget: null,
evtTarget: getEvtTarget(e),
coord: { x: e.clientX, y: e.clientY },
..._this.endParams,
name: 'hold'
});
_this.listen({ name: 'hold', params: [paramsClick] });
};
this.triggerFn = async (e) => {
if (this.isUnbound(getEvtTarget(e)))
return;
e.stopPropagation();
try {
this.options.b4Trigger && await this.options.b4Trigger.call(this, e);
}
catch {
return;
}
this.addSecondEvents();
super.listen({ name: 'trigger', params: [e] });
};
this.finishFn = (e) => {
this.removeSecondEvents();
super.listen({ name: 'finished', params: [e] });
};
this.transitionendFn = debounce((e) => {
if (e.propertyName !== 'transform')
return;
e.stopPropagation();
if (this.options.viewport.enable && this.nowVals) {
this.getViewportSizeDiff(this.nowVals.translate);
this.rebound(this.nowVals.translate);
}
});
this.preventDft = (e) => {
e?.preventDefault();
};
super.listen({ name: 'constructed' });
initial && this.init();
}
getStartVals() {
this.startVals = transformTools.get(this.targetEl, ['translate', 'scale', 'rotate'], this.options.translate.instead);
this.totalTrans = { ...this.startVals.translate };
this.nowVals = {
translate: {
...this.startVals.translate,
h: ~~getHypotenuse(this.startVals.translate.x, this.startVals.translate.y)
},
scale: { ...this.startVals.scale },
rotate: this.startVals.rotate,
};
this.lastVals = deepClone(this.nowVals);
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.parentEl = getEl(this.options.parent);
this.viewportEl = getEl(this.options.viewport.selector);
this.options.initialVal ? transformTools.set({ el: this.targetEl, data: this.options.initialVal, instead: this.options.translate.instead }) : null;
this.initialVals = this.options.translate.instead ?
transformTools.get(this.targetEl, ['translate', 'scale', 'rotate', 'skew'], this.options.translate.instead) :
this.targetEl.style.transform;
this.addPrimEvents();
if (ax.isTouchScr) {
if (this.handleEls.length) {
for (let k of this.handleEls)
k.addEventListener('touchstart', this.preventDft, { passive: false });
}
else {
this.targetEl.addEventListener('touchstart', this.preventDft, { passive: false });
}
}
this.targetEl.addEventListener("transitionend", this.transitionendFn, { passive: false });
if (!ax.isTouchScr) {
if (this.options.wheel) {
this.targetEl.removeEventListener(this.scrollObj.event, this.wheelFn);
this.targetEl.addEventListener(this.scrollObj.event, this.wheelFn, { passive: false });
}
if (this.options.click.hold2Menu) {
this.targetEl.removeEventListener('contextmenu', this.menuFn);
this.targetEl.addEventListener('contextmenu', this.menuFn);
}
}
this.setSpy();
this.setCompleted();
super.listen({ name: 'initiated', cb });
return this;
}
setEmpty() {
}
prevEvtDft(evt, target = this.evtTarget) {
if (ax.isTouchScr) {
if (!this.options.scale.enable && !this.options.rotate.enable) {
if (this.useHandle(target) || (!this.handleEls.length && contains(target, this.targetEl))) {
preventDft(evt, true);
}
}
else {
contains(target, this.targetEl) && preventDft(evt, true);
}
}
else {
if (this.useHandle(target) || (!this.handleEls.length && contains(target, this.targetEl))) {
preventDft(evt, true);
}
}
}
setSpy() {
if (!this.options.spy.enable)
return;
let opts = extend({
target: {
onIn: () => {
super.listen({ name: 'showing' });
},
onOut: () => {
this.options.keyboard.enable && !ax.isTouchScr && window.removeEventListener('keydown', this.keyboardFn);
super.listen({ name: 'hidden' });
},
onShown: () => {
this.options.keyboard.enable && !ax.isTouchScr && window.addEventListener('keydown', this.keyboardFn, { passive: false });
super.listen({ name: 'shown' });
}
},
source: this.options.spy,
});
this.spyIns = new Spy(getEl(this.options.keyboard.target) || this.targetEl, opts);
}
isUnbound(target) {
let unbounds = getEls(this.options.unbound, this.targetEl);
return unbounds.find((k) => contains(target, k));
}
updateEaseParamsListen(params, type = 'drift') {
let distH = ~~((this.options[type].timeThr - this.diffTime) * this.options[type].coef) * (type === 'swipe' ? (ax.isTouchScr ? 8 : 12) : 1), distX = ~~(distH * (this.diffVals.translate.x / this.diffVals.translate.h)), distY = ~~(distH * (this.diffVals.translate.y / this.diffVals.translate.h)), driftX = this.clampVals('translate', params.translate.value.x + distX), driftY = this.clampVals('translate', params.translate.value.y + distY);
params[type].direction = params.translate.direction;
params[type].diff = { x: distX, y: distY, h: distH };
params[type].duration = this.options[type].duration;
params[type].value = this.options.viewport.enable ? this.getViewLimitVals({ x: driftX, y: driftY }) : { x: driftX, y: driftY };
params.name = type;
this.listen({ name: type, params: [params] });
if (this.options[type].auto) {
this.targetEl.style.transitionDuration = `0ms`;
this.driftListen = ease({
from: params.translate.value,
to: params[type].value,
curve: this.options[type].curve,
duration: this.options[type].duration,
doing: (e) => {
params.translate.value = { x: Math.floor(e.value.x), y: Math.floor(e.value.y) };
this.listen({ name: (type === 'swipe' ? 'swiping' : 'drifting'), params: [params] });
}, done: () => {
let translateVals = transformTools.get(this.targetEl, ['translate'], this.options.translate.instead).translate;
if ((params[type].value.x === translateVals.x) && (params[type].value.y === translateVals.y)) {
this.listen({ name: (type === 'swipe' ? 'swiped' : 'drifted'), params: [params] });
}
}
});
}
}
updateNowTrans() {
let x = this.lastVals.translate.x + this.diffVals.translate.x, y = this.lastVals.translate.y + this.diffVals.translate.y;
this.nowVals.translate = { x: ~~x, y: ~~y };
this.correctRangeTrans();
}
getMoveVals(vals, startCoord) {
let c = this.getCenterCoord(vals), diff = this.getTriangleVals(c, startCoord), h = ~~diff.h, x = ~~diff.x, y = ~~diff.y, d = { x: x > 0 ? 1 : x < 0 ? -1 : 0, y: y > 0 ? 1 : y < 0 ? -1 : 0 };
return { c, h, x, y, d };
}
addPrimEvents() {
this.targetEl.addEventListener('pointerdown', this.triggerFn, { passive: false });
this.targetEl.removeEventListener('pointerup', this.triggerFn, { passive: false });
}
removePrimEvents() {
this.targetEl.removeEventListener('pointerdown', this.triggerFn);
this.targetEl.removeEventListener('pointerup', this.finishFn);
}
removeSecondEvents() {
document.removeEventListener(eventMap[0], this.startFn);
document.removeEventListener(eventMap[1], this.moveFn);
document.removeEventListener(eventMap[2], this.endFn);
document.removeEventListener(eventMap[3], this.cancelFn);
}
addSecondEvents() {
document.addEventListener(eventMap[0], this.startFn, { passive: false });
document.addEventListener(eventMap[1], this.moveFn, { passive: false });
document.addEventListener(eventMap[2], this.endFn, { passive: false });
document.addEventListener(eventMap[3], this.cancelFn, { passive: false });
}
setCompleted() {
this.started = false;
this.moveCount = this.touchesMoveCount = 0;
this.diffVals = { scale: 0, rotate: 0, translate: { x: 0, y: 0, h: 0 } };
this.holdHandler && clearTimeout(this.holdHandler);
this.canTrans = true;
this.preventEase = false;
this.targetEl.style.cssText = this.targetEl.style.cssText.replace('transition-duration: 0ms', '');
this.targetEl.removeAttribute('gesture');
}
getOrign(coord, rect) {
let x = coord.x - rect.left, y = coord.y - rect.top;
x < 0 ? x = 0 : x > rect.width ? x = rect.width : null;
y < 0 ? y = 0 : y > rect.height ? y = rect.height : null;
return { x, y };
}
getScaleTrans(options) {
let styles = style(this.targetEl), width = parseInt(styles.width), height = parseInt(styles.height), origin = this.options.origin || { x: width / 2, y: height / 2 }, rect = this.targetEl.getBoundingClientRect(), newOrigin = this.getOrign(options.coord, rect), transform = transformTools.get(this.targetEl, ['translate'], this.options.translate.instead), percent = (attr) => {
let value = newOrigin[attr] / rect[attr === 'x' ? 'width' : 'height'];
value < 0 ? value = 0 : value > 1 ? value = 1 : null;
return value;
}, orginDiff = (attr) => {
return (origin[attr] - (attr === 'x' ? width : height) * percent(attr)) * options.diff;
}, initVal = options.initVal || { x: transform.translate.x, y: transform.translate.y }, x = initVal.x + orginDiff('x'), y = initVal.y + orginDiff('y');
return { x: ~~x, y: ~~y };
}
getTouchCoords(event, target = 'targetTouches') {
let touches = [];
if (ax.isTouchScr) {
for (let k of event[target]) {
touches.push({
x: ~~k.clientX,
y: ~~k.clientY
});
}
}
else {
touches.push({
x: ~~event.clientX,
y: ~~event.clientY
});
}
return touches;
}
getCenterCoord(data) {
let result, avg = (n, axis) => {
let value = 0;
for (let k = 0; k < n; k++) {
value += data[k][axis];
}
return value / n;
};
if (data.length > 1) {
result = { x: ~~avg(2, 'x'), y: ~~avg(2, 'y') };
}
else if (data.length === 1) {
result = data[0];
}
else {
result = { x: 0, y: 0 };
}
return result;
}
getTriangleVals(now, last) {
let x = now.x - last.x, y = now.y - last.y, h = getHypotenuse(x, y), a = Math.atan2(y, x) * 180 / Math.PI;
return { x, y, h, a };
}
correctRangeTrans() {
let x = this.clampVals('translate', this.nowVals.translate.x), y = this.clampVals('translate', this.nowVals.translate.y), tmpX, tmpY, diffX, diffY, diffH;
if (x !== this.nowVals.translate.x) {
tmpX = x;
diffX = x - this.lastVals.translate.x;
}
else {
tmpX = this.nowVals.translate.x;
diffX = this.diffVals.translate.x;
}
if (y !== this.nowVals.translate.y) {
tmpY = y;
diffY = y - this.lastVals.translate.y;
}
else {
tmpY = this.nowVals.translate.y;
diffY = this.diffVals.translate.y;
}
diffH = getHypotenuse(diffX, diffY);
this.diffVals.translate = { x: diffX, y: diffY, h: diffH };
this.nowVals.translate = { x: tmpX, y: tmpY };
}
correctRangeRotate() {
this.nowVals.rotate = this.clampVals('rotate', this.nowVals.rotate);
let tmp = this.nowVals.rotate + this.diffVals.rotate;
if (tmp >= this.options.rotate.max) {
this.diffVals.rotate = this.options.rotate.max - this.nowVals.rotate;
}
else if (tmp <= this.options.rotate.min) {
this.diffVals.rotate = this.options.rotate.min - this.nowVals.rotate;
}
this.nowVals.rotate += this.diffVals.rotate;
}
correctDiffRotate() {
if (this.triangleVals.now.a > 0 && this.triangleVals.last.a < 0) {
if (this.triangleVals.now.a > 90 && this.triangleVals.last.a < -90) {
this.diffVals.rotate = 360 - this.diffVals.rotate;
}
else if (this.triangleVals.now.a < 90 && this.triangleVals.last.a > -90) {
this.diffVals.rotate = -this.diffVals.rotate;
}
}
else if (this.triangleVals.now.a < 0 && this.triangleVals.last.a > 0) {
if (this.triangleVals.now.a > -90 && this.triangleVals.last.a < 90) {
this.diffVals.rotate = -this.diffVals.rotate;
}
else if (this.triangleVals.now.a < -90 && this.triangleVals.last.a > 90) {
this.diffVals.rotate = -(360 + this.diffVals.rotate);
}
}
}
correctRangeScale() {
let absScale = {
x: this.clampVals('scale', Math.abs(this.nowVals.scale.x)),
y: this.clampVals('scale', Math.abs(this.nowVals.scale.y))
};
let tmpX = absScale.x + this.diffVals.scale, tmpY = absScale.y + this.diffVals.scale;
if (tmpX >= this.options.scale.max || tmpY >= this.options.scale.max) {
this.diffVals.scale = Math.min((this.options.scale.max - absScale.x), (this.options.scale.max - absScale.y));
}
else if (tmpX <= this.options.scale.min || tmpY <= this.options.scale.min) {
this.diffVals.scale = Math.min(this.options.scale.min - absScale.x, this.options.scale.min - absScale.y);
}
this.nowVals.scale.x += this.diffVals.scale * (this.nowVals.scale.x < 0 ? -1 : 1);
this.nowVals.scale.y += this.diffVals.scale * (this.nowVals.scale.y < 0 ? -1 : 1);
}
clampVals(prop, value) {
return clampVal({ val: value, min: this.options[prop].min, max: this.options[prop].max });
}
correctWheelDirection(value) {
return this.options.step.reverse ? !value : value;
}
getStepVal() {
if (!this.options.step.value) {
this.stepVal = this.options.step.mode === 'translate' ? 60 : this.options.step.mode === 'scale' ? 0.5 : this.options.step.mode === 'rotate' ? 10 : 0;
}
else {
this.stepVal = this.options.step.value;
}
}
getViewportSizeDiff(val) {
if (!this.options.viewport.enable)
return;
this.sizes = {
viewport: { width: 0, height: 0, left: 0, right: 0, top: 0, bottom: 0 },
target: { width: 0, height: 0, left: 0, right: 0, top: 0, bottom: 0 },
diff: { x: 0, y: 0 },
offset: { left: 0, right: 0, top: 0, bottom: 0 }
};
let tmp;
if (!this.viewportEl || this.viewportEl === document.body || this.viewportEl === document.documentElement) {
tmp = {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
left: 0,
top: 0,
right: document.documentElement.clientWidth,
bottom: document.documentElement.clientHeight
};
}
else {
let temp = this.viewportEl.getBoundingClientRect();
tmp = {
width: temp.width,
height: temp.height,
left: temp.left,
top: temp.top,
right: temp.right,
bottom: temp.bottom,
};
}
this.sizes.viewport = { ...tmp };
let { width, height, left, top, right, bottom } = this.targetEl.getBoundingClientRect();
this.sizes.target = { width, height, left, top, right, bottom };
this.sizes.diff = { x: this.sizes.viewport.width - this.sizes.target.width, y: this.sizes.viewport.height - this.sizes.target.height };
this.sizes.offset = {
left: this.sizes.viewport.left - this.sizes.target.left,
right: this.sizes.viewport.right - this.sizes.target.right,
top: this.sizes.viewport.top - this.sizes.target.top,
bottom: this.sizes.viewport.bottom - this.sizes.target.bottom,
};
this.getViewRange(val);
}
getViewRange(val) {
let value = val || transformTools.get(this.targetEl, ['translate'])['translate'];
this.viewRange = {
x: [value.x + this.sizes.offset.left, value.x + this.sizes.offset.right].sort(),
y: [value.y + this.sizes.offset.top, value.y + this.sizes.offset.bottom].sort(),
};
}
getDmpVals(value) {
let dmp = this.options.viewport.dmpRatio ** 2;
return this.options.viewport.bouncy ? value * dmp : value;
}
getBounceVals(data) {
let x = data.x, y = data.y;
if (x < this.viewRange.x[0]) {
x += this.getDmpVals(this.viewRange.x[0] - x);
}
else if (x > this.viewRange.x[1]) {
x += this.getDmpVals(this.viewRange.x[1] - x);
}
if (y < this.viewRange.y[0]) {
y += this.getDmpVals(this.viewRange.y[0] - y);
}
else if (y > this.viewRange.y[1]) {
y += this.getDmpVals(this.viewRange.y[1] - y);
}
return { x: ~~x, y: ~~y };
}
getViewLimitVals(data) {
let x = clampVal({ val: data.x, min: this.viewRange.x[0], max: this.viewRange.x[1] }), y = clampVal({ val: data.y, min: this.viewRange.y[0], max: this.viewRange.y[1] });
return { x, y };
}
getAutoDur(val1, val2) {
return Math.abs(val1 - val2) / 3 + 200;
}
rebound(val) {
let tmp = val || this.nowVals.translate, dur, condition = false;
if (tmp.x < this.viewRange.x[0]) {
dur = this.getAutoDur(this.viewRange.x[0], tmp.x);
tmp.x = this.viewRange.x[0];
condition = true;
}
else if (tmp.x > this.viewRange.x[1]) {
dur = this.getAutoDur(this.viewRange.x[1], tmp.x);
tmp.x = this.viewRange.x[1];
condition = true;
}
if (tmp.y < this.viewRange.y[0]) {
dur = this.getAutoDur(this.viewRange.y[0], tmp.y);
tmp.y = this.viewRange.y[0];
condition = true;
}
else if (tmp.y > this.viewRange.y[1]) {
dur = this.getAutoDur(this.viewRange.y[1], tmp.y);
tmp.y = this.viewRange.y[1];
condition = true;
}
if (!condition)
return;
this.targetEl.style.transitionDuration = `${this.options.viewport.duration || dur}ms`;
transformTools.set({
el: this.targetEl,
data: { translate: { x: tmp.x, y: tmp.y } }
});
}
reset(cb) {
this.targetEl.style.transform = this.initialVals;
super.listen({ name: 'reset', cb });
return this;
}
destroy(cb) {
if (this.destroyed) {
return this;
}
this.setCompleted();
this.targetEl.removeEventListener('pointerdown', this.triggerFn);
this.targetEl.removeEventListener("transitionend", this.transitionendFn);
if (ax.isTouchScr) {
if (this.handleEls.length) {
for (let k of this.handleEls)
k.removeEventListener('touchstart', this.preventDft);
}
else {
this.targetEl.removeEventListener('touchstart', this.preventDft);
}
}
this.removeSecondEvents();
if (!ax.isTouchScr) {
this.options.wheel && this.targetEl.removeEventListener(this.scrollObj.event, this.wheelFn);
this.options.keyboard.enable && window.removeEventListener('keydown', this.keyboardFn);
this.options.click.hold2Menu && this.targetEl.removeEventListener('contextmenu', this.menuFn);
this.spyIns && this.spyIns.destroy();
}
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class Dialog extends ModBaseListenCacheBubble {
options = {};
timestamp;
bubbleType;
parentEl;
lastPlace;
lastSize;
lastPlacement;
gestureIns;
wrapSize;
confirmEl;
cancelEl;
closeEl;
triggerShow;
content;
aniIn;
aniOut;
addPulseAnim;
removePulseAnim;
static optMaps = optPopup$1;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Dialog.optMaps,
component: true,
spread: ['mask', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
});
this.bubbleType = 'dialog';
this.timestamp = Date.now();
let _this = this;
this.triggerShow = function (evt) {
if (this === _this.targetEl && _this.options.canClick) {
let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
if (!tmp)
return;
}
if (_this.state === 'hidden') {
_this.show();
(_this.options.wing.actClass && _this.wings.includes(this)) && this.classList.add(_this.options.wing.actClass);
}
else if (_this.state === 'shown') {
!_this.options.keepShow && _this.hide();
}
};
this.triggerClose = () => {
!this.options.keepShow && this.hide();
};
this.addPulseAnim = () => {
this.mainEl.classList.add(`${ax.prefix}pulseShow`);
};
this.removePulseAnim = () => {
this.mainEl.classList.remove(`${ax.prefix}pulseShow`);
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.parentEl = getEl(this.options.parent) || document.body;
this.options.placement = this.options.placement || 'center';
this.setFeature();
this.wings = getEls(this.options.wing.selector);
this.renderBubble('dialog');
this.setAttrs();
this.fixAni(this.options.placement);
await getContent.call(this, {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.contEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
this.renderContent(data);
}
});
this.lastPlace = '';
this.handleFooter();
this.handleTools();
this.bindTrigger();
this.setDraggable();
this.contEl.querySelectorAll(`[${ax.alias}="closebubble"]`).forEach((k) => {
k.removeEventListener('click', this.triggerClose);
k.addEventListener('click', this.triggerClose, false);
});
if (['confirm', 'alert'].includes(this.options.feature)) {
this.removePulseEvt();
this.addPulseEvt();
}
this.initBullets();
super.listen({ name: 'initiated', cb });
return this;
}
setFeature() {
if (!this.options.feature)
return;
if (['alert', 'prompt', 'notice'].includes(this.options.feature)) {
this.options.footer.layout = 'right';
}
if (['prompt', 'notice'].includes(this.options.feature)) {
this.options.mask.enable = false;
}
if (['confirm', 'alert', 'prompt'].includes(this.options.feature)) {
this.options.mask.closable = false;
this.options.placement = 'center-top';
this.options.padding.value = `${ax.prefix}p-md`;
this.options.in = 'fadeInDown';
this.options.out = 'fadeOutDown';
this.options.tools.enable = false;
let footer = Dialog.optMaps.find((k) => k.prop === 'footer'), isSame = footer.value.children.toString() == this.options.footer.children.toString();
if (this.options.feature === 'alert') {
isSame && (this.options.footer.children = ['confirm']);
}
else if (this.options.feature === 'prompt') {
isSame && (this.options.footer.children = ['close', 'clear', 'confirm']);
}
}
if (this.options.feature === 'notice') {
this.options.placement = 'left-bottom';
}
}
addPulseEvt() {
this.maskEl.addEventListener('click', this.addPulseAnim, false);
this.mainEl.addEventListener('animationend', this.removePulseAnim, false);
}
removePulseEvt() {
this.maskEl.removeEventListener('click', this.addPulseAnim);
this.mainEl.removeEventListener('animationend', this.removePulseAnim);
}
fixAni(placement) {
this.aniIn = placement === 'max' && this.options.in === 'slideDown' ? 'fadeIn' : this.options.in;
this.aniOut = placement === 'max' && this.options.out === 'slideUp' ? 'fadeOut' : this.options.out;
}
handleTools() {
if (this.options.tools.enable) {
this.options.tools.children.forEach((k) => {
k.wrapEl.querySelector(`[${ax.alias}="icon"]`);
if (k.name === 'close') {
k.wrapEl.onclick = () => {
this.hide();
};
}
else if (k.name === 'widen') {
k.wrapEl.onclick = () => {
if (this.lastSize === 'max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.mainEl.setAttribute('size', this.options.size);
this.lastSize = this.options.size;
}
else {
classes(k.iconEl).replace(k.swap, k.icon);
this.mainEl.setAttribute('size', 'max');
this.lastSize = 'max';
}
};
}
else if (k.name === 'enlarge') {
k.wrapEl.onclick = () => {
if (this.lastPlacement === 'center-max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.mainEl.setAttribute('placement', this.options.placement);
this.lastPlacement = this.options.placement;
}
else {
classes(k.iconEl).replace(k.swap, k.icon);
this.mainEl.setAttribute('placement', 'center-max');
this.lastPlacement = 'center-max';
}
};
}
else {
k.action && k.action.call(this, k);
}
});
}
}
setAttrs() {
this.options.classes && classes(this.mainEl).add(this.options.classes);
this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
this.contEl.toggleAttribute('dedicated', this.options.dedicated);
this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
this.options.tools.enable ? this.mainEl.setAttribute('toolsplace', this.options.tools.placement) : this.mainEl.removeAttribute('toolsplace');
this.options.feature ? this.mainEl.setAttribute('feature', this.options.feature) : this.mainEl.removeAttribute('feature');
if (this.parentEl !== document.body) {
let pStyle = style(this.parentEl);
pStyle.position === 'static' && addStyle(this.parentEl, 'position', 'relative');
pStyle.overflow !== 'hidden' && addStyle(this.parentEl, 'overflow', 'hidden');
this.mainEl.toggleAttribute('restrict', true);
}
else {
this.mainEl.removeAttribute('restrict');
}
}
setDraggable() {
if (!this.headEl || !this.options.draggable)
return;
this.gestureIns = new Gesture(this.wrapEl, extend({
target: {
viewport: {
enable: true,
selector: this.parentEl,
},
translate: {
target: this.headEl,
},
onTranslate: () => {
this.wrapEl.style.animationName = 'none';
},
onTranslating: (data) => {
transformTools.set({
el: this.wrapEl,
data: { translate: data.translate.value }
});
},
},
source: this.options.gesture,
}));
}
bindTrigger() {
if (this.options.trigger === 'click') {
if (this.targetEl && !this.canTrigger) {
this.targetEl.removeEventListener('click', this.triggerShow);
this.targetEl.addEventListener('click', this.triggerShow, false);
}
if (this.wings.length > 0 && !this.canTrigger) {
this.wings.forEach((k) => {
k.removeEventListener('click', this.triggerShow);
k.addEventListener('click', this.triggerShow, false);
});
}
}
else if (this.options.trigger === 'sticky') {
this.show();
}
if (this.maskEl && this.options.mask.closable) {
this.maskEl.removeEventListener('click', this.triggerShow);
this.maskEl.addEventListener('click', this.triggerShow, false);
}
this.canTrigger = true;
}
unbindTrigger(mode = 'host') {
this.canTrigger = false;
if (this.options.trigger === 'click') {
this.targetEl.removeEventListener('click', this.triggerShow);
if (this.wings.length > 0 && mode === 'all') {
this.wings.forEach((item) => {
item.removeEventListener('click', this.triggerShow);
});
}
}
if (this.maskEl && this.options.mask.closable && mode === 'all') {
this.maskEl.removeEventListener('click', this.triggerShow);
}
}
toggleHide() {
let other = instance.data.filter((k) => k.ins !== this &&
k.type === 'dialog' &&
!k.ins.destroyed &&
k.ins.state === 'shown' &&
k.ins.parentEl === this.parentEl);
for (let k of other)
k.ins.hide();
}
async show(cb) {
if (this.destroyed || this.state !== 'hidden' || this.options.asleep) {
return this;
}
this.state = 'ing';
this.options.b4Show && await this.options.b4Show.call(this);
elState(this.mainEl).isVirtual && this.parentEl.appendChild(this.mainEl);
super.listen({ name: 'show', cb });
this.wrapHeight = parseInt(style(this.wrapEl).height);
requestAnimationFrame(async () => {
super.getDuration();
this.wrapEl.style.transitionDuration = `${this.duration}ms`;
this.targetEl && this.targetEl.classList.add(this.options.actClass);
if (this.aniIn === 'slideDown') {
easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'down', duration: this.duration, unaware: false });
}
else {
this.options.duration && (this.wrapEl.style.animationDuration = `${this.options.duration}ms`);
this.aniIn && (this.wrapEl.style.animationName = ax.prefix + this.aniIn);
}
!this.options.multiple && this.toggleHide();
this.lastShowTime = Date.now();
this.mainEl.toggleAttribute('show', true);
await delay({
duration: this.duration,
done: () => {
this.state = 'shown';
super.listen({ name: 'shown', cb });
}
});
});
return this;
}
async hide(cb) {
if (this.destroyed || this.state !== 'shown') {
return this;
}
this.state = 'ing';
if (!this.options.deadShow) {
this.options.b4Hide && await this.options.b4Hide.call(this);
super.listen({ name: 'hide', cb });
this.targetEl ? this.targetEl.classList.remove(this.options.actClass) : null;
this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
this.maskEl && (this.maskEl.style.opacity = 0);
if (this.aniOut === 'slideUp') {
easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'up', duration: this.duration, unaware: false });
}
else {
this.aniOut && (this.wrapEl.style.animationName = ax.prefix + this.aniOut);
}
for (let k of getEls('video,audio', this.mainEl))
k.pause();
await delay({
duration: this.duration,
done: () => {
this.state = 'hidden';
this.mainEl.removeAttribute('show');
this.maskEl && this.maskEl.removeAttribute("style");
this.wrapEl.style.height = null;
this.wrapEl.style.animationName = null;
this.mainEl.remove();
super.listen({ name: 'hidden', cb });
if (this.options.heading && !['fadeIn', 'slideDown'].includes(this.aniIn)) {
this.options.heading && (transformTools.remove({ el: this.wrapEl, prop: 'translate' }));
}
}
});
}
return this;
}
}
const confirm = ({ content, contType, contData, tplStr, tplEng, heading, init, yes, no, dialog = {} }) => {
if (isEmpty(content))
return;
return new Promise((resolve) => {
new Dialog(null, deepMerge({
content,
contType,
contData,
heading,
tplStr,
tplEng,
feature: 'confirm',
onInitiated: function () {
init && init(this);
},
onConfirmed: function () {
yes && yes(this);
resolve(true);
},
onCanceled: function () {
no && no(this);
resolve(false);
}
}, dialog)).show();
});
};
const alert = ({ content, contType, contData, heading, tplStr, tplEng, init, yes, dialog = {} }) => {
if (isEmpty(content))
return;
return new Promise((resolve) => {
new Dialog(null, deepMerge({
content,
contType,
contData,
heading,
tplStr,
tplEng,
feature: 'alert',
onInitiated: function () {
init && init(this);
},
onConfirmed: function () {
yes && yes(this);
resolve(true);
},
}, dialog)).show();
});
};
const notice = ({ content, contType = '', contData = {}, heading = '', label = '', tplStr, tplEng, init, yes, dialog = {} }) => {
if (isEmpty(content))
return;
return new Promise((resolve) => {
new Dialog(null, deepMerge({
content,
contType,
contData,
heading,
tplStr,
tplEng,
feature: 'notice',
footer: {
children: [{
name: 'confirm',
label,
}]
},
onInitiated: function () {
init && init(this);
},
onConfirmed: function () {
yes && yes(this);
resolve(true);
},
}, dialog)).show();
});
};
const prompt = (options) => {
let opts = Object.assign({ fields: [{ type: 'input' }] }, options), data = Array.isArray(opts.fields) ? opts.fields : [opts.fields], frags = document.createDocumentFragment(), ins = !opts.insName ? null : instance.find(opts.insName, 'dialog'), getParams = (data) => {
let maps = data.map((k) => { return { type: k.type, label: k.label, value: k.field.value }; }), vals = maps.map((k) => k.value), params = { value: vals, fields: maps };
return params;
};
if (ins) {
return new Promise((resolve) => {
ins.off('confirmed');
ins.on('confirmed', () => {
let params = getParams(ins.promptData);
resolve(params);
});
ins.show();
});
}
for (let k of data) {
let label = k.label ? `<div class="${ax.prefix}field-label">${k.label}</div>` : '', note = k.note ? `<div class="${ax.prefix}field-note">${k.note}</div>` : '', attrs = Object.assign(k.type === 'upload' ? { feature: 'gallery' } : k.type === 'datetime' ? { display: 'inline', footer: false, 'auto-fill': true, } : {}, k.attrs), input = createEl(`ax-${k.type || 'input'}`, { ...attrs }), tpl = `
<section class="${ax.prefix}field ${ax.prefix}field-apart">
${label}
<div class="${ax.prefix}field-cont">
<div class="${ax.prefix}field-input"></div>
${note}
</div>
</section>
`, dom = tplToEl(tpl);
dom.querySelector(`.${ax.prefix}field-input`).appendChild(input);
frags.appendChild(dom);
k.field = input;
}
return new Promise((resolve) => {
ins = new Dialog(null, deepMerge({
insName: opts.insName,
heading: opts.heading,
size: 'lg',
feature: 'prompt',
onInitiated: function () {
this.contEl.appendChild(frags);
this.promptData = data;
},
onConfirmed: function () {
let params = getParams(this.promptData);
opts.yes && opts.yes(params);
resolve(params);
!opts.insName && (ins = null);
},
onCleared: () => {
for (let k of data)
k.field.clear();
},
onClosed: () => {
!opts.insName && (ins = null);
}
}, opts.dialog)).show();
});
};
const removeStyles = (el, props) => {
let target = getEl(el);
if (!target || isEmpty(props))
return;
for (let k of props)
removeStyle(target, k);
};
const addStyles = (el, data) => {
let target = getEl(el);
if (!target || isEmpty(data))
return;
for (let k of Array.isArray(data) ? data : [data]) {
addStyle(target, k.key, k.value);
}
};
const regComp = (comp) => {
if (!comp || getDataType(comp) !== 'Class')
return;
let reg = (comp) => window.customElements.define(`ax-${comp.name.replace('Elem', '').toLowerCase()}`, comp);
if (comp.dependencies && comp.dependencies?.length) {
for (let i of comp.dependencies) {
try {
reg(i.comp);
}
catch { }
}
}
try {
reg(comp);
}
catch {
}
};
const promiseRaf = (cb) => {
if (isEmpty(cb))
return Promise.resolve();
return new Promise(resolve => {
requestAnimationFrame(() => {
cb();
resolve();
});
});
};
const setRtl = (value = true) => {
let dom = document.documentElement;
if (value) {
dom.setAttribute('dir', 'rtl');
ax.rtl = true;
}
else {
dom.removeAttribute('dir');
Reflect.deleteProperty(ax, 'rtl');
}
};
const isChildVisible = (parent, child) => {
let pEl = getEl(parent), cEl = getEl(child, pEl);
if (!pEl || !cEl)
return false;
let pRect = pEl.getBoundingClientRect(), cRect = cEl.getBoundingClientRect();
return !(cRect.right < pRect.left || cRect.left > pRect.right || cRect.bottom < pRect.top || cRect.top > pRect.bottom);
};
let drawColor = ({ el, hue = 0, mode = 'hsv', width, height }) => {
let canvas = getEl(el);
if (!canvas)
return;
let tmpW = width, tmpH = height, canvasStyle;
if (!tmpW || !tmpH) {
canvasStyle = style(canvas);
}
width = toPixel(tmpW || canvasStyle.width);
height = toPixel(tmpH || canvasStyle.height);
tmpW && canvas.setAttribute('width', width);
tmpH && canvas.setAttribute('height', height);
hue = hue === 360 ? 0 : hue;
let ctx = canvas.getContext('2d'), imageData = ctx.createImageData(width, height), data = imageData.data;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let s = x / width, vOrL = 1 - y / height, r, g, b;
if (mode === 'hsv') {
let c = vOrL * s, hPrime = hue / 60, x = c * (1 - Math.abs(hPrime % 2 - 1)), rgb = [0, 0, 0], m = vOrL - c;
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
r = Math.round((rgb[0] + m) * 255);
g = Math.round((rgb[1] + m) * 255);
b = Math.round((rgb[2] + m) * 255);
}
else {
let c = (1 - Math.abs(2 * vOrL - 1)) * s, hPrime = hue / 60, x = c * (1 - Math.abs(hPrime % 2 - 1)), rgb = [0, 0, 0], m = vOrL - c / 2;
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
r = Math.round((rgb[0] + m) * 255);
g = Math.round((rgb[1] + m) * 255);
b = Math.round((rgb[2] + m) * 255);
}
let index = (y * width + x) * 4;
data[index] = r;
data[index + 1] = g;
data[index + 2] = b;
data[index + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
return ctx;
};
const alpha2Hex = (alpha = 0) => typeof alpha === 'string' ? alpha : Math.round(alpha * 255).toString(16).padStart(2, '0');
const hex2Alpha = (hex = 0) => {
if (typeof hex === 'number')
return Math.max(0, Math.min(1, hex));
hex = hex.replace(/^#|0x/gi, '').trim();
if (!hex)
return 0;
if (hex.length === 1)
hex += hex;
return Math.max(0, Math.min(1, parseInt(hex, 16) / 255));
};
const parseRgb = (value, alpha = true) => {
value = value.trim();
let result = { r: 0, g: 0, b: 0 };
if (!value.startsWith('rgb') && !value.startsWith('RGB'))
return result;
let parts = value.match(/(\d+\.?\d*)/g);
result.r = parseInt(parts[0]);
result.g = parseInt(parts[1]);
result.b = parseInt(parts[2]);
alpha && (result.a = parts[3] ? parseFloat(parts[3]) : 1);
return result;
};
const rgb2Hex = (data, alpha = true) => {
let tmp = (typeof data === 'string') ? parseRgb(data) : data, r = Math.max(0, Math.min(255, tmp.r)), g = Math.max(0, Math.min(255, tmp.g)), b = Math.max(0, Math.min(255, tmp.b)), a = tmp.a !== undefined ? Math.max(0, Math.min(1, tmp.a)) : 1, alphaHex = alpha2Hex(a);
let result = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
alpha && (result += alphaHex);
return result;
};
const rgb2Hsl = (data, alpha = true) => {
let tmp = (typeof data === 'string') ? parseRgb(data) : data, r = tmp.r / 255, g = tmp.g / 255, b = tmp.b / 255, max = Math.max(r, g, b), min = Math.min(r, g, b), h = 0, s = 0, l = (max + min) / 2;
if (max === min) {
h = s = 0;
}
else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
let result = {
h: Math.round(h * 360),
s: Math.round(s * 100),
l: Math.round(l * 100)
};
alpha && (result.a = tmp.a);
return result;
};
const rgb2Hwb = (data, alpha = true) => {
let tmp = (typeof data === 'string') ? parseRgb(data) : data, r = tmp.r / 255, g = tmp.g / 255, b = tmp.b / 255, max = Math.max(r, g, b), min = Math.min(r, g, b), d = max - min, h = 0;
if (max === min) {
h = 0;
}
else {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
let w = min, blackness = 1 - max, result = {
h: Math.round(h * 360),
w: Math.round(w * 100),
b: Math.round(blackness * 100)
};
alpha && (result.a = tmp.a);
return result;
};
const hwb2Rgb = (data, alpha = true) => {
let tmp = {};
if (typeof data === 'string') {
let parts = data.match(/(\d+\.?\d*)/g);
tmp.h = parseInt(parts[0]);
tmp.w = parseInt(parts[1]);
tmp.b = parseInt(parts[2]);
tmp.a = parts[3] ? parseFloat(parts[3]) : 1;
}
else {
tmp = data;
}
let h = tmp.h, w = tmp.w / 100, b = tmp.b / 100, c = 1 - b - w, hPrime = h / 60, x = c * (1 - Math.abs(hPrime % 2 - 1)), rgb = [0, 0, 0];
if (c <= 0) {
const gray = 1 - b;
rgb = [gray, gray, gray];
}
else {
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
rgb[0] += w;
rgb[1] += w;
rgb[2] += w;
}
let result = {
r: Math.round(rgb[0] * 255),
g: Math.round(rgb[1] * 255),
b: Math.round(rgb[2] * 255),
};
result.r = Math.max(0, Math.min(255, result.r));
result.g = Math.max(0, Math.min(255, result.g));
result.b = Math.max(0, Math.min(255, result.b));
alpha && (result.a = tmp.a);
return result;
};
const hsl2Rgb = (data, alpha = true) => {
let tmp = {};
if (typeof data === 'string') {
let parts = data.match(/(\d+\.?\d*)/g);
tmp.h = parseInt(parts[0]);
tmp.s = parseInt(parts[1]);
tmp.l = parseInt(parts[2]);
tmp.a = parts[3] ? parseFloat(parts[3]) : 1;
}
else {
tmp = data;
}
let h = tmp.h, s = tmp.s / 100, l = tmp.l / 100, c = (1 - Math.abs(2 * l - 1)) * s, hPrime = h / 60, x = c * (1 - Math.abs(hPrime % 2 - 1)), rgb = [0, 0, 0], m = l - c / 2;
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
let result = {
r: Math.round((rgb[0] + m) * 255),
g: Math.round((rgb[1] + m) * 255),
b: Math.round((rgb[2] + m) * 255),
};
alpha && (result.a = tmp.a);
return result;
};
const hex2Rgb = (value, alpha = true) => {
let result = { r: 0, g: 0, b: 0 }, a;
if (value?.hasOwnProperty('hex')) {
value = value.hex;
a = value.a;
}
else {
value = value.trim();
}
if (typeof value !== 'string' || !value.startsWith('#') || value.length > 9)
return result;
let hex = value.substring(1);
if (hex.length === 3 || hex.length === 4) {
hex = hex.split('').map((k) => k + k).join('');
}
result.r = parseInt(hex.substring(0, 2), 16);
result.g = parseInt(hex.substring(2, 4), 16);
result.b = parseInt(hex.substring(4, 6), 16);
let tmp = (value?.hasOwnProperty('hex')) ? a : hex.substring(6, 8);
alpha && (result.a = tmp ? hex2Alpha(tmp) : 1);
return result;
};
const hwb2Hsl = (data, alpha = true) => {
let tmp = { h: 0, w: 0, b: 0, a: 1 };
if (typeof data === 'string') {
let parts = data.match(/(\d+\.?\d*)/g);
tmp.h = parseFloat(parts[0]);
tmp.w = parseFloat(parts[1]);
tmp.b = parseFloat(parts[2]);
tmp.a = parts[3] ? parseFloat(parts[3]) : 1;
}
else {
tmp = data;
}
let h = tmp.h, w = tmp.w / 100, bl = tmp.b / 100;
let c = 1 - w - bl;
let hPrime = h / 60;
let x = c * (1 - Math.abs(hPrime % 2 - 1));
let rgb = [0, 0, 0];
let gray = 1 - bl;
if (c <= 0) {
rgb = [gray, gray, gray];
}
else {
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
rgb[0] += w;
rgb[1] += w;
rgb[2] += w;
}
let r = rgb[0], g = rgb[1], b = rgb[2], max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min, s = 0;
if (d !== 0) {
s = d / (1 - Math.abs(2 * l - 1));
}
let result = {
h,
s: ~~(s * 100),
l: ~~(l * 100),
};
alpha && (result.a = tmp.a);
return result;
};
const hsl2Hwb = (data, alpha = true) => {
let tmp = { h: 0, s: 0, l: 0, a: 1 };
if (typeof data === 'string') {
let parts = data.match(/(\d+\.?\d*)/g);
tmp.h = parseFloat(parts[0]);
tmp.s = parseFloat(parts[1]);
tmp.l = parseFloat(parts[2]);
tmp.a = parts[3] ? parseFloat(parts[3]) : 1;
}
else {
tmp = data;
}
let h = tmp.h, s = tmp.s / 100, l = tmp.l / 100;
let c = (1 - Math.abs(2 * l - 1)) * s, hPrime = h / 60, x = c * (1 - Math.abs(hPrime % 2 - 1)), rgb = [0, 0, 0];
if (hPrime >= 0 && hPrime < 1)
rgb = [c, x, 0];
else if (hPrime >= 1 && hPrime < 2)
rgb = [x, c, 0];
else if (hPrime >= 2 && hPrime < 3)
rgb = [0, c, x];
else if (hPrime >= 3 && hPrime < 4)
rgb = [0, x, c];
else if (hPrime >= 4 && hPrime < 5)
rgb = [x, 0, c];
else if (hPrime >= 5 && hPrime < 6)
rgb = [c, 0, x];
let m = l - c / 2, r = rgb[0] + m, g = rgb[1] + m, b = rgb[2] + m;
let w = Math.min(r, g, b) * 100, bl = (1 - Math.max(r, g, b)) * 100;
let result = {
h: h,
w: ~~w,
b: ~~bl,
};
alpha && (result.a = tmp.a);
return result;
};
class ModBaseListenCacheNest extends ModBaseListenCache {
flatData;
treeData;
treeInputEl;
check(param, bool) {
}
updateArrowEl(param) {
}
eachCollapse(param) {
}
eachExpand(param) {
}
initCheckeds() {
if (!this.options.check.enable)
return;
let vals = valToArr(this.options.check.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => attrValBool(k.checked));
for (let k of items)
k.checked = false;
this.check([...items, ...vals]);
}
initReadonlys() {
this.readonly(valToArr(this.options.readonly));
}
initDisableds() {
this.disable(valToArr(this.options.disable));
}
getReadonlys() {
return (this.flatData || this.treeData).filter((k) => attrValBool(k.readonly));
}
getDisableds() {
return (this.flatData || this.treeData).filter((k) => attrValBool(k.disabled));
}
getExpandeds() {
return (this.flatData || this.treeData).filter((k) => attrValBool(k.expanded));
}
getCheckeds() {
return (this.flatData || this.treeData).filter((k) => attrValBool(k.checked));
}
getUncheckeds() {
return (this.flatData || this.treeData).filter((k) => !attrValBool(k.checked));
}
getArrowEl(item) {
if (!this.options.arrow.enable)
return;
item.arrowEl = createEl('i', { [ax.alias]: 'arrow' });
this.updateArrowEl(item);
}
toggleArrow(val, item) {
let tmp = attrValBool(val), map = tmp ? { new: 'show', old: 'hide', action: 'add' } : { new: 'hide', old: 'show', action: 'remove' };
item.headEl.toggleAttribute('expanded', tmp);
if (this.options.arrow.type === 'image') {
item.arrowEl.style.backgroundImage = `url("${this.options.arrow[map.new]}")`;
}
else {
if (this.options.arrow.show === this.options.arrow.hide) {
item.arrowEl.classList[map.action](this.options.arrow.anim);
}
else {
classes(item.arrowEl).replace(this.options.arrow[map.old], this.options.arrow[map.new]);
}
}
}
async collapse(data, cb) {
if (this.destroyed)
return;
let tmp = Array.isArray(data) ? data : [data];
for (let k of tmp) {
await this.eachCollapse(k);
}
cb && cb.call(this, this.getExpandeds());
return this;
}
async expand(data, cb) {
if (this.destroyed)
return;
let tmp = Array.isArray(data) ? data : [data];
for (let k of tmp) {
await this.eachExpand(k);
}
cb && cb.call(this, this.getExpandeds());
return this;
}
collapseAll(cb) {
if (this.destroyed)
return;
for (let k of this.getExpandeds())
this.eachCollapse(k);
this.listen({ name: 'collapsedAll', cb });
return this;
}
expandAll(cb) {
if (this.destroyed)
return;
for (let k of this.flatData) {
!attrValBool(k.expanded) && this.eachExpand(k);
}
this.listen({ name: 'expandedAll', cb });
return this;
}
lock(cb) {
if (this.destroyed || !this.targetEl)
return;
this.targetEl.toggleAttribute('inert', true);
this.destroyed = true;
this.treeInputEl.disabled = true;
this.listen({ name: 'locked', cb });
return this;
}
unlock(cb) {
if (!this.targetEl)
return;
this.targetEl.toggleAttribute('inert', false);
this.destroyed = false;
this.treeInputEl.disabled = false;
this.listen({ name: 'unlocked', cb });
return this;
}
readonly(data, cb) {
if (this.destroyed)
return;
let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean);
for (let k of items)
k.readonly = true;
this.listen({ name: 'readonly', cb, params: [items] });
return this;
}
readonlyAll(cb) {
if (this.destroyed)
return;
for (let k of this.flatData)
k.readonly = true;
this.listen({ name: 'readonlyAll', cb });
return this;
}
disable(data, cb) {
if (this.destroyed)
return;
let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean);
for (let k of items)
k.disabled = true;
this.listen({ name: 'disabled', cb, params: [items] });
return this;
}
disableAll(cb) {
if (this.destroyed)
return;
for (let k of this.flatData)
k.disabled = true;
this.listen({ name: 'disabledAll', cb });
return this;
}
enable(data, cb) {
if (this.destroyed)
return;
let tmp = isNull(data) ? this.flatData : (Array.isArray(data) ? data : [data]), items = tmp.map((k) => findItem(k, this.flatData)).filter((k) => k && (attrValBool(k.disabled) || attrValBool(k.readonly)));
for (let k of items) {
k.hasOwnProperty('disabled') && (k.disabled = false);
k.hasOwnProperty('readonly') && (k.readonly = false);
}
this.listen({ name: 'enabled', cb, params: [items] });
return this;
}
enableAll(cb) {
if (this.destroyed)
return;
this.enable(this.flatData);
this.listen({ name: 'enabledAll', cb });
return this;
}
toggleCheck(item) {
attrValBool(item.checked) ? this.check(item, false) : this.check(item, true);
}
uncheckAll(cb) {
if (this.destroyed || !this.options.check.enable)
return;
for (let k of this.flatData) {
k.checked = false;
}
this.listen({ name: 'uncheckedAll', cb });
return this;
}
getSiblings(item) {
return this.flatData.filter((k) => k.pId == item.pId && k !== item);
}
updateElCont(item, value, type = 'brief') {
let prop = type === 'content' ? 'cont' : type, val = isNull(value) ? item[type] : value, valType = getDataType(val);
valType.includes('HTML') ? (item[prop + 'El'].innerHTML = '', item[prop + 'El'].appendChild(val)) : (item[prop + 'El'].innerHTML = val);
}
async getElCont({ target, data = {}, prop = 'brief', cb }) {
let elProp = prop === 'content' ? 'contEl' : `${prop}El`;
await getContent.call(this, {
content: data?.content || target[prop],
contType: data?.contType || 'text',
contData: data?.contData || { ...target },
ajax: {
xhrName: 'contXhr',
target: target[elProp],
...(data?.ajax || {})
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: async (resp) => {
let content = ['Array', 'Object'].includes(getDataType(resp)) ? { ...target, [prop]: resp } : resp;
setContent({
content,
template: data?.tplStr || this.tplStr,
engine: data?.tplEng || this.tplEng,
prevent: (cont) => {
cb && cb(cont, target);
}
});
}
});
}
async setElCont({ item, data = {}, prop = 'brief', cb }) {
let target = findItem(item, this.flatData);
if (!target)
return;
elState(target.bodyEl).isVirtual && target.headEl.insertAdjacentElement('afterend', target.bodyEl);
await this.getElCont({
target,
data,
cb: (cont) => {
if (target[prop] === cont) {
this.updateElCont(target, cont, prop);
}
else {
target[prop] = cont;
!isProxy(target) && this.updateElCont(target, cont, prop);
}
cb && cb(cont, target);
}
});
}
}
let AXTMP_textFold = config.lang.more.fold, AXTMP_textUnfold = config.lang.more.unfold;
const optMore = [
{
attr: 'stor-keys',
prop: 'storKeys',
value: ['content', 'length', 'folded'],
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'length',
prop: 'length',
value: 60,
},
{
attr: 'folded',
prop: 'folded',
value: true,
},
{
attr: 'text-fold',
prop: 'textFold',
value: AXTMP_textFold,
},
{
attr: 'text-unfold',
prop: 'textUnfold',
value: AXTMP_textUnfold,
},
{
attr: 'class-fold',
prop: 'classFold',
value: `${ax.prefix}c-prim`,
},
{
attr: 'class-unfold',
prop: 'classUnfold',
value: `${ax.prefix}c-prim`,
},
{
attr: 'on-fold',
prop: 'onFold',
value: null,
},
{
attr: 'on-unfold',
prop: 'onUnfold',
value: null,
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null,
},
...optBase
];
class More extends ModBaseListenCache {
options = {};
intercepted;
button;
content;
folded;
handlers;
html;
pureHtml;
event;
text;
ell;
static hostType = 'node';
static optMaps = optMore;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: More.optMaps,
host: elem,
component: true,
});
this.content = '';
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.folded = this.options.folded;
this.getPureContent();
this.targetEl.innerHTML = this.content;
this.setAttrs();
if (this.content.length > this.options.length) {
this.intercepted = this.content.substring(0, this.options.length) + '...';
this.button = createEl('i');
this.targetEl.appendChild(this.button);
this.toggle(this.folded ? 'fold' : 'unfold');
this.button.onclick = () => {
this.folded ? this.toggle('unfold') : this.toggle('fold');
};
}
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
}
toggle(type) {
if (type === 'unfold') {
this.targetEl.removeChild(this.button.previousSibling);
this.button.innerHTML = this.options.textUnfold;
this.button.setAttribute('class', this.options.classUnfold);
this.button.insertAdjacentHTML('beforeBegin', this.content);
super.listen({ name: 'unfold' });
this.folded = false;
}
else if (type === 'fold') {
this.targetEl.removeChild(this.button.previousSibling);
this.button.innerHTML = this.options.textFold;
this.button.setAttribute('class', this.options.classFold);
this.button.insertAdjacentHTML('beforeBegin', this.intercepted);
super.listen({ name: 'fold' });
this.folded = true;
}
super.updateCache({ folded: this.folded });
}
getPureContent() {
if (this.options.content && typeof this.options.content === 'string') {
this.content = super.getStrFromContent(this.options.content);
}
else {
this.content = this.rawHtml ? this.rawHtml : this.targetEl.innerHTML;
}
this.content = purifyHtml(this.content);
}
destroy(cb) {
if (this.destroyed) {
return this;
}
this.button.onclick = null;
this.clearCache();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
async updateCont(text, cb) {
if (this.destroyed) {
return this;
}
this.options.content = text;
await this.init();
super.updateCache({ content: this.content });
super.listen({ name: 'updatedCont', cb, params: [this.content] });
return this;
}
}
const optPosition = [
{
attr: 'enable',
prop: 'enable',
value: true,
},
{
attr: 'placement',
prop: 'placement',
value: 'top-center',
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: true,
size: '0.5rem',
offset: '2.8rem',
gap: '.8rem',
}
},
{
attr: 'parent-mutation',
prop: 'parentMutation',
value: {
enable: true,
selector: '',
options: {
attributes: true,
characterData: true,
childList: true,
subtree: true,
}
}
},
{
attr: 'target-obs',
prop: 'targetObs',
value: {
enable: true,
attrs: ['class'],
size: true,
}
},
{
attr: 'bubble-obs',
prop: 'bubbleObs',
value: {
enable: true,
attrs: ['class'],
size: true,
}
},
{
attr: 'delay',
prop: 'delay',
value: 20,
},
{
attr: 'on-transferred',
prop: 'onTransferred',
value: null,
},
{
attr: 'on-reposition',
prop: 'onReposition',
value: null,
},
...optBase
];
class Position extends ModBaseListen {
options = {};
bubbleEl;
arrowEl;
gap;
parent;
placement;
observerCount;
completeCount;
trigger;
targetAttrsObs;
targetSizeObs;
bubbleAttrsObs;
bubbleSizeObs;
parentObs;
bubbleData;
browserData;
bodyData;
regularPlaces;
specialPlaces;
places;
timer;
fullGap;
static hostType = 'none';
static optMaps = optPosition;
constructor(target, bubble, options = {}, initial = config.initial) {
super();
super.ready({
type: Position.hostType,
options,
host: target,
maps: Position.optMaps,
spread: ['arrow', 'parentMutation', 'targetObs', 'bubbleObs']
});
this.targetEl = getEl(target);
this.bubbleEl = getEl(bubble);
if (!this.targetEl || !this.bubbleEl) {
throw new Error(`The host element and guest element must be exist!`);
}
this.gap = toPixel(this.options.arrow.gap);
let tmp = getEl(this.options.parentMutation.selector);
this.parent = this.options.parentMutation.enable && tmp ? tmp : null;
this.regularPlaces = [
'left-start', 'left-center', 'left-end',
'right-start', 'right-center', 'right-end',
'top-start', 'top-center', 'top-end',
'bottom-start', 'bottom-center', 'bottom-end',
];
this.specialPlaces = ['left-max', 'right-max', 'top-max', 'bottom-max', 'center', 'center-max',];
this.places = [...this.regularPlaces, ...this.specialPlaces];
this.trigger = debounce(() => {
let bubbleState = elState(this.bubbleEl);
if (bubbleState.isVirtual || !bubbleState.isVisible || bubbleState.isUncalc)
return;
let targetState = elState(this.targetEl);
if (targetState.isVirtual || !targetState.isVisible || targetState.isUncalc)
return;
this.resetPlacement();
}, this.options.delay);
this.targetAttrsObs = new MutationObserver((mutations) => {
for (let mutation of mutations) {
if (this.options.targetObs.attrs.includes(mutation.attributeName)) {
this.trigger();
}
}
});
this.targetSizeObs = new ResizeObserver(() => {
this.trigger();
});
this.bubbleAttrsObs = new MutationObserver((mutations) => {
for (let mutation of mutations) {
if (this.options.bubbleObs.attrs.includes(mutation.attributeName)) {
this.trigger();
}
}
});
this.bubbleSizeObs = new ResizeObserver(() => {
this.trigger();
});
this.parentObs = new MutationObserver(() => {
if (!this.unsettable('target') && this.targetData) {
if (offset(this.targetEl).left !== this.targetData.left || offset(this.targetEl).top !== this.targetData.top) {
this.trigger();
}
}
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.placement = this.correctPlace(this.options.placement);
if (!this.places.includes(this.placement))
return this;
this.options.placement = this.placement;
!['center', 'center-max'].includes(this.placement) && this.createArrow();
this.setAttrs();
this.resetPlacement();
this.options.enable && this.setObs();
super.listen({ name: 'initiated', cb });
return this;
}
setObs() {
window.addEventListener('resize', this.trigger);
window.addEventListener('scroll', this.trigger);
if (this.options.targetObs.enable) {
if (this.options.targetObs.attrs.length > 0) {
this.targetAttrsObs.observe(this.targetEl, {
attributes: true,
});
}
this.options.targetObs.size ? this.targetSizeObs.observe(this.targetEl) : null;
}
if (this.options.bubbleObs.enable) {
if (this.options.bubbleObs.attrs.length > 0) {
this.bubbleAttrsObs.observe(this.bubbleEl, {
attributes: true,
});
}
this.options.bubbleObs.size ? this.bubbleSizeObs.observe(this.bubbleEl) : null;
}
if (this.parent) {
this.parentObs.observe(this.parent, this.options.parentMutation.options);
}
}
removeObs() {
if (this.options.targetObs.enable) {
this.options.targetObs.attrs.length > 0 ? this.targetAttrsObs.disconnect() : null;
this.options.targetObs.size ? this.targetSizeObs.disconnect() : null;
}
if (this.options.bubbleObs.enable) {
this.options.bubbleObs.attrs.length > 0 ? this.bubbleAttrsObs.disconnect() : null;
this.options.bubbleObs.size ? this.bubbleSizeObs.disconnect() : null;
}
this.parent ? this.parentObs.disconnect() : null;
window.removeEventListener('resize', this.trigger);
window.removeEventListener('scorll', this.trigger);
}
correctPlace(value) {
return (value === 'left') ? 'left-center' :
(value === 'right') ? 'right-center' :
(value === 'top') ? 'top-center' :
(value === 'bottom') ? 'bottom-center' :
(value === 'max') ? 'center-max' : value;
}
setAttrs() {
this.bubbleEl.style.position = (['center', 'center-max'].includes(this.placement)) ? 'fixed' : 'absolute';
this.setPlacementAttr();
}
setPlacementAttr() {
this.bubbleEl.setAttribute('placement', this.placement);
}
createArrow() {
if (this.options.arrow.enable) {
this.arrowEl = createEl('i', { style: 'position:absolute', [ax.alias]: 'arrow' });
this.bubbleEl.appendChild(this.arrowEl);
}
}
setArrow(placement) {
let [left, right, top, bottom] = ['auto', 'auto', 'auto', 'auto'], exceedWidth = this.targetData.width > this.bubbleData.width / 2, exceedHeight = this.targetData.height > this.bubbleData.height / 2, arrowHalf = toPixel(getComputedStyle(this.arrowEl).width) / 2, arrowOffset = toPixel(this.options.arrow.offset), arrowRotate = '';
if (placement.includes('top') || placement.includes('bottom')) {
if (placement.includes('max')) {
let targetLeft = this.targetData.offsetLeft + this.targetData.width / 2, exceedStart = targetLeft < this.bubbleData.offsetLeft + arrowOffset - arrowHalf, exceedEnd = targetLeft > this.bubbleData.offsetRight - arrowOffset + arrowHalf;
left = (exceedEnd || exceedStart) ? '-10000px' : (this.targetData.offsetLeft - this.bubbleData.offsetLeft) + this.targetData.width / 2 - arrowHalf + 'px';
}
else if (placement.includes('start')) {
left = !exceedWidth ? Math.floor(this.targetData.width / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
}
else if (placement.includes('end')) {
right = !exceedWidth ? Math.floor(this.targetData.width / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
}
else {
left = this.bubbleData.width / 2 - 1 - arrowHalf + 'px';
}
}
else if (placement.includes('left') || placement.includes('right')) {
if (placement.includes('max')) {
let targetTop = this.targetData.offsetTop + this.targetData.height / 2, exceedStart = targetTop < this.bubbleData.offsetTop + arrowOffset - arrowHalf, exceedEnd = targetTop > this.bubbleData.offsetBottom - arrowOffset + arrowHalf;
top = (exceedEnd || exceedStart) ? '-10000px' : (this.targetData.offsetTop - this.bubbleData.offsetTop) + this.targetData.height / 2 - arrowHalf + 'px';
}
else if (placement.includes('start')) {
top = !exceedHeight ? Math.floor(this.targetData.height / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
}
else if (placement.includes('end')) {
bottom = !exceedHeight ? Math.floor(this.targetData.height / 2 - arrowHalf) + 'px' : this.options.arrow.offset;
}
else {
top = this.bubbleData.height / 2 - 1 - arrowHalf + 'px';
}
}
else {
left = '-10000px';
top = '-10000px';
}
if (placement.includes('top')) {
bottom = '-' + this.options.arrow.size;
arrowRotate = '45';
}
else if (placement.includes('bottom')) {
top = '-' + this.options.arrow.size;
arrowRotate = '-135';
}
else if (placement.includes('left')) {
right = '-' + this.options.arrow.size;
arrowRotate = '-45';
}
else if (placement.includes('right')) {
left = '-' + this.options.arrow.size;
arrowRotate = '135';
}
let tmp = `left:${left};right:${right};top:${top};bottom:${bottom};transform:rotate(${arrowRotate}deg);`;
this.arrowEl.style.cssText += tmp;
}
getRectsData() {
this.bodyData = {
width: document.body.offsetWidth,
height: document.body.offsetHeight,
};
this.browserData = {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
scrollTop: document.documentElement.scrollTop || document.body.scrollTop,
scrollLeft: document.documentElement.scrollLeft || document.body.scrollLeft
};
let targetRect = this.targetEl.getBoundingClientRect();
this.targetData = {
width: targetRect.width,
height: targetRect.height,
offsetLeft: targetRect.left,
offsetRight: targetRect.right,
offsetTop: targetRect.top,
offsetBottom: targetRect.bottom,
gapRight: this.browserData.width - targetRect.right,
gapBottom: this.browserData.height - targetRect.bottom,
...offset(this.targetEl)
};
this.getBubbleData();
}
getBubbleData() {
let bubbleRect = this.bubbleEl.getBoundingClientRect();
this.bubbleData = {
width: bubbleRect.width,
height: bubbleRect.height,
offsetLeft: bubbleRect.left,
offsetRight: bubbleRect.right,
offsetTop: bubbleRect.top,
offsetBottom: bubbleRect.bottom,
gapRight: this.browserData.width - bubbleRect.right,
gapBottom: this.browserData.height - bubbleRect.bottom
};
}
setPlacement(placement) {
let [left, right, top, bottom] = ['auto', 'auto', 'auto', 'auto'], cssText = '';
if (placement.includes('bottom') || placement.includes('top')) {
if (placement.includes('bottom')) {
left = placement === 'bottom' || placement === 'bottom-center' ? (this.targetData.left - (this.bubbleData.width - this.targetData.width) / 2) :
placement === 'bottom-start' ? this.targetData.left :
placement === 'bottom-end' ? this.targetData.left + this.targetData.width - this.bubbleData.width : 0;
top = `${toNumber(this.targetData.top + this.targetData.height + this.gap, { mode: 'ceil' })}px`;
left = `${toNumber(left, { mode: 'ceil' })}px`;
}
else if (placement.includes('top')) {
left = placement === 'top' || placement === 'top-center' ? (this.targetData.left - (this.bubbleData.width - this.targetData.width) / 2) :
placement === 'top-start' ? this.targetData.left :
placement === 'top-end' ? (this.targetData.left + this.targetData.width - this.bubbleData.width) : 0;
bottom = `${toNumber((this.bodyData.height - this.targetData.top + this.gap), { mode: 'ceil' })}px`;
left = `${toNumber(left, { mode: 'ceil' })}px`;
}
}
else if (placement.includes('left') || placement.includes('right')) {
if (placement.includes('left')) {
if (placement === 'left' || placement === 'left-center') {
top = `${toNumber(this.targetData.top - (this.bubbleData.height - this.targetData.height) / 2, { mode: 'ceil' })}px`;
}
else if (placement === 'left-start') {
top = `${toNumber(this.targetData.top, { mode: 'ceil' })}px`;
}
else if (placement === 'left-end') {
bottom = `${toNumber(this.bodyData.height - this.targetData.top - this.targetData.height, { mode: 'ceil' })}px`;
}
right = `${toNumber(this.browserData.width - this.targetData.left + this.gap, { mode: 'ceil' })}px`;
}
else if (placement.includes('right')) {
if (placement === 'right' || placement === 'right-center') {
top = `${toNumber(this.targetData.top - (this.bubbleData.height - this.targetData.height) / 2, { mode: 'ceil' })}px`;
}
else if (placement === 'right-start') {
top = `${toNumber(this.targetData.top, { mode: 'ceil' })}px`;
}
else if (placement === 'right-end') {
bottom = `${toNumber(this.bodyData.height - this.targetData.top - this.targetData.height, { mode: 'ceil' })}px`;
}
left = `${toNumber(this.targetData.left + this.targetData.width + this.gap, { mode: 'ceil' })}px`;
}
}
if (this.placement === 'center-max') {
cssText = `width:calc(100vw - ${ax.fullGap}*2);height:calc(100vh - ${ax.fullGap}*2);`;
left = ax.fullGap;
top = ax.fullGap;
}
else if (this.placement === 'center') {
cssText = `margin-left:-${toNumber(this.bubbleEl.getBoundingClientRect().width / 2, { mode: 'ceil' })}px;margin-top:-${toNumber(this.bubbleEl.getBoundingClientRect().height / 2, { mode: 'ceil' })}px;`;
left = '50%';
top = '50%';
}
else if (this.placement === 'top-max' || this.placement === 'bottom-max') {
left = `${toNumber(this.browserData.scrollLeft + toPixel(ax.fullGap), { mode: 'ceil' })}px`;
cssText = `width:calc(100vw - ${ax.fullGap}*2);`;
}
else if (this.placement === 'left-max' || this.placement === 'right-max') {
top = `${toNumber(this.browserData.scrollTop + toPixel(ax.fullGap), { mode: 'ceil' })}px`;
cssText = `height:calc(100vh - ${ax.fullGap}*2);`;
}
this.bubbleEl.style.cssText += (cssText + `left:${left};right:${right};top:${top};bottom:${bottom};`);
this.getBubbleData();
this.arrowEl ? this.setArrow(placement) : null;
}
resetBubbleAttrs() {
let tmp = this.bubbleEl.style.cssText.replace('margin-left:', '').replace('margin-top:', '').replace('width:', '').replace('height:', '') + `;left:auto;right:auto;top:auto;bottom:auto;`;
this.bubbleEl.style.cssText = tmp;
this.getBubbleData();
}
getSurroundGap() {
let left = this.targetData.offsetLeft - this.bubbleData.width - this.gap, top = this.targetData.offsetTop - this.bubbleData.height - this.gap, right = this.browserData.width - this.targetData.offsetRight - this.bubbleData.width - this.gap, bottom = this.browserData.height - this.targetData.offsetBottom - this.bubbleData.height - this.gap, startTop = this.targetData.offsetTop, startBottom = this.browserData.height - (startTop + this.bubbleData.height), centerTop = this.targetData.offsetTop - (this.bubbleData.height - this.targetData.height) / 2, centerBottom = this.browserData.height - (centerTop + this.bubbleData.height), endTop = this.targetData.offsetBottom - this.bubbleData.height, endBottom = this.browserData.height - this.targetData.offsetBottom, startLeft = this.targetData.offsetLeft, startRight = this.browserData.width - (startLeft + this.bubbleData.width), centerLeft = this.targetData.offsetLeft - (this.bubbleData.width - this.targetData.width) / 2, centerRight = this.browserData.width - (centerLeft + this.bubbleData.width), endLeft = this.targetData.offsetRight - this.bubbleData.width, endRight = this.browserData.width - this.targetData.offsetRight;
return {
left, right, top, bottom,
start: { left: startLeft, right: startRight, top: startTop, bottom: startBottom },
center: { left: centerLeft, right: centerRight, top: centerTop, bottom: centerBottom },
end: { left: endLeft, right: endRight, top: endTop, bottom: endBottom }
};
}
fixPlacement() {
if (this.targetData.gapRight > this.browserData.width || this.targetData.offsetLeft > this.browserData.width || ['center', 'center-max'].includes(this.placement))
return;
let gaps = this.getSurroundGap();
if (this.placement.includes('top') && (gaps.top < 0 && gaps.bottom >= 0)) {
this.placement = this.placement.replace('top', 'bottom');
}
else if (this.placement.includes('bottom') && (gaps.bottom < 0 && gaps.top >= 0)) {
this.placement = this.placement.replace('bottom', 'top');
}
else if (this.placement.includes('left') && (gaps.left < 0 && gaps.right >= 0)) {
this.placement = this.placement.replace('left', 'right');
}
else if (this.placement.includes('right') && (gaps.right < 0 && gaps.left >= 0)) {
this.placement = this.placement.replace('right', 'left');
}
if (!['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.placement)) {
if ((this.placement.includes('top') || this.placement.includes('bottom')) && this.bubbleData.width < this.browserData.width) {
if (this.bubbleData.width > this.targetData.width) {
if (this.targetData.offsetLeft < 0 && this.targetData.gapRight < this.browserData.width) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (this.targetData.gapRight < 0 && this.targetData.offsetLeft < this.browserData.width) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else {
if (gaps.end.left < 0 && gaps.center.left < 0) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (gaps.end.left < 0 && this.placement.includes('end')) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.end.left < 0 && gaps.center.left > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.end.left > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
this.placement = this.placement.replace('center', 'end');
}
if (gaps.start.right < 0 && gaps.center.right < 0) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else if (gaps.start.right < 0 && this.placement.includes('start')) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.start.right < 0 && gaps.center.right > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.start.right > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
this.placement = this.placement.replace('center', 'start');
}
}
}
else {
if (gaps.start.left < 0 && gaps.center.left < 0) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else if (gaps.start.left < 0 && this.placement.includes('start')) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.start.left < 0 && gaps.center.left > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.start.left > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
this.placement = this.placement.replace('center', 'start');
}
if (gaps.end.right < 0 && gaps.center.right < 0) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (gaps.end.right < 0 && this.placement.includes('end')) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.end.right < 0 && gaps.center.right > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.end.right > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
this.placement = this.placement.replace('center', 'end');
}
}
}
if ((this.placement.includes('left') || this.placement.includes('right')) && this.bubbleData.height < this.browserData.height) {
if (this.bubbleData.height > this.targetData.height) {
if (this.targetData.offsetTop < 0 && this.targetData.gapBottom < this.browserData.height) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (this.targetData.gapBottom < 0 && this.targetData.offsetTop < this.browserData.height) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else {
if (gaps.end.top < 0 && gaps.center.top < 0) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (gaps.end.top < 0 && this.placement.includes('end')) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.end.top < 0 && gaps.center.top > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.end.top > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
this.placement = this.placement.replace('center', 'end');
}
if (gaps.start.bottom < 0 && gaps.center.bottom < 0) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else if (gaps.start.bottom < 0 && this.placement.includes('start')) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.start.bottom < 0 && gaps.center.bottom > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.start.bottom > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
this.placement = this.placement.replace('center', 'start');
}
}
}
else {
if (gaps.start.top < 0 && gaps.center.top < 0) {
this.placement = this.placement.replace('start', 'end').replace('center', 'end');
}
else if (gaps.start.top < 0 && this.placement.includes('start')) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.start.top < 0 && gaps.center.top > 0 && this.placement.includes('end') && (this.options.placement.includes('start') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.start.top > 0 && this.placement.includes('center') && (this.options.placement.includes('start'))) {
this.placement = this.placement.replace('center', 'start');
}
if (gaps.end.bottom < 0 && gaps.center.bottom < 0) {
this.placement = this.placement.replace('end', 'start').replace('center', 'start');
}
else if (gaps.end.bottom < 0 && this.placement.includes('end')) {
this.placement = this.placement.replace('end', 'center');
}
else if (gaps.end.bottom < 0 && gaps.center.bottom > 0 && this.placement.includes('start') && (this.options.placement.includes('end') || this.options.placement.includes('center'))) {
this.placement = this.placement.replace('start', 'center');
}
else if (gaps.end.bottom > 0 && this.placement.includes('center') && (this.options.placement.includes('end'))) {
this.placement = this.placement.replace('center', 'end');
}
}
}
}
this.fullyExpose(gaps);
this.setPlacementAttr();
}
fullyExpose(gaps) {
if (this.options.placement === this.placement || this.placement.includes('max'))
return;
let placeArr = this.placement.split('-'), parentStr = placeArr[0], childStr = placeArr[1];
parentStr = (this.options.placement.includes('top') && gaps.top >= 0) ? 'top' :
(this.options.placement.includes('bottom') && gaps.bottom >= 0) ? 'bottom' :
(this.options.placement.includes('left') && gaps.left >= 0) ? 'left' :
(this.options.placement.includes('right') && gaps.right >= 0) ? 'right' : placeArr[0];
if (this.options.placement.includes('top') || this.options.placement.includes('bottom')) {
if (this.options.placement.includes('start') && gaps.start[(this.bubbleData.width > this.targetData.width) ? 'right' : 'left'] >= 0) {
childStr = 'start';
}
else if (this.options.placement.includes('end') && gaps.end[(this.bubbleData.width > this.targetData.width) ? 'left' : 'right'] >= 0) {
childStr = 'end';
}
else if (this.options.placement.includes('center') && gaps.center.left >= 0 && gaps.center.right >= 0) {
childStr = 'center';
}
}
else if (this.options.placement.includes('left') || this.options.placement.includes('right')) {
if (this.options.placement.includes('start') && gaps.start[(this.bubbleData.height > this.targetData.height) ? 'bottom' : 'top'] >= 0) {
childStr = 'start';
}
else if (this.options.placement.includes('end') && gaps.end[(this.bubbleData.height > this.targetData.height) ? 'top' : 'bottom'] >= 0) {
childStr = 'end';
}
else if (this.options.placement.includes('center') && gaps.center.top >= 0 && gaps.center.bottom >= 0) {
childStr = 'center';
}
}
this.placement = `${parentStr}-${childStr}`;
}
unsettable(type) {
let el = type === 'target' ? this.targetEl : this.bubbleEl;
return elState(el).isUncalc;
}
resetPlacement(cb) {
if (this.destroyed || !this.places.includes(this.placement) || this.unsettable()) {
return this;
}
this.getRectsData();
this.resetBubbleAttrs();
this.fixPlacement();
this.setPlacement(this.placement);
super.listen({ name: 'changed', cb, params: [this.placement] });
}
change(placement, cb) {
if (this.destroyed) {
return this;
}
placement && (this.placement = this.correctPlace(placement));
if (!this.places.includes(this.placement))
return this;
this.options.placement = this.placement;
this.setAttrs();
this.getRectsData();
this.resetBubbleAttrs();
this.setPlacement(this.placement);
super.listen({ name: 'changed', cb, params: [this.placement] });
return this;
}
transfer(elem, cb) {
if (this.destroyed || !elem)
return;
this.targetEl = getEl(elem);
if (this.targetEl) {
this.resetPlacement(cb);
super.listen({ name: 'transferred', cb, params: [this.targetEl] });
}
return this;
}
destroy(cb) {
if (this.destroyed)
return;
this.removeObs();
this.trigger.cancel();
this.destroyed = true;
super.listen({ name: 'destroyed', cb, params: [this.placement] });
return this;
}
}
const optHover = [
{
attr: 'timeout',
prop: 'timeout',
value: 50,
},
{
attr: 'intvl',
prop: 'intvl',
value: 50,
},
{
attr: 'throttle',
prop: 'throttle',
value: 200,
},
{
attr: 'threshold',
prop: 'threshold',
value: 7,
},
{
attr: 'hold',
prop: 'hold',
value: '',
},
{
attr: 'on-move',
prop: 'onMove',
value: null,
},
{
attr: 'on-enter',
prop: 'onEnter',
value: null,
},
{
attr: 'on-leave',
prop: 'onLeave',
value: null,
},
...optBase
];
class Hover extends ModBaseListen {
options = {};
curX;
curY;
preX;
preY;
isActive;
enterTimer;
leaveTimer;
eventToggle;
holdEl;
enterCompare;
globalEvent;
moveEvent;
enterEvent;
leaveEvent;
enterHold;
leaveHold;
static hostType = 'node';
static optMaps = optHover;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Hover.optMaps,
host: elem,
});
this.curX;
this.curY;
this.preX;
this.preY;
this.enterTimer;
this.leaveTimer;
this.isActive = false;
this.holdEl = getEl(this.options.hold);
this.eventToggle = (type, elem, event) => {
let obj = { event, target: elem };
if (type === 'enter') {
this.isActive = true;
super.listen({ name: 'enter', params: [{ ...obj, inside: true, name: 'enter' }] });
}
else if (type === 'leave') {
this.isActive = false;
super.listen({ name: 'leave', params: [{ ...obj, inside: false, name: 'leave' }] });
}
};
this.enterCompare = (elem, event) => {
let distX = this.preX - this.curX, distY = this.preY - this.curY, distance = Math.sqrt(distX ** 2 + distY ** 2);
if (distance < this.options.threshold) {
if (!this.isActive) {
this.eventToggle('enter', elem, event);
}
}
else {
this.preX = this.curX;
this.preY = this.curY;
this.enterTimer = setTimeout(() => {
this.enterCompare(elem, event);
}, this.options.intvl);
}
};
this.globalEvent = throttle((event) => {
let inTarget = contains(event.target, this.targetEl), inHold = this.holdEl ? contains(event.target, this.holdEl) : true, inside = inTarget && inHold;
super.listen({ name: 'move', params: [{ inside, event, name: 'move', target: event.target }] });
}, this.options.throttle);
this.moveEvent = (event) => {
this.curX = event.pageX;
this.curY = event.pageY;
};
this.enterEvent = (event) => {
clearTimeout(this.leaveTimer);
this.preX = event.pageX;
this.preY = event.pageY;
this.enterTimer = setTimeout(() => {
this.enterCompare(event.target, event);
}, this.options.intvl);
};
this.leaveEvent = (event) => {
clearTimeout(this.enterTimer);
this.leaveTimer = setTimeout(() => {
this.eventToggle('leave', event.target, event);
}, this.options.timeout);
};
this.enterHold = () => {
clearTimeout(this.leaveTimer);
};
this.leaveHold = (event) => {
clearTimeout(this.enterTimer);
this.leaveTimer = setTimeout(() => {
this.eventToggle('leave', this.targetEl, event);
}, this.options.timeout);
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
document.body.removeEventListener('mousemove', this.globalEvent);
this.targetEl.removeEventListener('mousemove', this.moveEvent);
this.targetEl.removeEventListener('mouseenter', this.enterEvent);
this.targetEl.removeEventListener('mouseleave', this.leaveEvent);
document.body.addEventListener('mousemove', this.globalEvent);
this.targetEl.addEventListener('mousemove', this.moveEvent);
this.targetEl.addEventListener('mouseenter', this.enterEvent);
this.targetEl.addEventListener('mouseleave', this.leaveEvent);
if (this.holdEl) {
this.holdEl.removeEventListener('mouseenter', this.enterHold);
this.holdEl.removeEventListener('mouseleave', this.leaveHold);
this.holdEl.addEventListener('mouseenter', this.enterHold);
this.holdEl.addEventListener('mouseleave', this.leaveHold);
}
super.listen({ name: 'initiated', cb });
}
destroy(cb) {
if (this.destroyed) {
return this;
}
document.body.removeEventListener('mousemove', this.globalEvent);
this.targetEl.removeEventListener('mousemove', this.moveEvent);
this.targetEl.removeEventListener('mouseenter', this.enterEvent);
this.targetEl.removeEventListener('mouseleave', this.leaveEvent);
if (this.holdEl) {
this.holdEl.removeEventListener('mouseenter', this.enterHold);
this.holdEl.removeEventListener('mouseleave', this.leaveHold);
}
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optPopup = [
{
attr: 'theme',
prop: 'theme',
value: '',
},
{
attr: 'placement',
prop: 'placement',
value: 'top',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'hover',
},
{
attr: 'page-close',
prop: 'pageClose',
value: true,
},
{
attr: 'can-close',
prop: 'canClose',
value: null,
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'in',
prop: 'in',
value: 'fadeIn',
},
{
attr: 'out',
prop: 'out',
value: 'fadeOut',
},
{
attr: 'multiple',
prop: 'multiple',
value: false,
},
{
attr: 'height',
prop: 'height',
value: '',
},
{
attr: 'adaptive',
prop: 'adaptive',
value: true,
},
{
attr: 'position',
prop: 'position',
value: {},
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: true,
size: '0.5rem',
offset: '2.8rem',
gap: '.8rem',
}
},
{
attr: 'wing',
prop: 'wing',
value: {
selector: '',
trigger: 'click',
actClass: '',
},
},
{
attr: 'on-reposition',
prop: 'onReposition',
value: null,
},
...optBubble
];
class Popup extends ModBaseListenCacheBubble {
options = {};
confirmEl;
cancelEl;
closeEl;
triggerShow;
clickOutHideEvt;
content;
bubbleType;
aniIn;
aniOut;
initialPlace;
isCompField;
static optMaps = optPopup;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
host: elem,
maps: Popup.optMaps,
component: false,
spread: ['arrow', 'tools', 'padding', 'footer', 'autoFill', 'bullet']
});
this.bubbleType = 'popup';
let _this = this;
this.triggerShow = function (evt) {
evt.preventDefault();
let isWing = _this.wings.includes(this) ? true : false, trigger = isWing ? (_this.options.wing.trigger || _this.options.trigger) : _this.options.trigger;
if (trigger === 'click') {
if (this === _this.targetEl && _this.options.canClick) {
let target = getEvtTarget(evt), tmp = _this.options.canClick.call(_this, target, evt);
if (!tmp)
return;
}
if (_this.state === 'hidden') {
_this.show();
if (!_this.options.multiple) {
let items = instance.data.filter((i) => i.type === _this.constructor.name.toLowerCase() && i.ins !== _this && i.ins.state === 'shown');
for (let k of items)
k.ins.hide();
}
else {
_this.options.wing.actClass && _this.wings.includes(this) && this.classList.add(_this.options.wing.actClass);
}
}
else if (_this.state === 'shown') {
!_this.options.keepShow && _this.hide();
}
}
else if (_this.options.trigger === 'input') {
if (!_this.targetEl?.value) {
!_this.options.keepShow && _this.hide();
}
else {
_this.show();
_this.options.wing.actClass && _this.wings.includes(this) && this.classList.add(_this.options.wing.actClass);
}
}
};
this.clickOutHideEvt = (evt) => {
if (this.options.canClose) {
let target = getEvtTarget(evt), tmp = this.options.canClose.call(this, target, evt);
if (!tmp)
return;
}
!contains(evt.target, [this.mainEl, this.targetEl, ...this.wings]) &&
this.state === 'shown' &&
!this.options.keepShow &&
elState(evt.target).isVisible &&
this.hide();
};
this.triggerClose = () => {
!this.options.keepShow && this.hide();
};
this.leaveTrigger = debounce(() => {
!this.options.keepShow && this.hide();
});
super.listen({ name: 'constructed' });
initial && this.targetEl && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.options.placement = this.options.placement || 'top';
this.options.trigger = this.options.trigger === 'hover' && ax.isTouchScr ? 'click' : this.options.trigger;
this.isCompField = fieldTypes.includes(this.options.contType.toLowerCase());
if (this.isCompField) {
this.options.tools.placement = 'outside';
}
this.wings = getEls(this.options.wing.selector);
this.renderBubble('popup');
this.setAttrs();
this.fixAni(this.options.placement);
await getContent.call(this, {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.contEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
this.renderContent(data);
}
});
this.createPosition();
this.handleFooter();
this.handleTools();
this.bindTrigger();
this.contEl.querySelectorAll(`[${ax.alias}="closebubble"]`).forEach((k) => {
k.removeEventListener('click', this.triggerClose);
k.addEventListener('click', this.triggerClose, false);
});
this.initBullets();
super.listen({ name: 'initiated', cb });
return this;
}
fixAni(placement) {
this.aniIn = placement.includes('max') && this.options.in === 'slideDown' ? 'fadeIn' : this.options.in;
this.aniOut = placement.includes('max') && this.options.out === 'slideUp' ? 'fadeOut' : this.options.out;
this.fixEaseAni(placement);
}
handleTools() {
if (this.options.tools.enable) {
this.options.tools.children.forEach((k) => {
if (k.name === 'close') {
k.wrapEl.onclick = () => this.hide();
}
else if (k.name === 'enlarge') {
if (this.positionIns.placement === 'center-max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.initialPlace = this.rawOpts.placement;
}
else {
this.initialPlace = this.positionIns.placement;
}
k.wrapEl.onclick = () => {
if (this.positionIns.placement === 'center-max') {
classes(k.iconEl).replace(k.swap, k.icon);
this.reposition(this.initialPlace);
}
else {
classes(k.iconEl).replace(k.icon, k.swap);
this.reposition('center-max');
}
};
}
else if (k.name === 'widen') {
if (this.positionIns.placement === 'top-max' || this.positionIns.placement === 'bottom-max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.initialPlace = this.positionIns.placement.split('-')[0];
}
else {
this.initialPlace = this.positionIns.placement;
}
k.wrapEl.onclick = () => {
if (!this.positionIns.placement.includes('top') && !this.positionIns.placement.includes('bottom')) {
console.warn('Only valid for placement=top-* and placement=bottom-*!');
return;
}
if (['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.positionIns.placement)) {
classes(k.iconEl).replace(k.swap, k.icon);
this.reposition(this.initialPlace);
}
else {
let position = this.positionIns.placement.split('-')[0];
classes(k.iconEl).replace(k.icon, k.swap);
this.reposition(position + '-max');
}
};
}
else if (k.name === 'heighten') {
if (this.positionIns.placement === 'left-max' || this.positionIns.placement === 'right-max') {
classes(k.iconEl).replace(k.icon, k.swap);
this.initialPlace = this.positionIns.placement.split('-')[0];
}
else {
this.initialPlace = this.positionIns.placement;
}
k.wrapEl.onclick = () => {
if (!this.positionIns.placement.includes('left') && !this.positionIns.placement.includes('right')) {
console.warn('Only valid for placement=left-* and placement=right-*!');
return;
}
if (['left-max', 'right-max', 'top-max', 'bottom-max'].includes(this.positionIns.placement)) {
classes(k.iconEl).replace(k.swap, k.icon);
this.reposition(this.initialPlace);
}
else {
let position = this.positionIns.placement.split('-')[0];
classes(k.iconEl).replace(k.icon, k.swap);
this.reposition(position + '-max');
}
};
}
else {
k.action && k.action.call(this, k);
}
});
}
}
setAttrs() {
this.options.classes && classes(this.mainEl).add(this.options.classes);
this.options.size ? this.mainEl.setAttribute('size', this.options.size) : this.mainEl.removeAttribute('size');
this.options.contType ? this.mainEl.setAttribute('conttype', this.options.contType) : this.mainEl.removeAttribute('conttype');
this.options.placement ? this.mainEl.setAttribute('placement', this.options.placement) : this.mainEl.removeAttribute('placement', this.options.placement);
this.contEl.toggleAttribute('dedicated', this.options.dedicated);
this.options.height ? addStyle(this.contEl, 'height', this.options.height) : removeStyle(this.contEl, 'height');
this.options.zIndex ? addStyle(this.mainEl, 'z-index', this.options.zIndex) : removeStyle(this.mainEl, 'z-index');
this.options.tools.enable ? this.mainEl.setAttribute('toolsplace', this.options.tools.placement) : this.mainEl.removeAttribute('toolsplace');
this.options.theme ? this.mainEl.setAttribute('theme', this.options.theme) : this.mainEl.removeAttribute('theme');
}
createPosition() {
let tmpArr = this.options.placement.split('-'), placement = this.options.placement;
if (this.options.adaptive && ax.screen === 'xxs') {
if (tmpArr[0] === 'left') {
placement = 'top-max';
}
else if (tmpArr[0] === 'right') {
placement = 'bottom-max';
}
else if (!tmpArr.includes('max') && ['top', 'bottom'].includes(tmpArr[0])) {
placement = tmpArr[0] + '-max';
}
}
this.positionIns = new Position(this.targetEl, this.mainEl, extend({
target: {
placement,
arrow: this.options.arrow,
targetObs: {
attrs: [],
},
bubbleObs: {
attrs: [],
},
delay: 0,
},
source: this.options.position
}));
}
bindTrigger() {
if (this.options.trigger === 'click' || this.options.trigger === 'input') {
if (!this.canTrigger) {
this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
this.targetEl.addEventListener(this.options.trigger, this.triggerShow, false);
}
if (this.wings.length > 0 && !this.canTrigger) {
this.wings.forEach((item) => {
let trigger = this.options.wing.trigger || this.options.trigger;
item.removeEventListener(trigger, this.triggerShow);
item.addEventListener(trigger, this.triggerShow, false);
});
}
}
else if (this.options.trigger === 'hover') {
this.hoverIns = new Hover(this.targetEl, {
onEnter: () => {
this.show();
},
onLeave: this.leaveTrigger,
hold: this.mainEl,
});
}
else if (this.options.trigger === 'sticky') {
this.options.multiple = true;
this.show();
}
if (this.options.pageClose && !this.options.multiple) {
!this.canTrigger && document.addEventListener('click', this.clickOutHideEvt, false);
}
this.canTrigger = true;
}
unbindTrigger(mode = 'host') {
this.canTrigger = false;
if (this.options.trigger === 'click' || this.options.trigger === 'input') {
this.targetEl.removeEventListener(this.options.trigger, this.triggerShow);
if (this.wings.length > 0 && mode === 'all') {
this.wings.forEach((item) => {
let trigger = this.options.wing.trigger || this.options.trigger;
item.removeEventListener(trigger, this.triggerShow);
});
}
}
else if (this.options.trigger === 'hover') {
this.hoverIns.destroy();
}
if (this.options.pageClose && !this.options.multiple && mode === 'all') {
document.removeEventListener('click', this.clickOutHideEvt, false);
}
}
fixEaseAni(placement) {
if (this.aniIn === 'easeIn') {
this.aniIn = placement.includes('left') ? 'easeInStart' :
placement.includes('right') ? 'easeInEnd' :
placement.includes('top') ? 'easeInTop' :
placement.includes('bottom') ? 'easeInBtm' : 'easeIn';
}
if (this.aniOut === 'easeOut') {
this.aniOut = placement.includes('left') ? 'easeOutStart' :
placement.includes('right') ? 'easeOutEnd' :
placement.includes('top') ? 'easeOutTop' :
placement.includes('bottom') ? 'easeOutBtm' : 'easeOut';
}
}
reposition(placement, cb) {
if (this.destroyed || !placement) {
return this;
}
this.positionIns.change(placement, (placement) => {
this.fixAni(placement);
this.updateCache({ placement });
super.listen({ name: 'reposition', cb, params: [placement] });
});
return this;
}
async show(cb) {
if (this.destroyed || this.options.asleep) {
return this;
}
if (this.state !== 'hidden') {
if (this.state === 'shown')
this.leaveTrigger.cancel();
return this;
}
this.state = 'ing';
this.options.b4Show && await this.options.b4Show.call(this);
elState(this.mainEl).isVirtual && document.body.appendChild(this.mainEl);
super.listen({ name: 'show', cb });
this.targetEl && this.targetEl.classList.add(this.options.actClass);
this.lastShowTime = Date.now();
this.hoverIns && (this.hoverIns.isActive = true);
requestAnimationFrame(async () => {
this.positionIns.change();
this.wrapHeight = this.positionIns.bubbleData.height;
super.getDuration();
this.mainEl.style.visibility = 'visible';
if (this.aniIn === 'slideDown') {
easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'down', duration: this.duration, unaware: false });
}
else {
this.options.duration && (this.mainEl.style.animationDuration = `${this.options.duration}ms`);
this.aniIn && (this.mainEl.style.animationName = ax.prefix + this.aniIn);
}
await delay({
duration: this.duration,
done: () => {
this.state = 'shown';
super.listen({ name: 'shown', cb });
}
});
});
return this;
}
async hide(cb) {
if (this.destroyed) {
return this;
}
if (this.state !== 'shown') {
if (this.state === 'ing')
this.mainEl.style.visibility = null;
return this;
}
this.state = 'ing';
if (!this.options.deadShow) {
this.options.b4Hide && await this.options.b4Hide.call(this);
super.listen({ name: 'hide', cb });
this.targetEl && this.targetEl.classList.remove(this.options.actClass);
this.options.wing.actClass && this.wings.map((k) => { k.classList.remove(this.options.wing.actClass); });
if (this.aniOut === 'slideUp') {
easeHeight({ el: this.wrapEl, height: this.wrapHeight, type: 'up', duration: this.duration, unaware: false });
}
else {
this.aniOut && (this.mainEl.style.animationName = ax.prefix + this.aniOut);
}
this.mainEl.querySelectorAll('video,audio').forEach((k) => {
k.pause();
});
this.hoverIns && (this.hoverIns.isActive = false);
await delay({
duration: this.duration,
done: () => {
this.state = 'hidden';
this.mainEl.style.visibility = null;
this.mainEl.remove();
super.listen({ name: 'hidden', cb });
this.aniOut === 'slideUp' && (this.wrapEl.style.height = 'auto');
}
});
}
return this;
}
}
const optDodge = [
{
attr: 'placeholder',
prop: 'placeholder',
value: '',
},
{
attr: 'on-setted',
prop: 'onSetted',
value: null,
},
{
attr: 'on-canceled',
prop: 'onCanceled',
value: null,
},
...optBase
];
class Dodge extends ModBaseListenCache {
options = {};
inputEl;
labelEl;
isFocus;
toggle;
timestamp;
placeholder;
static hostType = 'node';
static optMaps = optDodge;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Dodge.optMaps,
});
this.timestamp = Date.now();
this.inputEl = this.targetEl.querySelector("input,textarea");
if (!this.inputEl) {
throw new Error('Form field node not found!');
}
this.labelEl = null;
this.isFocus = false;
this.toggle = {
focus: () => {
this.inputEl.focus();
this.inputEl.removeAttribute('readonly');
this.targetEl.setAttribute('dodged', '');
this.isFocus = true;
},
blur: (e) => {
this.inputEl.blur();
this.inputEl.setAttribute('readonly', '');
!this.inputEl.value ? this.targetEl.removeAttribute('dodged') : this.targetEl.setAttribute('dodged', '');
this.isFocus = false;
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.placeholder = this.getPlaceholder();
this.setAttrs();
this.render();
this.inputEl.addEventListener('focus', this.toggle.focus, false);
this.inputEl.addEventListener('blur', this.toggle.blur, false);
this.labelEl.onclick = () => {
this.toggle.focus();
};
this.inputEl.value ? this.toggle.focus() : null;
super.listen({ name: 'initiated', cb });
return this;
}
getPlaceholder() {
let inputHolder = this.inputEl.getAttribute('placeholder');
return this.options.placeholder ? this.options.placeholder :
inputHolder ? inputHolder : config.lang.form.placeholder;
}
render() {
if (!this.labelEl) {
this.labelEl = createEl('label', '', this.placeholder);
this.inputEl.removeAttribute("placeholder");
this.inputEl.insertAdjacentElement('afterend', this.labelEl);
}
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}dodge`);
this.inputEl.toggleAttribute('readonly', true);
this.inputEl.classList.contains("ax-lg") ? this.targetEl.classList.add("ax-lg") : null;
}
set(value, cb) {
if (this.destroyed) {
return this;
}
if (value) {
this.inputEl.value = value;
this.toggle.focus();
}
else {
this.inputEl.focus();
}
super.listen({ name: 'set', cb, params: [value] });
return this;
}
cancel(cb) {
if (this.destroyed) {
return this;
}
this.inputEl.value = '';
this.inputEl.blur();
this.toggle.blur();
super.listen({ name: 'canceled', cb });
return this;
}
destroy(cb) {
if (this.destroyed) {
return this;
}
this.labelEl.onclick = null;
this.inputEl.removeEventListener('focus', this.toggle.focus);
this.inputEl.removeEventListener('blur', this.toggle.blur);
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optValid = [
{
attr: 'label',
prop: 'label',
value: '',
},
{
attr: 'placement',
prop: 'placement',
value: '',
},
{
attr: 'icon-show',
prop: 'iconShow',
value: true,
},
{
attr: 'type',
prop: 'type',
value: 'required',
},
{
attr: 'extend',
prop: 'extend',
value: {},
},
{
attr: 'parent',
prop: 'parent',
value: '',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'fail',
prop: 'fail',
value: '',
},
{
attr: 'succ',
prop: 'succ',
value: '',
},
{
attr: 'separator',
prop: 'separator',
value: ',',
},
{
attr: 'style-host',
prop: 'styleHost',
value: false,
},
{
attr: 'succ-show',
prop: 'succShow',
value: true,
},
{
attr: 'node-name',
prop: 'nodeName',
value: 'div',
},
{
attr: 'message',
prop: 'message',
value: {},
},
{
attr: 'popup',
prop: 'popup',
value: {},
},
{
attr: 'reg-local',
prop: 'regLocal',
value: '',
},
{
attr: 'reg-chars',
prop: 'regChars',
value: '',
},
{
attr: 'length-str',
prop: 'lengthStr',
value: 6,
},
{
attr: 'trigger',
prop: 'trigger',
value: 'blur',
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null,
},
{
attr: 'on-changed',
prop: 'onChanged',
value: null,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null
},
{
attr: 'on-hidden',
prop: 'onHidden',
value: null
},
...optBase
];
class Valid extends ModBaseListenCache {
options = {};
useRules;
dftRules;
inputEl;
timestamp;
name;
label;
parentEl;
valid;
hostValid;
msgEl;
otherBox;
checkFun;
types;
userRules;
result;
output;
msgIcon;
msgText;
popupIns;
msgIns;
obsProps;
observer;
static hostType = 'node';
static optMaps = optValid;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
host: elem,
maps: Valid.optMaps,
});
this.timestamp = Date.now();
if (!this.targetEl.getAttribute('name')) {
throw new Error('The element to be verified must have name attribute!');
}
this.name = this.targetEl.getAttribute('name');
this.label = this.options.label || this.name;
this.parentEl = getEl(this.options.parent) || this.targetEl.closest('form') || document.body;
this.valid = { target: this.targetEl, name: this.name, ins: this };
this.hostValid = null;
this.pushValids();
this.createMsgEl();
this.otherBox = getEl(this.options.placement);
this.createObs();
this.checkFun = debounce(() => {
this.do();
});
this.dftRules = {
'required': (data) => {
let fail = renderTpl(this.options.lang.required, { label: data.label });
return !isEmpty(data.value) ? { passed: true } : { passed: false, fail, type: 'required' };
},
...this.loopTestRules(['email', 'cellphone', 'landline', 'ip', 'id', 'zip', 'url', 'locale', 'password', 'letter', 'string', 'ymdhms', 'ymd', 'hms', 'ym', 'y', 'm', 'd', 'integer', 'number']),
'plate': (data) => {
let regex = data.value.length === 8 ? regExps.plate.nev : regExps.plate.oil;
return this.testRegex({ regex, value: data.value, name: 'plate' });
},
'date': (data) => {
let flag = isDateStr(data.value), fail = renderTpl(this.options.lang['date'], { label: data.label, value: data.value });
return flag ? { passed: true } : { passed: false, fail, type: 'date' };
},
...this.loopDateRules(['date=', 'date<', 'date<=', 'date>', 'date>=', 'date><', 'date><=', 'date>=<', 'date>=<=']),
...this.loopThanRules(['than=', 'than>', 'than>=', 'than<', 'than<=', 'than><', 'than><=', 'than>=<', 'than>=<=',]),
...this.loopLengthRules(['length=', 'length>', 'length>=', 'length<', 'length<=', 'length><', 'length><=', 'length>=<', 'length>=<=']),
...this.loopIncludeRules(['include', 'exclude']),
...this.loopValuesRules(['count=', 'count>', 'count>=', 'count<', 'count<=', 'count><', 'count><=', 'count>=<', 'count>=<=']),
...this.loopSameRules(['same', 'different']),
'strength': (data) => {
if (typeof data.value !== 'string') {
return { passed: false, fail: this.options.lang.strFormat };
}
let strength = this.getStrength(data.value), fail = renderTpl(this.options.lang['strength'], { label: data.label, name: data.name, value: strength, data: this.types['strength'] });
return strength >= this.types['strength'] ? { passed: true } : { passed: false, fail, type: 'strength' };
},
'specific': (data) => {
if (typeof data.value !== 'string') {
return { passed: false, fail: this.options.lang.strFormat };
}
let parse = validTools.parseSpecific(this.types['specific'], { label: data.label, name: data.name, value: data.value, tpl: this.options.lang['specific'] }), regExp = parse.regex, regText = parse.text;
return validTools.test(data.value, regExp) ? { passed: true } : { passed: false, fail: regText, type: 'specific' };
},
'combine': (data) => {
if (typeof data.value !== 'string') {
return { passed: false, fail: this.options.lang.strFormat };
}
let parse = validTools.parseCombine(this.types['combine'], { label: data.label, name: data.name, ins: this, value: data.value, tpl: this.options.lang['combine'] }), regExp = parse.regex, regText = parse.text;
return validTools.test(data.value, regExp) ? { passed: true } : { passed: false, fail: regText, type: 'combine' };
},
'async': (data) => {
return ajax.call(this, Object.assign({
url: this.types['async'],
data: {
label: data.label,
name: data.name,
value: data.value,
strength: this.getStrength(data.value),
},
}, this.options.ajax));
},
...this.options.extend
};
!this.parentEl?.ax?.hasSubmitListener && validTools.listenSubmit({ item: this.parentEl });
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.types = typeof this.options.type === 'string' ? paramToJson(this.options.type) : this.options.type;
this.getUserRules();
if (['change', 'blur', 'input'].includes(this.options.trigger)) {
this.targetEl.removeEventListener(this.options.trigger, this.checkFun);
this.targetEl.addEventListener(this.options.trigger, this.checkFun, false);
}
else if (this.options.trigger === 'load') {
this.checkFun();
}
super.listen({ name: 'initiated', cb });
return this;
}
setEmpty() {
this.msgEl ? this.msgEl.innerHTML = '' : null;
this.popupIns ? this.popupIns.destroy : null;
this.msgIns ? this.msgIns.destroy : null;
}
loopTestRules(types) {
let result = {};
types.forEach((k) => {
if (regExps.hasOwnProperty(k)) {
result[k] = (data) => {
if (Array.isArray(data.value)) {
return { passed: false, fail: this.options.lang.strFormat, id: 'strFormat' };
}
return this.testRegex({ regex: regExps[k], value: data.value, name: k });
};
}
});
return result;
}
loopIncludeRules(types) {
let result = {};
types.forEach((k) => {
result[k] = (data) => {
if (!Array.isArray(data.data)) {
return { passed: false, fail: this.options.lang.arrFormat };
}
let value = Array.isArray(data.value) ? data.value : data.value.split(this.options.separator), flag = isSubset(value, data.data), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: data.value, data: data.data });
k === 'exclude' && (flag = !flag);
return flag ? { passed: true } : { passed: false, fail, type: k };
};
});
return result;
}
loopSameRules(types) {
let result = {};
types.forEach((k) => {
result[k] = (data) => {
if (!Array.isArray(data.data)) {
return { passed: false, fail: this.options.lang.arrFormat };
}
let referField = this.parentEl.querySelector(`[name="${this.types[k][0]}"]`), referValue = this.getVals(referField, 'string'), targetValue = this.getVals(this.targetEl, 'string'), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: targetValue, data: data.data }), condition = k === 'same' ? (referValue === targetValue) : (referValue !== targetValue);
return condition ? { passed: true } : { passed: false, fail, type: k };
};
});
return result;
}
loopDateRules(types) {
let result = {};
types.forEach((k) => {
result[k] = (data) => {
if (Array.isArray(data.value)) {
return { passed: false, fail: this.options.lang.strFormat };
}
let flag = validTools.expired(data.value, data.data).join(''), fail = renderTpl(this.options.lang[k], { label: data.label, value: data.value, data: data.data }), condition = k === 'date=' ? (flag === '0-2') :
k === 'date<' ? (flag === '-1-2') :
k === 'date<=' ? (flag === '0-2' || flag === '-1-2') :
k === 'date>' ? (flag === '1-2') :
k === 'date>=' ? (flag === '1-2' || flag === '0-2') :
k === 'date><' ? (flag === '1-1') :
k === 'date><=' ? (flag === '1-1' || flag === '10') :
k === 'date>=<' ? (flag === '1-1' || flag === '0-1') :
k === 'date>=<=' ? (['1-1', '10', '0-1', '00'].includes(flag)) : true;
return condition ? { passed: true } : { passed: false, fail, type: k };
};
});
return result;
}
loopThanRules(types) {
let result = {};
types.forEach((k) => {
result[k] = (data) => {
if (Array.isArray(data.value)) {
return { passed: false, fail: this.options.lang.strFormat };
}
let flag = validTools.than(data.value, data.data).join(''), fail = renderTpl(this.options.lang[k], { label: data.label, value: data.value, data: data.data }), condition = k === 'than>' ? (flag === '1-2') :
k === 'than>=' ? (flag === '1-2' || flag === '0-2') :
k === 'than<' ? (flag === '-1-2') :
k === 'than<=' ? (flag === '0-2' || flag === '-1-2') :
k === 'than=' ? (flag === '0-2') :
k === 'than><' ? (flag === '1-1') :
k === 'than><=' ? (flag === '1-1' || flag === '10') :
k === 'than>=<' ? (flag === '1-1' || flag === '0-1') :
k === 'than>=<=' ? (['1-1', '10', '0-1', '00'].includes(flag)) : true;
return condition ? { passed: true } : { passed: false, fail, type: k };
};
});
return result;
}
loopLengthRules(types) {
let result = {};
types.forEach((k) => {
result[k] = (data) => {
if (Array.isArray(data.value)) {
return { passed: false, fail: this.options.lang.strFormat, id: 'strFormat' };
}
let pattern = k === 'length=' ? this.types[k] :
k === 'length>' ? `${this.types[k] + 1},` :
k === 'length>=' ? `${this.types[k]},` :
k === 'length<' ? `0,${this.types[k] - 1}` :
k === 'length<=' ? `0,${this.types[k]}` :
k === 'length><' ? `${this.types[k][0] + 1},${this.types[k][1] - 1}` :
k === 'length><=' ? `${this.types[k][0] + 1},${this.types[k][1]}` :
k === 'length>=<' ? `${this.types[k][0]},${this.types[k][1] - 1}` :
k === 'length>=<=' ? `${this.types[k][0]},${this.types[k][1]}` : '', regex = new RegExp(`^.{${pattern}}$`);
return this.testRegex({ regex, value: data.value, name: k });
};
});
return result;
}
loopValuesRules(types) {
let result = {};
for (let k of types) {
result[k] = (data) => {
let value = (Array.isArray(data.value)) ? data.value : data.value.split(this.options.separator).filter(Boolean), fail = renderTpl(this.options.lang[k], { label: data.label, name: data.name, value: value.length, data: data.data }), condition = k === 'count>=<=' ? (value.length >= this.types[k][0] && value.length <= this.types[k][1]) :
k === 'count><=' ? (value.length > this.types[k][0] && value.length <= this.types[k][1]) :
k === 'count>=<' ? (value.length >= this.types[k][0] && value.length < this.types[k][1]) :
k === 'count><' ? (value.length > this.types[k][0] && value.length < this.types[k][1]) :
k === 'count=' ? `${value.length} === ${this.types[k]}` : `${value.length} ${k.replace('count', '')} ${this.types[k]}`;
return new Function(`"use strict";return ${condition}`)() ? { passed: true } : { passed: false, fail, type: k };
};
}
return result;
}
testRegex({ regex, value, name }) {
let flag = validTools.test(value, regex), fail = renderTpl(this.options.lang[name], { label: this.label, value, data: this.types[name] });
((name === 'length<' || name === 'length<=') && !value) && (flag = true);
return flag ? { passed: true } : { passed: false, fail, type: name };
}
extendRules(rules) {
Object.assign(this.dftRules, rules);
}
getUserRules() {
this.userRules = {};
for (let k in this.types) {
if (this.types.hasOwnProperty(k) && this.dftRules.hasOwnProperty(k)) {
this.userRules[k] = this.dftRules[k];
this.userRules[k].data = this.types[k];
}
}
}
getVals(field = this.targetEl, format = '') {
return fieldTools.getVals({ target: field, parent: this.parentEl, format });
}
getStrength(value = this.getVals(this.targetEl)) {
return validTools.getStrength(value, {
chars: `[${this.options.regChars}]`,
local: `[${this.options.regLocal}]`,
length: this.options.lengthStr
});
}
do() {
if (this.destroyed)
return this;
let value = this.getVals(this.targetEl) || '';
return validTools.factory({
value,
name: this.name,
label: this.label,
ins: this,
rules: this.userRules,
text: {
succ: this.options.succ,
fail: this.options.fail,
},
cb: (resp) => {
this.result = resp;
this.output = { ...resp, name: this.name, label: this.label, value, ins: this, strength: this.getStrength(value) };
super.listen({ name: 'trigger', params: [this.output] });
Object.assign(this.observer.proxy, resp);
}
});
}
toggleStyle(passed) {
if (passed) {
this.msgEl.classList.remove(`${ax.prefix}c-error`);
this.msgEl.classList.add(`${ax.prefix}c-succ`);
this.targetEl.setAttribute('validate', 'passed');
if (this.options.styleHost) {
this.targetEl.classList.remove(`${ax.prefix}c-error`);
this.targetEl.classList.add(`${ax.prefix}c-succ`);
}
}
else {
this.msgEl.classList.remove(`${ax.prefix}c-succ`);
this.msgEl.classList.add(`${ax.prefix}c-error`);
this.targetEl.setAttribute('validate', 'failed');
if (this.options.styleHost) {
this.targetEl.classList.remove(`${ax.prefix}c-succ`);
this.targetEl.classList.add(`${ax.prefix}c-error`);
}
}
}
render(msg) {
this.toggleStyle(msg.passed);
if (msg.passed) {
this.msgIcon = this.options.iconShow ? icons.font["succ-f"] : '';
this.msgText = msg.succ;
}
else {
this.msgIcon = this.options.iconShow ? icons.font["error-f"] : '';
this.msgText = msg.fail;
}
this.msgEl.innerHTML = this.msgIcon + this.msgText;
if (this.otherBox) {
elState(this.msgEl).isVirtual && this.otherBox.appendChild(this.msgEl);
}
else {
if (typeof this.options.placement !== 'string') {
return this;
}
this.options.placement = this.options.placement.trim();
if (this.options.placement === 'down') {
let box = this.targetEl.closest(`.${ax.prefix}box-input`)?.querySelector(`[${ax.alias}="input"]`);
box ? box.insertAdjacentElement('afterEnd', this.msgEl) : null;
}
else if (this.options.placement === 'right') {
let box = this.targetEl.closest(`.${ax.prefix}box-input`)?.querySelector(`[${ax.alias}="help"]`);
box ? box.appendChild(this.msgEl) : null;
}
else if (this.options.placement === 'popup') {
if (!this.popupIns) {
this.popupIns = new Popup(this.targetEl, {
content: this.msgEl,
placement: 'bottom-start',
keepShow: true,
footer: false,
tools: false,
padding: false,
arrow: {
enable: false,
gap: 0,
},
classes: `${ax.prefix}plain`,
trigger: 'sticky'
});
}
}
else if (this.options.placement === 'message') {
if (!this.msgIns) {
this.msgIns = new Message({
content: this.msgText,
iconShow: true,
status: msg.passed ? 'succ' : 'error',
}).show();
}
else {
this.msgIns.update({
content: this.msgText,
status: msg.passed ? 'succ' : 'error',
}).then(() => this.msgIns.show());
}
}
else {
elState(this.msgEl).isVirtual ? this.targetEl.insertAdjacentElement('afterend', this.msgEl) : null;
}
}
}
createMsgEl() {
this.msgEl = this.hostValid ? this.hostValid.ins.msgEl : createEl(this.options.nodeName, { class: `${ax.prefix}valid` });
}
createObs() {
this.obsProps = this.hostValid ? this.hostValid.ins.obsProps : {};
this.observer = new Observe(this.obsProps);
this.observer.on('completed', () => {
this.render(this.result);
super.listen({ name: 'changed', params: [this.output] });
});
}
pushValids() {
if (ax.valids.length === 0) {
ax.valids.push({ parent: this.parentEl, children: [this.valid] });
}
else {
let index = ax.valids.findIndex(k => (k.parent === this.parentEl));
if (index > -1) {
let valids = ax.valids[index].children, temp = valids.find((k) => k.name === this.name);
!temp ? valids.push(this.valid) : (this.hostValid = temp);
}
else {
ax.valids.push({ parent: this.parentEl, children: [this.valid] });
}
}
}
hide(cb) {
if (this.destroyed) {
return this;
}
if (this.options.placement === 'message') ;
else if (this.options.placement === 'popup') {
this.popupIns.hide();
}
else {
this.msgEl.remove();
}
super.listen({ name: 'hidden', cb });
return this;
}
show(cb) {
if (this.destroyed) {
return this;
}
if (this.otherBox) {
elState(this.msgEl).isVirtual ? this.otherBox.appendChild(this.msgEl) : null;
}
else {
if (this.options.placement === 'message') {
this.msgIns.show();
}
else if (this.options.placement === 'popup') {
this.popupIns.show();
}
else {
elState(this.msgEl).isVirtual ? this.targetEl.insertAdjacentElement('afterend', this.msgEl) : null;
}
}
super.listen({ name: 'shown', cb });
return this;
}
destroy(cb) {
if (this.destroyed) {
return this;
}
if (['change', 'blur', 'input'].includes(this.options.trigger)) {
this.targetEl.removeEventListener(this.options.trigger, this.checkFun);
}
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_rootStart$1 = config.rootStart, AXTMP_idStart$1 = config.idStart, AXTMP_floorStart$1 = config.floorStart, AXTMP_pathHyphen$1 = config.pathHyphen;
const optMenu$1 = [
{
attr: 'theme',
prop: 'theme',
value: 'light',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'passive',
prop: 'passive',
value: false,
},
{
attr: 'expose',
prop: 'expose',
value: false,
},
{
attr: 'active',
prop: 'active',
value: '',
},
{
attr: 'disable',
prop: 'disable',
value: '',
},
{
attr: 'multiple',
prop: 'multiple',
value: false,
},
{
attr: 'expand-all',
prop: 'expandAll',
value: false,
},
{
attr: 'z-index',
prop: 'zIndex',
value: 0,
},
{
attr: 'trigger',
prop: 'trigger',
value: 'click',
},
{
attr: 'root-start',
prop: 'rootStart',
value: AXTMP_rootStart$1,
},
{
attr: 'id-start',
prop: 'idStart',
value: AXTMP_idStart$1,
},
{
attr: 'floor-start',
prop: 'floorStart',
value: AXTMP_floorStart$1,
},
{
attr: 'path-hyphen',
prop: 'pathHyphen',
value: AXTMP_pathHyphen$1,
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'page-close',
prop: 'pageClose',
value: false,
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: true,
icon: '',
},
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'linkage',
prop: 'linkage',
value: true,
},
{
attr: 'unpadded',
prop: 'unpadded',
value: false,
},
{
attr: 'lamp',
prop: 'lamp',
value: '',
},
{
attr: 'full',
prop: 'full',
value: false,
},
{
attr: 'spill',
prop: 'spill',
value: false,
},
{
attr: 'layout',
prop: 'layout',
value: 'indent|legend|icon|disk|cube|image|label|custom|tips||badge|arrow',
},
{
attr: 'tree',
prop: 'tree',
value: {},
},
{
attr: 'drawer',
prop: 'drawer',
value: {
host: '',
placement: 'left',
footer: false,
},
},
{
attr: 'nav',
prop: 'nav',
value: {
enable: false,
headWidth: '',
bodyWidth: '',
marginLeft: '',
marginRight: '',
align: 'left',
},
},
{
attr: 'on-activated',
prop: 'onActivated',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
...optBase
];
let AXTMP_connector = config.labelHyphen, AXTMP_separator$3 = config.splitHyphen, AXTMP_rootStart = config.rootStart, AXTMP_idStart = config.idStart, AXTMP_floorStart = config.floorStart, AXTMP_pathHyphen = config.pathHyphen;
const optTree = [
{
attr: 'name',
prop: 'name',
value: '',
},
{
attr: 'value',
prop: 'value',
value: '',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'passive',
prop: 'passive',
value: false,
},
{
attr: 'disable',
prop: 'disable',
value: '',
},
{
attr: 'readonly',
prop: 'readonly',
value: '',
},
{
attr: 'min',
prop: 'min',
value: 0,
},
{
attr: 'max',
prop: 'max',
value: 0,
},
{
attr: 'sliced',
prop: 'sliced',
value: true,
},
{
attr: 'expand',
prop: 'expand',
value: {
value: '',
all: false,
only: true,
linkage: false,
},
},
{
attr: 'select',
prop: 'select',
value: {
enable: true,
only: true,
value: '',
linkage: false,
span: 'tree',
addSelected: false,
},
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: true,
show: `${ax.prefix}icon-right`,
hide: `${ax.prefix}icon-right`,
anim: `${ax.prefix}rotate90`,
type: 'icon',
trigger: 'click',
},
},
{
attr: 'legend',
prop: 'legend',
value: {
enable: false,
parent: [`${ax.prefix}icon-folder`, `${ax.prefix}icon-folder-open`],
child: `${ax.prefix}icon-file-text`,
type: 'icon',
},
},
{
attr: 'check',
prop: 'check',
value: {
enable: false,
type: 'checkbox',
value: '',
min: 0,
max: 0,
sliced: true,
linkage: true,
only: false,
span: 'tree',
},
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
trigger: 'hover',
children: ['folder', 'file', 'edit', 'remove'],
},
},
{
attr: 'output',
prop: 'output',
value: {
enable: true,
target: '',
connector: AXTMP_connector,
separator: AXTMP_separator$3,
type: '',
from: 'selected',
field: 'label',
instant: true,
autosort: false,
},
},
{
attr: 'sql-data',
prop: 'sqlData',
value: {
deep: 0,
start: 0,
count: 0,
order: 'id asc',
where: '',
},
},
{
attr: 'paginated',
prop: 'paginated',
value: {
enable: false,
count: 10,
override: false,
exception: false,
},
},
{
attr: 'delay',
prop: 'delay',
value: 100,
},
{
attr: 'deferred',
prop: 'deferred',
value: false,
},
{
attr: 'shortcut',
prop: 'shortcut',
value: {
enable: false,
span: 'blank',
mean: 'selected',
},
},
{
attr: 'search',
prop: 'search',
value: {
target: '',
trigger: 'input',
delay: 500,
value: '',
limit: 0,
fuzzy: true,
ignore: true,
},
},
{
attr: 'drag',
prop: 'drag',
value: {
enable: false,
exclude: '',
},
},
{
attr: 'drop',
prop: 'drop',
value: {
attr: 'dropnode',
global: false,
},
},
{
attr: 'chain',
prop: 'chain',
value: false,
},
{
attr: 'auto-fill',
prop: 'autoFill',
value: true,
},
{
attr: 'root-start',
prop: 'rootStart',
value: AXTMP_rootStart,
},
{
attr: 'id-start',
prop: 'idStart',
value: AXTMP_idStart,
},
{
attr: 'floor-start',
prop: 'floorStart',
value: AXTMP_floorStart,
},
{
attr: 'path-hyphen',
prop: 'pathHyphen',
value: AXTMP_pathHyphen,
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'bubble',
prop: 'bubble',
value: {
enable: false,
type: 'popup',
},
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'display',
prop: 'display',
value: 'inline',
},
{
attr: 'layout',
prop: 'layout',
value: 'indent|arrow|check|legend|icon|disk|cube|image|label|badge|tips|custom|tools',
},
{
attr: 'feature',
prop: 'feature',
value: {
type: '',
expand: {
all: true,
only: false,
},
check: {
linkage: true,
only: false,
span: 'tree',
},
layout: {
dropdown: 'indent|arrow|icon|disk|cube|image|label|holder|tips|badge',
select: 'indent|arrow|icon|disk|cube|image|label|holder|tips|badge',
check: 'indent|arrow|check|icon|disk|cube|image|label|holder|tips|badge',
button: 'icon|arrow|disk|cube|image|label|tips|badge',
list: 'indent|arrow|icon|disk|cube|image(label|badge|tips|custom)'
}
},
},
{
attr: 'b4-expand',
prop: 'b4Expand',
value: null,
},
{
attr: 'b4-collapse',
prop: 'b4Collapse',
value: null,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-edit',
prop: 'b4Edit',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-graft',
prop: 'b4Graft',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-insertitem',
prop: 'onInsertItem',
value: null,
},
{
attr: 'on-insertitems',
prop: 'onInsertItems',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null
},
{
attr: 'on-added',
prop: 'onAdded',
value: null
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null
},
{
attr: 'on-disabledall',
prop: 'onDisabledAll',
value: null
},
{
attr: 'on-enabledall',
prop: 'onEnabledAll',
value: null
},
{
attr: 'on-readonly',
prop: 'onReadonly',
value: null
},
{
attr: 'on-readonlyall',
prop: 'onReadonlyAll',
value: null
},
{
attr: 'on-expand',
prop: 'onExpand',
value: null
},
{
attr: 'on-expanded',
prop: 'onExpanded',
value: null
},
{
attr: 'on-collapse',
prop: 'onCollapse',
value: null
},
{
attr: 'on-collapsed',
prop: 'onCollapsed',
value: null
},
{
attr: 'on-expandall',
prop: 'onExpandAll',
value: null
},
{
attr: 'on-expandedAll',
prop: 'onExpandedAll',
value: null
},
{
attr: 'on-collapsedall',
prop: 'onCollapsedAll',
value: null
},
{
attr: 'on-selected',
prop: 'onSelected',
value: null
},
{
attr: 'on-deselected',
prop: 'onDeselected',
value: null
},
{
attr: 'on-selectedall',
prop: 'onSelectedAll',
value: null
},
{
attr: 'on-checked',
prop: 'onChecked',
value: null
},
{
attr: 'on-unchecked',
prop: 'onUnchecked',
value: null
},
{
attr: 'on-checkedall',
prop: 'onCheckedAll',
value: null
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-turned',
prop: 'onTurned',
value: null
},
{
attr: 'on-got',
prop: 'onGot',
value: null
},
{
attr: 'on-set',
prop: 'onSet',
value: null
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-grafted',
prop: 'onGrafted',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-toofew',
prop: 'onTooFew',
value: null
},
{
attr: 'on-toomany',
prop: 'onTooMany',
value: null
},
{
attr: 'on-locked',
prop: 'onLocked',
value: null
},
{
attr: 'on-unlocked',
prop: 'onUnlocked',
value: null
},
{
attr: 'on-output',
prop: 'onOutput',
value: null
},
...optBase
];
const optDrag = [
{
attr: 'original',
prop: 'original',
value: true,
},
{
attr: 'group',
prop: 'group',
value: '',
},
{
attr: 'drags',
prop: 'drags',
value: '',
},
{
attr: 'drops',
prop: 'drops',
value: '',
},
{
attr: 'parent',
prop: 'parent',
value: '',
},
{
attr: 'wraps',
prop: 'wraps',
value: '',
},
{
attr: 'showEmpty',
prop: 'showEmpty',
value: true,
},
{
attr: 'handle',
prop: 'handle',
value: '',
},
{
attr: 'method',
prop: 'method',
value: 'hover',
},
{
attr: 'purpose',
prop: 'purpose',
value: 'auto',
},
{
attr: 'embed',
prop: 'embed',
value: {
position: 'after',
selector: '',
}
},
{
attr: 'pushable',
prop: 'pushable',
value: {
enable: true,
intent: 'cut',
}
},
{
attr: 'pullable',
prop: 'pullable',
value: true,
},
{
attr: 'point',
prop: 'point',
value: {
before: ['t/3', 't/2'],
after: ['b/3', 'b/2'],
},
},
{
attr: 'holder',
prop: 'holder',
value: {
enable: false,
style: [],
},
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: false,
icon: `._icon-right`,
placement: 'left',
selector: '',
},
},
{
attr: 'gesture',
prop: 'gesture',
value: {},
},
{
attr: 'flip',
prop: 'flip',
value: {
enable: true,
fluct: -100,
},
},
{
attr: 'throttle',
prop: 'throttle',
value: 100,
},
{
attr: 'duration',
prop: 'duration',
value: 200,
},
{
attr: 'ignore',
prop: 'ignore',
value: '',
},
{
attr: 'b4-drop',
prop: 'b4Drop',
value: null,
},
{
attr: 'b4-trigger',
prop: 'b4Trigger',
value: null,
},
{
attr: 'on-dragstart',
prop: 'onDragStart',
value: null,
},
{
attr: 'on-dragenter',
prop: 'onDragEnter',
value: null,
},
{
attr: 'on-dragleave',
prop: 'onDragLeave',
value: null,
},
{
attr: 'on-dragmove',
prop: 'onDragMove',
value: null,
},
{
attr: 'on-dropped',
prop: 'onDropped',
value: null,
},
{
attr: 'on-dragend',
prop: 'onDragEnd',
value: null,
},
{
attr: 'on-dragcancel',
prop: 'onDragCancel',
value: null,
},
{
attr: 'on-transferred',
prop: 'onTransferred',
value: null,
},
{
attr: 'on-swapped',
prop: 'onSwapped',
value: null,
},
{
attr: 'on-embeded',
prop: 'onEmbeded',
value: null,
},
{
attr: 'on-sorted',
prop: 'onSorted',
value: null,
},
{
attr: 'on-cloned',
prop: 'onCloned',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null,
},
{
attr: 'on-finished',
prop: 'onFinished',
value: null,
},
{
attr: 'on-dragout',
prop: 'onDragOut',
value: null,
},
{
attr: 'on-dropout',
prop: 'onDropOut',
value: null,
},
...optBase
];
const optFlip = [
{
attr: 'parent',
prop: 'parent',
value: ''
},
{
attr: 'children',
prop: 'children',
value: '',
},
{
attr: 'other',
prop: 'other',
value: '',
},
{
attr: 'fluct',
prop: 'fluct',
value: 0,
},
{
attr: 'easing',
prop: 'easing',
value: 'ease-out',
},
{
attr: 'prevent',
prop: 'prevent',
value: false,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-play',
prop: 'b4Play',
value: null,
},
{
attr: 'b4-play',
prop: 'b4Play',
value: null,
},
{
attr: 'b4-playall',
prop: 'b4PlayAll',
value: null,
},
{
attr: 'on-played',
prop: 'onPlayed',
value: null,
},
{
attr: 'on-playedall',
prop: 'onPlayedAll',
value: null,
},
...optBase
];
class Flip extends ModBaseListen {
options = {};
parentEl;
flipEls;
flipData;
childrenObs;
canPlay;
playedEls;
srcNode;
allPlayed;
parentH;
static hostType = 'none';
static optMaps = optFlip;
constructor(options = {}, initial = true) {
super();
super.ready({
options,
maps: Flip.optMaps,
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.parentEl = getEl(this.options.parent);
this.allPlayed = true;
this.playedEls = [];
this.canPlay = !this.options.prevent;
this.updateFlipEls();
super.listen({ name: 'initiated', cb });
return this;
}
async play(target) {
if (this.destroyed || !target?.ax?.flip || elState(target).isUncalc)
return;
if (this.options.b4Play) {
let resp = await this.options.b4Play.call(this, target);
resp && (target = resp);
}
let restDur = target.ax.flip.anim ? (target.ax.flip.anim.effect.getTiming().duration - target.ax.flip.anim.currentTime) : 0;
target.ax.flip.anim?.cancel();
let nowTranslate = this.getTranslate(target), nowRect = this.getRect(target), dist = {
x: target.ax.flip.now.x - nowRect.x,
y: target.ax.flip.now.y - nowRect.y,
};
let isSamePos = target.ax.flip.last.x === nowRect.x && target.ax.flip.last.y === nowRect.y;
if (!dist.x && !dist.y)
return new Promise(resolve => { resolve(null); });
target.ax.flip.last = nowRect;
let anim = target.animate([
{
transform: `translate(${dist.x + nowTranslate.x}px,${dist.y + nowTranslate.y}px)`,
},
{
transform: `translate(${nowTranslate.x}px,${nowTranslate.y}px)`,
}
], {
duration: isSamePos ? restDur : this.getDuration(dist),
easing: this.options.easing,
fill: 'forwards'
});
target.ax.flip.anim = anim;
await new Promise(resolve => requestAnimationFrame(resolve));
return new Promise(resolve => {
anim.onfinish = () => {
anim.cancel();
this.setFirstRect(target);
this.playedEls.push(target);
super.listen({ name: 'played', params: [target] });
resolve(null);
};
});
}
getDuration(dist) {
return Math.max(0, getAutoDur(getHypotenuse(dist.x, dist.y)) + this.options.fluct);
}
getTranslate(target) {
let m = new DOMMatrix(style(target).transform);
return { x: m.m41, y: m.m42 };
}
getRect(target) {
let tmp = target.getBoundingClientRect();
return {
x: tmp.left,
y: tmp.top,
};
}
setFirstRect(target) {
if (!target.ax) {
target.ax = { flip: {} };
}
else {
target.ax.flip = {};
}
target.ax.flip.last = this.getRect(target);
target.ax.flip.now = { ...target.ax.flip.last };
}
setNowRects() {
for (let k of this.flipEls) {
k.ax.flip.now = this.getRect(k);
}
}
updateFlipEls() {
if (!this.options.children) {
this.flipEls = this.parentEl ? [...this.parentEl.children] : [];
}
else {
this.flipEls = getEls(this.options.children, this.parentEl);
}
if (this.options.other) {
let tmp = getEls(this.options.other);
tmp.length && (this.flipEls = unique([...this.flipEls, ...tmp]));
}
for (let k of this.flipEls)
this.setFirstRect(k);
}
async add(target, cb) {
let els = getEls(target);
if (!els.length)
return this;
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, els);
resp && (els = resp);
}
for (let k of els) {
this.flipEls.push(k);
this.setFirstRect(k);
}
super.listen({ name: 'added', cb, params: [els] });
return this;
}
async remove(target, cb) {
let els = getEls(target);
if (!els.length)
return this;
if (this.options.b4Remove) {
let resp = await this.options.b4Remove.call(this, els);
resp && (els = resp);
}
this.flipEls = this.flipEls.filter((k) => !els.includes(k));
for (let el of els)
Reflect.deleteProperty(el, 'flip');
super.listen({ name: 'removed', cb, params: [els] });
return this;
}
async playAll(cb) {
if (this.flipEls.length < 2 || !this.canPlay || this.destroyed)
return this;
if (this.options.b4PlayAll) {
let resp = await this.options.b4PlayAll.call(this, this.flipEls);
resp && (this.flipEls = resp);
}
let promises = [...this.flipEls].map(k => this.play(k));
this.allPlayed = false;
await Promise.all(promises);
this.allPlayed = true;
super.listen({ name: 'playedAll', cb, params: [unique(this.playedEls)] });
this.playedEls = [];
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
for (let k of this.flipEls) {
k.ax.flip?.anim?.cancel();
Reflect.deleteProperty(k.ax, 'flip');
}
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class Drag extends ModBaseListen {
targetEl;
options = {};
curX;
curY;
preX;
preY;
isActive;
enterTimer;
leaveTimer;
eventToggle;
holdEl;
enterCompare;
globalEvent;
moveEvent;
enterEvent;
leaveEvent;
enterHold;
leaveHold;
holderDrag;
holderDrop;
holderEmpty;
dropArrow;
orgHolder;
selfEls;
dragEls;
dropEls;
lastDrop;
lastPoint;
dftParams;
dropOver;
dropEnd;
dragstartEvt;
dragendEvt;
dragenterEvt;
dragoverEvt;
dragdropEvt;
dragleaveEvt;
mousedownEvt;
mouseupEvt;
targetPoints;
targetTag;
holderAttr;
orgVal;
nowVal;
orgStyle;
parentEl;
wrapEls;
ignoreEls;
sourceNode;
flipIns;
gestureIns;
hoverCount;
cloned;
ghostEl;
otherGroupIns;
triggered;
lastTarget;
isTransferred;
childObs;
childObsOpts;
commTrigger;
commDragStart;
commDragEnter;
commDragLeave;
commDragOver;
commDragDrop;
commDragEnd;
commDragThrot;
commFinished;
static hostType = 'node';
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: optDrag,
host: elem,
component: false,
spread: ['arrow', 'pushable', 'holder', 'flip']
});
if (!this.targetEl)
throw new Error('The target node for drag start is missing!');
this.holderEmpty = createEl('div', { class: `${ax.prefix}holder-empty` }, this.options.lang.holderEmpty);
this.holderDrop = createEl('div', { class: `${ax.prefix}holder-drop ${ax.prefix}d-none` }, this.options.lang.holderDrop);
this.dropArrow = createEl('i', { class: `${ax.prefix}drop-arrow ${this.options.arrow.icon}`, placement: this.options.arrow.placement, point: 'inside' });
this.lastPoint = '';
this.targetPoints = [];
this.dragstartEvt = (evt) => {
evt.dataTransfer.effectAllowed = 'copyMove';
this.commDragStart(evt);
};
this.dragenterEvt = (evt) => {
evt.preventDefault();
this.commDragEnter(evt.target, evt);
};
this.dragleaveEvt = (evt) => {
this.commDragLeave(evt.target, evt.relatedTarget, evt);
};
this.dragoverEvt = (evt) => {
evt.preventDefault();
evt.dataTransfer.dropEffect = evt.ctrlKey ? 'copy' : 'move';
let resp = this.commDragOver(evt.target, evt);
resp === false && super.listen({ name: 'dragOut', params: [evt] });
};
this.dragdropEvt = async (evt) => {
evt.preventDefault();
let resp = await this.commDragDrop(evt.target, evt);
resp === false && super.listen({ name: 'dropOut', params: [evt] });
return;
};
this.dragendEvt = (evt) => {
this.commDragEnd(evt.target, evt);
};
this.commTrigger = async (evt) => {
try {
this.options.b4Trigger && await this.options.b4Trigger.call(this, evt);
}
catch {
return false;
}
this.updateDragsDrops();
this.removeDroppeds();
if (this.flipIns) {
this.flipIns.options.children = this.getFlipChldren();
this.flipIns.updateFlipEls();
}
let dragEl = this.dragEls.find((k) => k.contains(evt.target));
if (!dragEl)
return false;
if (this.handleEls.length === 0 || this.useHandle(evt.target)) {
evt.stopPropagation();
dragEl.setAttribute('draggable', 'true');
this.sourceNode = dragEl;
ax.dragNode = this.sourceNode;
this.addDestopEvents();
super.listen({ name: 'trigger', params: [{ target: dragEl, event: evt }] });
this.triggered = true;
}
};
this.commDragStart = (evt) => {
document.body.toggleAttribute('dragbody', true);
this.isTransferred = false;
this.cloned = false;
if (this.otherGroupIns.length) {
for (let k of this.otherGroupIns) {
k.isTransferred = false;
k.cloned = false;
}
}
this.setHolderAttrs();
requestAnimationFrame(() => {
this.sourceNode.classList.add(`${ax.prefix}drag-wait`);
});
super.listen({ name: 'dragStart', params: [{ target: null, source: this.sourceNode, point: 'outside', event: evt, type: '' }] });
};
this.commDragEnter = (evtTarget, evt) => {
let target = this.dropEls.find((k) => k === evtTarget) || this.wrapEls.find((k) => k === evtTarget);
if (!target)
return false;
this.toggleDropping(evtTarget, true);
this.hoverCount = 0;
super.listen({ name: 'dragEnter', params: [{ target, source: this.sourceNode, point: this.lastPoint, event: evt, type: this.getTransferType() }] });
};
this.commDragLeave = (evtTarget, relatedTarget, evt) => {
let target = this.dropEls.find((k) => k === evtTarget) || this.wrapEls.find((k) => k === evtTarget), related = this.dropEls.includes(relatedTarget);
if (!target || target === relatedTarget || (!related && target.contains(relatedTarget)))
return false;
this.toggleDropping(target, false);
this.removeArrow();
super.listen({ name: 'dragLeave', params: [{ target, source: this.sourceNode, relatedTarget, point: this.lastPoint, event: evt, type: this.getTransferType() }] });
return true;
};
this.commDragOver = (evtTarget, evt) => {
if (!this.options.pushable.enable)
return false;
if (!this.options.pullable && !contains(this.sourceNode, this.selfEls))
return false;
if (evtTarget === this.sourceNode)
return false;
if (evtTarget === this.holderDrop) {
return false;
}
this.commDragThrot(evtTarget, evt);
};
this.commDragDrop = async (evtTarget, evt) => {
this.removeDroppings();
this.removeArrow();
if (!this.options.pushable.enable || this.options.method !== 'drop')
return false;
if (!this.options.pullable && !contains(this.sourceNode, this.selfEls))
return false;
let target = evtTarget, param = { target, source: this.sourceNode, point: this.lastPoint, event: evt, type: this.getTransferType() };
if (this.wrapEls.includes(evtTarget)) {
try {
this.options.b4Drop && await this.options.b4Drop.call(this, param);
}
catch {
console.info('The event of releasing the mouse or finger has been blocked!');
return false;
}
this.flipIns && this.flipIns.setNowRects();
this.insertEl(target, this.sourceNode, evt, 'beforeend');
this.options.holder.enable && this.hideHolder();
this.flipIns && this.flipIns.playAll();
param.target = target;
super.listen({ name: 'transferred', params: [param] });
this.isTransferred = true;
}
else {
let toClone = this.canClone(evtTarget), drops = this.dropEls;
target = drops.find((k) => k.contains(evtTarget));
if (!target)
return false;
if (!this.insertable(target, this.sourceNode))
return false;
try {
this.options.b4Drop && await this.options.b4Drop.call(this, param);
}
catch {
console.info('The event of releasing the mouse or finger has been blocked!');
return false;
}
if (this.flipIns) {
if (target?.flip?.anim?.playState === 'running' || target === this.sourceNode)
return false;
let copyNode = this.cloneStart(toClone);
this.flipIns.setNowRects();
copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt });
this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, this.sourceNode, evt);
this.options.holder.enable && this.hideHolder();
this.flipIns.playAll();
}
else {
let copyNode = this.cloneStart(toClone);
copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt });
this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, this.sourceNode, evt);
this.options.holder.enable && this.hideHolder();
}
param.target = target;
super.listen({ name: 'transferred', params: [param] });
this.isTransferred = true;
}
this.toggleDropped(this.sourceNode, true);
super.listen({ name: 'dropped', params: [param] });
return;
};
this.commDragEnd = (evtTarget, evt) => {
let param = { target: evtTarget, source: this.sourceNode, point: this.lastPoint, event: evt };
this.revert();
super.listen({ name: 'dragEnd', params: [param] });
};
this.commFinished = (evt) => {
this.revert();
super.listen({ name: 'finished', params: [evt] });
};
this.commDragThrot = throttle((evtTarget, evt) => {
this.hoverCount++;
let param = { source: this.sourceNode, event: evt }, target;
if (this.wrapEls.includes(evtTarget)) {
target = evtTarget;
let isEmpty = !target.children.length || getEl(`:scope > .${ax.prefix}holder-empty`, target);
if (!isEmpty)
return;
this.flipIns && this.flipIns.setNowRects();
if (this.options.method === 'hover') {
this.insertEl(target, this.sourceNode, evt, 'beforeend');
}
else {
this.options.holder.enable && this.insertEl(target, this.holderDrop, evt, 'beforeend');
param.source = this.holderDrop;
}
this.flipIns && this.flipIns.playAll();
param.target = target;
param.point = 'inside';
param.type = 'embed';
super.listen({ name: 'transferred', params: [param] });
this.isTransferred = true;
super.listen({ name: 'dragMove', params: [param] });
}
else {
let toClone = this.options.method === 'hover' && this.canClone(evtTarget), drops = this.dropEls, copyNode, condition = this.options.method === 'hover' || (this.options.method === 'drop' && this.options.holder.enable), insertNode = this.options.method === 'drop' && this.options.holder.enable ? this.holderDrop : this.sourceNode;
target = drops.find((k) => k.contains(evtTarget));
if (!target)
return;
param.target = target;
if (this.flipIns) {
if (target?.flip?.anim?.playState === 'running')
return;
this.updatePoints(evt, target);
this.insertUpdateArrow(target);
super.listen({ name: 'dragMove', params: [param] });
if (!condition || !this.insertable(target, this.sourceNode))
return;
copyNode = this.cloneStart(toClone);
this.flipIns.setNowRects();
copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt }, (node) => {
insertNode = node;
this.sourceNode = node;
});
this.options.purpose === 'swap' ? this.swapNodes(target, this.sourceNode) : this.insertEl(target, insertNode, evt);
this.flipIns.playAll();
param.point = this.lastPoint;
param.type = this.getTransferType();
super.listen({ name: 'transferred', params: [param] });
this.isTransferred = true;
}
else {
this.updatePoints(evt, target);
this.insertUpdateArrow(target);
super.listen({ name: 'dragMove', params: [param] });
if (this.options.method === 'drop' || !this.insertable(target, this.sourceNode))
return;
copyNode = this.cloneStart(toClone);
copyNode && this.cloneEnd({ target, source: this.sourceNode, relatedTarget: copyNode, event: evt }, (node) => {
insertNode = node;
this.sourceNode = node;
});
this.insertEl(target, insertNode, evt);
param.point = this.lastPoint;
param.type = this.getTransferType();
super.listen({ name: 'transferred', params: [param] });
this.isTransferred = true;
}
}
}, this.options.throttle);
this.mousedownEvt = async (evt) => {
let resp = await this.commTrigger(evt);
if (resp === false)
return;
};
this.mouseupEvt = (evt) => {
this.commFinished(evt);
};
this.setMutationObs();
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.triggered = false;
this.parentEl = getEl(this.options.parent);
this.selfEls = [];
this.dragEls = [];
this.dropEls = [];
this.hoverCount = 0;
this.cloned = false;
this.updateWrapEls();
this.updateHandleEls();
this.setWrapsObs();
this.updateIgnoreEls();
this.sourceNode = null;
this.setAttrs();
this.holderAttr = ['left', 'right'].includes(this.options.arrow.placement) ? 'height' :
['top', 'bottom'].includes(this.options.arrow.placement) ? 'width' : '';
this.setFlip();
if (this.options.original) {
ax.isTouchScr ? this.setCommDrag() : this.setDestopDrag();
}
else {
this.setCommDrag();
}
this.handleEmpty();
super.listen({ name: 'initiated', cb });
}
setCommDrag() {
this.gestureIns = new Gesture(this.targetEl, {
rotate: false,
scale: false,
drift: false,
wheel: false,
translate: {
target: this.options.handle,
},
b4Trigger: (evt) => {
return new Promise(async (resolve, reject) => {
let resp = await this.commTrigger(evt);
resp === false ? reject() : resolve(null);
});
},
onStart: (evt) => {
this.commDragStart(evt);
this.ghostEl = this.getGhostNode(this.sourceNode);
this.sourceNode.parentNode.appendChild(this.ghostEl);
},
onEnter: (evt) => {
this.commDragEnter(evt.evtTarget, evt);
},
onLeave: (evt) => {
this.commDragLeave(evt.evtTarget, evt.relatedTarget, evt);
},
onMove: (evt) => {
this.setGhostPos(evt.translate.value);
let resp = this.commDragOver(evt.evtTarget, evt);
resp === false && super.listen({ name: 'dragOut', params: [evt] });
},
onEnd: async (evt) => {
let resp = await this.commDragDrop(evt.evtTarget, evt);
resp === false && super.listen({ name: 'dropOut', params: [evt] });
this.commDragEnd(evt.evtTarget, evt);
return;
},
onFinished: (evt) => {
this.revert();
super.listen({ name: 'finished', params: [evt] });
},
onCanceled: (data) => {
this.revert();
super.listen({ name: 'dragCancel', params: [{ ...data }] });
}
});
}
canClone(target) {
let tmp = this.options.original && !ax.isTouchScr ? !this.selfEls.includes(ax.dragNode) : this.otherGroupIns.find((k) => k.targetEl.contains(target));
return this.options.pushable.intent === 'clone' && tmp;
}
cloneStart(bool = true) {
if (!bool || this.cloned)
return;
let copyNode = this.getCopyNode(this.sourceNode);
this.flipIns && this.flipIns.add(copyNode);
this.sourceNode.style.position = 'absolute';
this.sourceNode.insertAdjacentElement('afterend', copyNode);
return copyNode;
}
cloneEnd(param, cb) {
if (!param.relatedTarget)
return;
super.listen({ name: 'cloned', params: [param] });
this.sourceNode.style.position = '';
this.cloned = true;
if (cb) {
cb(param.relatedTarget);
}
else {
this.sourceNode = param.relatedTarget;
}
}
getTransferType() {
return this.options.purpose === 'auto' ? (this.lastPoint === 'inside' ? 'embed' : 'sort') : this.options.purpose;
}
getFlipChldren() {
return this.options.drags ? [...this.dragEls, ...this.dropEls] : this.dropEls;
}
getCopyNode(node) {
let tmp = node.cloneNode(true);
tmp.removeAttribute('draggable');
tmp.classList.remove(`${ax.prefix}drag-wait`);
tmp.toggleAttribute('cloned', true);
return tmp;
}
getGhostNode(node) {
let tmp = node.cloneNode(true), styles = style(node), rects = node.getBoundingClientRect(), left = rects.left - parseFloat(styles.marginLeft), top = rects.top - parseFloat(styles.marginTop);
tmp.removeAttribute('draggable');
tmp.classList.remove(`${ax.prefix}drag-wait`);
tmp.classList.add(`${ax.prefix}drag-ghost`);
tmp.style.width = `min(${styles.width},100%)`;
tmp.style.height = styles.height;
tmp.style.left = left + 'px';
tmp.style.top = top + 'px';
tmp.initVal = { left, top };
return tmp;
}
setGhostPos(value) {
this.ghostEl.style.left = this.ghostEl.initVal.left + value.x + 'px';
this.ghostEl.style.top = this.ghostEl.initVal.top + value.y + 'px';
}
hideGhost() {
if (!this.ghostEl || elState(this.ghostEl).isVirtual)
return;
if (this.isTransferred) {
this.ghostEl.remove();
return;
}
let rects = this.sourceNode.getBoundingClientRect(), styles = style(this.ghostEl), left = rects.left - parseFloat(styles.marginLeft), top = rects.top - parseFloat(styles.marginTop), anim = this.ghostEl.animate([
{
opacity: styles.opacity,
left: styles.left,
top: styles.top,
},
{
opacity: 0,
left: left + 'px',
top: top + 'px',
}
], {
duration: this.options.duration,
easing: this.flipIns ? this.flipIns.options.easing : 'ease-out',
fill: 'forwards'
});
anim.addEventListener('finish', () => {
this.ghostEl.remove();
});
}
updateHandleEls() {
if (this.handleEls.length) {
for (let k of this.handleEls)
k.removeAttribute('handle');
}
this.handleEls = getEls(this.options.handle, this.parentEl);
for (let k of this.handleEls)
k.setAttribute('handle', '');
}
updateIgnoreEls() {
this.ignoreEls = getEls(this.options.ignore, this.targetEl);
}
updateWrapEls() {
this.wrapEls = this.options.wraps ? getEls(this.options.wraps, this.targetEl) : [this.targetEl];
}
setMutationObs() {
this.childObs = new MutationObserver(k => {
this.options.showEmpty && this.handleEmpty();
});
this.childObsOpts = { childList: true, subtree: false };
}
setWrapsObs() {
if (!this.options.showEmpty)
return;
for (let k of this.wrapEls)
this.childObs.observe(k, this.childObsOpts);
}
hideHolder() {
this.holderDrop.toggleAttribute('dropping', false);
if (elState(this.holderDrop).isVisible) {
this.holderDrop.classList.add(`${ax.prefix}d-none`);
this.holderDrop.remove();
}
}
replaceNodes(target, source) {
let pTarget = target.parentNode, pSource = source.parentNode, nTarget = target.nextElementSibling, nSource = source.nextElementSibling;
pTarget.insertBefore(source, nTarget);
pSource.insertBefore(target, nSource);
}
swapNodes(target, source) {
this.replaceNodes(target, source);
super.listen({ name: 'swapped', params: [{ target, source }] });
}
getEmbedEl(target) {
return getEl(this.options.embed.selector, target) || target;
}
insertable(target, source) {
let embedPoint = this.getEmbedPoint(), embedWrap = this.getEmbedEl(target), isAfter = target.nextElementSibling === source && this.lastPoint === 'after', isBefore = target.previousElementSibling === source && this.lastPoint === 'before', isSwap = this.options.purpose === 'swap', isInside = source.parentNode === embedWrap, isFirst = embedPoint === 'afterbegin' && target.firstChildElement === source, isLast = embedPoint === 'beforeend' && target.lastChildElement === source, condition = this.options.purpose === 'embed' ? isInside : (this.lastPoint === 'inside' && this.options.purpose === 'auto') ? isFirst || isLast : isAfter || isBefore;
return isSwap ? true : !condition;
}
getEmbedPoint() {
return this.options.embed.position === 'after' ? 'beforeend' :
this.options.embed.position === 'before' ? 'afterbegin' :
this.targetPoints.includes('t/2') || this.targetPoints.includes('l/2') ? 'afterbegin' : 'beforeend';
}
insertEl(target, source, event, position) {
if (position) {
target.insertAdjacentElement(position, source);
super.listen({ name: 'embeded', params: [{ target, source, position, event }] });
}
else {
if (target === this.holderDrop) {
target.insertAdjacentElement('beforebegin', source);
}
else {
if (this.options.purpose === 'embed' || (this.lastPoint === 'inside' && this.options.purpose === 'auto')) {
let embedWrap = this.getEmbedEl(target), position = this.getEmbedPoint();
if (this.options.purpose === 'embed' && source.parentNode === embedWrap)
return;
embedWrap.insertAdjacentElement(position, source);
super.listen({ name: 'embeded', params: [{ target: embedWrap, source, position, event }] });
}
else {
if ((target.nextElementSibling === source && this.lastPoint === 'after')
||
(target.previousElementSibling === source && this.lastPoint === 'before'))
return;
target.insertAdjacentElement(this.lastPoint === 'before' ? 'beforebegin' : 'afterend', source);
super.listen({ name: 'sorted', params: [{ target, source, position: this.lastPoint, event }] });
}
}
}
}
updatePoints(evt, target) {
this.targetPoints = getRectPoints(evt.orgEvt || evt, target);
let isBefore = this.targetPoints.find((k) => this.options.point.before.includes(k)), isAfter = this.targetPoints.find((k) => this.options.point.after.includes(k));
this.lastPoint = this.targetPoints.includes('outside') ? '' : isBefore ? 'before' : isAfter ? 'after' : 'inside';
}
insertUpdateArrow(target) {
if (!this.options.arrow.enable)
return;
if (!this.lastPoint) {
this.dropArrow.remove();
}
else {
this.dropArrow.setAttribute('point', this.lastPoint);
if (elState(this.dropArrow).isVirtual) {
let tmp = getEl(this.options.arrow.selector, target) || target;
tmp.appendChild(this.dropArrow);
}
}
}
removeArrow() {
this.options.arrow.enable && !elState(this.dropArrow).isVirtual && this.dropArrow.remove();
}
setHolderAttrs() {
if (!this.options.holder.enable)
return;
let tmp = style(this.sourceNode);
this.holderDrop.style.setProperty(`--${ax.prefix}holder-w`, `min(${tmp.width},100%)`);
this.holderDrop.style.setProperty(`--${ax.prefix}holder-h`, tmp.height);
this.holderDrop.style.setProperty(`--${ax.prefix}holder-r`, tmp.borderRadius);
this.holderDrop.style.setProperty(`--${ax.prefix}holder-m`, tmp.margin);
if (this.options.holder.style.length) {
for (let k of this.options.holder.style)
this.holderDrop.style.setProperty(k, tmp[k]);
}
}
toggleDropped(target, bool = true) {
target && target.toggleAttribute('dropped', bool);
}
removeDroppeds() {
for (let k of [...this.dragEls])
k.toggleAttribute('dropped', false);
}
toggleDropping(target, bool = true) {
(this.dropEls.includes(target) || this.wrapEls.includes(target)) && target.toggleAttribute('dropping', bool);
}
removeDroppings() {
for (let k of [...this.dropEls, ...this.wrapEls])
k.toggleAttribute('dropping', false);
}
removeDraggables() {
for (let k of [...this.dragEls])
k.removeAttribute('draggable');
}
setFlip() {
if (!this.options.flip.enable)
return;
let opts = extend({
target: {
children: this.getFlipChldren(),
b4Play: (data) => {
return new Promise(resolve => {
if (data !== this.holderDrop || (data === this.holderDrop && !this.holderDrop.classList.contains(`${ax.prefix}d-none`))) {
resolve(null);
}
else if (data === this.holderDrop && this.holderDrop.classList.contains(`${ax.prefix}d-none`)) {
data.classList.remove(`${ax.prefix}d-none`);
}
});
},
onPlayedAll: () => {
this.commDragThrot.cancel();
}
},
source: this.options.flip
});
this.flipIns = new Flip(opts);
}
setDestopDrag() {
if (ax.isTouchScr || !this.options.original)
return;
this.removeMouseEvents();
this.addMouseEvents();
}
addMouseEvents() {
if (ax.isTouchScr || !this.options.original)
return;
document.addEventListener('mousedown', this.mousedownEvt, { passive: false });
document.addEventListener('mouseup', this.mouseupEvt, { passive: false });
}
removeMouseEvents() {
if (ax.isTouchScr || !this.options.original)
return;
document.removeEventListener('mousedown', this.mousedownEvt);
document.removeEventListener('mouseup', this.mouseupEvt);
}
addDestopEvents() {
if (ax.isTouchScr || !this.options.original)
return;
this.targetEl.addEventListener('dragstart', this.dragstartEvt, { passive: false });
this.targetEl.addEventListener('dragenter', this.dragenterEvt, { passive: false });
this.targetEl.addEventListener('dragover', this.dragoverEvt, { passive: false });
this.targetEl.addEventListener('dragleave', this.dragleaveEvt, { passive: false });
this.targetEl.addEventListener('drop', this.dragdropEvt, { passive: false });
this.targetEl.addEventListener('dragend', this.dragendEvt, { passive: false });
}
removeDestopEvents() {
if (ax.isTouchScr || !this.options.original)
return;
this.targetEl.removeEventListener('dragstart', this.dragstartEvt);
this.targetEl.removeEventListener('dragenter', this.dragenterEvt);
this.targetEl.removeEventListener('dragover', this.dragoverEvt);
this.targetEl.removeEventListener('dragleave', this.dragleaveEvt);
this.targetEl.removeEventListener('drop', this.dragdropEvt);
this.targetEl.removeEventListener('dragend', this.dragendEvt);
}
setAttrs() {
}
getGoupDrags() {
this.otherGroupIns = instance.findAll('drag').filter((k) => k !== this && this.options.group && k.options.group === this.options.group);
if (!this.otherGroupIns.length)
return [];
return this.otherGroupIns.map((k) => k.options.drags ? k.getSelfDragEls() : k.getSelfDropEls()).flat();
}
getSelfDropEls(drops = this.options.drops) {
let tmp1 = getEls(drops, this.parentEl), tmp2 = !tmp1.length ? getEls(`[dropnode]`, this.parentEl || this.targetEl) : tmp1, tmp3 = !tmp2.length ? [...this.targetEl.children] : elsSort(tmp2), tmp4 = [];
if (this.ignoreEls.length) {
tmp4 = tmp3.filter((k) => !this.ignoreEls.includes(k) && k.getAttribute('draggable') !== 'false');
}
else {
tmp4 = tmp3.filter((k) => k.getAttribute('draggable') !== 'false');
}
return tmp4;
}
getSelfDragEls(drags = this.options.drags) {
let tmp1 = getEls(drags, this.targetEl), tmp2 = !tmp1.length ? getEls(`[dragnode]`, this.targetEl) : tmp1, tmp3 = [];
if (this.ignoreEls.length) {
tmp3 = tmp2.filter((k) => !this.ignoreEls.includes(k) && k.getAttribute('draggable') !== 'false');
}
else {
tmp3 = tmp2.filter((k) => k.getAttribute('draggable') !== 'false');
}
return tmp3;
}
updateDragsDrops() {
if (this.options.drags) {
this.selfEls = this.getSelfDragEls(this.options.drags);
this.dragEls = [...this.selfEls, ...this.getGoupDrags()];
this.dropEls = [this.holderDrop, ...this.getSelfDropEls(this.options.drops).filter((k) => !this.dragEls.includes(k))];
}
else {
this.selfEls = this.getSelfDropEls(this.options.drops);
this.dragEls = [...this.selfEls, ...this.getGoupDrags()];
this.dropEls = [this.holderDrop, ...this.dragEls];
}
}
handleEmpty(target) {
if (!this.options.showEmpty)
return;
let fn = (el) => {
let len = el.children.length, tmp = getEl(`:scope > .${ax.prefix}holder-empty`, el);
if (!len) {
el.appendChild(this.holderEmpty.cloneNode(true));
}
else if (len > 1 && tmp) {
tmp && tmp.remove();
}
};
if (target) {
fn(target);
}
else {
for (let k of this.wrapEls) {
fn(k);
}
}
}
updateList(data, cb) {
if (this.destroyed)
return this;
Object.assign(this.options, data);
super.listen({ name: 'updatedList', cb, params: [data] });
return this;
}
revert() {
if (!this.triggered)
return;
this.hideGhost();
this.targetPoints = [];
this.lastPoint = '';
this.hideHolder();
this.sourceNode.classList.remove(`${ax.prefix}drag-wait`);
this.removeDroppings();
this.removeDraggables();
this.removeArrow();
this.removeDestopEvents();
this.gestureIns && this.gestureIns.removeSecondEvents();
this.hoverCount = 0;
this.cloned = false;
document.body.toggleAttribute('dragbody', false);
this.isTransferred = false;
this.triggered = false;
}
destroy(cb) {
if (this.destroyed)
return;
this.revert();
this.gestureIns && this.gestureIns.destroy();
this.removeMouseEvents();
this.removeDestopEvents();
this.options.showEmpty && this.childObs.disconnect();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_emptyTpl = `<i class="${ax.prefix}c-ignore">${config.lang.tags.emptyholder}</i>`, AXTMP_editorHolder = config.lang.tags.placeholder, AXTMP_separator$2 = config.splitHyphen;
const optTags = [
{
attr: 'ajax',
prop: 'ajax',
value: {}
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'theme',
prop: 'theme',
value: '',
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'field',
prop: 'field',
value: 'label',
},
{
attr: 'type',
prop: 'type',
value: '',
},
{
attr: 'compact',
prop: 'compact',
value: false,
},
{
attr: 'shape',
prop: 'shape',
value: '',
},
{
attr: 'max',
prop: 'max',
value: 0,
},
{
attr: 'min',
prop: 'min',
value: 0,
},
{
attr: 'sliced',
prop: 'sliced',
value: true,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'unique',
prop: 'unique',
value: {
enable: false,
refer: 'id',
template: `{{this.field}}<i class="${ax.prefix}c-brief">({{this.key}}:{{this.value}})</i>`,
},
},
{
attr: 'empty',
prop: 'empty',
value: {
enable: true,
content: AXTMP_emptyTpl,
}
},
{
attr: 'editor',
prop: 'editor',
value: {
enable: false,
addable: true,
deletable: true,
selector: '',
placeholder: AXTMP_editorHolder,
},
},
{
attr: 'removable',
prop: 'removable',
value: false,
},
{
attr: 'separator',
prop: 'separator',
value: AXTMP_separator$2,
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-edit',
prop: 'b4Edit',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'on-added',
prop: 'onAdded',
value: null,
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null,
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null,
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null,
},
{
attr: 'on-duplicated',
prop: 'onDuplicated',
value: null,
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-output',
prop: 'onOutput',
value: null
},
...optBase
];
class Tags extends ModBaseListenCache {
options = {};
emptyEl;
content;
editEvent;
toggleSelected;
output;
maxIndex;
dataOrig;
dataObs;
data;
editEl;
last;
labelEl;
imgNone;
static hostType = 'node';
static optMaps = optTags;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
maps: Tags.optMaps,
host: elem,
component: true,
spread: ['edit', 'unique', 'empty']
});
this.emptyEl = createEl('span', { [ax.alias]: 'empty' }, this.options.empty.content);
this.content = '';
let _this = this;
this.editEvent = async (e) => {
let label = this.editEl.value.trim(), selectedItem = this.data.find((k) => k.selected);
if (label) {
this.editEl.style.width = label.length + 'em';
if (this.options.editor.addable && e.code === 'Enter') {
this.add(label, () => {
this.editEl.value = '';
this.editEl.focus();
});
}
selectedItem && (selectedItem.selected = false);
}
else {
this.editEl.style.cssText = this.editEl.style.cssText.replace('width:', '');
if (this.options.editor.deletable && e.code === 'Backspace' && this.data.length > 0) {
let endItem = this.data.slice(-1)[0];
if (endItem.selected) {
this.remove(endItem);
}
else {
endItem.selected = true;
}
}
else {
selectedItem && (selectedItem.selected = false);
}
}
};
this.toggleSelected = function (e) {
if (e.target.getAttribute(ax.alias) !== 'remove') {
let item = _this.data.find((k) => k.wrapEl === this);
item.selected = true;
_this.data.filter((k) => k !== item).forEach((k) => {
k.selected = false;
});
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.output = { value: '', raw: '', items: [] };
this.maxIndex = 0;
this.initContent();
this.setEmpty();
this.createEditor();
await getContent.call(this, {
content: this.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.targetEl,
...this.options.ajax
},
cb: async (data) => {
await this.renderContent(data);
}
});
this.setAttrs();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
initContent() {
if (this.options.content) {
this.content = this.options.content;
}
else {
this.content = this.rawHtml || this.targetEl.innerHTML;
}
}
setDataObs() {
this.dataOrig = [];
this.dataObs = new Observe(this.dataOrig, {
deep: true,
onSet: (obj) => {
if (obj.key === this.options.field || obj.key === 'label') {
obj.target.labelEl.innerHTML = obj.value;
}
else if (['selected', 'disabled'].includes(obj.key)) {
obj.target.wrapEl.toggleAttribute(obj.key, obj.value);
}
else if (obj.key === 'theme') {
obj.target.wrapEl.setAttribute(obj.key, obj.value);
}
else if (obj.key === 'icon' && obj.proxy.iconEl) {
classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
}
else if (obj.key === 'cube' && obj.proxy.cubeEl) {
obj.proxy.cubeEl.src = obj.value;
}
else if (obj.key === 'disk' && obj.proxy.diskEl) {
obj.proxy.diskEl.src = obj.value;
}
else if (obj.key === 'image' && obj.proxy.imageEl) {
obj.proxy.imageEl.src = obj.value;
}
else if (['href', 'target', 'rel', 'download'].includes(obj.key) && this.labelEl.nodeName === 'A') {
obj.target.labelEl[obj.key] = obj.value;
}
},
onCompleted: (data) => {
this.toggleEmpty();
if (this.options.storName) {
let tmp = {
content: !isEmpty(this.options.content) ? deepClone(this.dataOrig) : '',
};
super.updateCache(tmp);
}
}
});
this.data = this.dataObs.proxy;
}
setOutput() {
this.output.value = this.getStrVals();
this.output.items = [...this.data];
super.listen({ name: 'output', params: [this.output] });
}
async renderContent(data) {
try {
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, data, this.targetEl);
resp && (data = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('The content was blocked from being filled!');
return this;
}
this.setDataObs();
let tmp = this.getSource(data);
try {
let resp = await this.moreExceed({ data: tmp, source: this.data });
resp && (tmp = resp);
}
catch {
return;
}
this.render(tmp);
this.data.push(...tmp);
}
getStrVals() {
return this.data.map((k) => k[this.options.field]).join(this.options.separator);
}
getSource(obj) {
let result = [];
if (!isEmpty(obj)) {
if (Array.isArray(obj)) {
if (typeof obj[0] === 'string') {
result = obj.map(k => {
return { [this.options.field]: k, theme: '' };
});
}
else {
result = obj;
}
}
else if (typeof obj === 'object') {
result = [obj];
}
else if (typeof obj === 'string') {
let tmp = createEl('div', {}, obj), children = [...tmp.children];
if (children.length) {
if (children[0].nodeName === 'SELECT') {
result = select2Tree(children[0]);
}
else if (children[0].nodeName === 'INPUT') {
result = treeTools.fromInput(children[0], this.options.separator);
}
else {
for (let k of children) {
let obj = {};
k.hasAttribute('label') && (obj.label = k.getAttribute('label'));
k.hasAttribute('value') && (obj.value = k.getAttribute('value'));
k.hasAttribute('icon') && (obj.icon = k.getAttribute('icon'));
k.hasAttribute('disk') && (obj.disk = k.getAttribute('disk'));
k.hasAttribute('cube') && (obj.cube = k.getAttribute('cube'));
k.hasAttribute('image') && (obj.image = k.getAttribute('image'));
k.hasAttribute('disabled') && (obj.disabled = true);
k.hasAttribute('theme') && (obj.theme = k.getAttribute('theme'));
obj[this.options.field] = k.hasAttribute(this.options.field) ? k.getAttribute(this.options.field) : k.textContent;
if (k.nodeName === 'A') {
obj = {
...obj,
href: k.getAttribute('href'),
target: k.target,
rel: k.rel,
download: k.download,
};
}
result.push(obj);
}
}
}
else {
let arr = obj.trim().split(this.options.separator);
result = arr.map(k => {
return { [this.options.field]: k, theme: '' };
});
}
}
}
result = result.filter((k) => k && !this.data.includes(k));
result.forEach((k, i) => {
!k.hasOwnProperty('id') && (k.id = this.maxIndex + i);
});
this.maxIndex += result.length;
return result;
}
render(content) {
if (!isEmpty(content)) {
let fragment = document.createDocumentFragment();
for (let k of content) {
k.wrapEl = this.createTag(k);
fragment.appendChild(k.wrapEl);
}
this.targetEl.appendChild(fragment);
}
this.options.editor.enable && !this.options.editor.selector && this.targetEl.appendChild(this.editEl);
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}tags`);
classes(this.targetEl).add(this.options.classes);
this.options.theme ? this.targetEl.setAttribute('theme', this.options.theme) : this.targetEl.removeAttribute('theme');
this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
this.targetEl.toggleAttribute('compact', this.options.compact);
this.options.shape ? this.targetEl.setAttribute('shape', this.options.shape) : this.targetEl.removeAttribute('shape');
this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
}
setEmpty() {
this.targetEl.innerHTML = '';
}
useLegend(obj) {
if (obj.hasOwnProperty('icon')) {
obj.iconEl = createEl('i', { [ax.alias]: 'icon', class: `${obj.icon}` });
obj.labelEl.insertAdjacentElement('beforebegin', obj.iconEl);
}
if (obj.hasOwnProperty('disk')) {
obj.diskEl = createEl('img', { [ax.alias]: 'disk', src: `${obj.disk || ax.images.none}` });
obj.labelEl.insertAdjacentElement('beforebegin', obj.diskEl);
}
if (obj.hasOwnProperty('cube')) {
obj.cubeEl = createEl('img', { [ax.alias]: 'cube', src: `${obj.cube || ax.images.none}` });
obj.labelEl.insertAdjacentElement('beforebegin', obj.cubeEl);
}
if (obj.hasOwnProperty('image')) {
obj.imageEl = createEl('img', { [ax.alias]: 'image', src: `${obj.image || ax.images.none}` });
obj.labelEl.insertAdjacentElement('beforebegin', obj.imageEl);
}
}
createTag(obj) {
let labelObj = { [ax.alias]: 'label' }, text = this.data.find((k) => k !== obj && k[this.options.field] === obj[this.options.field]) ?
renderTpl(this.options.unique.template, { field: obj[this.options.field], value: obj[this.options.unique.refer], key: this.options.unique.refer }) :
obj[this.options.field];
obj.hasOwnProperty('href') && (labelObj.href = obj.href);
obj.hasOwnProperty('href') && obj.target && (labelObj.target = obj.target);
obj.hasOwnProperty('href') && obj.rel && (labelObj.rel = obj.rel);
obj.hasOwnProperty('href') && obj.download && (labelObj.download = obj.download);
obj.labelEl = createEl(labelObj.hasOwnProperty('href') ? 'a' : 'i', labelObj, text);
obj.wrapEl = createEl('span', { class: `${ax.prefix}tag` }, obj.labelEl);
obj.removeEl = createEl('i', { [ax.alias]: 'remove' });
this.options.removable && obj.wrapEl.appendChild(obj.removeEl);
this.useLegend(obj);
!this.options.theme && obj.theme && obj.wrapEl.setAttribute('theme', obj.theme);
obj.disabled && obj.wrapEl.setAttribute('disabled', '');
obj.selected && obj.wrapEl.setAttribute('selected', '');
return obj.wrapEl;
}
createEditor() {
if (!this.options.editor.enable || this.destroyed)
return;
let tmp = getEl(this.options.editor.selector);
if (!tmp) {
this.editEl = createEl('input', { type: 'text', placeholder: this.options.editor.placeholder });
}
else {
this.editEl = tmp;
!this.editEl.hasAttribute('placeholder') && this.editEl.setAttribute('placeholder', this.options.editor.placeholder);
}
this.editEl.removeEventListener('keyup', this.editEvent);
this.editEl.addEventListener('keyup', this.editEvent);
}
toggleEmpty() {
if (!this.options.empty.enable)
return;
if (!this.data.length) {
this.targetEl.insertAdjacentElement('afterbegin', this.emptyEl);
this.maxIndex = 0;
}
else {
this.emptyEl.remove();
}
}
renderFinish() {
this.toggleEmpty();
for (let k of this.data) {
k.wrapEl.addEventListener('click', this.toggleSelected, false);
k.removeEl.onclick = () => {
this.remove(k);
};
}
this.last = this.dataOrig[this.data.length - 1];
}
getVals(cb) {
if (this.destroyed)
return this;
let value = {
value: this.getStrVals(),
items: [...this.data],
};
super.listen({ name: 'got', cb, params: [value] });
return value;
}
async updateCont(content, cb) {
if (this.destroyed)
return this;
this.setEmpty();
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.targetEl,
...this.options.ajax
},
cb: async (data) => {
this.saveRaw();
await this.renderContent(data);
this.renderFinish();
super.updateCache({ content });
super.listen({ name: 'updatedCont', cb, params: [this.dataOrig] });
this.setOutput();
}
});
return this;
}
saveRaw() {
this.output.raw = this.getStrVals();
}
async add(data, cb) {
if (isEmpty(data) || this.destroyed)
return this;
let arr = this.getSource(data), dupTags = [], oldLen = 0, oldValues = this.data.map((k) => k[this.options.field]);
if (this.options.unique.enable) {
arr = unique(arr, this.options.field);
oldLen = arr.length;
arr = arr.map((k) => {
let output;
if (oldValues.includes(k[this.options.field])) {
dupTags.push(k);
}
else {
output = k;
}
return output;
}).filter(Boolean);
if (oldLen !== arr.length) {
new Message({
content: arr.length === 0 ? this.options.lang.includeFull : this.options.lang.includePart,
status: 'warn',
iconShow: true,
}).show();
super.listen({ name: 'duplicated', params: [dupTags] });
}
}
if (arr.length === 0)
return this;
try {
let resp = await super.moreExceed({ data: arr, source: this.data });
resp && (arr = resp);
}
catch {
return;
}
try {
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, arr);
resp && (arr = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Failed to add a new tags!');
return this;
}
if (!Array.isArray(arr) || !arr.length)
return this;
this.saveRaw();
this.render(arr);
this.data.push(...arr);
this.renderFinish();
this.setOutput();
super.listen({ name: 'added', cb, params: [arr] });
return this;
}
async remove(data, cb) {
if (isEmpty(data) || this.destroyed || !this.data.length)
return this;
let tags = findItems(data, this.data, '', { node: 'wrapEl', string: this.options.field, separator: this.options.separator });
try {
if (this.options.b4Remove) {
let resp = await this.options.b4Remove.call(this, tags);
resp && (tags = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Failed to delete the old tags!');
return this;
}
try {
let resp = await this.lessExceed({ data: tags, source: this.data });
resp && (tags = resp);
}
catch {
return;
}
if (!Array.isArray(tags) || !tags.length)
return this;
this.saveRaw();
for (let i = 0; i < this.data.length; i++) {
let tmp = this.data[i];
if (tags.includes(tmp)) {
this.data.splice(i--, 1);
tmp.wrapEl.remove();
}
}
this.setOutput();
super.listen({ name: 'removed', cb, params: [tags] });
return this;
}
async edit(item, data, cb) {
if (isEmpty(item) || this.destroyed || !this.data.length)
return this;
let tag = findItem(item, this.data, '', { node: 'wrapEl', string: this.options.field });
if (!tag) {
return this;
}
try {
if (this.options.b4Edit) {
let resp = await this.options.b4Edit.call(this, tag);
resp && (tag = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Failed to eidit the tag!');
return this;
}
if (!tag)
return this;
Object.assign(tag, data);
super.listen({ name: 'edited', cb, params: [tag] });
return this;
}
async clear(cb) {
if (this.destroyed || !this.data.length)
return this;
this.options.b4Clear && await this.options.b4Clear.call(this);
this.saveRaw();
this.data.splice(0);
this.maxIndex = 0;
this.targetEl.innerHTML = '';
this.options.editor.enable && this.targetEl.appendChild(this.editEl);
this.setOutput();
super.listen({ name: 'cleared', cb });
return this;
}
destroy(cb) {
this.data.forEach((k) => {
k.wrapEl.removeEventListener('click', this.toggleSelected);
k.removeEl.onclick = null;
});
this.options.editor.enable && this.editEl.removeEventListener('keyup', this.editEvent);
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class Tree extends ModBaseListenCacheNest {
options = {};
treeDataOrig;
searchs;
ignores;
editorEl;
lastExpanded;
dropTag;
pagination;
searchEl;
resultIns;
resultEl;
inputEl;
output;
value;
expandEvt;
selectEvt;
searchEvgt;
lineEvt;
bubbleIns;
receiver;
hoverIns;
contXhr;
floorMax;
chainChecking;
seqItems;
maxIndex;
excludeDrags;
rawData;
observeIns;
static hostType = 'node';
static optMaps = optTree;
static dependencies = [BadgeElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Tree.optMaps,
component: true,
spread: ['output', 'arrow', 'check', 'legend', 'select', 'shortcut', 'tools', 'drag', 'paginated', 'bubble']
});
let _this = this;
this.expandEvt = debounce(function () {
let attr = this.getAttribute(ax.alias) === 'arrow' ? 'arrowEl' : this.getAttribute(ax.alias) === 'legend' ? 'legendEl' : 'headEl', item = findItem(this, _this.flatData, attr);
_this.toggleExpanded(item);
}, this.options.delay);
this.selectEvt = debounce(function () {
let item = findItem(this, _this.flatData, 'labelEl');
_this.toggleSelected(item);
if (item && item.toolsEl && _this.options.tools.trigger === 'click') {
if (attrValBool(item.selected)) {
show({ el: item.toolsEl });
}
else {
hide({ el: item.toolsEl });
}
}
}, this.options.delay);
this.searchEvgt = debounce(function () {
_this.search(this.value);
}, this.options.search.delay);
this.lineEvt = debounce(function (e) {
if (!_this.options.shortcut.enable)
return;
let item = findItem(this, _this.flatData, 'headEl'), condition = false;
if (!item)
return;
if (_this.options.shortcut.span === 'blank' && (e.target === item.headEl || ['holder', 'group', 'gap'].includes(e.target.getAttribute(ax.alias)))) {
condition = true;
}
else if (!contains(e.target, [item.arrowEl, item.checkEl, item.toolsEl, ((_this.options.select.enable && !item.headEl.hasAttribute('unselectable')) || (item.labelEl.nodeName === 'A' && item.labelEl.hasAttribute('href'))) ? item.labelEl : null])) {
condition = true;
}
if (!condition)
return;
if (_this.options.shortcut.mean === 'selected') {
_this.toggleSelected(item);
}
else if (_this.options.shortcut.mean === 'checked') {
!item.checkEl.hasAttribute('disabled') && _this.toggleCheck(item);
}
else if (_this.options.shortcut.mean === 'expanded') {
_this.toggleExpanded(item);
}
else if (_this.options.shortcut.mean === 'auto') {
if (item.children) {
_this.toggleExpanded(item);
}
else {
_this.options.check.enable && !item.checkEl.hasAttribute('disabled') ? _this.toggleCheck(item) : _this.toggleSelected(item);
}
}
}, this.options.delay);
this.editorEl = createEl('input', { type: 'text' });
this.lastExpanded = -1;
this.dropTag = this.options.drop.attr || 'dropnode';
this.treeDataOrig = [];
this.pagination = { label: this.options.lang.paginated.main, id: this.options.rootStart, children: [], wrapEl: this.targetEl };
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.output = { value: '', raw: '', items: [] };
this.correctOpts();
super.useTpl();
this.searchs = [];
this.floorMax = 0;
this.chainChecking = false;
this.seqItems = [];
this.setFeature();
this.maxIndex = this.options.idStart;
if (this.options.bubble.enable) {
let host = this.targetEl;
this.receiver = getEl(this.options.output.target) || this.targetEl;
(this.receiver.nodeName.includes('INPUT') || this.receiver.nodeName.includes('TEXTAREA')) && this.receiver.toggleAttribute('readonly', true);
this.targetEl = createEl('div');
let footParam = this.options.output.enable && !this.options.output.instant ? {
enable: true,
children: [
'close',
{
name: 'clear',
action: (resp) => {
resp.el.onclick = () => {
this.clearVals();
};
},
},
{
name: 'confirm',
action: (resp) => {
resp.el.onclick = () => {
this.setVals();
this.bubbleIns.hide();
};
}
}
]
} : false;
this.bubbleIns = new Function('host', 'module', 'options', `"use strict";return new module(host,options)`)(host, ax[capStart(this.options.bubble.type.trim())], Object.assign({
trigger: 'click',
content: this.targetEl,
contType: 'node',
placement: this.options.bubble.type === 'popup' ? 'bottom-start' : '',
footer: footParam,
}, this.options.bubble));
}
else {
this.receiver = getEl(this.options.output.target);
}
await this.getDataToRender();
this.excludeDrags = !isEmpty(this.options.drag.exclude) ? findItems(this.options.drag.exclude, this.flatData) : [];
this.setAttrs();
this.setResult();
this.renderFinish();
super.initCheckeds();
this.initExpandeds();
this.initSelecteds();
super.initDisableds();
super.initReadonlys();
this.updateResult(this.getVals().value);
this.setSearch();
super.listen({ name: 'initiated', cb });
return this;
}
correctOpts() {
if (!isEmpty(this.options.value)) {
if (this.options.output.from === 'checked') {
this.options.check.value = this.options.value;
}
else {
this.options.select.value = this.options.value;
}
}
}
setFeature() {
if (!this.options.feature.type)
return;
extend({
target: this.options,
source: {
shortcut: {
enable: true,
mean: 'checked',
span: 'whole'
},
expand: { ...this.options.feature.expand },
check: {
enable: true,
...this.options.feature.check
},
select: {
enable: false,
},
arrow: {
enable: !this.options.feature.expand.all || this.options.feature.expand.only ? true : false
},
output: {
from: 'checked'
},
layout: this.options.feature.layout[this.options.feature.type]
}
});
}
async sqlToAdd(item) {
if (!this.options.content)
return;
let promise = treeTools.allToTree({
content: this.options.content,
contType: this.options.contType,
contData: { pId: item.id, pLabel: item.label, pValue: item.value, ...this.options.sqlData },
ajax: { spinSel: item.arrowEl, xhrName: 'contXhr' },
ins: this,
fill: false,
});
await promise.then(async (resp) => {
let data = resp.hasOwnProperty('data') && Array.isArray(resp.data) ? resp.data : resp;
await this.add({
data,
target: item,
isFront: false,
autoFill: !this.options.paginated.enable,
});
this.options.paginated.enable && this.turnFirstPage(item);
});
}
async getDataToRender() {
let base = {
rootStart: this.options.rootStart,
idStart: this.options.idStart,
floorStart: this.options.floorStart,
}, promise;
if (this.options.content) {
promise = treeTools.allToTree({
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
ins: this,
...base
});
}
else {
promise = treeTools.allToTree({
content: this.targetEl.innerHTML,
...base
});
}
await promise.then((res) => {
this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
this.rawData = res;
});
this.targetEl.innerHTML = '';
await this.renderData(this.treeDataOrig);
this.getTreeFlat();
super.listen({ name: 'rendered', params: [this.treeData, this.flatData] });
return this;
}
getTreeFlat() {
this.treeData = this.getObserver(this.treeDataOrig).proxy;
this.pagination.children = this.treeData;
this.flatData = treeTools.toFlat(this.treeData);
}
getObserver(data) {
this.observeIns = new Observe(data, {
deep: {
enable: true,
exclude: ['tools'],
},
onSet: (obj) => {
if (obj.key === 'icon' && obj.proxy.iconEl) {
classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
}
else if (obj.key === 'cube' && obj.proxy.cubeEl) {
obj.proxy.cubeEl.src = obj.value;
}
else if (obj.key === 'disk' && obj.proxy.diskEl) {
obj.proxy.diskEl.src = obj.value;
}
else if (obj.key === 'image' && obj.proxy.imageEl) {
obj.proxy.imageEl.src = obj.value;
}
else if (obj.key === 'label') {
obj.proxy.labelEl.innerHTML = obj.value;
}
else if (obj.key === 'tips' && obj.proxy.tipsEl) {
obj.proxy.tipsEl.innerHTML = obj.value;
}
else if (obj.key === 'brief' && obj.proxy.briefEl) {
super.updateElCont(obj.proxy, obj.value);
}
else if (obj.key === 'custom' && obj.proxy.customEl) {
super.updateElCont(obj.proxy, obj.value, 'custom');
}
else if (obj.key === 'badge' && obj.proxy.badgeEl) {
obj.proxy.badgeEl.setAttribute('label', obj.value);
}
else if (obj.key === 'href' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.href = obj.value;
}
else if (obj.key === 'rel' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.rel = obj.value;
}
else if (obj.key === 'target' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.target = obj.value;
}
else if (obj.key === 'onclilck') {
obj.proxy.labelEl.setAttribute(obj.key, obj.value);
}
else if (obj.key === 'floor') {
obj.proxy.indentHeadEl.innerHTML = obj.proxy.indentBodyEl.innerHTML = obj.proxy.indentFootEl.innerHTML = this.getIndentHtml(obj.value);
this.updateChildrenFloor(obj.proxy);
}
else if (obj.key === 'atEnd') ;
else if (obj.key === 'expanded' && obj.proxy.children) {
obj.proxy.arrowEl && super.toggleArrow(attrValBool(obj.value), obj.proxy);
this.toggleParentLegend(obj.proxy);
}
else if (obj.key === 'selected') {
obj.proxy.headEl.toggleAttribute('selected', attrValBool(obj.value));
this.updateSeqItems(obj, 'selected');
}
else if (obj.key === 'disabled') {
obj.proxy.headEl.toggleAttribute('disabled', attrValBool(obj.value));
}
else if (obj.key === 'readonly') {
obj.proxy.headEl.toggleAttribute('readonly', attrValBool(obj.value));
}
else if (obj.key === 'checked') {
let tmp = attrValBool(obj.value);
obj.proxy.headEl.toggleAttribute('checked', tmp);
obj.proxy.checkEl && obj.proxy.checkEl.setAttribute('check', tmp ? 'ed' : '');
this.updateSeqItems(obj, 'checked');
}
else if (obj.key === 'children') {
if (!obj.raw && obj.value) {
this.child2Parent(obj.proxy);
}
else if (obj.raw && !obj.value) {
this.parent2Child(obj.proxy);
}
}
},
onDeleted: (obj) => {
if (obj.key === 'children') {
treeTools.parentToChild(obj.proxy);
}
},
onCompleted: (data) => {
((data.keys.set.includes('selected') && this.options.output.from === 'selected')
||
(data.keys.set.includes('checked') && this.options.output.from === 'checked'))
&& this.updateVals();
if (this.options.check.enable && this.options.check.max) {
let checkeds = super.getCheckeds(), uncheckeds = super.getUncheckeds(), setDisabled = (data) => {
for (let k of data) {
!attrValBool(k.disabled) && k.checkEl.toggleAttribute('disabled', true);
k.headEl.toggleAttribute('exceeded', true);
}
};
if (checkeds.length >= this.options.check.max) {
setDisabled(uncheckeds);
super.listen({ name: 'stopChecked', params: [uncheckeds] });
}
else if (checkeds.length <= this.options.check.min) {
setDisabled(checkeds);
super.listen({ name: 'stopUnchecked', params: [checkeds] });
}
else {
for (let k of this.flatData) {
k.checkEl.removeAttribute('disabled');
k.headEl.toggleAttribute('exceeded', false);
}
super.listen({ name: 'rechecked' });
}
}
if (this.options.storName) {
let tmp = {
select: { value: treeTools.getBoolItems(this.flatData, 'selected').map((k) => k.id) },
check: { value: treeTools.getBoolItems(this.flatData, 'checked').map((k) => k.id) },
expand: treeTools.getBoolItems(this.flatData, 'expanded').map((k) => k.id),
disable: treeTools.getBoolItems(this.flatData, 'disabled').map((k) => k.id),
readonly: treeTools.getBoolItems(this.flatData, 'readonly').map((k) => k.id),
content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : '',
};
super.updateCache(tmp);
}
}
});
return this.observeIns;
}
updateSeqItems(data, type = 'selected') {
this.options.output.from === type && splice({ host: this.seqItems, source: data.proxy, intent: data.value ? 'end+' : 'remove' });
if (this.seqItems.length) {
if ((type === 'checked' && this.options.check.type === 'radio') || (type === 'selected' && this.options.select.only)) {
this.seqItems = this.seqItems.slice(-1);
}
}
}
initExpandeds() {
let vals = valToArr(this.options.expand.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => attrValBool(k.expanded) && k.children), tmp = [...items, ...vals];
for (let k of items)
k.expanded = false;
if (this.options.expand.all) {
if (this.options.expand.only) {
let firsts = this.getParentsGroupBy(this.flatData);
for (let k in firsts) {
firsts[k][0] && super.expand(firsts[k][0]);
}
}
else {
super.expandAll();
}
}
else {
if (this.options.expand.only) {
let firsts = this.getParentsGroupBy(tmp);
for (let k in firsts) {
firsts[k][0] && super.expand(firsts[k][0]);
}
}
else {
super.expand(tmp);
}
}
}
initSelecteds() {
if (!this.options.select.enable)
return;
let vals = valToArr(this.options.select.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => attrValBool(k.selected)), tmp = [...items, ...vals];
for (let k of items)
k.selected = false;
this.select(this.options.select.only ? tmp[0] : tmp);
}
getSelecteds() {
return this.flatData.filter((k) => attrValBool(k.selected));
}
getParentsGroupBy(items, key = 'pId') {
if (isEmpty(items))
return [];
return items.reduce((result, item) => {
let groupKey = item[key];
if (!result[groupKey]) {
result[groupKey] = [];
}
item.children && result[groupKey].push(item);
return result;
}, {});
}
getIndentHtml(floor) {
return '<i></i>'.repeat(floor);
}
updateChildrenFloor(item) {
if (item.children) {
for (let k of item.children) {
k.floor = item.floor + 1;
this.updateChildrenFloor(k);
}
}
}
async renderData(data) {
if (!data.length) {
this.targetEl.innerHTML = `<div class="${ax.prefix}tree-empty">${this.options.lang.empty}</div>`;
return;
}
let outer = createEl('ul');
let plantTree = async (parent, data) => {
let ul = createEl('ul', { class: `${ax.prefix}reset ${ax.prefix}tree-children` });
for (let k of data) {
this.createHeadEl(k, parent);
await this.createBodyEl(k);
if (k.hasOwnProperty('children')) {
k.childrenEl = await plantTree(k, k.children);
}
((!this.options.deferred && !this.options.paginated.enable)
||
(this.options.deferred && !this.options.paginated.enable && k.floor === this.options.floorStart)
||
(this.options.paginated.enable && k.floor === this.options.floorStart && this.options.paginated.exception))
&& ul.appendChild(k.wrapEl);
}
(parent.wrapEl || parent).appendChild(ul);
parent.wrapEl && this.createFootEl(parent);
return ul;
};
await plantTree(outer, data);
this.resultEl = createEl('div', { class: `${ax.prefix}tree-result` });
this.options.output.enable && !this.options.output.instant && this.targetEl.appendChild(this.resultEl);
if (this.options.name) {
this.inputEl = createEl('input', { type: 'hidden', name: this.options.name });
this.targetEl.appendChild(this.inputEl);
}
this.pagination.childrenEl = outer.childNodes[0];
super.listen({ name: 'insertItems', params: [data] });
this.targetEl.appendChild(this.pagination.childrenEl);
if (this.options.paginated.enable && !this.options.paginated.exception) {
this.createFootEl(this.pagination);
}
}
updateArrowEl(item) {
if (!this.options.arrow.enable)
return;
if (item.hasOwnProperty('children')) {
item.arrowEl.setAttribute('type', this.options.arrow.type);
this.options.lang.title.arrow && item.arrowEl.setAttribute('title', this.options.lang.title.arrow);
if (this.options.arrow.type === 'image') {
this.options.arrow.hide && (item.arrowEl.style.backgroundImage = `url("${this.options.arrow.hide}")`);
}
else {
item.arrowEl.classList.remove(`${ax.prefix}none`);
this.options.arrow.hide && item.arrowEl.classList.add(this.options.arrow.hide);
}
}
else {
item.arrowEl.removeAttribute('type');
item.arrowEl.removeAttribute('title');
if (this.options.arrow.type === 'image') {
item.arrowEl.removeAttribute('style');
}
else {
classes(item.arrowEl).remove([this.options.arrow.show, this.options.arrow.hide]).add(`${ax.prefix}none`);
}
}
}
async setBrief(target, data = {}, cb) {
if (this.destroyed)
return;
let item = findItem(target, this.flatData);
await this.createBodyEl(item, false);
await super.setElCont({
item,
data,
cb: (cont, target) => {
super.listen({ name: 'filled', cb, params: [cont, target] });
}
});
return this;
}
setLegendVal(el, val, type = 'icon') {
if (type === 'image') {
el.removeAttribute('class');
el.style.backgroundImage = `url("${val}")`;
}
else {
el.removeAttribute('style');
el.setAttribute('class', val);
}
}
toggleParentLegend(item) {
if (!this.options.legend.enable || item.legend || !Array.isArray(this.options.legend.parent) || !this.options.legend.parent[1])
return;
this.setLegendVal(item.legendEl, this.options.legend.parent[attrValBool(item.expanded) ? 1 : 0], this.options.legend.type);
}
updateLegendEl(item) {
if (!this.options.legend.enable)
return;
if (item.legend) {
this.setLegendVal(item.legendEl, item.legend, this.options.legend.type);
}
else {
if (item.hasOwnProperty('children')) {
this.setLegendVal(item.legendEl, this.options.legend.parent[attrValBool(item.expanded) ? 1 : 0], this.options.legend.type);
}
else {
this.setLegendVal(item.legendEl, this.options.legend.child, this.options.legend.type);
}
}
}
getLegendEl(item) {
item.legendEl = createEl('i', { [ax.alias]: 'legend' });
this.updateLegendEl(item);
}
createHeadEl(item, parent) {
if (item.wrapEl)
return;
item.wrapEl = createEl('li', { class: `${ax.prefix}tree-wrap` });
item.groupEl = createEl('div', { [ax.alias]: 'group' });
if (item.headEl) {
if (!item.labelEl) {
item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [ax.alias]: 'label' }, item.label);
item.headEl.appendChild(item.labelEl);
}
}
else {
item.headEl = createEl('div', { class: `${ax.prefix}tree-head` });
!item.labelEl && (item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [ax.alias]: 'label' }, item.label));
item.headEl.appendChild(item.labelEl);
}
item.wrapEl.appendChild(item.headEl);
item.href && (item.labelEl.href = item.href);
item.target && (item.labelEl.target = item.target);
item.indentHeadEl = createEl('span', { [ax.alias]: 'indent' });
item.indentBodyEl = createEl('span', { [ax.alias]: 'indent' });
item.indentFootEl = createEl('span', { [ax.alias]: 'indent' });
item.indentHeadEl.innerHTML = item.indentBodyEl.innerHTML = item.indentFootEl.innerHTML = this.getIndentHtml(item.floor);
item.onclick && item.labelEl.setAttribute('onclick', item.onclick);
this.options.arrow.enable && super.getArrowEl(item);
if (!item.iconEl) {
item.iconEl = item.hasOwnProperty('icon') ? createEl('i', { [ax.alias]: 'icon', class: item.icon }) : null;
}
if (!item.diskEl) {
item.diskEl = item.hasOwnProperty('disk') ? createEl('img', { [ax.alias]: 'disk', src: item.disk || ax.images.none }) : null;
}
if (!item.cubeEl) {
item.cubeEl = item.hasOwnProperty('cube') ? createEl('img', { [ax.alias]: 'cube', src: item.cube || ax.images.none }) : null;
}
if (!item.imageEl) {
item.imageEl = item.hasOwnProperty('image') ? createEl('img', { [ax.alias]: 'image', src: item.image || ax.images.none }) : null;
}
if (!item.badgeEl) {
item.badgeEl = item.badge ? createEl('ax-badge', { [ax.alias]: 'badge', label: item.badge.toString().trim() }) : null;
}
if (!item.tipsEl) {
item.tipsEl = item.tips ? createEl('i', { [ax.alias]: 'tips' }, item.tips) : null;
}
if (!item.customEl) {
item.customEl = item.custom ? createEl('div', { [ax.alias]: 'custom' }, item.custom) : null;
}
attrValBool(item.expanded) && item.headEl.toggleAttribute('expanded', true);
attrValBool(item.selected) && item.headEl.toggleAttribute('selected', true);
attrValBool(item.disabled) && item.headEl.toggleAttribute('disabled', true);
attrValBool(item.readonly) && item.headEl.toggleAttribute('readonly', true);
attrValBool(item.checked) && item.headEl.toggleAttribute('checked', true);
this.options.drag.enable && item.headEl.toggleAttribute([this.dropTag], true);
if (this.options.check.enable) {
item.checkType = this.getCheckType(parent);
item.checkEl = createEl(`ax-${item.checkType}`, { [ax.alias]: 'check' });
}
if (this.options.legend.enable) {
this.getLegendEl(item);
}
if (this.options.tools.enable) {
item.toolsEl = createTools(this.options.tools.children, item.headEl);
item.toolsEl.setAttribute(ax.alias, 'tools');
item.tools = deepClone(this.options.tools.children);
for (let k of item.tools) {
this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
if (k.name === 'file') {
item.addfileEl = k.wrapEl;
}
else if (k.name === 'folder') {
item.addfolderEl = k.wrapEl;
}
else if (k.name === 'remove') {
item.removeEl = k.wrapEl;
}
else if (k.name === 'edit') {
item.editEl = k.wrapEl;
}
}
}
super.parseLayout(item.headEl, this.options.layout, {
indent: item.indentHeadEl,
arrow: item.arrowEl,
label: item.labelEl,
check: item.checkEl,
legend: item.legendEl,
icon: item.iconEl,
disk: item.diskEl,
cube: item.cubeEl,
image: item.imageEl,
badge: item.badgeEl,
tips: item.tipsEl,
custom: item.customEl,
tools: item.toolsEl,
group: item.groupEl,
});
}
async createBodyEl(item, autoFill = this.options.autoFill) {
if (item.bodyEl)
return;
item.bodyEl = createEl('div', { class: `${ax.prefix}tree-body` });
item.bodyEl.appendChild(item.indentBodyEl);
item.indentBodyEl.insertAdjacentHTML('afterend', `<i class="${ax.prefix}none"></i>`);
if (!item.briefEl) {
item.briefEl = createEl('div', { class: `${ax.prefix}tree-brief` });
if (autoFill) {
await super.getElCont({
target: item,
data: item.brief,
cb: (cont) => {
item.brief = cont;
super.updateElCont(item);
}
});
}
}
item.bodyEl.appendChild(item.briefEl);
item.headEl.insertAdjacentElement('afterend', item.bodyEl);
}
createFootEl(item) {
if (!this.options.paginated.enable || item.pageEl)
return;
item.moreEl = createEl('i', { [ax.alias]: 'more' }, this.options.lang.paginated.more);
item.nextEl = createEl('i', { [ax.alias]: 'next' }, this.options.lang.paginated.next);
item.firstEl = createEl('i', { [ax.alias]: 'first' }, this.options.lang.paginated.first);
item.infoEl = createEl('i', { [ax.alias]: 'info' });
item.pageEl = createEl('div', { class: `${ax.prefix}tree-page` }, item.infoEl);
this.options.paginated.override ? item.pageEl.append(item.nextEl, item.firstEl) : item.pageEl.appendChild(item.moreEl);
item.footEl = createEl('div', { class: `${ax.prefix}tree-foot` });
if (item !== this.pagination) {
item.footEl.appendChild(item.indentFootEl);
item.indentFootEl.insertAdjacentHTML('afterend', `<i class="${ax.prefix}none"></i>`);
}
item.footEl.appendChild(item.pageEl);
item.children && item.wrapEl.appendChild(item.footEl);
}
togglePgnDisabled(item) {
if (this.options.paginated.enable) {
item.moreEl.toggleAttribute('disabled', item.atEnd);
item.nextEl.toggleAttribute('disabled', item.atEnd);
item.firstEl.toggleAttribute('disabled', item.current == 1 ? true : false);
}
}
turnNextPage(item, cb) {
if (this.destroyed)
return;
let target = item === this.pagination ? this.pagination : findItem(item, this.flatData);
if (!target)
return;
if (!this.options.paginated.enable || !target.children)
return;
let pages = Math.ceil(target.children.length / this.options.paginated.count);
if (this.options.paginated.override) {
if (target.current >= pages)
return;
target.current = target.current || 1;
let nextData = target.children.slice(target.current * this.options.paginated.count, (target.current + 1) * this.options.paginated.count);
target.childrenEl.innerHTML = '';
target.childrenEl.append(...nextData.map((k) => k.wrapEl));
target.current++;
}
else {
if (target.childrenEl.children.length >= target.children.length)
return;
let curCount = target.childrenEl.children.length, nextData = target.children.slice(curCount, curCount + this.options.paginated.count);
target.childrenEl.append(...nextData.map((k) => k.wrapEl));
target.current = Math.ceil(target.childrenEl.children.length / this.options.paginated.count);
}
target.atEnd = (pages === target.current) ? true : false;
this.togglePgnDisabled(target);
this.updateInfoEl(target);
super.listen({ name: 'turned', cb, params: [target] });
return this;
}
turnFirstPage(item, cb) {
if (this.destroyed)
return;
let target = item === this.pagination ? this.pagination : findItem(item, this.flatData);
if (!target)
return;
if (!this.options.paginated.enable || !target.children)
return;
let firstData = target.children.slice(0, this.options.paginated.count);
this.options.paginated.override && (target.childrenEl.innerHTML = '');
target.childrenEl.append(...firstData.map((k) => k.wrapEl));
target.current = 1;
target.atEnd = (target.childrenEl.children.length === target.children.length) ? true : false;
this.togglePgnDisabled(target);
this.updateInfoEl(target);
super.listen({ name: 'turned', cb, params: [target] });
return this;
}
updateInfoEl(item) {
if (!this.options.paginated.enable)
return;
let total = item.children.length, pages = Math.ceil(total / this.options.paginated.count), current = item.current, rest = Math.max(total - current * this.options.paginated.count, 0), obj = { total, current, pages, rest, count: this.options.paginated.count, label: item.label, id: item.id };
item.infoEl.innerHTML = renderTpl(this.options.lang.paginated.info, obj);
}
createChildrenEl(item) {
if (item.childrenEl)
return;
item.childrenEl = createEl('ul', { class: `${ax.prefix}reset ${ax.prefix}tree-children` });
let target = item.hasOwnProperty('brief') ? item.bodyEl : item.headEl;
target.insertAdjacentElement('afterEnd', item.childrenEl);
}
child2Parent(item) {
this.createChildrenEl(item);
this.updateArrowEl(item);
this.updateLegendEl(item);
this.updateEvt(item);
}
parent2Child(item) {
item.childrenEl.remove();
this.updateArrowEl(item);
this.updateLegendEl(item);
this.updateEvt(item);
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}tree`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.toggleAttribute('inert', this.options.passive);
this.targetEl.setAttribute('tools-trigger', this.options.tools.trigger);
this.targetEl.toggleAttribute('chain', this.options.chain);
this.options.feature.type && this.targetEl.setAttribute('feature', this.options.feature.type);
this.options.check.enable ? this.targetEl.setAttribute('check', this.options.check.span) : this.targetEl.removeAttribute('check');
this.options.select.enable ? this.targetEl.setAttribute('select', this.options.select.span) : this.targetEl.removeAttribute('select');
}
setDragDrop(item) {
if (!this.options.drag.enable || attrValBool(item.disabled) || this.excludeDrags.includes(item))
return;
item.dragIns = new Drag(item.wrapEl, extend({
target: {
drops: `[${this.dropTag}]`,
handle: item.headEl,
purpose: 'auto',
parent: !this.options.drop.global ? this.targetEl : null,
gesture: {
unbound: [item.toolsEl]
},
onDropped: (data) => {
if (data.point === 'before') {
this.graft({ source: data.from, target: data.to, isFront: true, isChild: false });
}
else if (data.point === 'after') {
this.graft({ source: data.from, target: data.to, isFront: false, isChild: false });
}
else if (data.point === 'inside') {
this.graft({ source: data.from, target: data.to, isFront: true, isChild: true });
}
}
},
source: this.options.drag,
}));
}
updateExpandEvt(k) {
if (k.children) {
if (k.arrowEl) {
if (this.options.arrow.trigger === 'click') {
k.arrowEl.removeEventListener('click', this.expandEvt);
k.arrowEl.addEventListener('click', this.expandEvt, false);
}
else if (this.options.arrow.trigger === 'hover') {
k.hoverIns && k.hoverIns.destroy();
k.hoverIns = new Hover(k.arrowEl, {
onMove: (isIn) => {
!isIn && this.options.expand.only ? super.collapse(k) : null;
},
onEnter: () => {
super.expand(k);
},
onLeave: () => {
super.collapse(k);
}
});
}
}
if (k.legendEl) {
k.legendEl.removeEventListener('click', this.expandEvt);
k.legendEl.addEventListener('click', this.expandEvt, false);
}
}
else {
if (this.options.arrow.trigger === 'click') {
k.arrowEl && k.arrowEl.removeEventListener('click', this.expandEvt);
}
else if (this.options.arrow.trigger === 'hover') {
k.hoverIns && k.hoverIns.destroy();
}
k.legendEl && k.legendEl.removeEventListener('click', this.expandEvt);
}
}
updateEvt(k) {
if (this.options.paginated.enable && k.children) {
this.turnFirstPage(k);
k.moreEl.onclick = () => this.turnNextPage(k);
k.nextEl.onclick = k.moreEl.onclick;
k.firstEl.onclick = () => this.turnFirstPage(k);
}
this.updateExpandEvt(k);
k.labelEl.removeEventListener('click', this.selectEvt);
k.labelEl.addEventListener('click', this.selectEvt, false);
if (k.toolsEl) {
let tmp = attrValBool(k.readonly);
if (k.removeEl) {
k.removeEl.onclick = () => {
if (tmp)
return;
this.remove(k);
};
}
if (k.editEl) {
k.editEl.onclick = () => {
if (tmp)
return;
this.inputLabel(k);
};
}
if (k.addfileEl) {
k.addfileEl.onclick = () => {
if (tmp)
return;
this.add({ target: k, isChild: true, expand: true });
};
}
if (k.addfolderEl) {
k.addfolderEl.onclick = () => {
if (tmp)
return;
this.add({ target: k, isChild: true, isLeaf: false, expand: true });
};
}
for (let [i, o] of this.options.tools.children.entries()) {
let tool = k.tools[i], refer = { ins: this, item: k };
o.action && o.action.call(refer, tool);
tool.action && tool.action.call(refer, tool);
}
}
if (this.options.shortcut.enable) {
k.headEl.removeEventListener('click', this.lineEvt);
k.headEl.addEventListener('click', this.lineEvt, false);
}
attrValBool(k.disabled) && k.headEl.toggleAttribute('disabled', true);
attrValBool(k.readonly) && k.headEl.toggleAttribute('readonly', true);
if (this.options.check.enable) {
k.checkEl.on('check', async (val) => {
let tmp = attrValBool(val.checked);
!this.chainChecking && tmp !== attrValBool(k.checked) && await this.check(k, tmp);
});
}
if (this.options.drag.enable) {
!k.dragIns && this.setDragDrop(k);
}
if (this.options.check.enable) {
if (this.options.check.span === 'leaf') {
k.children && (k.checkEl.toggleAttribute('disabled', true), k.headEl.toggleAttribute('uncheckable', true));
}
else if (this.options.check.span === 'branch') {
!k.children && (k.checkEl.toggleAttribute('disabled', true), k.headEl.toggleAttribute('uncheckable', true));
}
}
if (this.options.select.enable) {
if (this.options.select.span === 'leaf') {
k.children && k.headEl.toggleAttribute('unselectable', true);
}
else if (this.options.select.span === 'branch') {
!k.children && k.headEl.toggleAttribute('unselectable', true);
}
}
k.action && k.action.call(this, k);
}
renderFinish() {
for (let k of this.flatData) {
this.updateEvt(k);
}
if (this.options.paginated.enable && !this.options.paginated.exception) {
this.turnFirstPage(this.pagination);
this.pagination.moreEl.onclick = () => this.turnNextPage(this.pagination);
this.pagination.nextEl.onclick = this.pagination.moreEl.onclick;
this.pagination.firstEl.onclick = () => this.turnFirstPage(this.pagination);
}
}
getDrops() {
return isEmpty(this.options.drag.drops) ? this.flatData.map((k) => !attrValBool(k.disabled) ? k.headEl : null).filter(Boolean) :
this.options.drag.value.map((k) => findItem(k, this.flatData)).filter((k) => k && !attrValBool(k.disabled)).map((k) => k.headEl);
}
getReadonly() {
return this.flatData.find((k) => attrValBool(k.readonly));
}
getTriggerEl(item) {
return (item.href && item.arrowEl ? item.arrowEl : item.headEl);
}
addTrigger(item, target) {
if (item.children) {
if (!attrValBool(item.disabled)) {
let triggerEl = target || this.getTriggerEl(item);
if (this.options.arrow.trigger === 'click') {
triggerEl.removeEventListener('click', this.expandEvt);
triggerEl.addEventListener('click', this.expandEvt, false);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns ? this.hoverIns.destroy() : null;
this.hoverIns = new Hover(item.wrapEl, {
onEnter: () => {
super.expand(item);
super.listen({ name: 'trigger', params: [item] });
},
onLeave: () => {
super.collapse(item);
}
});
}
}
}
else {
if (!attrValBool(item.disabled)) {
item.headEl.removeEventListener('click', this.selectEvt);
item.headEl.addEventListener('click', this.selectEvt, false);
}
}
}
removeTrigger(item, target) {
if (item.children) {
if (!attrValBool(item.disabled)) {
let triggerEl = target || this.getTriggerEl(item);
if (this.options.arrow.trigger === 'click') {
triggerEl.removeEventListener('click', this.expandEvt);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns ? this.hoverIns.destroy() : null;
}
}
}
else {
if (!attrValBool(item.disabled)) {
item.headEl.removeEventListener('click', this.selectEvt);
}
}
}
toggleExpanded(data) {
if (this.destroyed)
return;
let item = findItem(data, this.flatData);
if (!item || !item.children)
return;
attrValBool(item.expanded) ? super.collapse(item) : super.expand(item);
super.listen({ name: 'trigger', params: [item] });
}
toggleSelected(data) {
let item = findItem(data, this.flatData);
if (!item || item.headEl.hasAttribute('editing') || !this.options.select.enable)
return;
let tmp = attrValBool(item.selected);
if (tmp) {
this.deselect(item);
}
else {
this.select(item);
this.options.select.only && this.deselect(this.flatData.filter((k) => k !== item && tmp));
}
}
async eachCollapse(data, cb) {
if (isNull(data))
return;
try {
if (this.options.b4Collapse) {
let resp = await this.options.b4Collapse.call(this, data);
resp && (data = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Branch collapsing has been prevented!');
return;
}
let item = findItem(data, this.flatData);
if (!item || !item.children || !elState(item.childrenEl).isVisible || item.childrenEl.style.height)
return;
super.listen({ name: 'collapse', cb, params: [item] });
item.expanded = false;
slideUp({
el: item.childrenEl,
duration: this.options.duration,
done: () => {
super.listen({ name: 'collapsed', cb, params: [item] });
}
});
}
async eachExpand(data, cb) {
if (isNull(data))
return;
let item = findItem(data, this.flatData);
if (!item || !item.children || elState(item.childrenEl).isVisible)
return;
try {
if (this.options.b4Expand) {
let resp = await this.options.b4Expand.call(this, data);
resp && (data = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Branch expansion has been prevented!');
return;
}
super.listen({ name: 'expand', cb, params: [item] });
if (!item.children.length && !isEmpty(this.options.contData) && this.options.contType === 'async') {
await this.sqlToAdd(item);
}
else {
if (this.options.deferred && !item.childrenEl.firstElementChild) {
item.arrowEl && item.arrowEl.toggleAttribute('spinning', true);
this.options.paginated.enable ? this.turnFirstPage(item) : item.childrenEl.append(...item.children.map((k) => k.wrapEl));
item.arrowEl && item.arrowEl.removeAttribute('spinning');
}
}
item.expanded = true;
this.options.expand.linkage && this.expandParents(item);
this.lastExpanded = item.id;
slideDown({
el: item.childrenEl,
duration: this.options.duration,
done: () => {
super.listen({ name: 'expanded', cb, params: [item] });
}
});
if (this.options.expand.only) {
let others = this.flatData.filter((k) => (k !== item && attrValBool(k.expanded) && k.floor === item.floor && k.children));
for (let k of others)
super.collapse(k);
}
}
floatDown(obj) {
if (!obj.hasOwnProperty('children') || !Array.isArray(obj.children))
return;
let enables = obj.children.filter((k) => !attrValBool(k.disabled)), type = this.getCheckType(obj);
for (let k of enables) {
if (attrValBool(obj.checked)) {
type === 'checkbox' && (k.checked = true);
}
else {
k.checked = false;
}
k.hasOwnProperty('children') && this.floatDown(k);
}
}
floatUp(obj) {
if (obj.floor === this.options.floorStart)
return;
let parents = treeTools.getParentsFromPath({ path: obj.path, flatData: this.flatData, pathHyphen: this.options.pathHyphen, pop: true }).parents.reverse(), setCheck = (item, enables, type) => {
if (type === 'checkbox') {
if (enables.every((k) => !attrValBool(k.checked))) {
item.checked = false;
item.checkEl.setAttribute('check', '');
}
else if (enables.every((k) => attrValBool(k.checked))) {
item.checked = true;
item.checkType === 'radio' && this.uncheckSibings(item);
}
else {
item.checked = false;
item.checkEl.setAttribute('check', 'ing');
}
}
else if (type === 'radio') {
if (enables.some((k) => attrValBool(k.checked))) {
item.checked = true;
item.checkType === 'radio' && this.uncheckSibings(item);
}
else {
item.checked = false;
item.checkEl.setAttribute('check', item.children.some((k) => k.checkEl.properties.check === 'ing') ? 'ing' : '');
}
}
};
for (let i of parents) {
let enables = i.children.filter((k) => !attrValBool(k.disabled)), type = this.getCheckType(i);
setCheck(i, enables, type);
}
}
eachCheck(item) {
this.chainChecking = true;
this.floatDown(item);
this.floatUp(item);
this.chainChecking = false;
}
getCheckType(parent) {
return parent?.childType || (['checkbox', 'radio'].includes(this.options.check.type) ? this.options.check.type : 'checkbox');
}
uncheckSibings(item) {
this.chainChecking = true;
let siblings = super.getSiblings(item).filter((k) => attrValBool(k.checked));
for (let k of siblings) {
k.checked = false;
this.options.check.linkage && this.floatDown(k);
}
this.chainChecking = false;
}
expandParents(data, cb) {
let tmp = findItems(data, this.flatData), items = tmp.map((k) => findItem(k, this.flatData)).filter(Boolean), pSet = [];
if (items.length) {
let parents = [];
for (let k of items) {
let p = treeTools.getParentsFromPath({ path: k.path, flatData: this.flatData, field: 'id', pathHyphen: this.options.pathHyphen }).parents;
p.pop();
parents.push(...p);
}
pSet = unique(parents);
for (let k of pSet)
super.expand(k);
}
cb && cb(pSet);
}
select(data, flag = true, cb) {
if (this.destroyed || !this.options.select.enable || isNull(data))
return;
let tmp = findItems(data, this.flatData), items = tmp.map((k) => findItem(k, this.flatData)).filter((k) => !attrValBool(k.selected) === flag && (this.options.select.span === 'leaf' ? !k.children : this.options.select.span === 'branch' ? k.children : true)), param = items, fn = (obj) => {
if (obj.headEl.hasAttribute('editing') || obj.headEl.hasAttribute('unselectable') || attrValBool(obj.selected))
return;
obj.selected = true;
};
if (!items.length)
return;
if (flag) {
if (this.options.select.only) {
let item = items[0];
if (item) {
fn(item);
this.deselect(this.flatData.filter((k) => k !== item && attrValBool(k.selected)));
}
param = [item];
}
else {
this.saveRaw();
for (let k of items)
fn(k);
}
this.options.select.linkage && this.expandParents(param);
}
else {
this.deselect(items);
}
super.listen({ name: flag ? 'selected' : 'deselected', cb, params: [param] });
return this;
}
selectAll(cb) {
if (this.destroyed || !this.options.select.enable || this.options.select.only)
return;
this.select(this.flatData);
super.listen({ name: 'selectedAll', cb });
return this;
}
deselectAll(cb) {
if (this.destroyed || !this.options.select.enable)
return;
this.select(this.flatData, false);
super.listen({ name: 'deselectedAll', cb });
return this;
}
deselect(data) {
if (isNull(data))
return;
let items = Array.isArray(data) ? data : [data], fn = (obj) => {
if (!attrValBool(obj.selected))
return;
obj.selected = false;
};
this.saveRaw();
for (let k of items)
fn(k);
}
checkOnlyone(item) {
this.saveRaw();
item.checked = true;
this.chainChecking = true;
let others = this.flatData.filter((k) => k !== item);
for (let k of others) {
k.checked = false;
k.checkEl && k.checkEl.removeAttribute('check');
}
this.chainChecking = false;
}
async check(data, flag = true, cb) {
if (this.destroyed)
return;
let filters = findItems(data, this.flatData), items = filters.filter((k) => !attrValBool(k.checked) === flag && (flag ? (this.options.check.span === 'leaf' ? !k.children : this.options.check.span === 'branch' ? !!k.children : true) : true)), fn = (obj) => {
obj.checked = flag;
flag && obj.checkType === 'radio' && this.uncheckSibings(obj);
this.options.check.linkage && this.eachCheck(obj);
};
if (!items.length)
return;
if (this.options.check.max) {
try {
let param = { data: items, source: this.getCheckeds(), min: this.options.check.min, max: this.options.check.max, sliced: this.options.check.sliced }, resp = await (flag ? this.moreExceed(param) : this.lessExceed(param));
resp && (items = resp);
}
catch {
return;
}
}
if (flag && this.options.check.only) {
this.checkOnlyone(items[0]);
}
else {
this.saveRaw();
for (let k of items)
fn(k);
}
super.listen({ name: flag ? 'checked' : 'unchecked', cb, params: [items] });
return this;
}
checkAll(cb) {
if (this.destroyed || !this.options.check.enable || this.options.check.type !== 'checkbox' || this.options.check.only)
return;
this.saveRaw();
for (let k of this.flatData) {
k.checked = true;
}
super.listen({ name: 'checkedAll', cb });
return this;
}
async add(options) {
if (this.destroyed)
return;
let opts = Object.assign({ isChild: true, isFront: true, repeat: true, isLeaf: true, autoFill: true, expand: true, }, options), type = getDataType(opts.data), target = findItem(opts.target, this.flatData), brother = findItem(opts.brother, this.flatData), tmp = [], items = [], appendFun = async (data) => {
let obj = treeTools.createBranchObj({
source: data,
flatData: this.flatData,
target,
isLeaf: opts.isLeaf,
isChild: opts.isChild
});
this.createHeadEl(obj);
await this.createBodyEl(obj);
this.createFootEl(obj);
this.createChildrenEl(obj);
super.listen({ name: 'insertItem', params: [obj] });
treeTools.addBranch({
source: obj,
rootEl: this.targetEl,
flatData: this.flatData,
treeData: this.treeData,
brother: target && !opts.isChild ? target : brother,
isFront: opts.isFront,
repeat: opts.repeat,
autoFill: opts.autoFill,
cb: (item) => {
items.push(item);
this.updateEvt(item);
}
});
};
tmp = isNull(opts.data) ? [null] : ((type === 'Array' && opts.data.length > 0) ? opts.data : [opts.data]);
try {
let resp = await super.moreExceed({ data: tmp, source: this.flatData });
resp && (tmp = resp);
}
catch {
return;
}
for (let k of tmp) {
try {
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
continue;
}
await appendFun(k);
}
if (items.length > 0) {
this.flatData = treeTools.toFlat(this.treeData);
opts.isChild && opts.expand && target && this.eachExpand(target);
if (this.options.select.enable && this.options.select.addSelected) {
if (!this.options.select.only) {
for (let k of items)
this.select(k);
}
else {
this.select(items.at(-1));
}
}
}
super.listen({ name: 'added', cb: opts.cb, params: [items, target] });
return this;
}
async remove(data, cb) {
if (this.destroyed || isNull(data) || !this.flatData.length)
return;
if (this.flatData.length === 0) {
console.warn('The source data is already empty!');
return;
}
let tmp = [], items = [], removeItem = (child) => {
treeTools.removeBranch({
source: child,
flatData: this.flatData,
treeData: this.treeData,
remove: false,
cb: (obj) => {
items.push(obj);
setTimeout(() => {
let parent = this.flatData.find((k) => k.id === obj.pId);
parent && !parent.children.length && super.collapse(parent);
}, 0);
}
});
};
tmp = findItems(data, this.flatData);
try {
let resp = await super.lessExceed({ data: tmp, source: this.flatData });
resp && (tmp = resp);
}
catch {
return;
}
for (let k of tmp) {
try {
if (this.options.b4Remove) {
let resp = await this.options.b4Remove.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
continue;
}
removeItem(k);
}
this.flatData = treeTools.toFlat(this.treeData);
super.listen({ name: 'removed', cb, params: [items] });
return this;
}
search(value, opts = {}, cb) {
if (this.destroyed || !this.flatData.length)
return;
let hyphen = config.splitHyphen;
if (typeof value === 'string') {
let tmp = value.trim();
hyphen = tmp.includes(',') ? ',' : tmp.includes(',') ? ',' : tmp.includes(' ') ? ' ' : config.splitHyphen;
}
let keys = valToArr(value, hyphen, false).map((k) => clearRegx(k)).filter(Boolean);
if (!keys.length) {
for (let k of this.searchs) {
k.labelEl.innerHTML = k.label;
}
if (!isEmpty(this.ignores)) {
for (let k of this.ignores)
k.wrapEl.classList.remove(`${ax.prefix}d-none`);
}
this.searchs = [];
this.ignores = [];
}
else {
let tmp = this.searchs;
this.searchs = arrSearch(Object.assign({ keys, props: 'label', source: this.flatData }, { fuzzy: this.options.search.fuzzy, ignore: this.options.search.ignore }, opts)).map((k) => k.source);
for (let k of this.searchs) {
k.labelEl.innerHTML = super.replaceMult(k.label, keys);
}
if (!isEmpty(tmp)) {
for (let k of tmp) {
if (!this.searchs.includes(k)) {
k.labelEl.innerHTML = k.label;
}
}
}
this.expandParents(this.searchs, (p) => {
let currents = unique([...p, ...this.searchs]);
this.ignores = this.flatData.filter((k) => !currents.includes(k));
for (let k of this.ignores)
k.wrapEl.classList.add(`${ax.prefix}d-none`);
for (let k of currents)
k.wrapEl.classList.remove(`${ax.prefix}d-none`);
});
}
super.updateCache({ search: { value: keys } });
super.listen({ name: 'searched', cb, params: [this.searchs, keys] });
return this;
}
inputLabel(item) {
let headEl = item.headEl, labelEl = item.labelEl;
if (headEl.hasAttribute('editing'))
return;
headEl.toggleAttribute('editing', true);
labelEl.innerHTML = '';
labelEl.appendChild(this.editorEl);
this.editorEl.focus();
this.editorEl.value = item.label;
this.editorEl.onblur = async () => {
let value = this.editorEl.value;
try {
if (this.options.b4Edit) {
let resp = await this.options.b4Edit.call(this, { key: 'label', value }, item);
resp && (value = resp);
}
item.label = value;
headEl.removeAttribute('editing');
}
catch (err) {
item.labelEl.innerHTML = item.label;
headEl.removeAttribute('editing');
err ? console.error(err) : console.warn(`No changes have been made to the label property!`);
return;
}
super.listen({ name: 'edited', params: [item] });
};
this.editorEl.onkeyup = (e) => {
(e.code === 'Enter') && this.editorEl.blur();
};
}
async edit(item, data, cb) {
if (this.destroyed || isNull(item) || isEmpty(data) || !this.flatData.length) {
return this;
}
let source = findItem(item, this.flatData);
if (!source)
return this;
for (let k in data) {
let val = data[k];
try {
if (this.options.b4Edit) {
let resp = await this.options.b4Edit.call(this, { key: k, value: val }, source);
resp && (val = resp);
}
if (k === 'action') {
source[k] = val.call({ ins: this, item: k }, source);
}
else if (['icon', 'disk', 'cube', 'onclick', 'href', 'target', 'rel', 'label', 'brief', 'tips', 'badge'].includes(k)) {
source[k] = val;
}
}
catch (err) {
err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
return this;
}
}
super.listen({ name: 'edited', cb, params: [source] });
return this;
}
async graft({ source, target, isFront = true, isChild = true, cb }) {
if (this.destroyed || isNull(source))
return;
try {
if (this.options.b4Graft) {
let resp = await this.options.b4Graft.call(this, source, target);
resp && resp.source && (source = resp.source);
resp && resp.target && (source = resp.target);
}
}
catch (err) {
err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
return this;
}
let sourceObj = findItem(source, this.flatData, '', { node: 'wrapEl' }), targetObj = findItem(target, this.flatData);
if (!sourceObj)
return;
treeTools.graftBranch({
source: sourceObj,
target: targetObj,
isFront,
isChild,
flatData: this.flatData,
treeData: this.treeData,
rootEl: this.targetEl,
cb: (obj, refer) => {
refer && refer.children && isChild && this.eachExpand(refer);
this.flatData = treeTools.toFlat(this.treeData);
super.listen({ name: 'grafted', cb, params: [obj, refer] });
return this;
}
});
return this;
}
setSearch() {
!isEmpty(this.options.search.value) && this.search(this.options.search.value);
this.searchEl = getEl(this.options.search.target);
if (this.searchEl) {
if (this.searchEl[ax.compSign]) {
this.searchEl.on(this.options.search.trigger, this.searchEvgt);
}
else {
this.searchEl.addEventListener(this.options.search.trigger, this.searchEvgt, false);
}
}
}
setResult() {
if (!this.options.output.enable || this.options.output.instant)
return;
this.resultIns = this.resultIns || new Tags(this.resultEl, {
content: '',
size: 'sm',
type: 'plain',
removable: true,
empty: { enable: true, content: this.options.lang.result },
});
this.resultIns.on('removed', async (items) => {
for (let k of items) {
let tmp = k.label.split(this.options.output.connector);
for (let i of tmp) {
this.options.output.form === 'checked' ? await this.check(i, false) : this.select(i, false);
}
}
});
}
updateVals() {
if (!this.options.output.enable)
return;
let { value, items } = this.getVals();
this.updateResult(value);
this.options.name && (this.inputEl.value = value);
this.output.value = value;
this.output.items = items;
super.listen({ name: 'output', params: [this.output] });
if (!this.options.output.instant)
return;
this.setVals();
}
saveRaw() {
this.output.raw = this.getVals().value;
}
updateResult(val) {
this.resultIns && (val ? this.resultIns.updateCont(val.split(this.options.output.separator)) : this.resultIns.clear());
}
clearResult() {
this.resultIns && this.resultIns.clear();
}
setVals(target = this.receiver, cb) {
if (this.destroyed)
return;
let receiver = getEl(target), val = this.getVals().value;
fieldTools.setVals({ target: receiver, value: val });
super.listen({ name: 'set', cb, params: [val] });
return this;
}
clearVals(all = false, cb) {
if (this.destroyed || !this.flatData.length)
return this;
if (all) {
super.uncheckAll();
this.deselectAll();
}
else {
this.options.output.from === 'checked' ? super.uncheckAll() : this.deselectAll();
}
this.value = '';
this.clearResult();
super.listen({ name: 'cleared', cb });
return this;
}
getVals(opt = {}, cb) {
if (this.destroyed)
return this;
let options = Object.assign({ ...this.options.output, isStr: true }, opt), items = this.getValItems(options.from), result = [];
if (options.type === 'chain') {
result = items.map((k) => {
let tmp = treeTools
.getParentsFromPath({ path: k.path, flatData: this.flatData, pathHyphen: this.options.pathHyphen, labelHyphen: options.connector, field: options.field })
.parents
.map((k) => k[options.field]);
return options.isStr ? tmp.join(options.connector) : tmp;
});
}
else {
let tmp = (options.type === 'leaf') ? items.filter((k) => !k.children) : (options.type === 'branch') ? items.filter((k) => k.children) : items;
result = tmp.map((k) => k[options.field]);
}
let value = options.isStr ? result.join(options.separator) : result;
super.listen({ name: 'got', cb, params: [value] });
return { value, items };
}
getValItems(from = 'selected') {
return !this.options.output.autosort ? this.seqItems : (from === 'checked' ? super.getCheckeds() : this.getSelecteds());
}
async updateCont(content, cb) {
if (this.destroyed)
return this;
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: async (data) => {
if (Array.isArray(data)) {
this.treeDataOrig = deepClone(data);
treeTools.addIdPath({ source: this.treeDataOrig });
this.targetEl.innerHTML = '';
await this.renderData(this.treeDataOrig);
this.getTreeFlat();
this.renderFinish();
super.updateCache({ content });
super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
}
}
});
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
for (let k of this.flatData) {
if (k.children) {
if (this.options.arrow.trigger === 'click') {
let triggerEl = k.hasOwnProperty('href') && k.arrowEl ? k.arrowEl : k.headEl;
triggerEl.removeEventListener('click', this.expandEvt);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns.destroy();
}
k.legendEl && k.legendEl.removeEventListener('click', this.expandEvt);
}
!k.children && k.headEl.removeEventListener('click', this.selectEvt);
this.options.shortcut.enable && k.headEl.removeEventListener('click', this.lineEvt);
this.options.drag.enable && k.dragIns.destroy();
if (this.options.paginated.enable && !this.options.deferred) {
k.moreEl.onclick = null;
k.nextEl.onclick = null;
k.firstEl.onclick = null;
}
}
this.resultIns && this.resultIns.destroy();
if (this.searchEl) {
if (this.searchEl[ax.compSign]) {
this.searchEl.off(this.options.search.trigger, this.searchEvgt);
}
else {
this.searchEl.removeEventListener(this.options.search.trigger, this.searchEvgt);
}
}
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class Menu extends ModBaseListenCache {
options = {};
flatData;
treeData;
expandEvt;
selectEvt;
pageEvt;
lastExpanded;
treeDataOrig;
drawerHost;
drawerIns;
treeIns;
hoverIns;
contXhr;
observeIns;
static hostType = 'node';
static optMaps = optMenu$1;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Menu.optMaps,
component: true,
spread: ['arrow', 'nav']
});
let _this = this;
this.pageEvt = function (event) {
if (!contains(event.target, _this.targetEl)) {
_this.treeIns.collapseAll();
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setAttrs();
this.getTree();
await this.treeIns.init();
this.drawerHost = getEl(this.options.drawer.host);
if (this.drawerHost) {
this.drawerIns = new Drawer(this.drawerHost, Object.assign({
content: this.targetEl,
contType: 'node',
}, this.options.drawer));
}
super.listen({ name: 'initiated', cb });
return this;
}
getTree() {
let _this = this;
let targetObj = {
storName: this.options.storName ? this.options.storName + '_tree' : '',
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: this.options.ajax,
passive: this.options.passive,
layout: this.options.layout,
disable: this.options.disable,
duration: this.options.duration,
select: {
value: this.options.active,
linkage: this.options.linkage,
span: 'leaf',
},
expand: {
value: this.options.active,
all: this.options.expose || this.options.expandAll ? true : false,
only: this.options.multiple || this.options.expose ? false : true,
linkage: this.options.linkage,
},
shortcut: {
enable: !this.options.expose,
span: 'blank',
mean: this.options.trigger === 'hover' ? 'selected' : 'auto',
},
arrow: {
enable: this.options.arrow.enable,
show: this.options.arrow.icon || `${ax.prefix}icon-${this.options.nav.enable ? 'down' : 'right'}`,
hide: this.options.arrow.icon || `${ax.prefix}icon-${this.options.nav.enable ? 'down' : 'right'}`,
anim: `${ax.prefix}rotate${this.options.nav.enable || this.options.spill ? '180' : '90'}`,
type: 'icon',
trigger: this.options.trigger,
},
onInitiated: function () {
if (_this.options.trigger === 'click' && _this.options.pageClose) {
document.body.removeEventListener('click', _this.pageEvt);
document.body.addEventListener('click', _this.pageEvt, false);
}
},
onAdded: (items, refer) => {
this.setHover(refer);
},
onGrafted: (item, refer) => {
this.setHover(refer);
},
onInsertItem: (item) => {
this.options.nav.enable && this.addNavAttr(item, item.floor === this.options.floorStart);
},
onInsertItems: (items) => {
let tmp = treeTools.toFlat(items);
for (let k of tmp) {
this.options.nav.enable && this.addNavAttr(k, k.floor === this.options.floorStart);
k?.children && this.setHover(k);
}
}
}, params = extend({ target: targetObj, source: this.options.tree, });
this.treeIns && this.treeIns.initiated && this.treeIns.destroy();
this.treeIns = new Tree(this.targetEl, params, false);
}
setHover(item) {
if (this.options.trigger !== 'hover' || !item?.children)
return;
item.triggerIns && item.triggerIns.destroy();
item.triggerIns = new Hover(item.wrapEl, {
onEnter: () => {
this.treeIns.expand(item.id);
},
onLeave: () => {
this.treeIns.collapse(item.id);
}
});
}
addNavAttr(item, firstItem = false) {
if (this.options.nav.bodyWidth) {
item.childrenEl ? addStyle(item.childrenEl, 'width', this.options.nav.bodyWidth) : removeStyle(item.childrenEl, 'width');
}
if (firstItem) {
this.options.nav.headWidth ? addStyle(item.wrapEl, 'width', this.options.nav.headWidth) : removeStyle(item.wrapEl, 'width');
this.options.nav.marginLeft ? addStyle(item.wrapEl, 'margin-left', this.options.nav.marginLeft) : removeStyle(item.wrapEl, 'margin-left');
this.options.nav.marginRight ? addStyle(item.wrapEl, 'margin-right', this.options.nav.marginRight) : removeStyle(item.wrapEl, 'margin-right');
}
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}menu`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.setAttribute('theme', this.options.theme);
this.targetEl.toggleAttribute('inert', this.options.passive);
this.targetEl.toggleAttribute('expose', this.options.expose);
this.targetEl.setAttribute('trigger', this.options.trigger);
this.targetEl.toggleAttribute('spill', (this.options.spill && !this.options.nav.enable));
this.targetEl.toggleAttribute('unpadded', this.options.unpadded);
this.options.lamp ? this.targetEl.setAttribute('lamp', this.options.lamp) : this.targetEl.removeAttribute('lamp');
this.targetEl.toggleAttribute('full', (this.options.full && !this.options.nav.enable));
this.options.zIndex ? addStyle(this.targetEl, 'z-index', this.options.zIndex) : removeStyle(this.targetEl, 'z-index');
this.targetEl.toggleAttribute('nav', this.options.nav.enable);
this.options.nav.align ? this.targetEl.setAttribute('align', this.options.nav.align) : this.targetEl.removeAttribute('align');
}
activate(data, cb) {
if (this.destroyed)
return;
let tmp = findItems(data, this.treeIns.flatData), branches = tmp.filter((k) => k.children), leaves = tmp.filter((k) => !k.children);
if (leaves.length) {
this.treeIns.select(leaves, true, () => {
this.treeIns.expand(branches);
});
}
else {
this.treeIns.expand(branches);
}
super.listen({ name: 'activated', cb, params: [tmp] });
return this;
}
async updateCont(content, cb) {
if (this.destroyed)
return this;
await this.treeIns.updateCont(content, (resp) => {
super.listen({ name: 'updatedCont', cb, params: [resp] });
});
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.treeIns.destroy();
document.body.removeEventListener('click', this.pageEvt);
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optMenu = [
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'passive',
prop: 'passive',
value: false,
},
{
attr: 'active',
prop: 'active',
value: '',
},
{
attr: 'disable',
prop: 'disable',
value: '',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'click',
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'max',
prop: 'max',
value: 0,
},
{
attr: 'embed',
prop: 'embed',
value: false,
},
{
attr: 'slider',
prop: 'slider',
value: {
enable: false,
arrowShow: false,
options: {
slides: 'auto',
scroll: {
drift: { mode: 'free', coef: 1 }
}
},
},
},
{
attr: 'menu',
prop: 'menu',
value: {
enable: false,
options: {
columns: 4,
size: 'lg',
}
},
},
{
attr: 'col',
prop: 'col',
value: {
enable: false,
position: 'left',
},
},
{
attr: 'attrs',
prop: 'attrs',
value: {
target: {},
head: {},
body: {},
},
},
{
attr: 'classes',
prop: 'classes',
value: {
target: '',
head: '',
body: '',
},
},
{
attr: 'divider',
prop: 'divider',
value: {
enable: false,
size: '',
},
},
{
attr: 'add-active',
prop: 'addActive',
value: true,
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
children: ['close'],
},
},
{
attr: 'layout',
prop: 'layout',
value: 'lamp',
},
{
attr: 'selector',
prop: 'selector',
value: {
head: '',
body: '',
},
},
{
attr: 'sticky',
prop: 'sticky',
value: 0,
},
{
attr: 'b4-activate',
prop: 'b4Activate',
value: null,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-edit',
prop: 'b4Edit',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-graft',
prop: 'b4Graft',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-insertitem',
prop: 'onInsertItem',
value: null,
},
{
attr: 'on-insertitems',
prop: 'onInsertItems',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null
},
{
attr: 'on-added',
prop: 'onAdded',
value: null
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null
},
{
attr: 'on-grafted',
prop: 'onGrafted',
value: null
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null
},
{
attr: 'on-disabledAll',
prop: 'onDisabledAll',
value: null
},
{
attr: 'on-enabledAll',
prop: 'onEnabledAll',
value: null
},
{
attr: 'on-activated',
prop: 'onActivated',
value: null
},
{
attr: 'on-updatedItemcont',
prop: 'onUpdatedItemCont',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
...optBase
];
class Tab extends ModBaseListenCacheNest {
options = {};
actEvt;
trigger;
treeDataOrig;
observeIns;
headsEl;
bodiesEl;
dividerEl;
rawData;
headLayout;
contXhr;
static hostType = 'node';
static optMaps = optMenu;
static dependencies = [BadgeElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Tab.optMaps,
component: false,
spread: ['slider', 'col', 'menu', 'tools', 'divider']
});
let _this = this;
this.actEvt = function (evt) {
if (this.hasAttribute('selected') || this.hasAttribute('disabled'))
return;
let toolsEl = this.querySelector(`:scope > [${ax.alias}="tools"]`);
if (toolsEl && toolsEl.contains(evt.target))
return;
let item = _this.treeData.find((k) => k.headEl === this);
_this.activate(item);
};
this.trigger = this.options.trigger === 'hover' ? 'mouseenter' : 'click';
this.treeDataOrig = [];
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
super.useTpl();
await this.getDataToRender();
this.setAttrs();
super.initDisableds();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
initActive() {
let activeItem = this.treeData.findIndex((k) => attrValBool(k.selected));
if (this.options.active === 0 || this.options.active) {
this.activate(this.options.active);
}
else if (activeItem < 0) {
this.activate(0);
}
}
async getDataToRender() {
let base = {
nodeType: 'tab',
}, promise;
if (this.options.content) {
promise = treeTools.allToTree({
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
ins: this,
...base
});
}
else {
if (this.targetEl.querySelector(`.${ax.prefix}tab-head`) && this.targetEl.querySelector(`.${ax.prefix}tab-body`)) {
this.treeDataOrig = this.htmlToArr();
treeTools.addIdPath({ source: this.treeDataOrig });
this.rawData = this.treeDataOrig;
this.updateHeadBodyAttrs();
}
else {
promise = treeTools.allToTree({
content: this.targetEl.innerHTML,
...base
});
}
}
if (promise) {
await promise.then((res) => {
this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
this.rawData = res;
});
this.targetEl.innerHTML = '';
this.renderData(this.treeDataOrig);
}
this.getTreeFlat();
super.listen({ name: 'rendered', params: [this.treeData] });
return this;
}
getTreeFlat() {
this.treeData = this.getObserver(this.treeDataOrig).proxy;
}
getObserver(data) {
this.observeIns ? this.observeIns.destroy() : null;
this.observeIns = new Observe(data, {
deep: {
enable: true,
exclude: ['tools'],
},
onSet: (obj) => {
if (obj.key === 'icon' && obj.target.iconEl) {
obj.target.iconEl.className = obj.value;
}
else if (obj.key === 'cube' && obj.target.cubeEl) {
obj.target.cubeEl.src = obj.value;
}
else if (obj.key === 'disk' && obj.target.diskEl) {
obj.target.diskEl.src = obj.value;
}
else if (obj.key === 'image' && obj.target.imageEl) {
obj.target.imageEl.src = obj.value;
}
else if (obj.key === 'label') {
obj.target.labelEl.innerHTML = obj.value;
}
else if (obj.key === 'tips' && obj.target.tipsEl) {
obj.target.tipsEl.innerHTML = obj.value;
}
else if (obj.key === 'badge' && obj.target.badgeEl) {
obj.target.badgeEl.setAttribute('label', obj.value);
}
else if (obj.key === 'selected') {
if (attrValBool(obj.value)) {
obj.target.headEl.setAttribute('selected', '');
obj.target.bodyEl.setAttribute('selected', '');
!obj.target.bodyEl.innerHTML && this.fillContent(obj.target);
}
else {
obj.target.headEl.removeAttribute('selected');
obj.target.bodyEl.removeAttribute('selected');
}
}
else if (obj.key === 'disabled') {
obj.target.headEl.toggleAttribute('disabled', attrValBool(obj.value));
}
else if (obj.key === 'content') {
this.fillContent(obj.target);
}
},
onCompleted: () => {
let activeItem = this.getSelected(), tmp = {
active: activeItem ? (activeItem.hasOwnProperty('id') ? activeItem.id : this.treeData.indexOf(activeItem)) : 0,
disabled: super.getDisableds().map((k, i) => k.hasOwnProperty('id') ? k.id : i),
content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : [],
};
super.updateCache(tmp);
}
});
return this.observeIns;
}
htmlToArr() {
let data = [];
this.headsEl = this.targetEl.querySelector(`.${ax.prefix}tab-head`);
this.bodiesEl = this.targetEl.querySelector(`.${ax.prefix}tab-body`);
if (!this.headsEl || !this.bodiesEl) {
return data;
}
let tmpHeads = getEls(this.options.selector.head, this.headsEl), tmpBodys = getEls(this.options.selector.body, this.bodiesEl), headsArr = tmpHeads.length ? tmpHeads : [...this.headsEl.children], bodiesArr = tmpBodys.length ? tmpBodys : [...this.bodiesEl.children];
if (headsArr.length !== bodiesArr.length) {
console.warn('Inconsistent number of heads and bodies!');
return data;
}
let setBoolean = (obj, props) => {
let loop = (prop) => {
let val = obj.headEl.hasAttribute(prop);
if (val && val !== 'false' && val !== '0') {
obj[prop] = true;
obj.headEl.setAttribute(prop, '');
}
else {
obj[prop] = false;
}
};
if (Array.isArray(props)) {
props.forEach((k) => {
loop(k);
});
}
else {
loop(props);
}
}, getPropsFromHead = (elem) => {
let obj = {}, tmpLabel = elem.querySelector(`[${ax.alias}="label"]`);
obj.headEl = elem;
obj.labelEl = tmpLabel || elem;
obj.label = obj.labelEl.textContent.trim();
obj.tipsEl = elem.querySelector(`[${ax.alias}="tips"]`);
obj.tips = obj.tipsEl ? obj.tipsEl.textContent.trim() : '';
obj.iconEl = elem.querySelector(`[${ax.alias}="icon"]`);
obj.icon = obj.iconEl ? obj.iconEl.getAttribute('class') : '';
obj.cubeEl = elem.querySelector(`[${ax.alias}="cube"]`);
obj.cube = obj.cubeEl ? obj.cubeEl.src : '';
obj.diskEl = elem.querySelector(`[${ax.alias}="disk"]`);
obj.disk = obj.diskEl ? obj.diskEl.src : '';
obj.badgeEl = elem.querySelector(`[${ax.alias}="badge"],ax-badge`);
obj.badge = obj.badgeEl ? obj.badgeEl.getAttribute('label') || obj.badgeEl.textContent.trim() : '';
setBoolean(obj, ['selected', 'disabled']);
return obj;
};
data = headsArr.map((k, i) => {
let tmp = getPropsFromHead(k), bodyEl = bodiesArr[i];
bodyEl.toggleAttribute('selected', attrValBool(tmp.selected));
this.options.tools.enable && this.getTools(tmp);
return { ...tmp, bodyEl, content: bodyEl.innerHTML };
});
return data;
}
renderData(data) {
this.dividerEl = createEl('ax-br');
this.options.divider.size && this.dividerEl.setAttribute('size', this.options.divider.size);
this.headsEl = createEl('ul', { class: `${ax.prefix}tab-head` });
this.bodiesEl = createEl('ul', { class: `${ax.prefix}tab-body` });
this.updateHeadBodyAttrs();
for (let k of data) {
if (!k.hasOwnProperty('label') || !k.hasOwnProperty('content')) {
continue;
}
else {
this.createItemEl(k);
this.headsEl.appendChild(k.headEl);
this.bodiesEl.appendChild(k.bodyEl);
}
}
super.listen({ name: 'insertItems', params: [data] });
this.targetEl.append(this.headsEl, this.options.divider.enable ? this.dividerEl : '', this.bodiesEl);
}
createItemEl(item) {
item.labelEl = createEl('i', { [ax.alias]: 'label' }, item.label);
item.iconEl = item.icon ? createEl('i', { [ax.alias]: 'icon', class: item.icon }) : null;
item.diskEl = item.disk ? createEl('img', { [ax.alias]: 'disk', src: item.disk }) : null;
item.cubeEl = item.cube ? createEl('img', { [ax.alias]: 'cube', src: item.cube }) : null;
item.imageEl = item.image ? createEl('img', { [ax.alias]: 'image', src: item.image }) : null;
item.headEl = createEl('li');
item.bodyEl = createEl('li');
item.badgeEl = item.badge ? createEl('ax-badge', { [ax.alias]: 'badge' }, item?.badge?.trim()) : null;
item.tipsEl = item.tips ? createEl('i', { [ax.alias]: 'tips' }, item.tips) : null;
attrValBool(item.selected) && (item.headEl.toggleAttribute('selected', true), item.bodyEl.toggleAttribute('selected', true));
attrValBool(item.disabled) && item.headEl.toggleAttribute('disabled', true);
item.headEl.append(...[item.iconEl, item.diskEl, item.cubeEl, item.imageEl, item.labelEl, item.tipsEl, item.badgeEl].filter(Boolean));
this.options.tools.enable && this.getTools(item);
}
getTools(item) {
if (this.options.tools.enable) {
item.toolsEl = createTools(this.options.tools.children, item.headEl);
item.toolsEl.setAttribute(ax.alias, 'tools');
item.tools = deepClone(this.options.tools.children);
for (let k of item.tools) {
this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
if (k.name === 'add') {
item.addEl = k.wrapEl;
}
else if (k.name === 'edit') {
item.editEl = k.wrapEl;
}
else if (k.name === 'close') {
item.closeEl = k.wrapEl;
}
else if (k.name === 'update') {
item.updateEl = k.wrapEl;
}
else if (k.name === 'move') {
item.moveEl = k.wrapEl;
}
}
}
}
async fillContent(obj, cb) {
await getContent.call(this, {
content: obj.content,
contType: obj.contType,
contData: obj.contData,
ajax: {
ajaxType: obj.ajaxType || this.options.ajaxType,
xhrName: 'contXhr',
spinSel: obj.bodyEl,
},
cb: (data) => {
setContent({
content: data,
target: obj.bodyEl,
engine: obj.engine || this.tplStr,
template: obj.template || this.tplEng
});
cb && cb(data);
}
});
}
updateHeadBodyAttrs() {
this.options.classes?.head && classes(this.headsEl).add(this.options.classes.head);
this.options.classes?.body && classes(this.bodiesEl).add(this.options.classes.body);
!isEmpty(this.options.attrs?.head) && setAttrs(this.headsEl, this.options.attrs.head);
!isEmpty(this.options.attrs?.body) && setAttrs(this.bodiesEl, this.options.attrs.body);
if (this.options.layout) {
if (!this.headsEl.getAttribute('class')?.includes(`${ax.prefix}group-`)) {
this.headLayout = `${ax.prefix}group-${this.options.layout}`;
this.headsEl.classList.add(this.headLayout);
}
}
else {
this.headLayout && this.headsEl.classList.remove(this.headLayout);
}
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}tab`);
this.options.classes?.target && classes(this.targetEl).add(this.options.classes.target);
!isEmpty(this.options.attrs?.target) && setAttrs(this.targetEl, this.options.attrs.target);
this.targetEl.toggleAttribute('inert', this.options.passive);
this.targetEl.toggleAttribute('embed', this.options.embed);
this.options.col.enable ? this.targetEl.setAttribute('col', this.options.col.position) : this.targetEl.removeAttribute('col');
}
updateEvt(k) {
this.addTrigger(k);
let tmp = attrValBool(k.disabled);
if (k.toolsEl) {
if (k.closeEl) {
k.closeEl.onclick = () => {
if (k.readonly)
return;
this.remove(k);
};
}
if (k.editEl) {
k.editEl.onclick = debounce(() => {
});
}
if (k.addEl) {
k.addEl.onclick = debounce(() => {
if (tmp)
return;
this.add({ data: {}, isFront: false, target: k });
});
}
if (k.updateEl) {
k.updateEl.onclick = debounce(() => {
if (tmp)
return;
this.updateItemCont({ content: k.content, target: k });
});
}
for (let [i, o] of this.options.tools.children.entries()) {
let tool = k.tools[i], refer = { ins: this, item: k };
o.action && o.action.call(refer, tool);
tool.action && tool.action.call(refer, tool);
}
}
tmp && k.headEl.toggleAttribute('disabled', true);
k.action && k.action.call(this, k);
}
renderFinish() {
this.initActive();
for (let k of this.treeData) {
this.updateEvt(k);
}
}
getSelected() {
return this.treeData.find((k) => attrValBool(k.selected));
}
addTrigger(item) {
if (!attrValBool(item.disabled)) {
item.headEl.removeEventListener(this.trigger, this.actEvt);
item.headEl.addEventListener(this.trigger, this.actEvt, false);
}
}
removeTrigger(item) {
if (attrValBool(item.disabled)) {
item.headEl.removeEventListener(this.trigger, this.actEvt);
}
}
toggleDisabled(item, type = 'disable') {
if (type === 'enable') {
item.disabled = false;
this.addTrigger(item);
}
else if (type === 'disable') {
item.disabled = true;
this.removeTrigger(item);
}
}
disable(data, cb) {
if (this.destroyed || (data !== 0 && isEmpty(data))) {
return this;
}
let tmp = Array.isArray(data) ? data : [data], arr = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), fun = (k) => this.toggleDisabled(k, 'disable');
arr.forEach(k => fun(k));
super.listen({ name: 'disabled', cb, params: [arr] });
return this;
}
disableAll(cb) {
if (this.destroyed) {
return this;
}
this.disable(this.treeData);
super.listen({ name: 'disabledAll', cb });
return this;
}
enable(data, cb) {
if (this.destroyed || (data !== 0 && isEmpty(data))) {
return this;
}
let tmp = Array.isArray(data) ? data : [data], arr = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), fun = (k) => this.toggleDisabled(k, 'enable');
arr.forEach(k => fun(k));
super.listen({ name: 'enabled', cb, params: [arr] });
return this;
}
enableAll(cb) {
if (this.destroyed) {
return this;
}
this.enable(this.treeData);
super.listen({ name: 'enabledAll', cb });
return this;
}
async activate(data, cb) {
if (this.destroyed || isNull(data))
return;
let item = findItem(data, this.treeData), other = this.treeData.find((k) => k !== item && attrValBool(k.selected));
if (!item)
return;
if (attrValBool(item.selected)) {
!item.bodyEl.innerHTML && this.fillContent(item);
}
else {
try {
if (this.options.b4Activate) {
let resp = await this.options.b4Add.call(this, item);
resp && (item = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Activating branche (${item.label}) has been prevented!`);
}
other && (other.selected = false);
item.selected = true;
item.disabled = false;
super.listen({ name: 'activated', cb, params: [item] });
}
return this;
}
async add(options) {
if (this.destroyed)
return this;
if (this.treeData.length >= this.options.max && this.options.max > 0) {
throw new Error('The number of children exceeds the maximum!');
}
let opts = Object.assign({ repeat: true, autoFill: true, isFront: false }, options), type = getDataType(opts.data), targetObj = findItem(opts.target, this.treeData), items = type === 'Array' ? opts.data : type === 'Object' ? [opts.data] : [{}];
if (!opts.repeat) {
let labels = this.treeData.map((k) => k.label);
items = items.filter((k) => !labels.includes(k.label));
}
if (items.length === 0) {
return this;
}
for (let k of items) {
try {
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
continue;
}
!k.hasOwnProperty('id') && (k.id = increaseId(this.treeData));
!k.hasOwnProperty('label') && (k.label = `${this.options.lang.label}${k.id}`);
!k.hasOwnProperty('content') && (k.content = `${this.options.lang.content}${k.id}`);
this.createItemEl(k);
}
if (targetObj) {
let tmp = this.treeData.indexOf(targetObj), index = opts.isFront ? tmp : tmp + 1;
splice({
host: this.treeData,
intent: 'add',
source: items,
index,
});
}
else {
splice({
host: this.treeData,
intent: opts.isFront ? 'start+' : 'end+',
source: items,
});
}
let heads = items.map((k) => k.headEl), bodies = items.map((k) => k.bodyEl);
appendEls({ parent: this.headsEl, nodes: heads, target: targetObj?.headEl, prepend: opts.isFront ? true : false });
appendEls({ parent: this.bodiesEl, nodes: bodies, target: targetObj?.bodyEl, prepend: opts.isFront ? true : false });
this.options.addActive && this.activate(items[items.length - 1]);
let tmp = items.map((k) => {
let _tmp = this.treeData.find((i) => (i.id === k.id));
this.updateEvt(_tmp);
return _tmp;
});
super.listen({ name: 'added', cb: opts.cb, params: [tmp] });
return this;
}
async remove(data, cb) {
if (this.destroyed || isNull(data)) {
return this;
}
if (this.treeData.length === 0) {
console.warn('The source data is already empty!');
return this;
}
let tmp = Array.isArray(data) ? data : [data], items = tmp.map((k) => findItem(k, this.treeData)).filter(Boolean), removeItem = (obj) => {
let index = this.treeData.indexOf(obj);
this.treeData.splice(index, 1);
obj.headEl.remove();
obj.bodyEl.remove();
};
for (let k of items) {
try {
if (this.options.b4Remove) {
let resp = await this.options.b4Remove.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
continue;
}
removeItem(k);
}
super.listen({ name: 'removed', cb, params: [items] });
return this;
}
async edit({ source, target, cb }) {
if (this.destroyed || isEmpty(source) || isNull(target)) {
return this;
}
let item = findItem(target, this.treeData);
if (!item)
return this;
for (let k in source) {
let val = source[k];
try {
if (this.options.b4Edit) {
let resp = await this.options.b4Edit.call(this, { key: k, value: val }, item);
resp && (val = resp);
}
if (k === 'action') {
item[k] = val.call({ ins: this, item: k }, item);
}
else if (['icon', 'disk', 'cube', 'image', 'label', 'tips', 'badge', 'disabled', 'content', 'contType', 'contData', 'ajaxType'].includes(k)) {
item[k] = k === 'disabled' ? attrValBool(val) : val;
}
else if (k === 'selected') {
attrValBool(val) ? this.activate(item) : item[k] = val;
}
}
catch (err) {
err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
return this;
}
}
super.listen({ name: 'edited', cb, params: [item] });
return this;
}
async graft({ source, target, isFront = true, cb }) {
if (this.destroyed || isNull(source)) {
return this;
}
let sourceObj = findItem(source, this.treeData), targetObj = findItem(target, this.treeData);
if (!sourceObj)
return this;
try {
if (this.options.b4Graft) {
let resp = await this.options.b4Graft.call(this, sourceObj, targetObj);
resp && resp.source && (sourceObj = resp.source);
resp && resp.target && (targetObj = resp.target);
}
}
catch (err) {
err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
return this;
}
let position = '';
if (targetObj) {
position = isFront ? 'beforeBegin' : 'afterEnd';
targetObj.headEl.insertAdjacentElement(position, sourceObj.headEl);
targetObj.bodyEl.insertAdjacentElement(position, sourceObj.bodyEl);
}
else {
position = isFront ? 'afterBegin' : 'beforeEnd';
this.headsEl.insertAdjacentElement(position, sourceObj.headEl);
this.bodiesEl.insertAdjacentElement('beforeEnd', sourceObj.bodyEl);
}
moveItem({ source: sourceObj, target: targetObj, data: this.treeData, isFront });
super.listen({ name: 'grafted', cb, params: [sourceObj, targetObj] });
return this;
}
updateItemCont({ target, content, contType, contData, ajaxType, cb }) {
if (this.destroyed)
return this;
let targetObj = findItem(target, this.treeData);
if (isEmpty(content) || !targetObj || content == targetObj.content)
return this;
contType ? (targetObj.contType = contType) : this.options.contType !== 'text' ? (targetObj.contType = this.options.contType) : null;
contData && (targetObj.contData = contData);
ajaxType && (targetObj.ajaxType = ajaxType);
targetObj.content = content;
super.listen({ name: 'updatedItemCont', cb, params: [targetObj] });
return this;
}
async updateCont(content, cb) {
if (this.destroyed) {
return this;
}
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
ajaxType: this.options.ajaxType,
xhrName: 'contXhr',
},
cb: (data) => {
if (Array.isArray(data)) {
this.treeDataOrig = deepClone(data);
treeTools.addIdPath({ source: this.treeDataOrig });
this.targetEl.innerHTML = '';
this.renderData(this.treeDataOrig);
this.getTreeFlat();
this.renderFinish();
super.updateCache({ content });
super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
}
}
});
return this;
}
destroy(cb) {
if (this.destroyed) {
return this;
}
this.treeData.forEach((k) => {
this.removeTrigger(k);
});
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class Tooltip extends Popup {
constructor(elem, options = {}, initial = config.initial) {
isNull(options.size) ? options.size = 'sm' : null;
options?.tools === true ? options.tools = { enable: true, placement: 'outside' } : !options?.tools ? options.tools = { enable: false, placement: 'outside' } : null;
!options?.placement ? options.placement = 'top' : null;
!options?.footer ? options.footer = false : null;
!options?.padding ? options.padding = false : null;
!options?.theme ? options.theme = 'text' : null;
super(elem, options, initial);
this.on('initiated', () => {
this.mainEl.classList.add(`${ax.prefix}tooltip`);
});
}
}
var Tooltip$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
default: Tooltip
});
const optDropdown = [
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'placement',
prop: 'placement',
value: 'bottom-start',
},
{
attr: 'list-type',
prop: 'listType',
value: '',
},
{
attr: 'unpadded',
prop: 'unpadded',
value: false,
},
{
attr: 'hoverable',
prop: 'hoverable',
value: false,
},
{
attr: 'divisible',
prop: 'divisible',
value: false,
},
{
attr: 'multiline',
prop: 'multiline',
value: false,
},
{
attr: 'cols',
prop: 'cols',
value: 0,
},
{
attr: 'lines',
prop: 'lines',
value: '',
},
{
attr: 'detectable',
prop: 'detectable',
value: false,
},
{
attr: 'child-sel',
prop: 'childSel',
value: `[${ax.alias}="label"]`,
},
{
attr: 'val-key',
prop: 'valKey',
value: '',
},
{
attr: 'feature',
prop: 'feature',
value: '',
},
{
attr: 'popup',
prop: 'popup',
value: {},
},
...optBase
];
class Dropdown extends ModBaseListenCache {
popupIns;
static hostType = 'node';
static optMaps = optDropdown;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
host: elem,
maps: Dropdown.optMaps,
component: true,
spread: []
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.popupIns && this.popupIns.destroy();
let _this = this, dftParams = {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
tools: false,
trigger: 'click',
placement: 'bottom-start',
classes: `${ax.prefix}dropdown`,
autoFill: {
enable: true,
childSel: this.options.childSel,
detectable: this.options.detectable,
key: this.options.valKey,
},
bullet: {
enable: !!this.options.listType,
type: this.options.listType,
unpadded: this.options.unpadded,
hoverable: this.options.hoverable,
divisible: this.options.divisible,
multiline: this.options.multiline,
cols: this.options.cols,
lines: this.options.lines,
action: this.options.action ? this.options.action.bind(this) : null,
},
padding: this.options.divisible || this.options.lines === 'fence' ? false : true,
onInitiated: function () {
_this.options.feature && this.mainEl.setAttribute('feature', _this.options.feature);
}
}, params = extend({
target: dftParams,
source: this.options.popup,
});
this.setFeature(params);
this.popupIns = new Popup(this.targetEl, params);
this.setAttrs();
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
}
setFeature(params) {
if (this.options.feature === 'button') {
params.footer = params.padding = params.autoFill.enable = false;
params.bullet.enable = params.bullet.divisible = true;
params.bullet.type = params.bullet.type || 'custom';
params.placement = 'bottom-center';
params.size = '';
}
else if (this.options.feature === 'tooltip') {
params.footer = params.bullet.enable = false;
params.placement = 'top-center';
params.size = '';
}
else if (this.options.feature === 'select') {
params.footer = params.padding = false;
params.bullet.enable = params.autoFill.enable = params.bullet.divisible = true;
params.bullet.type = 'select-single';
params.placement = 'bottom-center';
params.size = 'sm';
}
}
destroy() {
if (this.destroyed)
return this;
this.popupIns.destroy();
return this;
}
}
let AXTMP_hyphen$1 = config.splitHyphen;
const optRetrieval = [
{
attr: 'keys',
prop: 'keys',
value: '',
},
{
attr: 'props',
prop: 'props',
value: 'label',
},
{
attr: 'fuzzy',
prop: 'fuzzy',
value: true,
},
{
attr: 'order',
prop: 'order',
value: '',
},
{
attr: 'limit',
prop: 'limit',
value: 0,
},
{
attr: 'ignore',
prop: 'ignore',
value: true,
},
{
attr: 'hyphen',
prop: 'hyphen',
value: AXTMP_hyphen$1,
},
{
attr: 'null-handle',
prop: 'nullHandle',
value: 'reset',
},
{
attr: 'highlight',
prop: 'highlight',
value: {
enable: false,
props: 'label',
node: 'i',
classes: `${ax.prefix}c-issue`,
},
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'target',
prop: 'target',
value: '',
},
{
attr: 'editor',
prop: 'editor',
value: '',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'input',
},
{
attr: 'delay',
prop: 'delay',
value: 200,
},
{
attr: 'status',
prop: 'status',
value: {
enable: false,
placement: 'list-top',
},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'bullet',
prop: 'bullet',
value: {
type: 'custom',
childNode: 'div',
unpadded: false,
hoverable: false,
divisible: false,
multiline: false,
},
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-searched',
prop: 'onSearched',
value: null
},
{
attr: 'on-processed"',
prop: 'onProcessed"',
value: null
},
{
attr: 'on-updatedkeys',
prop: 'onUpdatedKeys',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
...optBase
];
class BtnElem extends CompBaseComm {
labelEl;
iconEl;
tailEl;
diskEl;
cubeEl;
imageEl;
badgeEl;
meanEl;
tipsIns;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-badge', comp: BadgeElem }];
static custAttrs = ['type', 'theme', 'href', 'tab', 'target', 'rel', 'download', 'shape', 'size', 'width', 'check', 'icon', 'tail', 'disk', 'cube', 'image', 'tips', 'badge', 'mean', ...this.baseAttrs];
static boolAttrs = ['disabled', 'shaded', 'grad'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, BtnElem);
}
getRawData() {
this.getRawProps(BtnElem);
this.initLabel();
this.getProxyProps();
}
initLabel() {
if (this.innerHTML) {
let child = this.firstElementChild;
if (child && child.nodeName === 'A') {
this.propsRaw.href = child.href;
child.hasAttribute('target') && (this.propsRaw.target = child.target);
child.hasAttribute('rel') && (this.propsRaw.rel = child.rel);
child.hasAttribute('download') && (this.propsRaw.download = child.download);
this.propsRaw.label = child.innerHTML;
}
else {
this.propsRaw.label = this.innerHTML;
}
}
else {
this.propsRaw.label = this.getAttribute('label');
}
}
getWrap(data) {
let obj = { [ax.alias]: 'wrap' }, node = '';
if (!isNull(data.href)) {
node = 'a';
obj.href = data.href;
data.target && (obj.target = data.target);
data.rel && (obj.rel = data.rel);
}
else {
node = 'span';
}
this.wrapEl = createEl(node, obj, this.labelEl);
}
insertIcon(val) {
this.iconEl = createEl('i', { class: val, [ax.alias]: 'icon' });
this.labelEl.insertAdjacentElement('beforeBegin', this.iconEl);
}
insertTail(val) {
this.tailEl = createEl('i', { class: val, [ax.alias]: 'tail' });
this.labelEl.insertAdjacentElement('afterEnd', this.tailEl);
}
insertMean(val) {
this.meanEl = createEl('i', { [ax.alias]: val });
this.wrapEl.appendChild(this.meanEl);
}
insertBadge(val) {
if (!isNull(val) && val !== '0') {
this.badgeEl = createEl('ax-badge', { [ax.alias]: 'badge' }, val?.trim());
this.wrapEl.appendChild(this.badgeEl);
}
}
insertDisk(val) {
if (val) {
this.diskEl = createEl('img', { [ax.alias]: 'disk', src: val });
this.labelEl.insertAdjacentElement('beforeBegin', this.diskEl);
}
}
insertCube(val) {
if (val) {
this.cubeEl = createEl('img', { [ax.alias]: 'cube', src: val });
this.labelEl.insertAdjacentElement('beforeBegin', this.cubeEl);
}
}
insertImage(val) {
if (val) {
this.imageEl = createEl('img', { [ax.alias]: 'image', src: val });
this.labelEl.insertAdjacentElement('beforeBegin', this.imageEl);
}
}
insertTips(val) {
if (val) {
this.tipsIns = new Tooltip(this, {
content: val,
trigger: 'sticky',
deadShow: true,
});
}
}
fillWrap(data) {
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label);
this.getWrap(data);
data.icon ? this.insertIcon(data.icon) : null;
data.tail ? this.insertTail(data.tail) : null;
data.mean ? this.insertMean(data.mean) : null;
data.cube ? this.insertCube(data.cube) : null;
data.image ? this.insertImage(data.image) : null;
data.disk ? this.insertDisk(data.disk) : null;
data.hasOwnProperty('badge') ? this.insertBadge(data.badge) : null;
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
href: this.changedHref,
target: this.changedTarget,
rel: this.changedTarget,
download: this.changedTarget,
tab: this.changedTab,
icon: this.changedIcon,
disk: this.changedDisk,
cube: this.changedCube,
image: this.changedImage,
tips: this.changedTips,
tail: this.changedTail,
mean: this.changedMean,
badge: this.changedBadge,
};
changedLabel(opt) {
this.labelEl.innerHTML = opt.newVal || '';
}
changedHref(opt) {
if (opt.newVal === null || opt.oldVal === null) {
this.innerHTML = '';
this.fillWrap(this.propsProxy);
this.render();
}
else {
this.wrapEl.href = opt.newVal;
}
}
changedTarget(opt) {
if (opt.newVal) {
this.wrapEl.setAttribute(opt.name, opt.newVal);
}
else {
this.wrapEl.removeAttribute(opt.name);
}
}
changedTab(opt) {
opt.newVal ? this.wrapEl.tabIndex = opt.newVal : this.wrapEl.removeAttribute('tabindex');
}
changedIcon(opt) {
if (this.iconEl) {
this.iconEl.setAttribute('class', opt.newVal);
}
else {
this.insertIcon(opt.newVal);
}
}
changedTail(opt) {
if (this.tailEl) {
this.tailEl.setAttribute('class', opt.newVal);
}
else {
this.insertTail(opt.newVal);
}
}
changedDisk(opt) {
if (this.diskEl) {
this.diskEl.setAttribute('src', opt.newVal);
}
else {
this.insertDisk(opt.newVal);
}
}
changedCube(opt) {
if (this.cubeEl) {
this.cubeEl.setAttribute('src', opt.newVal);
}
else {
this.insertCube(opt.newVal);
}
}
changedImage(opt) {
if (this.imageEl) {
this.imageEl.setAttribute('src', opt.newVal);
}
else {
this.insertImage(opt.newVal);
}
}
changedMean(opt) {
if (this.meanEl) {
this.meanEl.setAttribute(ax.alias, opt.newVal);
}
else {
this.insertMean(opt.newVal);
}
}
changedBadge(opt) {
if (this.badgeEl) {
isNull(opt.newVal) || opt.newVal === '0' ? this.badgeEl.remove() : this.badgeEl.setAttribute('label', opt.newVal);
}
else {
this.insertBadge(opt.newVal);
}
}
changedTips(opt) {
if (this.tipsIns) {
this.tipsIns.updateCont(opt.newVal);
if (opt.newVal) {
this.tipsIns.popupIns.state !== 'shown' && this.tipsIns.popupIns.show();
}
else {
this.tipsIns.popupIns.hide();
}
}
else {
opt.newVal ? this.insertTips(this.propsProxy.tips) : null;
}
}
}
class Retrieval extends ModBaseListenCache {
options = {};
mainEl;
inputEl;
statusEl;
inputEvt;
keys;
data;
output;
contXhr;
editorEl;
static hostType = 'none';
static optMaps = optRetrieval;
static dependencies = [RadioElem, CheckboxElem, BadgeElem, BtnElem];
constructor(options = {}, initial = true) {
super();
super.ready({
options,
type: Retrieval.hostType,
maps: Retrieval.optMaps,
component: false,
spread: ['status', 'highlight']
});
this.targetEl = getEl(this.options.target);
this.inputEl = getEl(this.options.editor);
this.statusEl = createEl('div', { class: `${ax.prefix}retrieval-status` });
this.inputEvt = debounce(() => {
let keys = this.getInputVals();
this.updateKeys(keys);
}, this.options.delay);
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.keys = this.options.keys || this.getInputVals();
this.useTpl();
await getContent.call(this, {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.targetEl,
...this.options.ajax
},
cb: (data) => {
if (isEmpty(data))
return this;
this.data = this.getStdData(data);
super.listen({ name: 'processed', params: [this.data] });
this.searchData();
this.render();
}
});
if (elState(this.statusEl).isVirtual && this.options.status.enable) {
if (this.options.status.placement === 'list-top') {
this.targetEl.insertAdjacentElement('beforebegin', this.statusEl);
}
else if (this.options.status.placement === 'list-btm') {
this.targetEl.insertAdjacentElement('afterend', this.statusEl);
}
else if (this.options.status.placement === 'editor-top') {
this.editorEl && this.editorEl.insertAdjacentElement('beforebegin', this.statusEl);
}
else if (this.options.status.placement === 'editor-btm') {
this.editorEl && this.editorEl.insertAdjacentElement('afterend', this.statusEl);
}
else {
let target = getEl(this.options.status.placement);
target && target.appendChild(this.statusEl);
}
}
this.input2Render();
super.listen({ name: 'initiated', cb });
return this;
}
setEmpty() {
this.targetEl && (this.targetEl.innerHTML = '');
}
setAttrs() {
if (this.targetEl) {
this.targetEl.classList.add(`${ax.prefix}retrieval`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
}
}
getStdData(data) {
let dataType = getDataType(data), result = [];
if (dataType === 'String') {
let tmp = valToArr(data, this.options.hyphen, false);
result = tmp.filter(Boolean).map((k) => {
let obj = { label: k, value: k };
return obj;
});
}
else if (dataType === 'Array') {
if (data.length === 0)
return [];
let childType = getDataType(data[0]);
if (['String', 'Number'].includes(childType)) {
result = data.filter(Boolean).map((k) => {
let obj = { label: k + '', value: k + '' };
return obj;
});
}
else if (childType === 'Object') {
if (data[0].hasOwnProperty('label')) {
result = data.filter(Boolean).map((k) => {
!k.hasOwnProperty('value') && (k.value = k.label);
return k;
});
}
else {
console.error(`The object array must contain the "label" property.`);
result = [];
}
}
else {
console.error(`The items in the object array must be either strings or objects containing the "label" property.`);
result = [];
}
}
else {
console.error(`The data type received is incorrect; a string, string array, or object array is required.`);
result = [];
}
return result;
}
searchData(keys = this.keys, data = this.data) {
if (this.destroyed)
return this;
if (isEmpty(keys) && this.options.nullHandle === 'reset') {
this.output = data.map((k) => {
return { source: k, weight: 0, keys: [] };
});
}
else {
this.output = arrSearch({
keys,
props: this.options.props,
source: data,
hyphen: this.options.hyphen,
fuzzy: this.options.fuzzy,
ignore: this.options.ignore,
order: this.options.order,
limit: this.options.limit
});
}
for (let k of this.output) {
k.source.el = this.createItemEl(k);
k.source.action && k.source.action.call(this, k);
}
this.updateStatus();
super.listen({ name: 'searched', params: [this.output] });
}
useTpl() {
let tplEl = getEl(this.options.tplStr);
this.tplEng = this.options.tplEng || renderTpl;
this.tplStr = tplEl?.innerHTML || this.options.tplStr || bulletTools.getIBulletTpl(this.options.bullet);
}
createItemEl(item) {
let tplData = this.options.highlight.enable ? this.getHighlightData(item) : item.source, html = super.getTplcont(tplData);
return tplToEl(html);
}
getHighlightData(data) {
if (!this.options.highlight.enable)
return data;
let props = getIntArr([valToArr(this.options.highlight.props, this.options.hyphen, false), valToArr(this.options.props, this.options.hyphen, false)]), copy = { ...data.source }, keys = data.keys.map((k) => clearRegx(k)).filter(Boolean);
for (let k in copy) {
if (props.includes(k) && keys.length !== 0) {
copy[k] = super.replaceMult(copy[k], keys, { ignore: this.options.ignore, nodename: this.options.highlight.node, classes: this.options.highlight.classes });
}
}
return copy;
}
async render(data = this.output) {
if (this.destroyed)
return this;
isEmpty(data) && console.warn('There is no content to render, but no errors occurred!');
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, data, this.targetEl);
resp && (data = resp);
}
if (this.targetEl) {
this.targetEl.innerHTML = '';
data.length > 0 && this.targetEl.append(...data.map((k) => k.source.el));
super.listen({ name: 'rendered', params: [data, this.targetEl] });
}
this.renderCount++;
}
updateKeys(keys = this.getInputVals()) {
if (this.destroyed || keys.toString() == this.keys.toString())
return this;
this.keys = keys;
this.searchData();
this.render();
super.listen({ name: 'updatedKeys', params: [keys] });
}
input2Render() {
if (!this.inputEl || this.destroyed)
return this;
this.inputEl.removeEventListener(this.options.trigger, this.inputEvt);
this.inputEl.addEventListener(this.options.trigger, this.inputEvt, false);
}
getInputVals() {
if (['radio', 'checkbox', 'radio-comp', 'checkbox-comp'].includes(this.inputEl.type)) {
return this.inputEl.checked ? this.inputEl.value : '';
}
else {
return this.inputEl?.value || '';
}
}
resetList() {
if (this.destroyed)
return this;
this.output = this.data.map((k) => {
return { source: k, weight: 0, keys: [] };
});
for (let k of this.output) {
k.source.el = this.createItemEl(k);
k.source.action && k.source.action.call(this, k);
}
this.render();
}
clearList() {
if (this.destroyed)
return this;
if (this.inputEl) {
this.inputEl?.clear ? this.inputEl.clear() : this.inputEl.value = '';
}
this.keys = '';
this.output = [];
this.render();
}
updateStatus() {
let data = { value: this.output.length, keys: this.keys };
this.statusEl.innerHTML = isEmpty(data.keys) ? this.options.lang.nullKeys : renderTpl(this.options.lang.status, data);
}
async updateCont(content, cb) {
if (this.destroyed)
return this;
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.targetEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
if (isEmpty(data))
return this;
this.data = this.getStdData(data);
super.listen({ name: 'processed', params: [this.data] });
this.searchData();
this.render();
this.updateCache({ content });
this.listen({ name: 'updatedCont', cb, params: [data] });
}
});
return this;
}
destroy(cb) {
if (this.inputEl) {
this.inputEl.removeEventListener(this.options.trigger, this.inputEvt);
}
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optAutocomplete = [
{
attr: 'field',
prop: 'field',
value: 'value',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'popup',
prop: 'popup',
value: {},
},
{
attr: 'retrieval',
prop: 'retrieval',
value: {},
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-hidden',
prop: 'onHidden',
value: null,
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null,
},
{
attr: 'on-reset2show',
prop: 'onReset2Show',
value: null,
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null,
},
...optBase
];
class Autocomplete extends ModBaseListenCache {
options = {};
mainEl;
rendered;
popupIns;
retrievalIns;
contXhr;
static hostType = 'node';
static optMaps = optAutocomplete;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
host: elem,
maps: Autocomplete.optMaps,
component: false,
spread: []
});
this.rendered = false;
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
if (!this.targetEl)
return this;
super.getDirRtl();
this.createPopup();
this.createRetrieval();
this.setAttrs();
super.listen({ name: 'initiated', cb });
return this;
}
setVals(val) {
let nodeName = this.targetEl.nodeName;
if (['AX-INPUT', 'AX-TEXTAREA'].includes(nodeName)) {
this.targetEl.setAttribute('value', val);
}
else if (['INPUT', 'TEXTAREA'].includes(nodeName)) {
this.targetEl.value = val;
}
}
setEmpty() {
this.popupIns && this.popupIns.destroy();
this.popupIns?.contEl && (this.popupIns.contEl.innerHTML = '');
this.retrievalIns && this.retrievalIns.destroy();
}
setAttrs() {
this.popupIns.mainEl.classList.add(`${ax.prefix}autocomplete`);
}
createPopup() {
this.popupIns = new Popup(this.targetEl, extend({
target: {
placement: this.isRtl ? 'bottom-end' : 'bottom-start',
tools: { enable: true, placement: 'outside' },
pageClose: false,
footer: false,
trigger: 'input',
content: '',
padding: false,
b4Show: () => {
return new Promise((resolve) => {
if (this.rendered) {
resolve();
}
else {
this.popupIns.state = 'hidden';
}
});
},
onHidden: () => {
this.rendered = false;
}
},
source: this.options.popup
}));
}
createRetrieval() {
this.retrievalIns = new Retrieval(extend({
target: {
target: this.popupIns.contEl,
editor: this.targetEl,
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: this.options.ajax,
tplStr: this.options.tplStr,
tplEng: this.options.tplEng,
status: true,
highlight: true,
nullHandle: 'clear',
bubble: {
divisible: true,
hoverable: true,
},
},
source: this.options.retrieval
}));
this.retrievalIns.on('rendered', (data) => {
for (let k of data) {
k.source.el.onclick = async () => {
let val = k.source[this.options.field];
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, k, this.targetEl);
resp && (val = resp);
}
this.setVals(val);
this.hide();
};
}
if (this.retrievalIns.renderCount > 0) {
this.rendered = true;
this.retrievalIns.getInputVals().trim() && this.popupIns.show();
this.rendered = false;
}
});
}
reset2Show(cb) {
if (this.destroyed)
return this;
this.retrievalIns.resetList();
this.show();
super.listen({ name: 'reset2Show', cb });
return this;
}
clear(cb) {
if (this.destroyed)
return this;
this.retrievalIns.clearList();
this.hide();
super.listen({ name: 'cleared', cb });
return this;
}
show(cb) {
if (this.destroyed)
return this;
this.rendered = true;
this.popupIns.show();
super.listen({ name: 'shown', cb });
return this;
}
hide(cb) {
if (this.destroyed)
return this;
this.popupIns.hide();
super.listen({ name: 'hidden', cb });
return this;
}
updateCont(content, cb) {
if (this.destroyed)
return this;
this.retrievalIns.updateCont(content, (data) => {
this.updateCache({ content });
this.listen({ name: 'updatedCont', cb, params: [data] });
});
return this;
}
destroy(cb) {
this.retrievalIns.destroy();
this.popupIns.destroy();
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optScroll = [
{
attr: 'wrapper',
prop: 'wrapper',
value: '',
},
{
attr: 'flow',
prop: 'flow',
value: 'v',
},
{
attr: 'bounce',
prop: 'bounce',
value: true,
},
{
attr: 'delay',
prop: 'delay',
value: 200,
},
{
attr: 'gridded',
prop: 'gridded',
value: false,
},
{
attr: 'snap',
prop: 'snap',
value: {
enable: false,
mode: 'auto',
force: false,
offset: 0,
selector: '',
},
},
{
attr: 'drift',
prop: 'drift',
value: {
enable: false,
mode: 'auto',
value: 0,
coef: 2,
},
},
{
attr: 'swipe',
prop: 'swipe',
value: {
enable: false,
mode: 'auto',
value: 0,
coef: 2,
},
},
{
attr: 'bar',
prop: 'bar',
value: {
enable: false,
sticky: false,
triggerable: true,
},
},
{
attr: 'dmp-ratio',
prop: 'dmpRatio',
value: 0.5,
},
{
attr: 'initial',
prop: 'initial',
value: {
value: null,
mode: 'scroll',
},
},
{
attr: 'child',
prop: 'child',
value: {
size: null,
gap: 0,
settable: false,
},
},
{
attr: 'toinit-mode',
prop: 'toInitMode',
value: 'scroll',
},
{
attr: 'duration',
prop: 'duration',
value: 300,
},
{
attr: 'resize-thr',
prop: 'resizeThr',
value: 1,
},
{
attr: 'rtl',
prop: 'rtl',
value: false,
},
{
attr: 'wheel',
prop: 'wheel',
value: {
mode: 'const',
value: 0,
reverse: false,
},
},
{
attr: 'keyboard',
prop: 'keyboard',
value: false,
},
{
attr: 'completed-thr',
prop: 'completedThr',
value: 50,
},
{
attr: 'padding-start',
prop: 'paddingStart',
value: 0,
},
{
attr: 'padding-end',
prop: 'paddingEnd',
value: 0,
},
{
attr: 'insertable',
prop: 'insertable',
value: true,
},
{
attr: 'gesture',
prop: 'gesture',
value: {},
},
{
attr: 'b4-tostart',
prop: 'b4ToStart',
value: null,
},
{
attr: 'b4-toend',
prop: 'b4ToEnd',
value: null,
},
{
attr: 'on-completed',
prop: 'onCompleted',
value: null,
},
{
attr: 'on-exceeded',
prop: 'onExceed',
value: null,
},
{
attr: 'on-start',
prop: 'onStart',
value: null,
},
{
attr: 'on-move',
prop: 'onMove',
value: null,
},
{
attr: 'on-end',
prop: 'onEnd',
value: null,
},
{
attr: 'on-getsnappeds',
prop: 'onGetSnappeds',
value: null,
},
{
attr: 'on-refactored',
prop: 'onRefactored',
value: null,
},
{
attr: 'on-snap',
prop: 'onSnap',
value: null,
},
{
attr: 'on-snapped',
prop: 'onSnapped',
value: null,
},
{
attr: 'on-resized',
prop: 'onResized',
value: null,
},
{
attr: 'on-scroll',
prop: 'onScroll',
value: null,
},
{
attr: 'on-scrolled',
prop: 'onScrolled',
value: null,
},
{
attr: 'on-locate',
prop: 'onLocate',
value: null,
},
{
attr: 'on-located',
prop: 'onLocated',
value: null,
},
...optBase
];
class Scroll extends ModBaseListenCache {
options = {};
forwardMap;
reverseMap;
wrapEl;
snappeds;
unsnappeds;
snapped;
started;
scrolled;
cross;
childAvgSize;
resizeCount;
mutateCount;
canResize;
canMutate;
initialResize;
key2Trans;
resizeListener;
mutationListener;
targetSize;
reverseSize;
wrapSize;
paddingStart;
paddingEnd;
rangeEnd;
rangeStart;
activeSize;
baseSize;
isBaby;
transNow;
transLast;
gap;
barSize;
progress;
trackEl;
thumbEl;
barIns;
gestureIns;
wrapStyleObs;
sizeObs;
lastSnapped;
respThrot;
axis;
tmpTarget;
static hostType = 'node';
static optMaps = optScroll;
constructor(elem, options = {}, initial = config.initial) {
super();
super.ready({
options,
host: elem,
maps: Scroll.optMaps,
component: false,
spread: ['snap', 'drift', 'swipe', 'bar', 'keyboard']
});
this.axis = this.options.flow === 'v' ? 'y' : 'x';
this.forwardMap = propsMap[this.axis];
this.reverseMap = propsMap[this.axis === 'x' ? 'y' : 'x'];
this.wrapEl = this.options.wrapper ? getEl(this.options.wrapper) : this.targetEl.firstElementChild;
if (!this.wrapEl)
return this;
this.snappeds = [];
this.unsnappeds = [];
this.snapped = null;
this.started = false;
this.scrolled = true;
this.cross = '';
this.childAvgSize = null;
this.resizeCount = 0;
this.mutateCount = 0;
this.canResize = true;
this.canMutate = true;
this.initialResize = false;
this.resizeListener = debounce((data) => {
this.resizeCount++;
for (let k of data) {
if (!k.contentRect.width && !k.contentRect.height)
return;
this.response();
}
super.listen({ name: 'resized', params: [data] });
if (this.resizeCount === this.options.resizeThr || (!this.wrapEl.firstElementChild && this.resizeCount === this.options.resizeThr - 1)) {
this.setTransInit();
this.initialResize = true;
super.listen({ name: 'prepared', params: [data] });
}
}, this.options.delay);
this.mutationListener = debounce((data) => {
this.mutateCount++;
for (let k of data) {
if (k.type === "attributes") {
this.updateProg();
this.options.bar.enable && this.updateBarProg();
}
if (k.type === "childList") {
this.options.snap.enable && this.getSnappeds();
this.response();
}
}
super.listen({ name: 'refactored', params: [data] });
}, this.options.delay);
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setEmpty();
this.setAttrs();
this.transNow = this.transLast = 0;
this.gap = toPixel(this.options.child.gap);
this.createBar();
this.updateDiff();
this.initSnapArgs();
this.getSnappeds();
await promiseRaf(() => {
this.getGestureIns();
this.setObserver();
});
super.listen({ name: 'initiated', cb });
return this;
}
initSnapArgs() {
if (!this.options.snap.enable)
return this;
if (this.options.snap.mode === 'auto') {
!this.options.snap.selector && (this.options.snap.selector = '[unalignable]');
}
else {
!this.options.snap.selector && (this.options.snap.selector = '[alignable]');
!this.options.snap.offset && (this.options.snap.offset = 50);
}
}
setEmpty() {
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}scroll`);
this.wrapEl.classList.add(`${ax.prefix}scroll-wrap`);
this.targetEl.setAttribute('flow', this.options.flow);
this.targetEl.toggleAttribute('gridded', this.options.gridded);
this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
}
getGestureIns() {
this.gestureIns = new Gesture(this.wrapEl, extend({
target: {
wheel: true,
keyboard: {
enable: this.options.keyboard,
prev: this.options.flow === 'h' ? (this.isRtl ? 'ArrowRight' : 'ArrowLeft') : 'ArrowUp',
next: this.options.flow === 'h' ? (this.isRtl ? 'ArrowLeft' : 'ArrowRight') : 'ArrowDown',
target: this.targetEl,
},
spy: this.options.keyboard,
step: {
mode: 'translate',
axis: this.axis,
value: this.options.wheel.value,
linkage: false,
duration: this.options.duration,
},
drift: {
enable: this.options.drift.enable,
coef: this.options.drift.coef,
auto: false,
},
swipe: {
enable: this.options.swipe.enable,
coef: 1,
auto: false,
},
initialVal: { [this.axis]: this.transNow },
onStep: (data) => {
this.getStepVal(data.step.direction[this.axis]);
},
onStepped: (data) => {
this.scrollTo({
target: data.translate.value[this.axis],
duration: this.options.duration,
snap: true,
});
},
onTranslate: (data) => {
super.listen({ name: 'start', params: [data.translate] });
},
onTranslating: (data) => {
if (data.translate.diff.h > 2) {
this.transNow = data.translate.value[this.axis];
this.cross = this.crossLinkage();
if (this.cross.includes('baby')) {
if (data.pointer === 'wheel')
return this;
if (this.cross === 'baby-start') {
this.transNow = this.getDmpVals('start+');
}
else if (this.cross === 'baby-start-reverse') {
this.transNow = this.getDmpVals('start-');
}
}
else if (this.cross === 'teen-start') {
if (data.pointer === 'wheel') {
this.toStart();
return this;
}
this.transNow = this.getDmpVals('start+');
}
else if (this.cross === 'teen-end') {
if (data.pointer === 'wheel') {
this.toEnd();
return this;
}
this.transNow = this.getDmpVals('end+');
}
else if (this.cross === 'adult-start') {
if (data.pointer === 'wheel') {
this.toStart();
return this;
}
this.transNow = this.getDmpVals('start+');
}
else if (this.cross === 'adult-end') {
if (data.pointer === 'wheel') {
this.toEnd();
return this;
}
this.transNow = this.getDmpVals('end+');
}
transformTools.set({
el: this.wrapEl,
data: { translate: { [this.axis]: this.transNow } }
});
this.handleExceedLimit({ linkage: this.cross });
super.listen({ name: 'move', params: [data.translate] });
}
},
onTranslated: (data) => {
this.transLast = this.transNow;
this.handleExceedLimit({
start: async (ratio) => {
this.options.b4ToStart && await this.options.b4ToStart.call(this, ratio);
this.toStart();
this.gestureIns.preventEase = true;
},
end: async (ratio) => {
this.options.b4ToEnd && await this.options.b4ToEnd.call(this, ratio);
this.toEnd(undefined, false);
this.gestureIns.preventEase = true;
},
normal: () => {
this.options.snap.enable && !data.translate.canDrfit && this.setSnapped();
}
});
super.listen({ name: 'end', params: [data.translate] });
},
onSwipe: (data) => {
this.setEaseTo(data, 'swipe');
},
onDrift: (data) => {
this.setEaseTo(data);
},
},
source: this.options.gesture,
}));
}
getRtlRange() {
let rtlHandler = () => {
let tmp = this.rangeStart;
this.rangeStart = this.rangeEnd * -1;
this.rangeEnd = tmp * -1;
}, dirAttr = this.targetEl.getAttribute('dir');
if (dirAttr === 'rtl') {
rtlHandler();
this.isRtl = true;
return;
}
if (getRtl()) {
this.isRtl = true;
rtlHandler();
}
}
setTransInit() {
let target = isNull(this.options.initial.value) ? (this.isRtl ? this.rangeStart : this.rangeEnd) : this.options.initial.value, params = { target, snap: true };
this.options.initial.mode === 'localte' ? this.locateTo(params) : this.scrollTo(params);
}
createBar() {
if (this.options.bar.enable) {
if (!this.trackEl) {
this.thumbEl = createEl('span');
this.trackEl = createEl('div', { class: `${ax.prefix}scroll-bar` }, this.thumbEl);
this.options.bar.sticky && this.trackEl.setAttribute('shown', '');
this.targetEl.appendChild(this.trackEl);
}
if (this.options.bar.triggerable && !ax.isTouchScr) {
let prog = 0;
this.barIns = new Gesture(this.trackEl, {
onTranslate: () => {
prog = this.progress;
this.trackEl.setAttribute('scrolling', '');
},
onTranslating: (data) => {
this.locateTo({
target: prog + data.translate.value[this.axis] / this.barSize.diff,
isRatio: true,
});
},
onTranslated: () => {
this.trackEl.removeAttribute('scrolling');
}
});
}
}
}
setObserver() {
this.wrapStyleObs = new MutationObserver(mutations => {
this.canMutate && this.mutationListener(mutations);
});
this.wrapStyleObs.observe(this.wrapEl, {
childList: true,
attributes: true,
attributeFilter: ['style']
});
this.sizeObs = new ResizeObserver((entries) => {
this.canResize && this.resizeListener(entries);
});
this.sizeObs.observe(this.targetEl);
this.sizeObs.observe(this.wrapEl);
}
response() {
this.updateDiff();
if (this.isBaby) {
this.toStart();
}
else if (this.wrapEl[this.forwardMap.offset] > this.paddingStart) {
this.toStart();
}
else if (this.transNow < this.rangeStart) {
this.toEnd(undefined, false);
}
else {
this.options.snap.enable && this.setSnapped();
}
}
getDmpVals(placement) {
let val = 0, dmp = this.options.dmpRatio ** 2;
if (placement === 'start+') {
val = this.options.bounce ? this.paddingStart * super.getRtlCoef() + (this.transNow - this.paddingStart * super.getRtlCoef()) * dmp : this.paddingStart;
}
else if (placement === 'end+') {
let tmp = this.isRtl ? this.rangeEnd : this.rangeStart;
val = this.options.bounce ? tmp + (this.transNow - tmp) * dmp : tmp;
}
else if (placement === 'start-') {
val = this.options.bounce ? this.paddingStart * super.getRtlCoef() - (this.paddingStart * super.getRtlCoef() - this.transNow) * dmp : this.paddingStart;
}
return val;
}
getTruePadding(val) {
let result;
if (val === 'center') {
let firstSize = ~~(style(this.wrapEl.firstElementChild)[this.forwardMap.size]).replace('px', ''), value = !isNull(this.childAvgSize) ? this.childAvgSize : firstSize;
result = (this.targetSize - value) / 2;
}
else if (typeof val === 'number') {
if (val <= 0) {
result = 0;
}
else if (val < 1) {
result = this.targetSize * val;
}
else {
result = val;
}
}
else if (typeof val === 'string') {
result = toPixel(val);
}
return result;
}
setChildSize() {
let getVal = (val) => {
let type = typeof val;
if (type === 'string') {
if (val.includes('/')) {
let avg = ~~(val.split('/')[1].trim());
return avg <= 1 ? this.targetSize : (this.targetSize - (avg - 1) * this.gap) / avg;
}
else {
return toPixel(val);
}
}
else if (type === 'number') {
return val < 0 ? 0 : (val <= 1 && val >= 0) ? this.targetSize * val : val;
}
else {
return null;
}
};
if (!isEmpty(this.options.child.size)) {
let children = [...this.wrapEl.children];
if (Array.isArray(this.options.child.size)) {
if (this.options.child.settable) {
let vals = this.options.child.size.map((k) => getVal(k));
children.forEach((k, i) => {
!isNull(vals[i]) && (k.style[this.forwardMap.size] = vals[i] + 'px');
});
}
}
else {
let val = getVal(this.options.child.size);
this.childAvgSize = val;
if (!isNull(val) && this.options.child.settable) {
for (let k of children) {
k.style[this.forwardMap.size] = val + 'px';
}
}
}
}
}
updateDiff() {
let targetStyle = style(this.targetEl), wrapStyle = style(this.wrapEl), targetHeight = parseInt(targetStyle.height), wrapHeight = parseInt(wrapStyle.height), targetWidth = parseInt(targetStyle.width), wrapWidth = parseInt(wrapStyle.width), outerSize = 0, reverseSize = 0, innerSize = 0;
if (this.axis === 'x') {
outerSize = targetWidth;
reverseSize = targetHeight;
innerSize = wrapWidth;
}
else if (this.axis === 'y') {
outerSize = targetHeight;
reverseSize = targetWidth;
innerSize = wrapHeight;
}
this.targetSize = outerSize;
this.reverseSize = reverseSize;
this.wrapSize = innerSize;
this.setChildSize();
this.paddingStart = this.getTruePadding(this.options.paddingStart);
this.paddingEnd = this.getTruePadding(this.options.paddingEnd);
if (this.paddingStart + this.paddingEnd >= outerSize) {
this.paddingStart = this.paddingEnd = 0;
console.warn('The combined padding values on both sides exceed the container size; padding values have been removed!');
}
this.rangeEnd = this.paddingStart;
this.rangeStart = outerSize - innerSize - this.paddingEnd;
this.isBaby = outerSize - innerSize - this.paddingEnd - this.paddingStart > 0;
this.getRtlRange();
this.activeSize = this.isBaby ? 0 : this.rangeEnd - this.rangeStart;
this.baseSize = this.targetSize - this.paddingStart - this.paddingEnd;
this.updateProg();
this.getBarSize();
this.updateBarProg();
}
getNowTargetDist(target) {
if (!target)
return 0;
let targetType = getDataType(target);
if (targetType === 'Number') {
return Math.abs(target - this.transNow);
}
else if (targetType.includes('HTML')) {
if (this.isRtl) {
return Math.abs(this.getChildParentOffset(target) + this.transNow + this.rangeStart);
}
else {
return Math.abs(this.getChildParentOffset(target) + this.transNow - this.rangeEnd);
}
}
else {
return 0;
}
}
setEaseTo(data, type = 'drift') {
data[type].value[this.axis] = this.getEaseDist(data.translate.direction[this.axis], this.getEdgeValue(data[type].value[this.axis]), type);
let target = (this.options.snap.enable && this.options.snap.mode === 'auto') ? this.getNearestSnap(data[type].value[this.axis]).nearest : data[type].value[this.axis];
this.scrollTo({
target,
snap: true,
});
}
getEaseDist(dir, value, type = 'drift') {
let result = value;
if (this.options[type].mode === 'ratio') {
let dft = this.options[type].value || 1;
result = this.transNow + this.baseSize * dft * dir;
}
else if (this.options[type].mode === 'const') {
this.options[type].value && (result = this.transNow + this.options[type].value * dir);
}
else if (this.options[type].mode === 'snap' && this.options.snap.enable && this.options.snap.mode === 'auto') {
let tmp = this.getEaseNextTrans(dir, type);
!isNull(tmp) && (result = tmp);
}
else if (this.options[type].mode === 'slide') {
let tmp = this.getEaseNextTrans(dir, type, 'slide');
!isNull(tmp) && (result = tmp);
}
return result;
}
getEaseNextTrans(dir, type = 'drift', mode = 'snap') {
let result = null, chidlren = mode === 'slide' ? [...this.wrapEl.children] : this.snappeds, nearest = mode === 'slide' ? this.getNearestSlide() : this.snapped, idx = chidlren.findIndex((k) => k === nearest);
if (idx > -1) {
let num = [0, 1].includes(this.options[type].value) ? 1 : this.options[type].value, dist = dir === 1 ? this.getNowTargetDist(chidlren[idx - num]) : dir === -1 ? this.getNowTargetDist(chidlren[idx + num]) * -1 : 0;
result = this.transNow + dist;
}
return result;
}
getStepVal(dir) {
if (this.options.wheel.mode === 'ratio') {
let dft = this.options.wheel.value || 0.25, val = this.baseSize * dft;
this.gestureIns.stepVal = val;
}
else if (this.options.wheel.mode === 'const') {
this.options.wheel.value && (this.gestureIns.stepVal = this.options.wheel.value);
}
else if (this.options.wheel.mode === 'snap' && this.options.snap.enable && this.options.snap.mode === 'auto') {
this.getWheelNextTrans(dir);
}
else if (this.options.wheel.mode === 'slide') {
this.getWheelNextTrans(dir, 'slide');
}
this.gestureIns.stepVal = this.gestureIns.stepVal * super.getRtlCoef();
}
getWheelNextTrans(dir, mode = 'snap') {
let chidlren = mode === 'slide' ? [...this.wrapEl.children] : this.snappeds, nearest = mode === 'slide' ? this.getNearestSlide() : this.snapped, idx = chidlren.findIndex((k) => k === nearest);
if (idx > -1) {
let num = [0, 1].includes(this.options.wheel.value) ? 1 : this.options.wheel.value;
this.gestureIns.stepVal = dir === 1 ? this.getNowTargetDist(chidlren[idx + num]) : dir === -1 ? this.getNowTargetDist(chidlren[idx - num]) : 0;
}
}
getEdgeValue(data, isRatio = false) {
let value = this.isRtl ? this.rangeStart : this.rangeEnd;
if (this.isBaby)
return value;
let dataType = getDataType(data);
if (dataType.includes('HTML') || dataType === 'String') {
let el = getEl(data, this.targetEl);
el && (value -= this.getChildParentOffset(el));
}
else {
if (isRatio) {
let ratio = clampVal({ min: 0, max: 1, val: data });
value = this.rangeEnd - this.activeSize * ratio;
}
else {
value = data;
}
}
if (value || value === 0) {
if (value >= this.rangeEnd) {
value = this.rangeEnd;
}
else if (value <= this.rangeStart) {
value = this.rangeStart;
}
}
return value;
}
updateProg(value = this.transNow) {
if (this.activeSize <= 0) {
this.progress = 1;
}
else {
this.progress = (this.isRtl ? (value - this.rangeStart) : (this.rangeEnd - value)) / this.activeSize;
}
}
getBarSize() {
if (this.options.bar.enable) {
let track = parseInt(style(this.trackEl)[this.forwardMap.size]), ratio = Math.min(this.baseSize / this.wrapSize, 1), thumb = track * ratio;
this.barSize = { track, thumb, diff: track - thumb };
}
}
updateBarProg() {
if (this.options.bar.enable) {
let exceedRatio = this.progress < 0 ? Math.abs(this.progress) : this.progress > 1 ? this.progress - 1 : 0, progress = (this.progress >= 0 || this.progress <= 1) ? this.progress : 1, exceedSize = this.barSize.thumb * (1 - exceedRatio ** 2), thumbPos = (this.barSize.track - exceedSize) * progress;
this.thumbEl.style[this.forwardMap.size] = exceedSize + 'px';
this.thumbEl.style[this.forwardMap.start] = thumbPos + 'px';
}
}
exceedListen(ratio, placement) {
this.listen({ name: 'exceeded', params: [ratio, placement] });
ratio >= 1 && this.listen({ name: 'completed', params: [ratio, placement] });
}
handleExceedLimit({ start, end, normal, linkage }) {
let ratio = 0, cross = linkage || this.crossLinkage();
if (cross.includes('start')) {
ratio = Math.abs(this.transNow / this.options.completedThr);
start && start(ratio.toFixed(2));
linkage && this.exceedListen(toNumber(ratio, { places: 2 }), 'start');
}
else if (cross.includes('end')) {
ratio = Math.abs(this.transNow * super.getRtlCoef() - this.rangeStart) / this.options.completedThr;
end && end(ratio.toFixed(2));
linkage && this.exceedListen(toNumber(ratio, { places: 2 }), 'end');
}
else {
normal && normal();
}
}
crossLinkage(value = this.transNow) {
let result = 'regular';
value = value * super.getRtlCoef();
if ((this.isRtl ? -this.rangeEnd : this.rangeStart) > 0) {
if (this.isBaby) {
if (value > this.paddingStart) {
result = 'baby-start';
}
else {
result = 'baby-start-reverse';
}
}
else {
if (value > this.paddingStart) {
result = 'teen-start';
}
else if (value < this.isRtl ? -this.rangeEnd : this.rangeStart) {
result = 'teen-end';
}
}
}
else {
if (value > this.paddingStart) {
result = 'adult-start';
}
else if (value < (this.isRtl ? -this.rangeEnd : this.rangeStart)) {
result = 'adult-end';
}
}
return result;
}
toStart(duration, snap = true) {
if (this.destroyed || this.transNow === this.rangeEnd)
return this;
this.scrollTo({
target: this.paddingStart * super.getRtlCoef(),
snap,
duration: duration || this.options.duration,
after: () => {
super.listen({ name: 'toStart' });
}
});
}
toEnd(duration, snap = true) {
if (this.destroyed || this.transNow === this.rangeStart)
return this;
this.scrollTo({
target: this.isRtl ? this.rangeEnd : this.rangeStart,
snap,
duration: duration || this.options.duration,
after: () => {
super.listen({ name: 'toEnd' });
}
});
}
toPrev() {
if (this.destroyed || this.transNow === this.rangeEnd)
return this;
}
toNext() {
if (this.destroyed || this.transNow === this.rangeStart)
return this;
}
getSnappeds() {
if (this.options.snap.enable) {
if (this.options.snap.mode === 'auto') {
this.unsnappeds = super.single2Els(this.options.snap.selector, this.wrapEl);
this.snappeds = [...this.wrapEl.children].filter(k => !this.unsnappeds.includes(k));
}
else {
this.snappeds = super.single2Els(this.options.snap.selector, this.wrapEl);
}
super.listen({ name: 'getSnappeds', params: [this.snappeds] });
}
}
getChildParentOffset(child, parent = this.wrapEl) {
let tmp = this.isRtl && this.forwardMap.position === 'left' ? 'right' : this.forwardMap.position;
return child.getBoundingClientRect()[tmp] - parent.getBoundingClientRect()[tmp];
}
sortEls(arr, val = this.transNow) {
let tmp = arr.map((k) => {
let offset = Math.abs(val - this.paddingStart * super.getRtlCoef() + this.getChildParentOffset(k));
return { el: k, offset };
});
tmp.sort((a, b) => a.offset - b.offset);
return tmp;
}
getNearestSnap(val = this.transNow) {
let snappeds = this.sortEls(this.snappeds, val), nearest = null;
if (this.options.snap.mode === 'auto') {
if (this.options.snap.offset) {
let temp = snappeds.find((k) => k.offset <= this.options.snap.offset);
nearest = temp ? temp.el : null;
}
else {
nearest = snappeds[0].el;
}
}
else {
nearest = snappeds[0].offset <= this.options.snap.offset ? snappeds[0].el : null;
}
return { nearest, snappeds };
}
getNearestSlide(val = this.transNow) {
let tmp = this.sortEls([...this.wrapEl.children], val);
return tmp[0]?.el;
}
setSnapped(options = {}) {
if (this.destroyed || this.wrapEl.children.length === 0 || !this.options.snap.enable)
return this;
this.scrolled = false;
let opt = Object.assign({ force: this.options.snap.force }, options), current = this.getNearestSnap(), snappeds = current.snappeds, nearest = current.nearest, toEl = opt.target ? getEl(opt.target, this.wrapEl) : null, target = this.tmpTarget || toEl || nearest;
if (!nearest || !target)
return this;
if (target !== this.snapped || opt.force) {
this.toggleSnappedAttr(target, snappeds);
super.listen({ name: 'snap', cb: opt.before, params: [target] });
this.tmpTarget = null;
}
this.scrollTo({
target,
duration: opt.duration || this.options.duration,
after: () => {
if (target === this.snapped) {
super.listen({ name: 'snapped', cb: opt.after, params: [target] });
}
}
});
}
toggleSnappedAttr(target, snappeds = this.getNearestSnap().snappeds) {
let el = getEl(target, this.wrapEl), last;
if (el) {
el.setAttribute('snapped', '');
last = snappeds.find(k => k.el !== el && k.el.hasAttribute('snapped'));
last && last.el.removeAttribute('snapped');
this.snapped = el;
}
}
scrollTo({ target = this.transNow, duration, before, after, snap = false, isRatio = false }) {
if (this.destroyed)
return this;
this.scrolled = false;
let trans = this.getEdgeValue(this.tmpTarget || target, isRatio);
if (this.transNow === trans)
return;
let now = this.transNow, compare = Math.abs(this.transNow - trans) / this.targetSize, dur = duration || duration == 0 ? duration : Math.trunc(this.options.duration * compare);
this.wrapEl.style.transitionDuration = clampVal({ val: dur, min: 200, max: 2000 }) + 'ms';
transformTools.set({ el: this.wrapEl, data: { translate: { [this.axis]: trans } } });
super.listen({ name: 'scroll', cb: before, params: [trans, now] });
this.transLast = this.transNow = trans;
delay({
duration: dur,
done: () => {
if (this.options.snap.enable) {
snap ? this.setSnapped() : this.getNearestSnap();
}
super.listen({ name: 'scrolled', cb: after, params: [trans, now] });
this.scrolled = true;
this.tmpTarget = null;
}
});
}
locateTo({ target = this.transNow, before, after, snap = false, isRatio = false }) {
if (this.destroyed)
return this;
let trans = this.getEdgeValue(this.tmpTarget || target, isRatio);
if (this.transNow === trans)
return;
let now = this.transNow;
this.wrapEl.style.transitionDuration = '0ms';
transformTools.set({ el: this.wrapEl, data: { translate: { [this.axis]: trans } } });
super.listen({ name: 'locate', cb: before, params: [trans, now] });
this.transLast = this.transNow = trans;
if (this.options.snap.enable) {
snap ? this.setSnapped() : this.getNearestSnap();
}
this.tmpTarget = null;
super.listen({ name: 'located', cb: after, params: [trans, now] });
}
destroy(cb) {
if (this.destroyed)
return this;
this.sizeObs.disconnect();
this.wrapStyleObs.disconnect();
this.options.bar.enable && this.options.bar.triggerable && !ax.isTouchScr && this.barIns.destroy();
this.gestureIns.destroy();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optMasonry = [
{
attr: 'gap',
prop: 'gap',
value: 0,
},
{
attr: 'cols',
prop: 'cols',
value: 0,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'media',
prop: 'media',
value: {
title: '',
brief: '',
},
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'on-added',
prop: 'onAdded',
value: null,
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null,
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null,
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null,
},
...optBase
];
class Masonry extends ModBaseListenCache {
options = {};
itemsTmp;
itemsObs;
items;
itemSizeObs;
gap;
canListen;
static hostType = 'node';
static optMaps = optMasonry;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Masonry.optMaps,
host: elem,
component: false,
});
this.itemsTmp = [];
this.itemsObs = new Observe(this.itemsTmp, {
onSet: (data) => {
if (getDataType(data.value).includes('HTML')) {
this.targetEl.appendChild(data.value);
this.itemSizeObs.observe(data.value);
}
},
onDeleted: (data) => { },
onCompleted: () => {
}
});
this.items = this.itemsObs.proxy;
this.itemSizeObs = new ResizeObserver((data) => {
for (let k of data) {
this.updateItemStyle(k.target);
}
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setAttrs();
this.gap = this.getGap();
this.targetEl.style.columnGap = `${this.gap}px`;
if (Array.isArray(this.options.content) && this.options.content.length > 0) {
this.items.push(...this.options.content);
}
else if (this.targetEl.innerHTML.trim()) {
this.items.push(...this.targetEl.children);
}
super.listen({ name: 'initiated', cb });
return this;
}
getGap() {
return Math.ceil(toPixel(this.options.gap || style(this.targetEl).columnGap));
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}masonry`);
classes(this.targetEl).add(this.options.classes);
this.options.cols ? addStyle(this.targetEl, 'grid-template-columns', `repeat(${this.options.cols}, 1fr)`) : removeStyle(this.targetEl, 'grid-template-columns');
}
updateItemStyle(el) {
let height = el.offsetHeight;
el.style.gridRow = `span ${Math.ceil(height + this.gap)}`;
}
setItem(el) {
this.itemSizeObs.observe(el);
}
async add(data, cb) {
if (this.destroyed)
return this;
let tmp = Array.isArray(data) ? data : [data];
this.options.b4Add && await this.options.b4Add.call(this, tmp);
this.items.push(...tmp);
super.listen({ name: 'add', cb, params: [tmp] });
return this;
}
async remove(data, cb) {
if (this.destroyed)
return this;
let tmp = Array.isArray(data) ? data : [data];
this.options.b4Remove && await this.options.b4Remove.call(this, tmp);
for (let k = 0; k < tmp.length; k++) {
let item = tmp[k], idx = this.items.findIndex((k) => k === item);
if (idx > -1) {
this.items.splice(idx, 1);
this.items[idx].remove();
}
}
super.listen({ name: 'remove', cb, params: [tmp] });
return this;
}
async clear(cb) {
if (this.destroyed)
return this;
this.options.b4Clear && await this.options.b4Clear.call(this);
this.items.splice(0);
this.targetEl.innerHTML = '';
super.listen({ name: 'cleared', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.clearCache();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let OCTMP_hyphen$1 = config.splitHyphen;
const optSwipe = [
{
attr: 'flow',
prop: 'flow',
value: 'h',
},
{
attr: 'keyboard',
prop: 'keyboard',
value: false,
},
{
attr: 'active',
prop: 'active',
value: 0,
},
{
attr: 'duration',
prop: 'duration',
value: 500,
},
{
attr: 'throttle',
prop: 'throttle',
value: 0,
},
{
attr: 'slides',
prop: 'slides',
value: 1,
},
{
attr: 'divide',
prop: 'divide',
value: 1,
},
{
attr: 'group',
prop: 'group',
value: 0,
},
{
attr: 'loop',
prop: 'loop',
value: false,
},
{
attr: 'autoHeight',
prop: 'autoHeight',
value: false,
},
{
attr: 'countdown',
prop: 'countdown',
value: {},
},
{
attr: 'gap',
prop: 'gap',
value: 0,
},
{
attr: 'unalign',
prop: 'unalign',
value: '[unalignable]',
},
{
attr: 'centered',
prop: 'centered',
value: {
enable: false,
fill: false,
},
},
{
attr: 'active',
prop: 'active',
value: 0,
},
{
attr: 'keyboard',
prop: 'keyboard',
value: false,
},
{
attr: 'resize-reset',
prop: 'resizeReset',
value: true,
},
{
attr: 'drift',
prop: 'drift',
value: 1,
},
{
attr: 'wheel',
prop: 'wheel',
value: 1,
},
{
attr: 'scroll',
prop: 'scroll',
value: {},
},
{
attr: 'height',
prop: 'height',
value: 0,
},
{
attr: 'width',
prop: 'width',
value: 0,
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
placement: 'right-top',
children: [],
},
},
{
attr: 'total',
prop: 'total',
value: {
enable: false,
placement: 'right-top',
format: `<i></i><s>/</s><u></u>`,
selector: '',
},
},
{
attr: 'pgn',
prop: 'pgn',
value: {
enable: false,
classes: '',
type: 'lamp',
selector: '',
data: [],
before: null,
after: null,
},
},
{
attr: 'nav',
prop: 'nav',
value: {
enable: true,
classes: '',
fill: false,
intvl: 500,
prev: {
selector: '',
classes: '',
text: '',
},
next: {
selector: '',
classes: '',
text: '',
},
},
},
{
attr: 'thumb',
prop: 'thumb',
value: {
content: null,
type: 'swipe',
attribute: 'selected',
mode: 'scroll',
},
},
{
attr: 'zoom',
prop: 'zoom',
value: {
enable: false,
step: 0.5,
min: 0,
max: 10,
value: 2,
selector: '',
},
},
{
attr: 'autoplay',
prop: 'autoplay',
value: {
enable: false,
delay: 4000,
countdown: false,
},
},
{
attr: 'integrated',
prop: 'integrated',
value: false,
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'hyphen',
prop: 'hyphen',
value: OCTMP_hyphen$1,
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'lazy',
prop: 'lazy',
value: false,
},
{
attr: 'media',
prop: 'media',
value: {
title: '',
brief: '',
},
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'on-prepared',
prop: 'onPrepared',
value: null,
},
{
attr: 'on-changed',
prop: 'onChanged',
value: null,
},
{
attr: 'on-paused',
prop: 'onPaused',
value: null,
},
{
attr: 'on-played',
prop: 'onPlayed',
value: null,
},
...optBase
];
const getSlidersData = async function (opts) {
let wrapEl = getEl(opts.wrap), parentEl = getEl(opts.parent), grossData = [];
if (!isEmpty(opts.content)) {
await getContent.call(this, {
content: opts.content,
contType: opts.contType,
contData: opts.contData,
hyphen: opts.hyphen,
ajax: {
xhrName: 'contXhr',
spinSel: parentEl,
...(opts.ajax || {})
},
cb: (data) => {
grossData = data;
}
});
}
else if (wrapEl && wrapEl.innerHTML.trim()) {
grossData = [...wrapEl.children];
}
else {
grossData = [];
}
let fillSlider = async (node, data) => {
let childType = getDataType(data);
if (childType === 'String' || childType === 'Number') {
node.innerHTML = data;
}
else if (childType === 'Object') {
if (data.hasOwnProperty('content')) {
await getContent.call(this, {
content: data.content,
contType: data.contType,
contData: data.contData,
hyphen: data.hyphen || opts.hyphen,
ajax: {
xhrName: 'contXhr',
spinSel: node,
...(data.ajax || {})
},
cb: (resp) => {
let respType = getDataType(resp);
if (['String', 'Number'].includes(respType)) {
node.innerHTML = resp;
}
else if (respType.includes('HTML')) {
node.appendChild(resp);
}
else if (['Object', 'Array'].includes(respType)) {
node.innerHTML = getStrFromTpl.call(this, resp, data.tplStr, data.tplEng);
}
}
});
}
else {
node.innerHTML = getStrFromTpl.call(this, data);
}
}
else if (childType === 'Array') {
node.innerHTML = getStrFromTpl.call(this, data);
}
}, dataType = getDataType(grossData), result = [];
if (dataType.includes('HTML')) {
result = [{ source: grossData, slider: grossData }];
}
else if (dataType === 'String') {
let tmp = createEl('div', '', grossData), els = [...(tmp.querySelector('ul,ol') || tmp).children];
result = els.map((k) => {
return { source: k, slider: k };
});
}
else if (dataType === 'Array' || dataType === 'Object') {
let tmp = (dataType === 'Object') ? [grossData] : grossData.filter((k) => !isNull(k));
if (tmp.length === 0)
return;
result = tmp.map((k) => {
let childType = getDataType(k), slider;
if (childType.includes('HTML')) {
slider = k;
}
else {
slider = createEl('li');
if (opts.lazy) {
k.spy = new Spy(slider, {
root: parentEl || wrapEl,
repeat: false,
onIn: () => {
fillSlider(slider, k);
}
});
}
else {
fillSlider(slider, k);
}
}
return { source: k, slider };
});
}
opts.cb && opts.cb(result);
return result;
};
class Swipe extends ModBaseListenCache {
options = {};
intercepted;
button;
content;
folded;
handlers;
html;
pureHtml;
event;
text;
ell;
countdownEl;
intervalEvt;
startClone;
endClone;
sliderTpl;
prepareListen;
resetListener;
setBulletActive;
spyIns;
slidersTmp;
bulletsTmp;
paused;
scrollOpt;
scrollIns;
wrapEl;
navEl;
pgnEl;
pgnIns;
prevEl;
nextEl;
totalEl;
numEl;
denEl;
bullets;
bulletSeq;
interval;
countdownIns;
toolsEl;
keyToSwipe;
sliders;
group;
actIdx;
slidersObs;
bulletsObs;
slideSize;
slideSizeDivide;
slides;
totalClone;
thumbIns;
thumbs;
setSnapEvt;
zoomIns;
canZoom;
snapSlider;
prepared;
static hostType = 'node';
static optMaps = optSwipe;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Swipe.optMaps,
host: elem,
component: true,
spread: ['autoplay', 'total', 'tools', 'pgn', 'nav', 'centered', 'zoom']
});
this.countdownEl = createEl('div');
this.intervalEvt = () => {
this.toNextBullet();
this.startCountdown();
};
this.startClone = [];
this.endClone = [];
this.sliderTpl = { label: '', content: '', thumb: '', brief: '', slider: null, cb: null };
this.snapSlider = {};
this.prepareListen = throttle(() => {
this.fillWedgets();
this.setBulletActive(this.bullets.find((k) => this.actIdx === k.index) || 0);
this.toggleNavDisabled();
this.targetEl.classList.remove(`${ax.prefix}initiating`);
this.setAutoPlay();
this.prepared = true;
super.listen({ name: 'prepared' });
});
this.resetListener = throttle(() => {
this.getSingleSize();
this.setSlideSize();
(this.group > this.sliders.length) && (this.group = this.sliders.length);
super.listen({ name: 'resized' });
});
this.setBulletActive = (data) => {
let bullet = this.findBullet(data);
if (!bullet || bullet.active)
return;
bullet.active = true;
let other = this.bullets.find((k) => k !== bullet && k.active);
other && Reflect.deleteProperty(other, 'active');
};
let _this = this;
this.setSnapEvt = function () {
let idx = _this.thumbs.findIndex((k) => k === this);
_this[_this.options.thumb.mode === 'locate' ? 'toLocate' : 'toSnap'](idx);
};
super.listen({ name: 'constructed' });
if (initial) {
if (this.options.lazy) {
this.spyIns = new Spy(this.targetEl, {
repeat: false,
onIn: () => {
this.init();
}
});
}
else {
this.init();
}
}
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.slidersTmp = [];
this.bulletsTmp = [];
this.paused = true;
this.setAttrs();
this.createWrap();
await this.getSliders(this.options.content, (resp) => {
this.slidersTmp = resp;
});
this.setSlidesObs();
this.setBulletsObs();
this.actIdx = this.getIdxFromActive(this.options.active);
this.appendSliders();
this.group = clampVal({ val: this.options.group, min: 0, max: this.sliders.length });
this.setScroll();
this.getThumbSlides();
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
classes(this.targetEl).add(`${ax.prefix}swipe,${ax.prefix}initiating`);
this.options.width && (this.targetEl.style.width = (isNaN(this.options.width) ? this.options.width : this.options.width + 'px'));
this.options.height && (this.targetEl.style.height = (isNaN(this.options.height) ? this.options.height : this.options.height + 'px'));
}
getDriftParams() {
if (this.group)
return { enable: true, mode: 'snap', value: 1 };
let tmp = { mode: 'auto', coef: 6 };
if (typeof this.options.drift === 'number' && this.options.drift > 0) {
tmp = { mode: 'snap', value: this.options.divide * this.options.drift };
}
else if (this.options.drift === 'viewport' && this.options.slides > 0) {
tmp = { mode: 'snap', value: this.options.slides * this.options.divide };
}
return { enable: true, ...tmp };
}
getWheelVal() {
return this.options.divide * (this.group ? 1 : this.options.wheel);
}
getZoomEl(data) {
let tmp = getEl(this.options.zoom.selector, data.slider);
return this.options.zoom.selector ? tmp : data.slider.firstElementChild;
}
setZoomVal(slider, value = this.options.zoom.value) {
if (!slider.zoomEl)
return;
slider.zoomEl.style.transitionDuration = `var(--${ax.prefix}dur-3)`;
slider.zoomEl.style.transitionTimingFunction = `var(--${ax.prefix}bez-eo)`;
slider.zoomIns.nowVals.translate = { ...slider.rawTrans.translate };
transformTools.set({
el: slider.zoomEl,
data: { scale: value, translate: slider.zoomIns.nowVals.translate }
});
}
enableZoom() {
if (!this.options.zoom.enable)
return;
this.scrollIns.gestureIns.on('dblclick', (data) => {
let slider = this.sliders.find((k) => k.slider.contains(data.evtTarget)), target = this.getZoomEl(slider);
if (!target)
return;
this.enable2Init(slider);
this.setZoomVal(slider, this.options.zoom.value);
});
}
enable2Init(slider, zoomEl) {
if (!this.options.zoom.enable)
return;
if (!slider.zoomIns) {
slider.zoomEl = zoomEl || this.getZoomEl(slider);
this.setZoomIns(slider);
}
else {
slider.zoomIns.destroyed && slider.zoomIns.init();
}
}
toggleZoom(parent = this.snapSlider, toSet = true) {
let scaleVal = transformTools.get(parent.zoomEl, ['scale']).scale.x, setVal = scaleVal < parent.rawTrans.scale.x || scaleVal === this.options.zoom.value ? parent.rawTrans.scale.x : this.options.zoom.value;
toSet && this.setZoomVal(parent, setVal);
setVal === parent.rawTrans.scale.x && parent.zoomIns.destroy();
}
setZoomIns(parent) {
parent.rawTrans = transformTools.get(parent.zoomEl, ['translate', 'scale', 'rotate']);
parent.zoomIns = new Gesture(parent.zoomEl, {
step: {
mode: 'scale',
value: this.options.zoom.step,
},
wheel: true,
scale: {
enable: true,
min: this.options.zoom.min || parent.rawTrans.scale.x,
max: this.options.zoom.max,
},
viewport: {
enable: true,
selector: parent.slider,
},
onDblclick: (data) => {
this.toggleZoom(parent);
},
onScaling: (data) => {
transformTools.set({
el: data.target,
data: { scale: data.scale.value }
});
},
onTranslating: (data) => {
transformTools.set({
el: data.target,
data: { translate: data.translate.value }
});
}
});
}
setScroll() {
this.scrollOpt = extend({
target: {
wrapper: this.wrapEl,
gridded: this.options.divide > 1 ? true : false,
flow: this.options.flow,
keyboard: this.options.keyboard,
snap: {
enable: true,
selector: this.options.unalign,
},
wheel: {
mode: 'snap',
value: this.getWheelVal(),
},
drift: this.getDriftParams(),
initial: {
value: this.getInitSlider(),
},
duration: this.options.duration,
resizeThr: this.options.slides > 0 ? 2 : 1,
paddingStart: this.options.centered.enable ? 'center' : 0,
paddingEnd: this.options.centered.enable ? 'center' : 0,
child: { size: (this.options.slides > 0 ? `1 / ${this.options.slides}` : null), gap: this.options.gap },
onGetSnappeds: function () {
},
onPrepared: this.prepareListen,
onRefactored: this.resetListener,
onResized: this.resetListener,
onInitiated: () => {
this.enableZoom();
},
onSnap: (slider) => {
this.actIdx = Math.max(this.sliders.findIndex((k) => k.slider === slider), 0);
if (this.scrollIns.initialResize) {
this.setBulletActive(slider);
}
(this.options.autoHeight && this.options.flow === 'h') && (this.targetEl.style.height = style(slider).height);
if (this.thumbs.length) {
this.thumbIns && !isChildVisible(this.thumbIns.targetEl, this.thumbIns.sliders[this.actIdx].slider) && this.thumbIns.toSnap(this.actIdx);
for (let [i, k] of this.thumbs.entries())
k.toggleAttribute(this.options.thumb.attribute, this.actIdx !== i ? false : true);
}
for (let k of this.sliders) {
if (k.slider !== slider) {
if (k.zoomIns) {
transformTools.get(k.zoomEl, ['scale']).scale.x !== 1 && this.setZoomVal(k, 1);
k.zoomIns.destroy();
}
for (let i of getEls('video,audio', k.slider))
i.pause();
}
}
this.snapSlider = this.sliders[this.actIdx];
super.listen({ name: 'changed', params: [this.snapSlider, this.actIdx] });
},
onSnapped: (slider) => {
},
onMove: () => {
this.autoPause(true);
}
},
source: this.options.scroll
});
if (this.group && this.options.slides > 1) ;
if (this.options.slides >= 1) ;
this.scrollIns = new Scroll(this.targetEl, this.scrollOpt);
}
async getSliders(data = this.options.content, cb) {
let result = [];
await getSlidersData.call(this, {
content: data,
contType: this.options.contType,
contData: this.options.contData,
ajax: this.options.ajax,
hyphen: this.options.hyphen,
parent: this.targetEl,
wrap: this.wrapEl,
lazy: this.options.lazy,
tplStr: this.options.tplStr,
tplEng: this.options.tplEng,
cb: (resp) => {
result = [...resp];
}
});
cb && cb(result);
return result;
}
findSlider(data) {
let dataType = getDataType(data), result;
if (dataType === 'Number') {
result = this.sliders[data]?.slider;
}
else if (dataType === 'Object') {
result = data?.slider;
}
else {
result = getEl(data, this.wrapEl);
}
return result;
}
appendSliders(data = this.sliders, placement = 'end') {
let target, sliders = data.map((k) => k.slider);
if (placement === 'start') {
sliders.reverse();
for (let k of sliders) {
this.wrapEl.insertAdjacentElement('afterbegin', k);
}
}
else if (placement === 'end') {
this.wrapEl.append(...sliders);
}
else {
target = this.findSlider(placement);
if (target) {
sliders.reverse();
for (let k of sliders) {
target.insertAdjacentElement('afterend', k);
}
}
}
}
createWrap() {
let firstChild = this.targetEl.firstElementChild;
if (firstChild) {
firstChild.classList.add(`${ax.prefix}swipe-wrap`);
this.wrapEl = firstChild;
}
else {
this.wrapEl = createEl('ul', { class: `${ax.prefix}swipe-wrap ${ax.prefix}reset` }, '');
this.targetEl.appendChild(this.wrapEl);
}
if (this.targetEl.querySelector(`.${ax.prefix}swipe-nav`)) {
this.navEl = this.targetEl.querySelector(`.${ax.prefix}swipe-nav`);
}
else if (this.options.integrated) {
this.navEl = createEl('div', { class: `${ax.prefix}swipe-nav` }, '');
this.targetEl.appendChild(this.navEl);
}
}
fillWedgets() {
this.getBullets();
this.fillNav();
this.fillPgn();
this.fillTotal();
}
updateWedgets() {
this.getBullets();
this.updatePgn();
this.updateTotal();
}
setSlidesObs() {
this.slidersObs = new Observe(this.slidersTmp, {
onCompleted: () => {
this.updateGap();
this.updateWedgets();
this.scrollIns.setSnapped({ force: true });
}
});
this.sliders = this.slidersObs.proxy;
}
setBulletsObs() {
this.bulletsObs = new Observe(this.bulletsTmp, {
deep: true,
onSet: (resp) => {
if (resp.key === 'active' && resp.value === true) {
resp.proxy.el.setAttribute('active', '');
this.bulletSeq = this.findPrevNextBullet(resp.proxy);
this.toBullet(resp.proxy);
this.toggleNavDisabled(resp.proxy);
this.numEl && (this.numEl.innerHTML = this.bullets.findIndex((k) => k === resp.proxy) + 1);
}
},
onDeleted: (resp) => {
if (resp.key === 'active') {
resp.target.el.removeAttribute('active');
}
},
onCompleted: () => {
}
});
this.bullets = this.bulletsObs.proxy;
}
getThumbSlides(ins = this.options.thumb.content) {
this.thumbs = [];
if (this.options.thumb.type === 'dom') {
let tmp = getEl(this.options.thumb.content);
tmp && (this.thumbs = [...tmp.children]);
}
else if (this.options.thumb.type === 'dom') {
let isArr = Array.isArray(this.options.thumb.content);
if (isArr) {
this.thumbs = this.options.thumb.content;
}
else {
let tmp = getEls(this.options.thumb.content);
this.thumbs = tmp;
}
}
else if (['step', 'pill'].includes(this.options.thumb.type)) {
let tmp = getEl(this.options.thumb.content);
tmp && (this.thumbs = tmp.content.map((k) => k.wrapEl));
}
else if (this.options.thumb.type === 'swipe') {
let type = getDataType(ins), getInsFromDom = (dom) => {
let tmp = instance.data.find((k) => k.type = k.ins.targetEl === dom);
return tmp ? tmp.ins : null;
};
if (type.includes('HTML')) {
this.thumbs = getEls('li', ins);
this.thumbIns = getInsFromDom(ins);
}
else if (type === 'Instance') {
this.thumbIns = ins;
this.thumbs = ins.sliders.map((k) => k.slider);
}
else if (type === 'String') {
let tmp = getEl(ins);
if (tmp) {
this.thumbIns = getInsFromDom(tmp);
this.thumbs = getEls('li', ins);
}
else {
this.thumbIns = instance.find(ins, 'swipe');
this.thumbIns && (this.thumbs = ins.sliders.map((k) => k.slider));
}
}
}
this.thumbs = this.thumbs.filter((k) => k && getDataType(k).includes('HTML'));
if (!this.thumbs.length)
return;
if (this.thumbIns) {
this.thumbIns.on('prepared', () => {
this.thumbIns.scrollIns.gestureIns.on('click', (data) => {
let tmp = this.thumbs.find((k) => k.contains(data.evtTarget));
tmp && this.setSnapEvt.call(tmp);
});
});
}
else {
for (let k of this.thumbs) {
k.removeEventListener('click', this.setSnapEvt);
k.addEventListener('click', this.setSnapEvt, false);
}
}
}
findPrevNextBullet(data) {
let item = this.findBullet(data);
if (!item)
return { prev: null, next: null };
let idx = this.bullets.findIndex((k) => k === item), prev = this.bullets[idx - 1], next = this.bullets[idx + 1];
if (!prev) {
if (this.options.loop) ;
else if (this.options.autoplay.enable) {
prev = this.bullets.at(-1);
}
}
if (!next) {
if (this.options.loop) ;
else if (this.options.autoplay.enable) {
next = this.bullets[0];
}
}
return { prev, next, current: item };
}
toggleNavDisabled(data) {
if (this.options.loop || !this.options.nav.enable)
return;
if (this.bullets.length < 2) {
this.prevEl.setAttribute('disabled', '');
this.nextEl.setAttribute('disabled', '');
}
else {
let item = this.findBullet(data);
if (!item)
return;
if (item === this.bullets[0]) {
this.prevEl.setAttribute('disabled', '');
this.nextEl.removeAttribute('disabled');
}
else if (item === this.bullets.at(-1)) {
this.nextEl.setAttribute('disabled', '');
this.prevEl.removeAttribute('disabled');
}
else {
this.prevEl.removeAttribute('disabled');
this.nextEl.removeAttribute('disabled');
}
}
}
setSlideSize() {
if (this.options.slides > 0) {
this.sliders.forEach((k) => {
this.setSingleSize(k);
});
}
this.updateGap();
}
updateGap() {
if (this.options.divide > 1) {
this.sliders.forEach((k, i) => {
this.setSingleGap(k, i);
});
}
else {
if (this.options.gap > 0) {
this.sliders.forEach((k) => {
this.setSingleGap(k);
});
}
}
}
getIdxFromActive(active) {
let result = this.getActiveIdex(active);
return clampVal({ val: result, min: 0, max: this.sliders.length - 1 });
}
getActiveIdex(data) {
let result = -1;
if (typeof data === 'number') {
result = data;
}
else {
let tmp = getEl(data, this.targetEl);
tmp && (result = this.sliders.findeIndex((k) => k.slider === tmp));
}
result >= this.sliders.length && (result = -1);
return result;
}
getInitSlider() {
if (this.sliders.length === 0 || this.actIdx === -1)
return null;
if (this.options.centered.enable && this.options.centered.fill) {
if (this.options.slides > 1 && this.actIdx < ~~(this.options.slides / 2)) {
this.actIdx = ~~(this.options.slides / 2);
}
}
return this.sliders[this.actIdx].slider;
}
getAccuracy(value, higher = true) {
let places = value.toString().split(".")[1] ? value.toString().split(".")[1].length : 0;
return places > 3 ? toNumber(value + (higher ? 0.1 : 0), { mode: higher ? 'ceil' : 'floor', places: 1 }) : value;
}
getSingleSize() {
if (this.options.slides > 0) {
this.slideSize = this.getAccuracy(this.scrollIns.childAvgSize, this.scrollIns.gap > 0 ? false : true);
}
if (this.options.divide > 1) {
let netValueDivide = this.scrollIns.reverseSize - this.scrollIns.gap * (this.options.divide - 1), singleValueDivide = netValueDivide / this.options.divide;
this.slideSizeDivide = this.getAccuracy(singleValueDivide, this.scrollIns.gap > 0 ? false : true);
}
}
setSingleSize(item) {
if (!(this.options.slides > 0))
return;
item.slider.style[this.scrollIns.forwardMap.size] = this.slideSize + 'px';
}
setSingleGap(item, index) {
let idx = isNull(index) ? this.sliders.findIndex((k) => k === item) : index;
if (this.options.divide > 1) {
item.slider.style[this.scrollIns.reverseMap.size] = this.getAccuracy(this.slideSizeDivide, false) + 'px';
if (idx % this.options.divide !== 0 && this.scrollIns.gap) {
item.slider.style[this.scrollIns.reverseMap.gap] = this.scrollIns.gap + 'px';
}
idx >= this.options.divide && (item.slider.style[this.scrollIns.forwardMap.gap] = this.scrollIns.gap + 'px');
}
else {
idx !== 0 && (item.slider.style[this.scrollIns.forwardMap.gap] = this.scrollIns.gap + 'px');
}
}
getBullets() {
this.bullets.length = 0;
let unsnappeds = [], len = this.sliders.length;
if (this.options.slides > 0) {
this.sliders.forEach((k, i) => {
let obj = { target: k, el: createEl('li'), index: i };
if (this.options.centered.enable) {
this.bullets.push(obj);
}
else {
if (this.options.loop) {
if (this.group && this.options.slides > 1) {
if (i % (this.options.slides * this.options.divide) === 0) {
this.bullets.push(obj);
}
else {
k.slider.setAttribute(this.options.unalign, '');
}
}
else {
this.bullets.push(obj);
}
}
else {
let num = this.options.divide * (this.group || this.options.slides);
if ((i % num === 0 && this.sliders.length - i >= num) || i === len - num) {
this.bullets.push(obj);
}
else {
if (this.group) {
unsnappeds.push(k.slider);
setSingleSel(k.slider, this.options.unalign);
}
}
}
this.updateUnsnappeds(unsnappeds);
}
});
}
else {
if (this.scrollIns.isBaby) {
this.bullets.push({ target: this.sliders[0], el: createEl('li'), index: 0 });
}
else {
let splits = this.getSplits(), tmp = this.getSanpOffsetArr();
for (let k of tmp) {
for (let v of splits) {
((k.offsetStart <= v && k.offsetEnd > v)) && this.bullets.push({ target: k.target, el: createEl('li'), index: k.index });
}
}
}
}
}
updateUnsnappeds(unsnappeds) {
this.scrollIns.unsnappeds = unique([...this.scrollIns.unsnappeds, ...unsnappeds]);
this.scrollIns.snappeds = [...this.wrapEl.children].filter(k => !this.scrollIns.unsnappeds.includes(k));
}
getSplits() {
let num = Math.floor(this.scrollIns.wrapSize / this.scrollIns.baseSize), getSplits = (num, unit) => {
let result = [];
for (let k = 0; k < num; k++) {
result.push(k * unit);
}
return result;
}, result = getSplits(num, this.scrollIns.baseSize);
result.push(this.scrollIns.wrapSize - this.scrollIns.baseSize);
return result;
}
getSanpOffsetArr() {
let result = [];
this.sliders.forEach((k, i) => {
if (this.scrollIns.snappeds.includes(k.slider)) {
let idx = this.scrollIns.snappeds.findIndex((v) => v === k.slider), nextSnapped = this.scrollIns.snappeds[idx + 1], offsetStart = k.slider[this.scrollIns.forwardMap.offset], offsetEnd = nextSnapped ? this.scrollIns.snappeds[idx + 1][this.scrollIns.forwardMap.offset] : offsetStart + k.slider[this.scrollIns.forwardMap.outer];
result.push({ offsetStart, offsetEnd, target: k, index: i });
}
});
return result;
}
updateTotal(value = this.getTotal()) {
if (!this.options.total.enable)
return false;
if (!value.bullets) {
this.numEl.innerHTML = this.denEl.innerHTML = 0;
}
else {
this.numEl.innerHTML = value.curBullet + 1;
this.denEl.innerHTML = value.bullets;
}
}
fillTotal() {
if (!this.options.total.enable)
return false;
let total = this.getTotal();
this.totalEl = createEl('span', { class: `${ax.prefix}swipe-total` }, this.options.total.format);
this.numEl = this.totalEl.querySelector('i');
this.denEl = this.totalEl.querySelector('u');
this.updateTotal(total);
this.options.total.placement && this.totalEl.setAttribute('placement', this.options.total.placement);
let tmp = getEl(this.options.total.selector);
(tmp || this.targetEl).appendChild(this.totalEl);
}
getTotal() {
return { curSlider: this.actIdx, sliders: this.sliders.length, curBullet: this.bullets.findIndex((k) => k.active), bullets: this.bullets.length };
}
fillNav() {
if (!this.options.nav.enable)
return false;
let addNav = (type) => {
let result = null, text = (type === 'prev') ? (this.options.flow === 'h' ? `${ax.prefix}icon-left` : `${ax.prefix}icon-up`) :
(type === 'next') ? (this.options.flow === 'h' ? `${ax.prefix}icon-right` : `${ax.prefix}icon-down`) : '', className = `${ax.prefix}swipe-${type}`, el = getEl(`.${className}`, this.targetEl);
if (el) {
result = el;
result.classList.add(`${text}`);
}
else if (this.options.nav[type].selector) {
result = getEl(this.options.nav[type].selector);
result && result.classList.contains(`${ax.prefix}swipe-${type}`) && result.classList.add(`${text}`);
}
else {
result = createEl('i', { class: `${className} ${text}` });
this.navEl ? this.navEl.appendChild(result) : this.targetEl.appendChild(result);
}
if (result) {
this.options.nav[type].classes && classes(result).add(this.options.nav[type].classes);
this.options.nav.classes && classes(result).add(this.options.nav.classes);
this.options.nav.fill && result.setAttribute('filled', '');
}
return result;
};
if (this.options.nav.enable) {
this.prevEl = addNav('prev');
this.nextEl = addNav('next');
if (this.prevEl) {
this.prevEl.onclick = throttle(() => {
this.toPrevBullet();
}, { intvl: this.options.nav.intvl, prevent: true });
}
if (this.nextEl) {
this.nextEl.onclick = throttle(() => {
this.toNextBullet();
}, { intvl: this.options.nav.intvl, prevent: true });
}
}
}
fillPgn() {
if (!this.options.pgn.enable)
return false;
this.pgnIns = null;
let className = `${ax.prefix}swipe-pgn`, pgnTmp = [...this.targetEl.children].find((k) => k.classList.contains(className));
if (pgnTmp) {
this.pgnEl = pgnTmp;
}
else if (this.options.pgn.selector) {
let selType = getDataType(this.options.pgn.selector);
if (selType.includes('HTML')) {
this.pgnEl = this.options.pgn.selector;
}
else if (selType === 'String') {
if (getSelectorType(this.options.pgn.selector)) {
this.pgnEl = getEl(this.options.pgn.selector);
}
else {
this.pgnIns = instance.find(this.options.pgn.selector, 'swipe');
this.pgnIns && (this.pgnEl = this.pgnIns.wrapEl);
}
}
else if (selType === 'Object') {
this.pgnIns = this.options.pgn.selector;
this.pgnEl = this.pgnIns.wrapEl;
}
}
else {
this.pgnEl = createEl('ul', { class: `${className} ${ax.prefix}reset` }, '');
this.navEl && this.prevEl ? this.prevEl.insertAdjacentElement('afterend', this.pgnEl) : this.targetEl.appendChild(this.pgnEl);
}
if (this.pgnEl) {
this.options.pgn.type && this.pgnEl.setAttribute('type', this.options.pgn.type);
this.options.pgn.classes && classes(this.pgnEl).add(this.options.pgn.classes);
if (this.pgnEl.children.length) {
this.bullets.forEach((k, i) => {
if (this.pgnEl.children[i]) {
k.el = this.pgnEl.children[i];
i === this.actIdx && this.setBulletActive(k);
}
});
this.setBulletAction();
}
else {
this.updatePgn();
}
}
}
setBulletAction() {
this.bullets.forEach((k) => {
k.el.onclick = () => {
this.setBulletActive(k);
this.scrollIns.scrollTo({ target: k.target.slider, snap: true });
};
});
}
updatePgn() {
if (!this.options.pgn.enable)
return;
this.pgnEl.innerHTML = '';
let len = this.bullets.length, fragment = document.createDocumentFragment();
this.bullets.forEach((k, i) => {
i === this.actIdx && this.setBulletActive(k);
let html;
switch (this.options.pgn.type) {
case 'text':
html = k.target.source.label || this.options.pgn.data[i];
break;
case 'thumb':
html = `<img src="${k.target.source.thumb || this.options.pgn.data[i]}"/>`;
break;
case 'index':
html = i + 1;
break;
default:
html = '';
}
if (this.options.pgn.before) {
this.options.pgn.before.call(this, { index: i, total: len, html, bullet: k, parent: this.pgnEl });
}
else {
k.el.innerHTML = html;
}
fragment.appendChild(k.el);
});
this.pgnEl.appendChild(fragment);
this.options.pgn.after && this.options.pgn.after.call(this, { total: len, parent: this.pgnEl });
this.setBulletAction();
}
findNavSnap(type = 'next') {
let index = this.scrollIns.snappeds.findIndex((k) => k === this.scrollIns.snapped), target = null;
if (index < 0)
return target;
if (type === 'next') {
if (this.options.loop && index === this.scrollIns.snappeds.length - 1) {
target = this.scrollIns.snappeds[0];
}
else {
index !== this.scrollIns.snappeds.length - 1 && (target = this.scrollIns.snappeds[index + 1]);
}
}
else if (type === 'prev') {
if (this.options.loop && index === 0) {
target = this.scrollIns.snappeds.at(-1);
}
else {
index !== 0 && (target = this.scrollIns.snappeds[index - 1]);
}
}
else if (type === 'start') {
target = this.scrollIns.snappeds[0];
}
else if (type === 'end') {
target = this.scrollIns.snappeds.at(-1);
}
return target;
}
findSnap(data) {
let dataType = getDataType(data), result;
if (dataType === 'Number') {
let tmp = this.sliders[data];
result = tmp && this.scrollIns.snappeds.includes(tmp.slider) ? tmp.slider : null;
}
else if (dataType.includes('HTML') || dataType === 'String') {
let tmp = getEl(data, this.wrapEl);
result = tmp && this.scrollIns.snappeds.includes(tmp) ? tmp : null;
}
else if (dataType === 'Object' && data.hasOwnProperty('slider')) {
result = this.scrollIns.snappeds.includes(data.slider) ? data.slider : null;
}
return result;
}
findBullet(data) {
let dataType = getDataType(data), result;
if (dataType === 'Number') {
result = this.bullets[data];
}
else if (dataType.includes('HTML') || dataType === 'String') {
result = this.bullets.find((k) => k.target.slider === getEl(data, this.wrapEl));
}
else if (dataType === 'Object' && data.hasOwnProperty('el')) {
result = data;
}
return result;
}
toBullet(data, opt = {}) {
if (this.destroyed)
return;
let bullet = this.findBullet(data);
if (!bullet || this.bulletSeq.current === bullet)
return;
this.scrollIns.scrollTo({
target: bullet.target.slider,
snap: true,
before: () => {
this.setBulletActive(bullet);
opt.before && opt.before.call(this, bullet);
},
after: () => {
opt.after && opt.after.call(this, bullet);
}
});
}
toPrevBullet(cb) {
if (this.destroyed)
return;
this.bulletSeq.prev && this.toBullet(this.bulletSeq.prev, {
after: () => {
cb && cb.call(this, this.bulletSeq.prev);
}
});
}
toNextBullet(cb) {
if (this.destroyed)
return;
this.bulletSeq.next && this.toBullet(this.bulletSeq.next, {
after: () => {
cb && cb.call(this, this.bulletSeq.next);
}
});
}
toSnap(data, opt = {}) {
if (this.destroyed)
return;
let target = this.findSnap(data);
if (!target || this.scrollIns.snapped === target)
return;
this.scrollIns.scrollTo({
target,
snap: true,
before: () => {
opt.before && opt.before.call(this, target);
},
after: () => {
opt.after && opt.after.call(this, target);
}
});
}
toLocate(data, opt = {}) {
if (this.destroyed)
return;
let target = this.findSnap(data);
if (!target || this.scrollIns.snapped === target)
return;
this.scrollIns.locateTo({
target,
snap: true,
before: () => {
opt.before && opt.before.call(this, target);
},
after: () => {
opt.after && opt.after.call(this, target);
}
});
}
toPrevSnap(cb) {
if (this.destroyed)
return;
let target = this.findNavSnap('prev');
if (!target)
return;
this.scrollIns.scrollTo({
target,
snap: true,
after: () => {
cb && cb.call(this, target);
}
});
}
toNextSnap(cb) {
if (this.destroyed)
return;
if (this.destroyed)
return;
let target = this.findNavSnap('next');
if (!target)
return;
this.scrollIns.scrollTo({
target,
snap: true,
after: () => {
cb && cb.call(this, target);
}
});
}
toStart(cb) {
if (this.destroyed)
return;
let item = this.bullets[0];
if (item.active)
return;
this.toBullet(item, {
after: (bullet) => {
cb && cb.call(this, bullet);
}
});
}
toEnd(cb) {
if (this.destroyed)
return;
let item = this.bullets.at(-1);
if (item.active)
return;
this.toBullet(item, {
after: (bullet) => {
cb && cb.call(this, bullet);
}
});
}
setLoopPlay() {
if (this.options.loop === false) {
return false;
}
if (this.options.slides === 'auto') {
this.startClone = this.slides.map((k) => k.dom.cloneNode(true));
this.endClone = this.slides.map((k) => k.dom.cloneNode(true));
this.totalClone = this.slides.length;
}
else {
this.startClone = this.slides.slice(0, this.options.slides).map((k) => k.dom.cloneNode(true));
this.endClone = this.slides.slice(this.slides.length - this.options.slides).map((k) => k.dom.cloneNode(true));
this.totalClone = this.options.slides;
}
this.scrollIns.add(this.endClone, { placement: 'start' });
this.scrollIns.add(this.startClone, { placement: 'end' });
}
startCountdown() {
if (!this.countdownIns)
return;
this.countdownIns.setCompleted();
this.countdownIns.animateTo(0, { duration: this.options.autoplay.delay });
}
setAutoPlay() {
if (!this.options.autoplay.enable)
return;
if (this.options.autoplay.countdown) {
if (!this.countdownIns) {
this.countdownIns = new Progress(this.countdownEl, extend({
target: {
label: false,
type: 'circle',
curve: 'linear',
width: 'xxs',
control: true,
duration: this.options.autoplay.delay,
onPause: () => {
this.autoPause();
},
onContinue: (resp) => {
this.continue(resp.durRest);
}
},
source: this.options.countdown,
}));
}
else {
this.countdownIns.init();
}
this.targetEl.appendChild(this.countdownEl);
}
this.autoPlay();
}
continue(duration) {
delay({
duration,
done: () => {
this.toNextBullet(() => {
this.autoPlay();
});
}
});
}
play(delay, cb) {
if (this.destroyed || !this.paused)
return;
this.interval && clearInterval(this.interval);
this.interval = setInterval(this.intervalEvt, delay || this.options.autoplay.delay);
this.paused = false;
super.listen({ name: 'played', cb });
return this;
}
pause(cb) {
if (this.destroyed || this.paused)
return;
clearInterval(this.interval);
this.paused = true;
super.listen({ name: 'paused', cb });
return this;
}
autoPlay(delay, cb) {
if (this.destroyed || !this.paused)
return;
if (!this.options.autoplay.enable)
return;
this.play(delay, cb);
this.startCountdown();
return this;
}
autoPause(clear = false, cb) {
if (this.destroyed || this.paused)
return;
if (!this.options.autoplay.enable)
return;
this.pause(cb);
if (clear && this.countdownIns) {
this.countdownEl.remove();
this.countdownIns.destroy();
}
return this;
}
async add(data, options) {
if (this.destroyed || isEmpty(data))
return;
let tmp, opts = Object.assign({ placement: 'end' }, options);
await this.getSliders(data, (resp) => {
tmp = resp;
this.sliders.push(...tmp);
});
this.appendSliders(tmp, opts.placement);
super.listen({ name: 'add', cb: opts.cb, params: [tmp] });
return { ins: this, data: tmp };
}
remove(data = 'end', cb) {
if (this.destroyed || isEmpty(data))
return;
let tmp;
if (data === 'start') {
tmp = this.sliders[0]?.slider;
}
else if (data === 'end') {
tmp = this.sliders.at(-1)?.slider;
}
else {
tmp = this.findSlider(data);
}
if (!tmp)
return;
tmp.remove();
super.listen({ name: 'remove', cb, params: [this.sliders.find((k) => k.slider === tmp)] });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
for (let k of this.sliders) {
k.spy && k.spy.destroy();
}
this.scrollIns.destroy();
this.spyIns && this.spyIns.destroy();
this.countdownIns && this.countdownIns.destroy();
window.removeEventListener('keydown', this.keyToSwipe);
this.bullets.forEach((k) => {
k.el.onclick = null;
});
this.prevEl && (this.prevEl.onclick = null);
this.nextEl && (this.nextEl.onclick = null);
if (this.toolsEl) {
this.options.tools.children.forEach((k) => {
k.el.onclick = null;
});
}
for (let k of this.thumbs)
k.removeEventListener('click', this.setSnapEvt);
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
updateCont(text, cb) {
if (this.destroyed) {
return this;
}
this.options.content = text;
this.init();
super.updateCache({ content: this.content });
super.listen({ name: 'updatedCont', cb, params: [this.content] });
return this;
}
}
let AXTMP_hyphen = config.splitHyphen;
const optLazy = [
{
attr: 'root',
prop: 'root',
value: null
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'hyphen',
prop: 'hyphen',
value: AXTMP_hyphen,
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'type',
prop: 'type',
value: 'src',
},
{
attr: 'trigger',
prop: 'trigger',
value: 'ing',
},
{
attr: 'spy',
prop: 'spy',
value: {},
},
{
attr: 'on-showing',
prop: 'onShowing',
value: null,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null,
},
...optBase
];
class Lazy extends ModBaseListenCache {
nodeName;
resType;
spyIns;
removeAttrFn;
options = {};
static hostType = 'node';
static optMaps = optLazy;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Lazy.optMaps,
host: elem,
});
this.nodeName = this.targetEl.nodeName;
this.removeAttrFn = () => {
this.targetEl.removeAttribute('lazy-src');
super.listen({ name: 'shown', params: [this.targetEl] });
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.resType = this.options.type || (this.targetEl.hasAttribute('src') ? 'src' : 'async');
if (this.resType === 'src') {
this.targetEl.src = ax.images.blank;
!this.targetEl.hasAttribute('lazy-src') && this.targetEl.setAttribute('lazy-src', '');
}
this.spyIns = new Spy(this.targetEl, extend({
target: {
root: this.options.root,
repeat: false,
},
source: this.options.spy
}));
this.spyIns.on(this.options.trigger === 'ed' ? 'shown' : 'in', async () => {
super.listen({ name: 'showing', params: [this.targetEl] });
if (this.resType === 'src') {
this.targetEl.src = this.options.content;
if (['VIDEO', 'AUDIO'].includes(this.nodeName)) {
this.targetEl.onloadeddata = this.removeAttrFn;
}
else if (['IMG', 'IFRAME'].includes(this.nodeName)) {
this.targetEl.onload = this.removeAttrFn;
}
else {
this.removeAttrFn();
}
}
else if (this.resType === 'async') {
await getContent.call(this, {
content: this.options.content,
contType: this.options.contType || 'async',
contData: this.options.contData,
ajax: Object.assign({ target: this.targetEl }, this.options.ajax),
hyphen: this.options.hyphen,
cb: (data) => {
setContent({
target: this.targetEl,
content: data,
template: this.options.tplStr,
engine: this.options.tplEng,
});
this.targetEl.removeAttribute('lazy-async');
this.targetEl.removeAttribute('lazy-type');
this.targetEl.removeAttribute('lazy-data');
this.targetEl.removeAttribute('lazy-tpl');
super.listen({ name: 'shown', params: [this.targetEl] });
}
});
}
super.listen({ name: 'trigger', params: [this.targetEl] });
});
super.listen({ name: 'initiated', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.spyIns.destroy();
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optInfinite = [
{
attr: 'trigger',
prop: 'trigger',
value: 'scroll',
},
{
attr: 'spy',
prop: 'spy',
value: {
enable: true,
},
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'spin',
prop: 'spin',
value: '<ax-spin></ax-spin>',
},
{
attr: 'max',
prop: 'max',
value: 20,
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'media',
prop: 'media',
value: {
title: '',
brief: '',
},
},
{
attr: 'b4-append',
prop: 'b4Append',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'on-append',
prop: 'onAppend',
value: null,
},
{
attr: 'on-finish',
prop: 'onFinish',
value: null,
},
{
attr: 'on-error',
prop: 'onError',
value: null,
},
...optBase
];
class Infinite extends ModBaseListenCache {
options = {};
content;
index;
contReq;
contXhr;
statusEl;
spinEl;
nextEl;
nextBtn;
tipsEl;
listSpyIns;
statusSpyIns;
static hostType = 'node';
static optMaps = optInfinite;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Infinite.optMaps,
host: elem,
component: false,
spread: ['spy']
});
this.content = [];
this.index = 0;
this.contReq = {
contType: this.options.contType,
contData: this.options.contData,
ajax: {
error: (resp) => {
this.finish(true);
super.listen({ name: 'error', params: [resp] });
},
xhrName: 'contXhr',
...this.options.ajax,
},
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setAttrs();
this.useTpl();
this.getStatusEl();
this.targetEl.appendChild(this.statusEl);
await this.getInitContent();
this.options.spy.enable && this.getListSpyIns();
if (this.options.trigger === 'scroll') {
this.getStatusSpyIns();
}
else if (this.options.trigger === 'click') {
this.nextBtn.onclick = () => {
this.getStatusSpyIns();
};
}
else if (this.options.trigger === 'clicks') {
this.nextBtn.onclick = () => {
this.renderList(this.index);
};
}
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}infinite`);
classes(this.targetEl).add(this.options.classes);
this.targetEl.setAttribute('trigger', this.options.trigger);
}
finish(err = false) {
this.statusEl.setAttribute('status', 'finish');
this.tipsEl.innerHTML = err ? this.options.lang.error : this.options.lang.finish;
this.statusSpyIns && this.statusSpyIns.destroy();
super.listen({ name: 'finish' });
}
getListSpyIns() {
this.listSpyIns = new Spy(null, extend({
target: {
repeat: false,
visible: false,
in: `${ax.prefix}fadeIn`,
},
source: this.options.spy,
}));
}
getStatusSpyIns() {
this.statusSpyIns = new Spy(this.statusEl, {
root: this.targetEl,
onIn: debounce(() => {
this.renderList(this.index);
})
});
}
async renderList(index) {
if (this.destroyed || index >= this.content.length)
return;
this.statusEl.setAttribute('status', 'loading');
this.tipsEl.innerHTML = this.options.lang.loading;
await this.getPageData(this.content[index], async (data) => {
this.options.b4Append && await this.options.b4Append.call(this, data);
this.statusEl.setAttribute('status', 'loaded');
this.tipsEl.innerHTML = this.options.lang.loaded;
let fragment = document.createDocumentFragment();
for (let k of data) {
k.classList.add(`${ax.prefix}infinite-item`);
fragment.appendChild(k);
}
this.targetEl.insertBefore(fragment, this.statusEl);
this.listSpyIns && this.listSpyIns.add(data);
super.listen({ name: 'append', params: [data] });
this.index++;
(this.index >= this.content.length) && this.finish();
});
}
getStatusEl() {
this.statusEl = this.targetEl.querySelector(`.${ax.prefix}infinite-status`) || createEl('div', { class: `${ax.prefix}infinite-status`, status: 'preload' });
this.spinEl = createEl('div', { [ax.alias]: 'spin' }, this.options.spin);
this.statusEl.appendChild(this.spinEl);
let nextTmp = this.targetEl.querySelector(`[${ax.alias}="next"]`);
if (nextTmp) {
this.nextEl = nextTmp;
}
else {
this.nextEl = createEl('div', { [ax.alias]: 'next' }, this.options.lang.next);
['click', 'clicks'].includes(this.options.trigger) && this.statusEl.appendChild(this.nextEl);
}
this.nextBtn = this.nextEl.firstElementChild;
let tipsTmp = this.targetEl.querySelector(`[${ax.alias}="tips"]`);
if (tipsTmp) {
this.tipsEl = tipsTmp;
}
else {
this.tipsEl = createEl('div', { [ax.alias]: 'tips' }, this.options.lang.preload);
this.statusEl.appendChild(this.tipsEl);
}
}
async getInitContent() {
let result = [];
if (this.options.content) {
let contType = getDataType(this.options.content);
if (contType === 'String') {
result = parseUrlArr(this.options.content, { max: this.options.max });
}
else if (contType === 'Array' && this.options.content.length) {
let firstType = getDataType(this.options.content[0]);
if (firstType === 'Object') {
for (let k of this.options.content) {
let tmp = extend({ target: deepClone(this.contReq), source: k });
result.push(await getContent.call(this, tmp));
}
}
else if (firstType === 'Array') {
for (let k of this.options.content) {
if (!k.length)
continue;
let sonType = getDataType(k[0]);
if (sonType.includes('HTML')) {
result = [...this.options.content];
}
else if (sonType === 'Object') {
let tmp = k.map((k) => tplToEl(super.getTplcont(k)));
result.push(tmp);
}
}
}
else {
result = this.options.content;
}
}
}
else {
let pages = getEls(`[${ax.alias}="page"]`, this.statusEl);
result = pages.map((k) => k.href).filter(Boolean);
}
this.content = result.filter((k) => !isEmpty(k));
}
async getPageData(data, cb) {
if (this.destroyed)
return;
let dataType = getDataType(data), result = [], contReq = deepClone(this.contReq);
if (dataType === 'String') {
result = this.options.contType === 'text' ? tplToEls(data) : await getContent.call(this, { content: data, ...contReq });
}
if (dataType.includes('HTML')) {
result = [...data.children];
}
else if (dataType === 'Object') {
let params = extend({
target: contReq,
source: data
}), tmp;
tmp = await getContent.call(this, params);
if (isEmpty(tmp)) {
if (typeof tmp === 'string') {
result = tplToEls(data);
}
else if (Array.isArray(tmp) && getDataType(tmp[0].include('HTML'))) {
result = tmp;
}
}
}
else if (dataType === 'Array') {
result = this.arr2Nodes(data);
}
let resultType = getDataType(result);
if (resultType === 'String') {
result = tplToEls(result);
}
else if (resultType === 'Array') {
result = this.arr2Nodes(result);
}
result = result.filter(Boolean);
cb && cb(result);
return result;
}
arr2Nodes(data) {
let result = [];
if (!data.length)
return result;
let itemType = getDataType(data[0]);
if (itemType.includes('HTML')) {
result = data;
}
else if (itemType === 'Object') {
result = data.map((k) => tplToEl(super.getTplcont(k)));
}
return result;
}
destroy(cb) {
if (this.destroyed)
return this;
this.nextBtn && (this.nextBtn.onclick = null);
this.listSpyIns && this.listSpyIns.destroy();
this.statusSpyIns && this.statusSpyIns.destroy();
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optVirtualize = [
{
attr: 'axis',
prop: 'axis',
value: 'y',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'size',
prop: 'size',
value: 0,
},
{
attr: 'spill',
prop: 'spill',
value: 2,
},
{
attr: 'names',
prop: 'names',
value: {
wrap: 'div',
list: 'div',
cont: 'div',
item: 'section'
},
},
{
attr: 'index',
prop: 'index',
value: 0,
},
{
attr: 'dynamic',
prop: 'dynamic',
value: true,
},
{
attr: 'content',
prop: 'content',
value: ''
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'b4-append',
prop: 'b4Append',
value: null,
},
{
attr: 'b4-updateitem',
prop: 'b4UpdateItem',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'on-append',
prop: 'onAppend',
value: null,
},
{
attr: 'on-getcont',
prop: 'onGetCont',
value: null,
},
{
attr: 'on-exhausted',
prop: 'onExhausted',
value: null,
},
{
attr: 'on-tostart',
prop: 'onToStart',
value: null,
},
{
attr: 'on-toend',
prop: 'onToEnd',
value: null,
},
{
attr: 'on-updateItem',
prop: 'onUpdatedItem',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-error',
prop: 'onError',
value: null,
},
...optBase
];
class Virtualize extends ModBaseListenCache {
options = {};
propsMap;
contReq;
autoRenderEvt;
obsRenderEvt;
avgSize;
targetSize;
wrapEl;
contEl;
listEl;
startSpaceEl;
endSpaceEl;
sizesObs;
itemSizes;
startSpyIns;
endSpyIns;
itemObs;
targetObs;
listSize;
paddingStart;
startIdx;
endIdx;
offsetVal;
scrollVal;
nodes;
paddingEnd;
wrapSize;
contXhr;
content;
static hostType = 'node';
static optMaps = optVirtualize;
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Virtualize.optMaps,
host: elem,
component: false,
spread: []
});
this.propsMap = propsMap[this.options.axis];
this.contReq = {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
spinSel: this.targetEl,
error: (resp) => {
super.listen({ name: 'error', params: [resp] });
},
xhrName: 'contXhr',
...this.options.ajax,
},
};
this.autoRenderEvt = () => {
this.renderFromStart();
};
this.obsRenderEvt = debounce(() => {
this.initialized && this.renderFromStart();
});
this.avgSize = Math.max(parseInt(style(document.body).lineHeight), toPixel(this.options.size));
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setAttrs();
this.getDirRtl();
this.targetSize = this.targetEl[this.propsMap.inner];
this.useTpl();
this.getNodesTree();
await this.getInitData();
this.setSizesObs();
this.setSpy();
this.targetEl.addEventListener("scroll", this.autoRenderEvt, false);
this.itemObs = new MutationObserver(this.obsRenderEvt);
this.targetObs = new ResizeObserver(this.obsRenderEvt);
this.targetObs.observe(this.targetEl);
this.renderFromStart(this.options.index);
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}virt`);
this.targetEl.setAttribute('axis', this.options.axis);
classes(this.targetEl).add(this.options.classes);
}
getAvgArr(len) {
return Array(len).fill(null).map(() => { return { size: this.avgSize, rendered: false }; });
}
setSizesObs() {
this.sizesObs = new Observe(this.getAvgArr(this.content.length), {
deep: true,
onCompleted: () => {
if (this.itemSizes.findIndex((k) => !k.rendered) < 0) {
super.listen({ name: 'exhausted', params: [this.content] });
}
}
});
this.itemSizes = this.sizesObs.proxy;
}
setSpy() {
this.startSpyIns = new Spy(this.startSpaceEl, {
onIn: () => {
super.listen({ name: 'toStart' });
},
});
this.endSpyIns = new Spy(this.endSpaceEl, {
onIn: () => {
super.listen({ name: 'toEnd' });
},
});
}
setNodeMutation(el) {
this.itemObs.observe(el, {
childList: true,
subtree: true,
attributes: true,
});
}
getNodesTree() {
let tmpWrap = this.targetEl.querySelector(`.${ax.prefix}virt-wrap`);
if (tmpWrap) {
this.wrapEl = tmpWrap;
}
else {
this.wrapEl = createEl(this.options.names.wrap, { class: `${ax.prefix}virt-wrap` });
this.targetEl.appendChild(this.wrapEl);
}
let tmpCont = this.wrapEl.querySelector(`.${ax.prefix}virt-cont`);
if (tmpCont) {
this.contEl = tmpWrap;
}
else {
this.contEl = createEl(this.options.names.cont, { class: `${ax.prefix}virt-cont` });
this.wrapEl.appendChild(this.contEl);
}
let tmpList = this.contEl.querySelector(`.${ax.prefix}virt-list`);
if (tmpList) {
this.wrapEl = tmpList;
}
else {
this.listEl = createEl(this.options.names.list, { class: `${ax.prefix}virt-list` });
this.contEl.appendChild(this.listEl);
}
this.startSpaceEl = createEl('div', { class: `${ax.prefix}virt-space` }, `${this.options.lang.preload}`);
this.endSpaceEl = createEl('div', { class: `${ax.prefix}virt-space` }, `${this.options.lang.preload}`);
this.contEl.insertAdjacentElement('afterbegin', this.startSpaceEl);
this.contEl.appendChild(this.endSpaceEl);
}
getWrapSize() {
return this.options.dynamic ? this.itemSizes.reduce((sum, cur) => sum + cur.size, 0) : this.avgSize * this.itemSizes.length;
}
get2SetWrapSize() {
this.wrapSize = this.getWrapSize();
this.wrapEl.style[this.propsMap.size] = this.wrapSize + "px";
}
async getInitData() {
let resp = await this.getData();
this.content = resp.content;
}
async getData(data, cb) {
let resp = await getContent.call(this, data ? Object.assign(this.contReq, data) : this.contReq), respType = getDataType(resp), result = { content: [], source: resp };
this.respSource = resp;
if (respType === 'Array') {
result.content = resp;
}
else if (respType === 'Object' && resp.hasOwnProperty('data')) {
result.content = (Array.isArray(resp.data)) ? resp.data : (resp?.data?.list || []);
}
else if (respType === 'String') {
result.content = tplToEls(resp);
}
super.listen({ name: 'getCont', cb, params: [result] });
return result;
}
getItemNode(data) {
let dataType = getDataType(data), result;
if (dataType.includes('HTML')) {
result = data;
}
else {
result = createEl(this.options.names.item, {});
result.innerHTML = dataType === 'Object' ? super.getTplcont(data) : data.toString();
}
this.setNodeMutation(result);
return result;
}
getDirScrollVal() {
if (this.options.axis !== 'x') {
return this.targetEl[this.propsMap.scroll];
}
else {
let scrollLeft = this.targetEl[this.propsMap.scroll]; this.targetEl.getAttribute('dir');
return scrollLeft * super.getRtlCoef();
}
}
setDirScrollVal(val = 0) {
if (this.options.axis !== 'x') {
this.targetEl[this.propsMap.scroll] = val;
}
else {
this.targetEl[this.propsMap.scroll] = val * super.getRtlCoef();
}
}
renderFromStart(start) {
if (this.destroyed)
return;
this.listEl.innerHTML = '';
this.listSize = 0;
this.paddingStart = 0;
this.startIdx = 0;
this.endIdx = this.itemSizes.length - 1;
this.offsetVal = 0;
this.scrollVal = this.getDirScrollVal();
this.nodes = [];
if (start) {
this.startIdx = start - 1;
}
else {
if (this.scrollVal) {
for (let i = 0; i < this.itemSizes.length; i++) {
this.paddingStart += this.itemSizes[i].size;
if (this.paddingStart > this.scrollVal) {
this.startIdx = i;
break;
}
else if (i === this.itemSizes.length - 1 && this.paddingStart <= this.scrollVal) {
return;
}
}
}
}
this.paddingEnd = 0;
for (let i = this.startIdx; i < this.itemSizes.length; i++) {
this.paddingEnd += this.itemSizes[i].size;
if (this.paddingEnd > this.targetSize) {
this.endIdx = i;
break;
}
}
this.compensate();
for (let i = this.startIdx; i <= this.endIdx; i++) {
this.appendUpdateSize(i, 'beforeend', (size) => {
this.listSize += size;
});
}
let fillObj = {};
this.fillBlank(this.listSize, (val) => {
fillObj = val;
});
this.get2SetWrapSize();
if (start) {
this.updateScrollVal(start + (fillObj?.indexDiff || 0));
}
else {
fillObj?.padding && (this.paddingStart -= fillObj.padding);
}
this.get2SetContOffset();
super.listen({ name: 'rendered', params: [{ startIdx: this.startIdx, endIdx: this.endIdx, nodes: this.nodes, scrollVal: this.scrollVal, offsetVal: this.offsetVal, wrapSize: this.wrapSize, listSize: this.listSize }] });
}
fillBlank(total = this.listSize, cb) {
let obj = { startIdx: 0, indexDiff: 0, padding: 0 };
if (total < this.targetSize) {
for (let i = 1; i < this.content.length; i++) {
let index = this.startIdx - i;
if (index < 0)
break;
this.appendUpdateSize(index, 'afterbegin', (size) => {
total += size;
obj.padding += size;
});
if (total >= this.targetSize) {
obj.startIdx = index;
obj.indexDiff = index - this.startIdx;
this.startIdx = index;
this.listSize = total;
break;
}
}
cb && cb(obj);
}
}
appendUpdateSize(index, dir = 'afterbegin', cb) {
if (index < 0 || index >= this.content.length)
return;
let itemEl = this.getItemNode(this.content[index]);
this.nodes.push({ el: itemEl, index });
this.listEl.insertAdjacentElement(dir, itemEl);
this.options.dynamic && (this.itemSizes[index].size = getElSpace((itemEl), this.options.axis));
this.itemSizes[index].rendered = true;
cb && cb(this.itemSizes[index].size);
}
updateSizeOnly(index) {
let itemEl = this.getItemNode(this.content[index]);
this.listEl.insertAdjacentElement('beforeend', itemEl);
this.options.dynamic && (this.itemSizes[index].size = getElSpace((itemEl), this.options.axis));
}
renderFromEnd() {
this.listSize = 0;
this.listEl.innerHTML = '';
this.nodes = [];
this.endIdx = this.content.length - 1;
for (let i = this.endIdx; i >= 0; i--) {
this.appendUpdateSize(i, 'afterbegin', (size) => {
this.listSize += size;
});
if (this.listSize > this.targetSize) {
for (let k = 1; k <= this.options.spill; k++) {
this.appendUpdateSize(i - k, 'afterbegin', (size) => {
this.listSize += size;
});
}
this.startIdx = i - this.options.spill;
break;
}
}
this.get2SetWrapSize();
this.offsetVal = this.wrapSize - this.listSize;
this.setContOffset();
this.setScrollVal(this.wrapSize);
super.listen({ name: 'rendered', params: [{ startIdx: this.startIdx, endIdx: this.endIdx, nodes: this.nodes, scrollVal: this.scrollVal, offsetVal: this.offsetVal, wrapSize: this.wrapSize }] });
}
getPadStartFromIdx(index) {
if (!this.options.dynamic) {
return this.avgSize * index;
}
else {
let result = 0;
for (let i = 0; i < index; i++) {
result += this.itemSizes[i].size;
}
return result;
}
}
setScrollVal(val = this.paddingStart) {
this.targetEl.removeEventListener('scroll', this.autoRenderEvt);
this.setDirScrollVal(val);
this.scrollVal = val;
setTimeout(() => {
this.targetEl.addEventListener('scroll', this.autoRenderEvt, false);
}, 0);
}
updateScrollVal(start) {
this.paddingStart = this.getPadStartFromIdx(start);
this.setScrollVal();
}
compensate() {
this.endIdx = clampVal({ val: this.endIdx + this.options.spill, min: 0, max: this.itemSizes.length - 1 });
this.startIdx = clampVal({ val: this.startIdx - this.options.spill, min: 0, max: this.itemSizes.length - 1 });
}
get2SetContOffset() {
if (!this.startIdx) {
this.offsetVal = 0;
}
else {
this.offsetVal = this.paddingStart;
if (!this.options.dynamic) {
this.offsetVal -= this.avgSize * (this.options.spill + 1);
}
else {
for (let i = 0; i <= this.options.spill; i++) {
this.offsetVal -= this.itemSizes[this.startIdx + i].size;
}
}
}
this.setContOffset();
}
getContOffset(val) {
return this.isRtl && this.options.axis === 'x' ? { x: Math.min(0, val * -1) } : { [this.options.axis]: Math.max(0, val) };
}
setContOffset(val = this.offsetVal) {
transformTools.set({
el: this.contEl,
data: {
translate: this.getContOffset(val),
}
});
}
scrollTo(index = 0, cb) {
if (!index) {
this.setDirScrollVal();
}
else {
this.renderFromStart(index);
}
cb && cb.call(this, index);
}
toStart() {
this.scrollTo();
}
toEnd() {
this.renderFromEnd();
}
async append(data, cb) {
if (this.destroyed)
return;
let resp = await this.getData(data);
if (resp.content.length) {
if (this.options.b4Append) {
let tmp = await this.options.b4Append.call(this, resp.content);
tmp && (resp.content = tmp);
}
this.content.push(...resp.content);
this.itemSizes.push(...this.getAvgArr(resp.content.length));
this.renderFromStart();
super.listen({ name: 'append', cb, params: [resp] });
}
return this;
}
async updateItem(data = { index: 0, override: true }) {
if (this.destroyed)
return;
let item = this.content[data.index], itemType = getDataType(item), contType = getDataType(data.content);
if (itemType.includes('HTML')) {
data.override && (item.innerHTML = '');
if (contType.includes('HTML')) {
item.appendChild(data.content);
}
else {
item.insertAdjacentHTML('beforeend', data.content.toString());
}
}
else if (['String', 'Number'].includes(itemType) && ['String', 'Number'].includes(contType)) {
data.override && (this.content[data.index] = '');
this.content[data.index] += (data.content + '');
}
else if (itemType === 'Object' && contType === 'Object') {
data.override && (this.content[data.index] = {});
Object.assign(this.content[data.index], data.content);
}
if (this.options.b4UpdateItem) {
let resp = await this.options.b4UpdateItem.call(this, this.content[data.index]);
resp && (this.content[data.index] = resp);
}
if (itemType.includes('HTML') && !isEmpty(data.attrs)) {
for (let k in data.attrs) {
item.setAttribute(k, data.attrs[k]);
}
}
this.updateSizeOnly(data.index);
this.obsRenderEvt.cancel();
this.obsRenderEvt();
super.listen({ name: 'updateItem', cb: data.cb, params: [this.content[data.index]] });
}
async clear(cb) {
if (this.destroyed)
return;
this.options.b4Clear && await this.options.b4Clear.call(this);
this.content = [];
this.itemSizes = [];
this.renderFromStart();
super.listen({ name: 'cleared', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return;
this.targetEl.removeEventListener("scroll", this.autoRenderEvt);
this.startSpyIns.destroy();
this.endSpyIns.destroy();
this.itemObs.disconnect();
this.targetObs.unobserve(this.targetEl);
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optPagination = [
{
attr: 'list-sel',
prop: 'listSel',
value: ''
},
{
attr: 'count',
prop: 'count',
value: 10
},
{
attr: 'counts',
prop: 'counts',
value: ''
},
{
attr: 'dropdown',
prop: 'dropdown',
value: {}
},
{
attr: 'current',
prop: 'current',
value: 1,
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'expanded',
prop: 'expanded',
value: false,
},
{
attr: 'visible',
prop: 'visible',
value: {
edge: 2,
center: 2,
},
},
{
attr: 'align',
prop: 'align',
value: '',
},
{
attr: 'type',
prop: 'type',
value: '',
},
{
attr: 'flexible',
prop: 'flexible',
value: false,
},
{
attr: 'layout',
prop: 'layout',
value: 'first|prev|pages|next|last',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'delay',
prop: 'delay',
value: 100,
},
{
attr: 'names',
prop: 'names',
value: {
main: 'div',
total: 'span',
count: 'span',
locate: 'span',
pages: 'span',
tips: 'span',
ellipsis: 'span',
prev: 'a',
next: 'a',
first: 'a',
last: 'a',
item: 'a',
section: 'section',
},
},
{
attr: 'content',
prop: 'content',
value: 1000,
type: 'ignore',
},
{
attr: 'cont-type',
prop: 'contType',
value: '',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'b4-locate',
prop: 'b4Locate',
value: null,
},
{
attr: 'b4-renderlist',
prop: 'b4RenderList',
value: null,
},
{
attr: 'on-located',
prop: 'onLocated',
value: null,
},
{
attr: 'on-gotcont',
prop: 'onGotCont',
value: null,
},
{
attr: 'on-tofirst',
prop: 'onToFirst',
value: null,
},
{
attr: 'on-tolast',
prop: 'onToLast',
value: null,
},
{
attr: 'on-exceeded',
prop: 'onExceeded',
value: null,
},
{
attr: 'on-renderedlist',
prop: 'onRenderedList',
value: null,
},
{
attr: 'on-renderedpages',
prop: 'onRenderedPages',
value: null,
},
...optBase
];
class InputElem extends CompBaseCommField {
unitEl;
customEl;
imageEl;
labelEl;
limitEl;
diskEl;
cubeEl;
iconEl;
btnEl;
meanEl;
type;
select;
btnEvt;
constructor() {
super();
this.type = 'text-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.select = () => this.inputEl.select();
this.btnEvt = (evt) => {
if (evt.code === 'Enter' && elState(this.btnEl).isVisible && this.btnEl.click && !this.propsProxy.blocked) {
preventDft(evt);
this.btnEl.click();
}
};
this.addEventListener('click', (e) => {
let target = getEvtTarget(e);
target === this.wrapEl && this.inputEl.focus();
}, false);
this.inputEl.addEventListener('input', (e) => {
let tmp = this.propsProxy.value;
this.propsProxy.value = this.value = this.inputEl.value;
this.updateLimit();
let data = { oldVal: tmp, newVal: this.inputEl.value };
this.listen({ name: 'input', params: [data] });
(tmp !== this.inputEl.value) && this.listen({ name: 'changed', params: [data] });
}, false);
}
static custAttrs = ['name', 'placeholder', 'type', 'size', 'limit', 'tools', 'icon', 'cube', 'disk', 'image', 'btn', 'action', 'label', 'unit', 'custom', 'mean', 'task', 'attrs', ...this.evtsArr];
static boolAttrs = ['disabled', 'readonly', 'blocked', 'full'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, InputElem, { tools: getAttrArr(newVal, 'close') });
}
getRawData() {
this.getRawProps(InputElem);
this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
this.getProxyProps();
this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.inputEl = createEl('input', { type: data.type || 'text', placeholder: data.placeholder || config.lang.form.placeholder, [ax.embedSign]: '' });
data.value && (this.inputEl.value = data.value || '');
data.name && (this.inputEl.name = data.name || '');
this.wrapEl.appendChild(this.inputEl);
super.getToolsEl(data.tools);
this.limitEl = createEl('div', { [ax.alias]: 'limit' });
this.labelEl = createEl('span', { [ax.alias]: 'label' });
this.unitEl = createEl('span', { [ax.alias]: 'unit' });
this.diskEl = createEl('img', { [ax.alias]: 'disk' });
this.cubeEl = createEl('img', { [ax.alias]: 'cube' });
this.imageEl = createEl('img', { [ax.alias]: 'image' });
this.iconEl = createEl('i', { [ax.alias]: 'icon' });
this.btnEl = createEl('span', { [ax.alias]: 'btn' });
this.customEl = createEl('span', { [ax.alias]: 'custom' });
this.meanEl = createEl('i', { [ax.alias]: 'mean' });
}
updateLimit() {
let total = ~~this.propsProxy.limit, value = this.propsProxy.value, len = value.length, tmp = total - len, remaining = tmp <= 0 ? 0 : tmp;
if (!total) {
return this;
}
this.limitEl.innerHTML = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxLength, { total, value: len, remaining });
if (tmp <= 0) {
if (tmp < 0) {
this.inputEl.value = value.slice(0, total);
this.inputEl.dispatchEvent(this.zeroEvt);
}
this.setAttribute('exceeded', '');
}
else {
this.removeAttribute('exceeded');
}
elState(this.limitEl).isVirtual && this.appendChild(this.limitEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
~~this.propsProxy.limit && this.appendChild(this.limitEl);
}
changedMaps = {
disabled: this.changedBool,
readonly: this.changedBool,
blocked: this.changedBool,
full: this.changedBool,
name: this.changedName,
type: this.changedName,
placeholder: this.changedName,
value: this.changedValue,
icon: this.changedIcon,
disk: this.changedImage,
cube: this.changedImage,
image: this.changedImage,
task: this.changedTask,
label: this.changedLabel,
unit: this.changedUnit,
custom: this.changedCustom,
action: this.changedAction,
btn: this.changedBtn,
mean: this.changedMean,
limit: this.changedLimit,
tools: this.changedTools,
attrs: this.changedAttrs,
};
changedBool(opt) {
if (opt.name === 'blocked') {
if (this.propsProxy['blocked']) {
this.btnEl.setAttribute('disabled', '');
}
else {
this.btnEl.removeAttribute('disabled');
}
}
else {
this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
}
}
changedTools(opt) {
this.toolsEl && this.toolsEl.remove();
if (this.propsProxy.tools.length > 0) {
super.getToolsEl(this.propsProxy.tools);
this.propsProxy.tools.forEach((k) => {
if (k.name === 'close') {
k.wrapEl.onclick = () => this.clear();
}
else {
k.action && k.action.bind(this);
}
});
this.inputEl.insertAdjacentElement('afterend', this.toolsEl);
}
}
changedValue(opt) {
this.value = opt.newVal || '';
let tmp = this.inputEl.value;
this.inputEl.value = opt.newVal;
(tmp !== this.value) && this.listen({ name: 'changed', params: [{ oldVal: tmp, newVal: this.value }] });
}
changedLimit(opt) {
this.updateLimit();
}
changedName(opt) {
if (opt.name === 'type' && !['text', 'number', 'search', 'email', 'url', 'tel', 'password', 'time', 'week', 'datetime', 'datetime-local', 'month'].includes(opt.newVal))
return;
isNull(opt.newVal) ? this.inputEl.removeAttribute(opt.name) : this.inputEl.setAttribute(opt.name, opt.newVal);
opt.name === 'name' && (this.name = opt.newVal || '');
}
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal;
elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
}
else {
this.labelEl.remove();
}
}
changedUnit(opt) {
if (opt.newVal) {
this.unitEl.innerHTML = opt.newVal;
elState(this.unitEl).isVirtual && this.wrapEl.appendChild(this.unitEl);
}
else {
this.unitEl.remove();
}
}
changedCustom(opt) {
if (opt.newVal) {
this.customEl.innerHTML = opt.newVal;
if (elState(this.customEl).isVirtual) {
elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.customEl) : this.wrapEl.appendChild(this.customEl);
}
}
else {
this.customEl.remove();
}
}
changedBtn(opt) {
if (opt.newVal) {
this.btnEl.innerHTML = opt.newVal;
if (elState(this.btnEl).isVirtual) {
elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.btnEl) : this.wrapEl.appendChild(this.btnEl);
}
this.inputEl.addEventListener('keydown', this.btnEvt, false);
}
else {
this.btnEl.remove();
this.inputEl.removeEventListener('keydown', this.btnEvt);
}
}
changedAction(opt) {
if (opt.newVal) {
this.btnEl.onclick = () => {
new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.btnEl, el: this });
};
}
else {
this.btnEl.onclick = null;
}
}
changedIcon(opt) {
if (opt.newVal) {
this.iconEl.classList.add(opt.newVal);
elState(this.iconEl).isVirtual && this.inputEl.insertAdjacentElement('beforebegin', this.iconEl);
}
else {
this.iconEl.remove();
}
}
changedImage(opt) {
if (opt.newVal) {
this[`${opt.name}El`].src = opt.newVal;
elState(this[`${opt.name}El`]).isVirtual && this.inputEl.insertAdjacentElement('beforebegin', this[`${opt.name}El`]);
}
else {
this[`${opt.name}El`].remove();
}
}
changedMean(opt) {
if (opt.newVal) {
this.meanEl.classList.add(opt.newVal);
if (elState(this.meanEl).isVirtual) {
elState(this.unitEl).isVisible ? this.unitEl.insertAdjacentElement('beforebegin', this.meanEl) : this.wrapEl.appendChild(this.meanEl);
}
}
else {
this.meanEl.remove();
}
}
changedTask(opt) {
if (opt.newVal) {
this.meanEl.onclick = () => {
new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.meanEl, el: this });
};
}
else {
this.meanEl.onclick = null;
}
}
}
class Pagination extends ModBaseListenCache {
options = {};
listEl;
mainEl;
pagesEl;
firstEl;
lastEl;
prevEl;
nextEl;
totalEl;
tipsEl;
locateEl;
countEl;
ellEl;
locateInput;
locateBtn;
countInput;
countBtn;
items;
outputObs;
output;
content;
data;
nodes;
spyIns;
dropdwonIns;
altIns;
static hostType = 'node';
static optMaps = optPagination;
static dependencies = [InputElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Pagination.optMaps,
host: elem,
component: true,
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.setOutputObs();
this.listEl = getEl(this.options.listSel);
this.setAttrs();
this.useTpl();
this.getNodesTree();
await this.getInitData();
this.renderLocateEl();
this.renderCountEl();
this.altIns && this.altIns.on('located', (data) => {
this.locate(data.current);
});
super.listen({ name: 'initiated', cb });
return this;
}
setOutputObs() {
this.outputObs = new Observe({ current: -1, count: this.options.count, total: 0, pages: -1, }, {
lenient: false,
onSet: (data) => {
if (['total', 'count'].includes(data.key)) {
if (data.key === 'total') {
data.proxy.pages = Math.ceil(data.value / (data.proxy.count || 1)) || 1;
}
else if (data.key === 'count') {
data.proxy.pages = Math.ceil(data.proxy.total / (data.value || 1)) || 1;
}
data.proxy.current = Math.min(data.proxy.current, data.proxy.pages);
}
else if (data.key === 'current') {
data.proxy.current = clampVal({ val: data.value, min: 1, max: data.proxy.pages });
}
this.renderTotalEl();
this.renderTipsEl();
},
onCompleted: (data) => {
if (!data.keys.set.includes('pages') && !data.keys.set.includes('current'))
return;
if (isEmpty(this.items) || data.keys.set.includes('pages')) {
this.renderPagesEl();
this.rerenderListEl();
}
else if (data.keys.set.includes('current')) {
if (this.hasEll()) {
this.renderPagesEl();
this.rerenderListEl();
}
else {
this.toggleSelected();
}
}
if (data.proxy.pages <= 1) {
this.setDisabled();
}
else {
if (data.proxy.current <= 1) {
this.setDisabled('start');
this.setEnabled('end');
}
else if (data.proxy.current >= data.proxy.pages) {
this.setDisabled('end');
this.setEnabled('start');
}
else {
this.setEnabled();
}
}
this.altIns && this.altIns.locate(data.proxy.current);
}
});
this.output = this.outputObs.proxy;
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}pagination`);
this.options.align ? this.targetEl.setAttribute('align', this.options.align) : this.targetEl.removeAttribute('align');
this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.toggleAttribute('flexible', this.options.flexible);
this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
}
getNodesTree() {
this.targetEl.innerHTML = '';
this.mainEl = createEl(this.options.names.main, { [ax.alias]: 'main' }, this.pagesEl);
this.pagesEl = createEl(this.options.names.pages, { [ax.alias]: 'pages' });
this.firstEl = createEl(this.options.names.first, { [ax.alias]: 'first' }, this.options.lang?.first);
this.lastEl = createEl(this.options.names.last, { [ax.alias]: 'last' }, this.options.lang?.last);
this.prevEl = createEl(this.options.names.prev, { [ax.alias]: 'prev' }, this.options.lang?.prev);
this.nextEl = createEl(this.options.names.next, { [ax.alias]: 'next' }, this.options.lang?.next);
this.totalEl = createEl(this.options.names.total, { [ax.alias]: 'total' });
this.tipsEl = createEl(this.options.names.tips, { [ax.alias]: 'tips' });
this.locateEl = createEl(this.options.names.lacate, { [ax.alias]: 'locate' });
this.countEl = createEl(this.options.names.count, { [ax.alias]: 'count' });
this.ellEl = createEl(this.options.names.ellipsis, { [ax.alias]: 'ell' }, this.options.lang?.ellipsis);
super.parseLayout(this.targetEl, this.options.layout, {
prev: this.prevEl,
next: this.nextEl,
first: this.firstEl,
last: this.lastEl,
total: this.totalEl,
count: this.countEl,
tips: this.tipsEl,
locate: this.locateEl,
pages: this.pagesEl,
group: this.mainEl,
});
this.prevEl.onclick = () => {
this.prev();
};
this.nextEl.onclick = () => {
this.next();
};
this.firstEl.onclick = () => {
this.first();
};
this.lastEl.onclick = () => {
this.last();
};
}
async getInitData() {
if (typeof this.options.content === 'number' || this.options.contType === 'total') {
this.respSource = Array(~~this.options.content).fill(null).map((k, i) => { return { index: i }; });
this.content = this.respSource;
this.output.total = this.options.content;
}
else if (this.options.content.moduleName === 'pagination') {
this.altIns = this.options.content;
this.content = [...this.altIns.content];
this.output.total = this.content.length;
}
else if ((typeof this.options.content === 'string') && this.options.contType === 'ins') {
this.altIns = instance.find(this.options.content, 'pagination');
this.content = this.altIns ? [...this.altIns.content] : [];
this.output.total = this.content.length;
}
else {
let resp = await this.getData();
this.content = resp.content;
}
if (this.options.current < 1 || this.options.current > this.output.pages) {
console.warn('The value is out of range,it has been fixed!');
super.listen({ name: 'exceeded', params: [{ val: this.options.current, min: 1, max: this.output.pages }] });
}
this.updateCur(this.options.current);
if (this.isSqlReq()) {
this.data = this.content;
}
else {
this.data = this.sliceData(this.content);
}
if (this.output.current === 1) {
super.listen({ name: 'toFirst' });
}
else if (this.output.current === this.output.pages) {
super.listen({ name: 'toLast' });
}
super.listen({ name: 'located', params: [{ current: this.output.current, data: this.data }] });
}
async getData(data, cb) {
let result = { content: [], source: null };
let contReq = {
content: this.options.content,
contType: this.options.contType,
contData: Object.assign({ current: this.options.current, count: this.options.count }, this.options.contData),
ajax: {
spinSel: this.listEl,
error: (resp) => {
super.listen({ name: 'error', params: [resp] });
},
xhrName: 'contXhr',
...this.options.ajax,
},
}, resp = await getContent.call(this, data ? extend({ target: contReq, source: data }) : contReq), respType = getDataType(resp);
result.source = resp;
if (respType === 'Array') {
result.content = resp;
this.output.total = result.content.length;
}
else if (respType === 'Object' && resp.hasOwnProperty('data')) {
if (Array.isArray(resp.data)) {
result.content = resp.data;
this.output.total = result.content.length;
}
else {
result.content = resp?.data?.list || [];
this.output.total = resp?.data?.total || result.content.length;
}
}
else if (respType === 'String') {
result.content = tplToEls(resp);
this.output.total = result.content.length;
}
this.respSource = result.source;
super.listen({ name: 'gotCont', cb, params: [result] });
return result;
}
isSqlReq(resp = this.respSource) {
return resp?.data?.hasOwnProperty('list') && resp?.data?.hasOwnProperty('total');
}
sliceData(data = this.content, current = this.output.current) {
let start = (current - 1) * this.output.count;
return data.slice(start, start + this.output.count);
}
async getCurCont(current = this.output.current) {
current = this.correctCur(current);
let result;
if (this.isSqlReq()) {
let resp = await this.getData({ contData: { current, count: this.output.count } });
this.content = resp.content;
result = resp.content;
}
else {
result = this.sliceData(this.content, current);
}
return result;
}
getItemNode(data) {
let dataType = getDataType(data), result;
if (dataType.includes('HTML')) {
result = data;
}
else {
result = createEl(this.options.names.section, {});
result.innerHTML = dataType === 'Object' ? super.getTplcont(data) : data.toString();
}
return result;
}
renderTotalEl() {
this.totalEl.innerHTML = renderTpl(this.options.lang?.total, this.output);
}
renderTipsEl() {
this.tipsEl.innerHTML = renderTpl(this.options.lang?.tips, this.output);
}
renderLocateEl() {
let tmp = { size: 'sm', feature: 'plain', label: this.options.lang?.locate, unit: this.options.lang?.page, value: this.output.current, btn: `<i class='_icon-arrow-right'></i>` };
this.locateInput = createEl('ax-input', tmp);
this.locateInput.on('connected', () => {
this.locateInput.btnEl.onclick = debounce(() => {
let val = ~~this.locateInput.value;
(val < 1 || val > this.output.pages) && console.warn('The value is out of range,it has been fixed!');
val = this.correctCur(val);
this.locateInput.value = val;
this.locate(val);
}, this.options.delay);
this.locateInput.onkeyup = (e) => (e.code === 'Enter') && this.locateInput.btnEl.click();
});
this.locateEl.appendChild(this.locateInput);
}
renderCountEl() {
let tmp = { size: 'sm', feature: 'plain', label: this.options.lang?.count, unit: this.options.lang?.unit, value: this.output.count, btn: `<i class='_icon-arrow-right'></i>` };
this.countInput = createEl('ax-input', tmp);
this.countInput.on('connected', () => {
this.countInput.btnEl.onclick = debounce(() => {
this.output.count = ~~this.countInput.value;
}, this.options.delay);
this.countInput.onkeyup = (e) => (e.code === 'Enter') && this.countInput.btnEl.click();
if (this.options.counts) {
this.dropdwonIns = new ax.Dropdown(this.countInput, {
content: this.options.counts,
feature: 'select',
popup: {
canClick: (target) => {
return this.countInput.inputEl.contains(target);
},
onTargetSet: (val) => {
this.countInput.btnEl.click();
}
}
});
}
});
this.countEl.appendChild(this.countInput);
}
renderPagesEl(current = this.output.current) {
this.pagesEl.innerHTML = '';
this.items = [];
for (let i = 1; i <= this.output.pages; i++) {
if (this.options.expanded) {
this.items.push(this.createItem(i));
}
else {
let condL = i > this.options.visible?.edge && i < current - this.options.visible?.center, condR = i > current + this.options.visible?.center && i <= this.output.pages - this.options.visible?.edge;
if (condL || condR) {
if (this.items.at(-1) && this.items.at(-1).getAttribute(ax.alias) === 'ell') {
continue;
}
else {
let tmp = this.ellEl.cloneNode(false);
tmp.innerHTML = renderTpl(this.options.lang?.ellipsis, this.output);
this.items.push(tmp);
}
}
else {
this.items.push(this.createItem(i));
}
}
}
this.pagesEl.append(...this.items);
super.listen({ name: 'renderedPages', params: [{ nodes: this.items, ...this.output }] });
}
createItem(current) {
let tmp = createEl(this.options.names.item, { [ax.alias]: 'page', page: current }, current);
this.output.current == current && tmp.setAttribute('selected', '');
tmp.onclick = debounce(() => {
this.locate(current);
}, this.options.delay);
return tmp;
}
hasEll() {
return this.items.find((k) => k.getAttribute(ax.alias, 'ell'));
}
correctCur(current) {
return clampVal({ val: current, min: 1, max: this.output.pages });
}
updateCur(current = this.output.current) {
this.output.current = ~~current;
}
async rerenderListEl() {
if (this.destroyed || !this.listEl)
return;
if (this.options.b4RenderList) {
let resp = await this.options.b4RenderList.call(this, this.data);
resp && (this.data = resp);
}
this.nodes = [];
for (let k of this.data) {
let tmp = this.getItemNode(k);
tmp && this.nodes.push(tmp);
}
this.listEl.innerHTML = '';
this.listEl.append(...this.nodes);
super.listen({ name: 'renderedList', params: [{ nodes: this.nodes, data: this.data, wrap: this.listEl, ...this.output }] });
}
toggleSelected(current = this.output.current) {
let item = this.items.find((k) => k.getAttribute('page') == current);
if (item) {
item.setAttribute('selected', '');
let tmp = this.items.find((k) => k !== item && k.hasAttribute('selected'));
tmp && tmp.removeAttribute('selected');
}
}
render({ content = [], tplStr = this.tplStr, tplEng = this.tplEng, nodeName = this.options.names.section, wrapSel }) {
if (this.destroyed)
return;
if (isEmpty(content))
return;
this.nodes = [];
let wrapEl = getEl(wrapSel);
for (let k of content) {
let str = super.getTplcont(k, tplStr, tplEng), node = createEl(nodeName, {}, str);
this.nodes.push(node);
}
if (wrapEl) {
wrapEl.innerHTML = '';
wrapEl.append(...this.nodes);
}
super.listen({ name: 'renderedList', params: [{ nodes: this.nodes, data: content, wrap: wrapEl, ...this.output }] });
}
async locate(current, cb) {
if (this.destroyed)
return;
current = ~~current;
if (this.options.b4Locate) {
let resp = await this.options.b4Locate.call(this, { to: current, ...this.output });
if (!isNull(resp)) {
typeof resp === 'number' ? (current = resp) : (current = ~~resp);
}
}
if (current < 1 || current > this.output.pages) {
console.warn('The value is out of range,it has been fixed!');
super.listen({ name: 'exceeded', params: [{ val: current, min: 1, max: this.output.pages }] });
}
current = this.correctCur(current);
this.data = await this.getCurCont(current);
this.updateCur(current);
if (this.output.current === 1) {
super.listen({ name: 'toFirst' });
}
else if (this.output.current === this.output.pages) {
super.listen({ name: 'toLast' });
}
super.listen({ name: 'located', cb, params: [{ current, data: this.data }] });
}
prev() {
this.locate(this.output.current - 1);
}
next() {
this.locate(this.output.current + 1);
}
first() {
this.locate(1);
}
last() {
this.locate(this.output.pages);
}
setDisabled(type = 'both') {
if (type === 'start') {
this.prevEl.setAttribute('disabled', '');
this.firstEl.setAttribute('disabled', '');
}
else if (type === 'end') {
this.nextEl.setAttribute('disabled', '');
this.lastEl.setAttribute('disabled', '');
}
else {
this.prevEl.setAttribute('disabled', '');
this.firstEl.setAttribute('disabled', '');
this.nextEl.setAttribute('disabled', '');
this.lastEl.setAttribute('disabled', '');
}
}
setEnabled(type = 'both') {
if (type === 'start') {
this.prevEl.removeAttribute('disabled');
this.firstEl.removeAttribute('disabled');
}
else if (type === 'end') {
this.nextEl.removeAttribute('disabled');
this.lastEl.removeAttribute('disabled');
}
else {
this.prevEl.removeAttribute('disabled');
this.firstEl.removeAttribute('disabled');
this.nextEl.removeAttribute('disabled');
this.lastEl.removeAttribute('disabled');
}
}
destroy(cb) {
if (this.destroyed)
return this;
this.spyIns.destroy();
super.listen({ name: 'destroyed', cb });
return this;
}
}
let OCTMP_separator = config.rangeHyphen, OCTMP_hyphen = config.rangeHyphen;
const optRange = [
{
attr: 'name',
prop: 'name',
value: ''
},
{
attr: 'step',
prop: 'step',
value: 1,
},
{
attr: 'max',
prop: 'max',
value: 100,
},
{
attr: 'min',
prop: 'min',
value: 0,
},
{
attr: 'value',
prop: 'value',
value: 0,
},
{
attr: 'multiple',
prop: 'multiple',
value: false,
},
{
attr: 'full',
prop: 'full',
value: false,
},
{
attr: 'rtl',
prop: 'rtl',
value: false,
},
{
attr: 'locked',
prop: 'locked',
value: false,
},
{
attr: 'limit-show',
prop: 'limitShow',
value: true,
},
{
attr: 'tip-show',
prop: 'tipShow',
value: true,
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'fence',
prop: 'fence',
value: {
enable: false,
min: 0,
max: 100,
},
},
{
attr: 'button',
prop: 'button',
value: {
enable: false,
decrease: `<i class="${ax.prefix}icon-minus-o-f"></i>`,
increase: `<i class="${ax.prefix}icon-plus-o-f"></i>`,
}
},
{
attr: 'ruler',
prop: 'ruler',
value: {
enable: false,
majorEqual: 4,
minorEqual: 'auto',
labels: [],
}
},
{
attr: 'result',
prop: 'result',
value: {
enable: false,
target: null,
}
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'keyboard',
prop: 'keyboard',
value: false,
},
{
attr: 'separator',
prop: 'separator',
value: OCTMP_separator,
},
{
attr: 'hyphen',
prop: 'hyphen',
value: OCTMP_hyphen,
},
{
attr: 'flow',
prop: 'flow',
value: 'h',
},
{
attr: 'disabled',
prop: 'disabled',
value: false,
},
{
attr: 'on-set',
prop: 'onSet',
value: null,
},
{
attr: 'on-tostart',
prop: 'onToStart',
value: null,
},
{
attr: 'on-toend',
prop: 'onToEnd',
value: null,
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null,
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null,
},
{
attr: 'on-restored',
prop: 'onRestored',
value: null,
},
...optBase
];
class Range extends ModBaseListenCache {
options = {};
inputEl;
axisCoef;
resizeObs;
sizes;
keyEvt;
focusEvt;
focusHandle;
handles;
gestures;
fence;
resultParent;
initVal;
rawVal;
places;
output;
decrEl;
incrEl;
resultEl;
wrapEl;
mainEl;
trackEl;
thumbEl;
baseEl;
bubbleEl;
bubbles;
handleEl;
rulerEl;
tickEl;
tmpRatios;
offset;
ceilValue;
ticks;
fenceEl;
propsMap;
static hostType = 'node';
static optMaps = optRange;
constructor(elem, options = {}, initial = true) {
super();
let tmp = getEl(elem), host;
if (!tmp)
return this;
if (tmp.nodeName === 'INPUT') {
this.inputEl = tmp;
this.inputEl.type = 'hidden';
host = createEl('div', { class: `${ax.prefix}range` });
tmp.insertAdjacentElement('beforebegin', host);
host.appendChild(tmp);
}
else {
host = tmp;
host.classList.add(`${ax.prefix}range`);
this.inputEl = createEl('input', { type: 'hidden', value: tmp.textContent.trim() });
tmp.innerHTML = '';
host.appendChild(this.inputEl);
}
super.ready({
options,
maps: Range.optMaps,
host,
component: true,
spread: ['button', 'ruler', 'result', 'fence']
});
if (this.options.flow === 'h') {
this.propsMap = propsMap.x;
}
else {
this.propsMap = propsMap.y;
this.propsMap.position = 'bottom';
this.propsMap.start = 'insetBlockEnd';
this.propsMap.startAlt = 'inset-block-end';
}
this.axisCoef = this.options.flow === 'v' ? -1 : 1;
this.resizeObs = new ResizeObserver(debounce(() => {
this.updateSizes();
}));
this.sizes = {
handle: 0,
track: 0,
ruler: 0,
thumb: 0,
bubble: { min: 0, max: 0, from: 0, to: 0, single: 0 },
ratio: { radius: 0, min: 0, max: 0, full: 0 },
offset: {
from: { min: 0, max: 0 },
to: { min: 0, max: 0 },
single: { min: 0, max: 0 },
}
};
let _this = this;
this.keyEvt = function (e) {
if (!['ArrowLeft', 'ArrowDown', 'ArrowRight', 'ArrowUp'].includes(e.code))
return;
preventDft(e, true);
_this.focusHandle = this;
if ([_this.isRtl ? 'ArrowRight' : 'ArrowLeft', 'ArrowDown'].includes(e.code)) {
_this.decrease();
}
else {
_this.increase();
}
};
this.focusEvt = function () {
this.focus();
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.handles = { from: null, to: null, single: null };
this.gestures = { from: null, to: null, single: null, thumb: null };
this.correctOpts();
this.resultParent = getEl(this.options.result.target);
this.getInitVal();
this.rawVal = Array.isArray(this.options.value) ? [...this.initVal] : this.initVal;
this.getPlaces();
this.output = { multiple: this.options.multiple, raw: '', value: '', range: [0, 0], ratio: [0, 0] };
this.initRender();
this.getDirRtl();
this.setAttrs();
this.resizeObs.observe(this.trackEl);
this.updateSizes();
this.setVals(this.initVal);
this.ticks = [];
this.setTicks();
this.setFence();
if (!this.options.disabled) {
if (this.options.button.enable) {
this.decrEl.onclick = () => this.decrease();
this.incrEl.onclick = () => this.increase();
}
if (this.options.multiple) {
this.setHandleIns('from');
this.setHandleIns('to');
this.tmpRatios = [...this.output.ratio];
this.gestures.thumb = new Gesture(this.thumbEl, {
onTranslating: (e) => {
this.slideSet(this.thumbEl, e.translate.diff[this.propsMap.axis] * this.axisCoef);
},
onTranslated: () => {
this.tmpRatios = [...this.output.ratio];
}
});
}
else {
this.setHandleIns('single');
}
this.baseEl.onclick = (e) => {
let clientObj = getClientObj(e), offset;
if (!clientObj) {
return false;
}
offset = (clientObj[this.propsMap.axis] - this.baseEl.getBoundingClientRect()[this.propsMap.position]) * this.axisCoef;
if (this.options.multiple) {
let fromOffset = this.output.ratio[0] * this.sizes.track, toOffset = this.output.ratio[1] * this.sizes.track;
if (offset > toOffset) {
this.slideSet(this.thumbEl, offset - toOffset - this.sizes.handle / 2);
}
else if (offset < toOffset) {
this.slideSet(this.thumbEl, offset - fromOffset - this.sizes.handle / 2);
}
this.tmpRatios = [...this.output.ratio];
}
else {
this.slideSet(this.handles.single, offset - this.sizes.handle / 2);
}
};
if (!this.options.multiple) {
this.thumbEl.onclick = (e) => {
let clientObj = getClientObj(e), offset;
if (clientObj) {
offset = (clientObj[this.propsMap.axis] - this.baseEl.getBoundingClientRect()[this.propsMap.position]) * this.axisCoef;
this.slideSet(this.handles.single, offset - this.sizes.handle / 2);
}
};
}
if (this.bubbles.min) {
this.bubbles.min.onclick = () => {
this.toStart();
};
}
if (this.bubbles.max) {
this.bubbles.max.onclick = () => {
this.toEnd();
};
}
if (this.options.keyboard) {
for (let k in this.handles) {
let tmp = this.handles[k];
if (tmp) {
tmp.removeEventListener('keydown', this.keyEvt);
tmp.addEventListener('keydown', this.keyEvt, false);
tmp.removeEventListener('pointerup', this.focusEvt);
tmp.addEventListener('pointerup', this.focusEvt, false);
}
}
}
}
super.listen({ name: 'initiated', cb });
return this;
}
correctOpts() {
this.options.max = parseFloat(this.options.max);
this.options.min = parseFloat(this.options.min);
this.options.step = parseFloat(this.options.step);
if (this.options.fence.enable) {
this.fence = {
min: clampVal({ val: this.options.fence.min, min: this.options.min, max: this.options.max }),
max: clampVal({ val: this.options.fence.max, min: this.options.min, max: this.options.max })
};
}
else {
this.fence = { min: this.options.min, max: this.options.max };
}
}
updateSizes() {
let handle = (this.handles.single || this.handles.from).getBoundingClientRect()[this.propsMap.size], track = this.trackEl.getBoundingClientRect()[this.propsMap.size], min = this.bubbles.min ? this.bubbles.min.getBoundingClientRect()[this.propsMap.size] : 0, max = this.bubbles.max ? this.bubbles.max.getBoundingClientRect()[this.propsMap.size] : 0, from = this.bubbles.from ? this.bubbles.from.getBoundingClientRect()[this.propsMap.size] : 0, to = this.bubbles.to ? this.bubbles.to.getBoundingClientRect()[this.propsMap.size] : 0, single = this.bubbles.single ? this.bubbles.single.getBoundingClientRect()[this.propsMap.size] : 0, fullRatio = (track - handle) / track, radiusRadio = (handle / 2) / track, minRatio = ((this.fence.min - this.options.min) / (this.options.max - this.options.min)) * fullRatio, maxRatio = ((this.fence.max - this.options.min) / (this.options.max - this.options.min)) * fullRatio;
extend({
target: this.sizes,
source: {
handle, track,
bubble: { min, max, from, to, single },
ratio: { radius: radiusRadio, min: minRatio, max: maxRatio, full: fullRatio },
}
});
}
setHandleIns(type) {
this.gestures[type] = new Gesture(this.handles[type], {
onTranslate: () => {
this.offset = style(this.handles[type])[this.propsMap.start];
},
onTranslating: (e) => {
let diff = e.translate.diff[this.propsMap.axis] * this.axisCoef * super.getRtlCoef(), value = parseFloat(this.offset) + diff;
this.slideSet(this.handles[type], value);
},
onTranslated: () => {
type !== 'single' && (this.tmpRatios = [...this.output.ratio]);
}
});
}
setHandleActive(el) {
el.setAttribute('active', '');
for (let k in this.handles) {
this.handles[k] !== el && (this.handles[k].removeAttribute('active'));
}
}
getRatioFromVal(value) {
return ((value - this.options.min) / (this.options.max - this.options.min)) * this.sizes.ratio.full;
}
getValFromRatio(ratio) {
return ratio * (this.options.max - this.options.min) / this.sizes.ratio.full + this.options.min;
}
decrease(step = this.options.step) {
let isToFocus = this.handles.to && this.focusHandle === this.handles.to, min = isToFocus ? this.output.range[0] : this.fence.min, value = (this.output.range[isToFocus ? 1 : 0] - step), handleDiff = (this.output.range[1] - this.output.range[0]);
if (this.options.multiple) {
value < min && (value = min);
if (this.options.locked) {
this.setVals([value, value + handleDiff]);
}
else {
this.setVals(isToFocus ? [this.output.range[0], value] : [value, this.output.range[1]]);
}
}
else {
this.setVals(this.output.range[0] - step);
}
this.options.multiple && (this.tmpRatios = [...this.output.ratio]);
}
increase(step = this.options.step) {
let isFromFocus = this.handles.from && this.focusHandle === this.handles.from, max = isFromFocus ? this.output.range[1] : this.fence.max, value = (this.output.range[isFromFocus ? 0 : 1] + step), handleDiff = (this.output.range[1] - this.output.range[0]);
if (this.options.multiple) {
value > max && (value = max);
if (this.options.locked) {
this.setVals([value - handleDiff, value]);
}
else {
this.setVals(isFromFocus ? [value, this.output.range[1]] : [this.output.range[0], value]);
}
}
else {
this.setVals(this.output.range[0] + step);
}
this.options.multiple && (this.tmpRatios = [...this.output.ratio]);
}
setAttrs() {
this.targetEl.setAttribute('flow', this.options.flow);
classes(this.targetEl).add(this.options.classes);
this.targetEl.toggleAttribute('multiple', this.options.multiple);
this.targetEl.toggleAttribute('full', this.options.full);
this.targetEl.toggleAttribute('inert', this.options.disabled);
this.targetEl.setAttribute('size', this.options.size);
this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
}
getInitVal() {
if (this.inputEl.value) {
if (this.inputEl.value.includes(this.options.separator)) {
this.options.multiple = true;
this.initVal = this.inputEl.value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
}
else {
this.initVal = this.options.multiple ? [parseFloat(this.inputEl.value), this.options.max] : parseFloat(this.inputEl.value);
}
}
else {
if (this.options.multiple && !Array.isArray(this.options.value)) {
let tmp = typeof this.options.value === 'number' ? [this.options.value] :
(this.options.value.split(this.options.separator).slice(0, 2).map((k) => parseFloat(k)).sort((a, b) => a - b));
this.initVal = [isNull(tmp[0]) ? this.options.min : tmp[0], isNull(tmp[1]) ? this.options.max : tmp[1]];
}
else if (!this.options.multiple && Array.isArray(this.options.value)) {
this.initVal = this.options.value[0];
}
else if (typeof this.options.value === 'string' && this.options.value.includes(this.options.separator)) {
this.options.multiple = true;
this.initVal = this.options.value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
}
else {
this.initVal = Array.isArray(this.options.value) ? [...this.options.value].sort((a, b) => a - b) : this.options.value;
}
}
}
getPlaces() {
let stepPlaces = this.options.step.toString().split('.')[1] ? this.options.step.toString().split('.')[1].length : 0, endsPlaces = Math.max(getPlaces(this.options.min), getPlaces(this.options.max));
this.places = stepPlaces > 0 ? stepPlaces : endsPlaces;
}
correctVal(value) {
let obj = { min: this.fence.min, max: this.fence.max };
if (Array.isArray(value)) {
let tmp = value.map((k) => toNumber(clampVal({ val: k, ...obj }), { places: this.places }));
this.options.multiple && tmp.sort((a, b) => a - b);
return tmp;
}
else if (value === '' || isNull(value)) {
return [this.fence.min, this.fence.max];
}
else {
let tmp;
if (typeof value === 'string' && value.includes(this.options.separator)) {
tmp = value.split(this.options.separator).map((k) => parseFloat(k)).sort((a, b) => a - b);
}
else {
tmp = [toNumber(clampVal({ val: value, ...obj }), { places: this.places }), this.output.range[1]];
}
return this.options.multiple ? tmp.sort((a, b) => a - b) : tmp;
}
}
initRender() {
if (this.wrapEl) {
this.wrapEl.innerHTML = '';
this.options.name && (this.inputEl.name = this.options.name);
this.inputEl.value = '';
}
else {
this.wrapEl = createEl('div', { class: `${ax.prefix}range-wrap` });
this.targetEl.appendChild(this.wrapEl);
!this.inputEl.name && (this.inputEl.name = this.options.name);
}
this.bubbles = {};
this.wrapEl.innerHTML = `
<div class="${ax.prefix}range-main">
<div class="${ax.prefix}range-track">
<div ${ax.alias}="base"></div>
<div ${ax.alias}="thumb"></div>
</div>
<div class="${ax.prefix}range-bubble">
${this.options.limitShow ? '<span ' + ax.alias + '="min">' + this.options.min + '</span><span ' + ax.alias + '="max">' + this.options.max + '</span>' : ''}
</div>
<div class="${ax.prefix}range-handle"></div>
<div class="${ax.prefix}range-ruler"><ul></ul></div>
</div>
`;
this.mainEl = this.wrapEl.querySelector(`.${ax.prefix}range-main`);
this.trackEl = this.wrapEl.querySelector(`.${ax.prefix}range-track`);
this.thumbEl = this.wrapEl.querySelector(`[${ax.alias}="thumb"]`);
this.baseEl = this.wrapEl.querySelector(`[${ax.alias}="base"]`);
this.bubbleEl = this.wrapEl.querySelector(`.${ax.prefix}range-bubble`);
this.bubbles.min = this.bubbleEl.querySelector(`[${ax.alias}="min"]`);
this.bubbles.max = this.bubbleEl.querySelector(`[${ax.alias}="max"]`);
this.handleEl = this.wrapEl.querySelector(`.${ax.prefix}range-handle`);
this.rulerEl = this.wrapEl.querySelector(`.${ax.prefix}range-ruler`);
this.tickEl = this.rulerEl.querySelector('ul');
this.decrEl = createEl('span', { class: `${ax.prefix}range-btn`, [ax.alias]: 'decrease' }, this.options.button.decrease);
this.incrEl = createEl('span', { class: `${ax.prefix}range-btn`, [ax.alias]: 'increase' }, this.options.button.increase);
if (this.options.button.enable) {
this.mainEl.insertAdjacentElement('beforebegin', this.decrEl);
this.mainEl.insertAdjacentElement('afterend', this.incrEl);
}
this.resultEl = createEl('span', { class: `${ax.prefix}range-result` });
if (this.options.result.enable) {
this.resultParent ? this.resultParent.appendChild(this.resultEl) : this.wrapEl.appendChild(this.resultEl);
}
if (this.options.multiple) {
this.handles.from = createEl('span', { [ax.alias]: 'from', tabindex: 0 });
this.handles.to = createEl('span', { [ax.alias]: 'to', tabindex: 0 });
this.handleEl.append(this.handles.from, this.handles.to);
if (this.options.tipShow) {
this.bubbles.from = createEl('span', { [ax.alias]: 'from' });
this.bubbles.to = createEl('span', { [ax.alias]: 'to' });
this.bubbles.merge = createEl('span', { [ax.alias]: 'merge' });
this.bubbleEl.append(this.bubbles.from, this.bubbles.to, this.bubbles.merge);
}
}
else {
this.handles.single = createEl('span', { [ax.alias]: 'single', tabindex: 0 });
this.handleEl.append(this.handles.single);
if (this.options.tipShow) {
this.bubbles.single = createEl('span', { [ax.alias]: 'single' });
this.bubbleEl.append(this.bubbles.single);
}
}
}
setVals(value, cb) {
if (this.destroyed)
return;
this.output.range = this.correctVal(value);
let radiusPercent = this.sizes.ratio.radius * 100, getTipHTML = (val) => toNumber(val, { places: this.places });
if (this.options.multiple) {
this.output.ratio = [this.getRatioFromVal(this.output.range[0]), this.getRatioFromVal(this.output.range[1])];
let fromPercent = this.output.ratio[0] * 100, toPercent = this.output.ratio[1] * 100;
this.handles.from.style[this.propsMap.start] = `${fromPercent}%`;
this.handles.to.style[this.propsMap.start] = `${toPercent}%`;
this.sizes.ratio.center = this.output.ratio[1];
this.thumbEl.style[this.propsMap.size] = `${toPercent - fromPercent}%`;
this.thumbEl.style[this.propsMap.start] = `${fromPercent + radiusPercent}%`;
this.sizes.thumb = this.thumbEl.getBoundingClientRect()[this.propsMap.size];
if (this.options.tipShow) {
this.bubbles.from.style[this.propsMap.start] = `${fromPercent}%`;
this.bubbles.from.innerHTML = getTipHTML(this.output.range[0]);
this.bubbles.to.style[this.propsMap.start] = `${toPercent}%`;
this.bubbles.to.innerHTML = getTipHTML(this.output.range[1]);
this.bubbles.merge.style[this.propsMap.start] = `${fromPercent + (toPercent - fromPercent) / 2}%`;
this.bubbles.merge.innerHTML = `${getTipHTML(this.output.range[0])}<i>${this.options.hyphen}</i>${getTipHTML(this.output.range[1])}`;
this.sizes.bubble.from = this.bubbles.from.getBoundingClientRect()[this.propsMap.size];
this.sizes.bubble.to = this.bubbles.to.getBoundingClientRect()[this.propsMap.size];
this.mergeTips();
}
}
else {
this.output.ratio[0] = this.getRatioFromVal(this.output.range[0]);
let singlePercent = this.output.ratio[0] * 100;
this.handles.single.style[this.propsMap.start] = `${singlePercent}%`;
this.thumbEl.style[this.propsMap.size] = `${singlePercent + radiusPercent}%`;
this.sizes.thumb = this.thumbEl.getBoundingClientRect()[this.propsMap.size];
if (this.options.tipShow) {
this.bubbles.single.style[this.propsMap.start] = `${singlePercent}%`;
this.bubbles.single.innerHTML = getTipHTML(this.output.range[0]);
this.sizes.bubble.single = this.bubbles.single.getBoundingClientRect()[this.propsMap.size];
}
}
this.output.value = (this.options.multiple ? this.output.range.join(this.options.separator) : this.output.range[0]).toString();
this.output.raw = this.inputEl.value;
this.options.limitShow && this.hideEnds();
this.inputEl.value = this.output.value;
this.options.result.enable && (this.resultEl.innerHTML = renderTpl(this.options.lang.result, this.output));
super.listen({ name: 'output', params: [this.output] });
super.listen({ name: 'set', cb, params: [this.output] });
this.endsListen(cb);
return this;
}
endsListen(cb) {
if (this.options.multiple) {
if (this.output.range[0] <= this.fence.min) {
this.decrEl.toggleAttribute('inert', true);
super.listen({ name: 'toStart', cb, params: [this.fence] });
}
else {
this.decrEl.removeAttribute('inert');
}
if (this.output.range[1] >= this.fence.max) {
this.incrEl.toggleAttribute('inert', true);
super.listen({ name: 'toEnd', cb, params: [this.fence] });
}
else {
this.incrEl.removeAttribute('inert');
}
}
else {
if (this.output.range[0] <= this.fence.min) {
this.decrEl.toggleAttribute('inert', true);
super.listen({ name: 'toStart', cb, params: [this.fence] });
}
else if (this.output.range[0] >= this.fence.max) {
this.incrEl.toggleAttribute('inert', true);
super.listen({ name: 'toEnd', cb, params: [this.fence] });
}
else {
this.decrEl.removeAttribute('inert');
this.incrEl.removeAttribute('inert');
}
}
}
getVals() {
return this.output;
}
toEnd(cb) {
if (this.destroyed)
return;
let value, diff;
if (this.options.multiple) {
diff = this.fence.max - this.output.range[1];
value = [this.output.range[0] + diff, this.output.range[1] + diff];
}
else {
value = this.fence.max;
}
this.setVals(value);
cb && cb.call(this, value);
return this;
}
toStart(cb) {
if (this.destroyed)
return;
let value, diff;
if (this.options.multiple) {
diff = this.fence.min - this.output.range[0];
value = [this.output.range[0] + diff, this.output.range[1] + diff];
}
else {
value = this.fence.min;
}
this.setVals(value);
cb && cb.call(this, value);
return this;
}
slideSet(dom, value) {
if (this.destroyed)
return;
let result;
if (dom === this.thumbEl && this.options.multiple) {
let fromRatio = this.tmpRatios[0] + value / this.sizes.track, diffRatio = this.tmpRatios[1] - this.tmpRatios[0], toRatio = fromRatio + diffRatio, from = this.getValFromRatio(fromRatio), to = this.getValFromRatio(toRatio), diff = this.getValFromRatio(toRatio) - this.getValFromRatio(fromRatio);
if (this.options.locked) {
if (from < this.fence.min) {
result = [this.fence.min, this.fence.min + diff];
}
else if (to > this.fence.max) {
result = [this.fence.max - diff, this.fence.max];
}
else {
result = [from, to];
}
}
else {
result = [from, to];
}
}
else {
let ratio = (value / this.sizes.track);
if (dom === this.handles.from) {
if (ratio > this.output.ratio[1]) {
ratio = this.output.ratio[1];
}
else if (ratio < this.sizes.ratio.min) {
ratio = this.sizes.ratio.min;
}
result = [this.getValFromRatio(ratio), this.output.range[1]];
}
else if (dom === this.handles.to) {
if (ratio > this.sizes.ratio.max) {
ratio = this.sizes.ratio.max;
}
else if (ratio < this.output.ratio[0]) {
ratio = this.output.ratio[0];
}
result = [this.output.range[0], this.getValFromRatio(ratio)];
}
else if (dom === this.handles.single) {
if (ratio > this.sizes.ratio.max) {
ratio = this.sizes.ratio.max;
}
else if (ratio < this.sizes.ratio.min) {
ratio = this.sizes.ratio.min;
}
result = this.getValFromRatio(ratio);
}
}
this.setVals(result);
}
mergeTips() {
if (this.sizes.thumb < (this.sizes.bubble.from + this.sizes.bubble.to) / 2) {
this.targetEl.setAttribute('merged', '');
}
else {
this.targetEl.removeAttribute('merged');
}
}
hideEnds() {
if (this.options.multiple) {
let offsetFrom = this.output.ratio[0] * this.sizes.track, offsetTo = this.output.ratio[1] * this.sizes.track;
if (offsetFrom < this.sizes.bubble.min + this.sizes.bubble.from / 2 - this.sizes.handle / 2) {
this.targetEl.setAttribute('hidemin', '');
}
else {
this.targetEl.removeAttribute('hidemin');
}
if (this.sizes.track - offsetTo < this.sizes.bubble.max + this.sizes.bubble.from / 2 + this.sizes.handle / 2) {
this.targetEl.setAttribute('hidemax', '');
}
else {
this.targetEl.removeAttribute('hidemax');
}
}
else {
let offsetSingle = this.output.ratio[0] * this.sizes.track;
if (offsetSingle < this.sizes.bubble.min + this.sizes.bubble.single / 2 - this.sizes.handle / 2) {
this.targetEl.setAttribute('hidemin', '');
}
else {
this.targetEl.removeAttribute('hidemin');
}
if (this.sizes.track - offsetSingle < this.sizes.bubble.max + this.sizes.bubble.single / 2 + this.sizes.handle / 2) {
this.targetEl.setAttribute('hidemax', '');
}
else {
this.targetEl.removeAttribute('hidemax');
}
}
}
setTicks() {
if (!this.options.ruler.enable)
return;
this.ceilValue = (this.options.max - this.options.min) / this.options.ruler.majorEqual;
this.sizes.ruler = this.rulerEl.getBoundingClientRect()[this.propsMap.size];
for (let k = 0; k <= this.options.ruler.majorEqual; k++) {
let value = toNumber((this.options.min + this.ceilValue * k), { places: this.places }), content = this.options.ruler.labels.length > 0 ? this.options.ruler.labels[k] : value, offsetRatio = k / this.options.ruler.majorEqual, majorEl = createEl('li', { style: `${this.propsMap.startAlt}:${offsetRatio * 100}%`, 'data-content': content });
this.tickEl.appendChild(majorEl);
majorEl.onclick = () => {
this.setVals(value);
};
this.ticks.push({
index: k,
dom: majorEl,
ratio: offsetRatio,
content: content,
value,
});
if (k !== this.options.ruler.majorEqual) {
this.setMinorTicks(offsetRatio);
}
}
}
setFence() {
if (!this.options.fence.enable)
return;
let fullSize = (this.options.max - this.options.min), sizeRatio = (this.fence.max - this.fence.min) / fullSize, offsetRatio = (this.fence.min - this.options.min) / fullSize;
this.fenceEl = createEl('div', { [ax.alias]: 'fence', style: `${this.propsMap.size}:${sizeRatio * 100}%;${this.propsMap.startAlt}:${offsetRatio * 100}%` });
this.rulerEl.appendChild(this.fenceEl);
}
setMinorTicks(offsetRatio) {
let count = 0, unitRatio = 0, ceilSize = this.sizes.ruler / this.options.ruler.majorEqual;
if (this.options.ruler.minorEqual === 'auto') {
count = ceilSize < 40 ? 5 :
(ceilSize >= 40 && ceilSize < 80) ? 6 :
(ceilSize >= 80 && ceilSize < 160) ? 7 :
(ceilSize >= 160 && ceilSize < 320) ? 8 :
(ceilSize >= 320 && ceilSize >= 640) ? 9 : 10;
}
else if (this.options.ruler.minorEqual > 0) {
count = this.options.ruler.minorEqual;
}
unitRatio = 1 / (count * this.options.ruler.majorEqual);
for (let k = 0; k < count; k++) {
this.tickEl.insertAdjacentHTML('beforeend', `<li style="${this.propsMap.startAlt}:${(offsetRatio + unitRatio * k) * 100}%"></li>`);
}
}
disable(cb) {
this.targetEl.toggleAttribute('inert', true);
this.inputEl.disabled = true;
super.listen({ name: 'disabled', cb });
return this;
}
enable(cb) {
this.targetEl.removeAttribute('inert');
this.inputEl.disabled = false;
super.listen({ name: 'enabled', cb });
return this;
}
clear(cb) {
if (this.destroyed)
return this;
this.options.multiple ? this.setVals([this.fence.min, this.fence.max]) : this.setVals(this.fence.min);
super.listen({ name: 'cleared', cb });
return this;
}
restore(cb) {
if (this.destroyed)
return this;
this.setVals(this.rawVal);
super.listen({ name: 'restored', cb, params: [this.rawVal] });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.resizeObs.disconnect();
for (let k in this.gestures)
this.gestures[k]?.destroy();
if (this.options.keyboard) {
for (let k in this.handles) {
let tmp = this.handles[k];
if (tmp) {
tmp.removeEventListener('keydown', this.keyEvt);
tmp.removeEventListener('pointerup', this.focusEvt);
}
}
}
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_placeholder = config.lang.form.placeholder;
const optDatetime = [
{
attr: 'name',
prop: 'name',
value: ''
},
{
attr: 'value',
prop: 'value',
value: ''
},
{
attr: 'disabled',
prop: 'disabled',
value: false
}, {
attr: 'size',
prop: 'size',
value: ''
},
{
attr: 'format',
prop: 'format',
value: '',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'mode',
prop: 'mode',
value: 'single',
},
{
attr: 'feature',
prop: 'feature',
value: 'single',
},
{
attr: 'multiline',
prop: 'multiline',
value: false,
}, {
attr: 'placeholder',
prop: 'placeholder',
value: AXTMP_placeholder,
},
{
attr: 'label',
prop: 'label',
value: '',
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
children: ['close'],
},
},
{
attr: 'max-selection',
prop: 'maxSelection',
value: 100,
},
{
attr: 'rows',
prop: 'rows',
value: 1,
},
{
attr: 'cols',
prop: 'cols',
value: 1,
},
{
attr: 'datespan',
prop: 'datespan',
value: [],
},
{
attr: 'timespan',
prop: 'timespan',
value: [],
},
{
attr: 'full',
prop: 'full',
value: false,
},
{
attr: 'footer',
prop: 'footer',
value: {
enable: true,
layout: 'plain',
children: ['clear', 'confirm'],
},
},
{
attr: 'now-hide',
prop: 'nowHide',
value: false,
},
{
attr: 'now-show',
prop: 'nowShow',
value: false,
},
{
attr: 'clear-show',
prop: 'clearShow',
value: true,
},
{
attr: 'close-show',
prop: 'closeShow',
value: true,
},
{
attr: 'cancel-show',
prop: 'cancelShow',
value: false,
},
{
attr: 'result-Show',
prop: 'resultShow',
value: false,
},
{
attr: 'confirm-hide',
prop: 'confirmHide',
value: true,
},
{
attr: 'auto-fill',
prop: 'autoFill',
value: false,
},
{
attr: 'manual',
prop: 'manual',
value: false,
},
{
attr: 'auto-correct',
prop: 'autoCorrect',
value: true,
},
{
attr: 'required',
prop: 'required',
value: false,
},
{
attr: 'week-start',
prop: 'weekStart',
value: 'monday',
},
{
attr: 'separator',
prop: 'separator',
value: ',',
},
{
attr: 'btn-sel',
prop: 'btnSel',
value: '',
},
{
attr: 'pos-sel',
prop: 'posSel',
value: '',
},
{
attr: 'input-sel',
prop: 'inputSel',
value: '',
},
{
attr: 'child-sel',
prop: 'childSel',
value: '',
},
{
attr: 'display',
prop: 'display',
value: 'popup',
},
{
attr: 'toDrawer',
prop: 'toDrawer',
value: true,
},
{
attr: 'bubble',
prop: 'bubble',
value: {},
},
{
attr: 'fill-now',
prop: 'fillNow',
value: false,
},
{
attr: 'next',
prop: 'next',
value: '',
},
{
attr: 'lunar',
prop: 'lunar',
value: {
enable: false,
handler: '',
map: {},
tplStr: `<div>农历:{{this.animal}}年 {{this.month}}{{this.date}}</div>
<div>干支:{{this.gzYear}}年 {{this.gzMonth}}月 {{this.gzDate}}日</div>
<div>节日/节气:{{this.term}} {{this.lunarFestival}} {{this.solarFestival}}</div>
`,
tplEng: null,
arrange: ['solarFestival', 'lunarFestival', 'term', 'date'],
tags: [],
}
},
{
attr: 'events',
prop: 'events',
value: {
enable: false,
display: 'popup',
tplStr: `<div ${ax.alias}="label">{{this.label}}</div><div ${ax.alias}="content">{{this.content}}</div>`,
tplEng: null,
heading: `YYYY年MM月DD日 WW`,
list: [],
},
},
{
attr: 'menu',
prop: 'menu',
value: [],
},
{
attr: 'b4-fill',
prop: 'b4fill',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-set',
prop: 'b4Set',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'b4-cancel',
prop: 'b4Cancel',
value: null,
},
{
attr: 'b4-confirm',
prop: 'b4Confirm',
value: null,
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null,
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null,
},
{
attr: 'on-set',
prop: 'onSet',
value: null,
},
{
attr: 'on-setrange',
prop: 'onSetRange',
value: null,
},
{
attr: 'on-createdpanels',
prop: 'onCreatedPanels',
value: null,
},
{
attr: 'on-canceled',
prop: 'onCanceled',
value: null,
},
{
attr: 'on-confirmed',
prop: 'onConfirmed',
value: null,
}, {
attr: 'on-cleareded',
prop: 'onCleared',
value: null,
},
{
attr: 'on-opened',
prop: 'onOpened',
value: null,
},
{
attr: 'on-closed',
prop: 'onClosed',
value: null,
},
{
attr: 'on-transferred',
prop: 'onTransferred',
value: null,
},
{
attr: 'on-updatedtime',
prop: 'onUpdatedTime',
value: null,
},
...optBase
];
class TextareaElem extends CompBaseCommField {
labelEl;
limitEl;
type;
select;
headEl;
meanEl;
constructor() {
super();
this.type = 'textarea-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.select = () => this.inputEl.select();
this.addEventListener('click', (e) => {
let target = getEvtTarget(e);
target === this.wrapEl && this.inputEl.focus();
}, false);
this.inputEl.addEventListener('input', (e) => {
let tmp = this.propsProxy.value;
this.propsProxy.value = this.inputEl.value;
this.value = this.inputEl.value;
this.updateLimit();
this.addScrollable(this.inputEl);
let data = { oldVal: tmp, newVal: this.inputEl.value };
this.listen({ name: 'input', params: [data] });
(tmp !== this.inputEl.value) && this.listen({ name: 'changed', params: [data] });
}, false);
}
static custAttrs = ['name', 'placeholder', 'size', 'tools', 'limit', 'label', 'mean', 'task', 'attrs', ...this.evtsArr];
static boolAttrs = ['disabled', 'readonly', 'single', 'full'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, TextareaElem, { tools: getAttrArr(newVal, 'close') });
}
getRawData() {
this.getRawProps(TextareaElem);
this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
this.getProxyProps();
this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.inputEl = createEl('textarea', { placeholder: data.placeholder || config.lang.form.placeholder, [ax.embedSign]: '' });
data.value && (this.inputEl.value = data.value || '');
data.name && (this.inputEl.name = data.name || '');
this.wrapEl.appendChild(this.inputEl);
this.getToolsEl(data.tools);
this.limitEl = createEl('div', { [ax.alias]: 'limit' });
this.labelEl = createEl('span', { [ax.alias]: 'label' });
this.headEl = createEl('div', { [ax.alias]: 'head' }, this.labelEl);
this.meanEl = createEl('i', { [ax.alias]: 'mean' });
}
updateLimit() {
let total = ~~this.propsProxy.limit, value = this.propsProxy.value, len = value.length, tmp = total - len, remaining = tmp <= 0 ? 0 : tmp;
if (!total) {
return this;
}
this.limitEl.innerHTML = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxLength, { total, value: len, remaining });
if (tmp <= 0) {
if (tmp < 0) {
this.inputEl.value = value.slice(0, total);
this.inputEl.dispatchEvent(this.zeroEvt);
}
this.setAttribute('exceeded', '');
}
else {
this.removeAttribute('exceeded');
}
elState(this.limitEl).isVirtual && this.appendChild(this.limitEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
~~this.propsProxy.limit && this.appendChild(this.limitEl);
}
changedMaps = {
disabled: this.changedBool,
readonly: this.changedBool,
full: this.changedBool,
name: this.changedName,
placeholder: this.changedName,
value: this.changedValue,
tools: this.changedTools,
label: this.changedLabel,
mean: this.changedMean,
single: this.changedSingle,
task: this.changedTask,
attrs: this.changedAttrs,
};
changedBool(opt) {
this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
}
changedName(opt) {
isNull(opt.newVal) ? this.inputEl.removeAttribute(opt.name) : this.inputEl.setAttribute(opt.name, opt.newVal);
opt.name === 'name' && (this.name = opt.newVal || '');
}
changedTools(opt) {
this.toolsEl && this.toolsEl.remove();
if (this.propsProxy.tools.length > 0) {
this.getToolsEl(this.propsProxy.tools);
this.propsProxy.tools.forEach((k) => {
if (k.name === 'close') {
k.wrapEl.onclick = () => this.clear();
}
else {
k.action && k.action.bind(this);
}
});
if (!this.propsProxy['single'] && this.propsProxy['label']) {
this.headEl.appendChild(this.toolsEl);
}
else {
this.inputEl.insertAdjacentElement('afterend', this.toolsEl);
}
}
}
changedValue(opt) {
this.value = opt.newVal || '';
let tmp = this.inputEl.value;
this.inputEl.value = this.value;
(tmp !== this.value) && this.listen({ name: 'changed', params: [{ oldVal: tmp, newVal: this.value }] });
}
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal;
elState(this.headEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.headEl);
!this.propsProxy.single && this.propsProxy.tools.length > 0 && this.headEl.appendChild(this.toolsEl);
this.propsProxy.mean && this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
}
else {
this.headEl.remove();
this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
this.propsProxy.mean && this.propsProxy.single && this.wrapEl.appendChild(this.meanEl);
}
}
changedSingle(opt) {
if (this.propsProxy.single) {
this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
this.propsProxy.mean && this.wrapEl.appendChild(this.meanEl);
}
else {
if (this.propsProxy.label) {
this.propsProxy.mean && this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
this.propsProxy.tools.length > 0 && this.headEl.appendChild(this.toolsEl);
}
else {
this.propsProxy.tools.length > 0 && this.wrapEl.appendChild(this.toolsEl);
this.meanEl.remove();
}
}
}
changedMean(opt) {
if (opt.newVal) {
this.meanEl.classList.add(opt.newVal);
if (elState(this.meanEl).isVirtual) {
if (!this.propsProxy.single) {
this.headEl.insertAdjacentElement('afterbegin', this.meanEl);
}
else {
this.wrapEl.appendChild(this.meanEl);
}
}
}
else {
this.meanEl.remove();
}
}
changedTask(opt) {
if (opt.newVal) {
this.meanEl.onclick = () => {
new Function('"use strict";return ' + opt.newVal)().call(this, { btn: this.meanEl, el: this });
};
}
else {
this.meanEl.onclick = null;
}
}
}
class Datetime extends ModBaseListenCache {
options = {};
value;
raw;
client;
output;
data;
format;
spreadFooter;
separator;
selectedsProxy;
selecteds;
resultIns;
bubbleEl;
bubbleIns;
canClick;
inputEl;
positionEl;
childEl;
monthStr;
panelIdx;
datespan;
timespan;
wrapEl;
menuEl;
resultEl;
outerEl;
prevEl;
nextEl;
mainEl;
panelsEl;
footEl;
bubbleFootEl;
footBtnsEl;
footTipsEl;
confirmEl;
clearEl;
closeEl;
cancelEl;
nowEl;
daytimeBtnEl;
yearSearchEl;
rangeChkEl;
detailEl;
headingEl;
eventEl;
lunarEl;
detailIns;
timePanelsEl;
prevYearEl;
prevMonthEl;
nextYearEl;
nextMonthEl;
static hostType = 'node';
static optMaps = optDatetime;
static dependencies = [InputElem, TextareaElem, BtnElem, CheckboxElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
maps: Datetime.optMaps,
host: elem,
component: true,
spread: ['lunar', 'events', 'footer', 'manual', 'tools']
});
this.value = [];
this.raw = [];
this.monthStr = repeatStr(`<li><span ${ax.alias}="content"><i ${ax.alias}="label">{{this.data[this.index-1]}}</i></span></li>`, 12, this.options.lang.month);
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
super.getDirRtl();
this.output = { value: '', raw: '', items: [] };
this.data = {
startDate: '',
selecteds: [],
type: '',
panels: [
],
menu: [],
year: {
panelEl: '',
listEl: '',
list: []
},
month: {
panelEl: '',
listEl: '',
list: []
},
daytime: [],
};
this.setFeature();
this.format = trim(this.options.format || 'YYYY/MM/DD');
this.data.type = dateTools.getDateType(this.format);
this.getDateTimeSpan();
this.options.mode === 'range' && this.options.cols === 1 && (this.options.cols = 2);
if (ax.screen === 'xxs') {
this.options.display !== 'inline' && this.options.toDrawer && (this.options.display = 'drawer');
if (this.options.lunar.enable) {
this.options.cols = 1;
this.options.rows = 1;
}
else {
if (this.options.cols > 1) {
this.options.cols = 1;
this.options.rows = 2;
}
}
this.spreadFooter = false;
}
else {
this.spreadFooter = (this.data.type !== 'daytime' && this.options.cols > 1) || (this.data.type === 'daytime' && this.options.mode === 'range');
}
this.separator = this.options.mode === 'range' ? (this.options.lang.range.hyphen || this.options.separator) : this.options.separator;
this.getTargets();
this.selectedsProxy = new Observe(this.data.selecteds, {
deep: true,
});
this.selecteds = this.selectedsProxy.proxy;
this.selectedsProxy.on('completed', (data) => {
if (this.resultEl) {
let newContent = data.proxy.map((k) => {
return { label: dateTools.fillFormat(k, this.format, this.options.lang), source: k };
});
this.resultIns.update({
content: newContent,
});
}
this.options.autoFill && this.confirm(false);
});
(this.data.type !== 'daytime') && this.handleDayCont();
this.createSkeleton();
(this.data.type !== 'daytime') ? this.createPanels() : this.handleTimeCont();
if (this.options.display === 'inline') {
if (this.targetEl) {
this.targetEl.insertAdjacentElement(this.targetEl.classList.contains(`${ax.prefix}datetime-wrap`) ? 'beforeend' : 'afterend', this.bubbleEl);
this.bubbleEl.insertAdjacentHTML('beforebegin', `<div class="${ax.prefix}datetime-br"></div>`);
this.bubbleEl.insertAdjacentHTML('afterend', `<div class="${ax.prefix}datetime-br"></div>`);
}
}
else {
if (this.options.display === 'dialog') {
this.bubbleIns = this.bubbleIns || new Dialog(this.targetEl, extend({
target: {
content: this.bubbleEl,
size: '',
padding: false,
tools: true,
multiple: false,
footer: { enable: false },
wing: { selector: this.options.btnSel },
canClick: this.canClick,
},
source: this.options.bubble
}));
}
else if (this.options.display === 'drawer') {
this.options.full = true;
this.bubbleIns = this.bubbleIns || new Drawer(this.targetEl, extend({
target: {
content: this.bubbleEl,
size: '',
padding: false,
tools: true,
multiple: false,
footer: { enable: false },
placement: 'bottom',
wing: { selector: this.options.btnSel },
canClick: this.canClick,
},
source: this.options.bubble,
}));
}
else {
this.bubbleIns = this.bubbleIns || new Popup(this.positionEl, extend({
target: {
content: this.bubbleEl,
trigger: 'click',
tools: { enable: true, placement: 'outside' },
size: '',
padding: false,
placement: this.isRtl ? 'bottom-end' : 'bottom-start',
footer: { enable: false },
wing: { selector: this.options.btnSel },
canClick: this.canClick,
},
source: this.options.bubble
}));
}
}
if (this.bubbleIns) {
this.bubbleIns.on('show', () => {
this.options.autoCorrect && this.checkB4Show();
});
this.bubbleIns.on('shown', () => {
super.listen({ name: 'shown' });
});
}
this.setAttrs();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
setFeature() {
if (this.options.feature === 'static') {
this.options.footer = false;
}
else if (this.options.feature === 'flat') {
this.options.footer = false;
this.options.autoFill = true;
this.options.display = 'inline';
}
}
getTargets() {
if (this.targetEl && this.targetEl.classList.contains(`${ax.prefix}datetime-wrap`)) {
this.targetEl.innerHTML = '';
this.inputEl = createEl('ax-textarea', { mean: `${ax.prefix}icon-calendar`, placeholder: this.options.placeholder || config.lang.form.placeholder });
this.options.name && this.inputEl.setAttribute('name', this.options.name);
this.options.label && this.inputEl.setAttribute('label', this.options.label);
if (this.options.tools.enable && !isEmpty(this.options.tools.children)) {
this.inputEl.propsProxy.tools = this.options.tools.children;
this.inputEl.changedTools();
this.canClick = (el) => (this.inputEl.toolsEl && this.inputEl.toolsEl.contains(el)) || (this.inputEl.labelEl && this.inputEl.labelEl.contains(el)) ? false : true;
}
this.inputEl.toggleAttribute('single', !this.options.multiline);
this.rawHtml.trim() && this.inputEl.setAttribute('value', this.rawHtml.trim());
this.options.size ? this.inputEl.setAttribute('size', this.options.size) : this.inputEl.removeAttribute('size');
this.targetEl.appendChild(this.inputEl);
this.positionEl = this.targetEl;
}
else {
this.positionEl = getEl(this.options.posSel) || this.targetEl;
this.inputEl = getEl(this.options.inputSel) || this.targetEl;
this.inputEl && this.inputEl.classList.add(`${ax.prefix}bind-datetime`);
this.childEl = getEl(this.options.childSel, this.inputEl);
}
}
setAttrs() {
this.options.classes && this.targetEl && classes(this.targetEl).add(this.options.classes);
this.bubbleEl.setAttribute('mode', this.options.mode);
this.data.type ? this.bubbleEl.setAttribute('type', this.data.type) : this.bubbleEl.removeAttribute('type');
this.bubbleEl.setAttribute('display', this.options.display);
this.options.feature ? this.bubbleEl.setAttribute('feature', this.options.feature) : this.bubbleEl.removeAttribute('feature');
if (this.inputEl) {
this.inputEl.toggleAttribute('readonly', true);
this.inputEl.toggleAttribute('disabled', this.options.disabled);
}
this.bubbleEl.toggleAttribute('disabled', this.options.disabled);
this.bubbleEl.toggleAttribute('full', this.options.full);
this.bubbleEl.setAttribute('footer', this.options.footer.enable);
this.bubbleEl.toggleAttribute('lunar', this.options.lunar.enable);
}
createPanel(index, dateObj) {
let curDate = dateTools.getDate(dateObj, this.data.type, this.options.lang), panelObj = {}, getWeek = () => {
let tpl = (this.options.weekStart === 'monday') ? `<li>{{this.data[this.index-1]}}</li>` : `<li>{{this.data[this.index===1?6:this.index-2]}}</li>`;
return repeatStr(tpl, 7, this.options.lang.week);
};
if (this.data.type.includes('date')) {
curDate.setMonth(curDate.getMonth() + index);
panelObj.month = curDate.getMonth();
panelObj.year = curDate.getFullYear();
panelObj.panelEl = tplToEl(`
<li panel='${this.options.lunar.enable ? 'lunar' : 'date'}'>
<div ${ax.alias}="head">
<span ${ax.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}</span><span ${ax.alias}="month"><i>${panelObj.month + 1}</i>${this.options.lang.unit.M}</span>
</div>
<div ${ax.alias}="body" days>
<ul ${ax.alias}="column" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-7">
${getWeek()}
</ul>
<ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-7"></ul>
</div>
</li>
`);
panelObj.type = 'date';
panelObj.headEl = panelObj.panelEl.querySelector(`[${ax.alias}="head"]`);
panelObj.yearEl = panelObj.headEl.querySelector(`[${ax.alias}="year"]`);
panelObj.monthEl = panelObj.headEl.querySelector(`[${ax.alias}="month"]`);
panelObj.listEl = panelObj.panelEl.querySelector(`[${ax.alias}="list"]`);
panelObj.list = this.createPanelDayList(panelObj.listEl, curDate);
}
else if (this.data.type === 'month') {
curDate.setFullYear(curDate.getFullYear() + index);
panelObj.year = curDate.getFullYear();
panelObj.panelEl = tplToEl(`
<li panel='month'>
<div ${ax.alias}="head">
<span ${ax.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}</span>
</div>
<div body>
<ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3">${this.monthStr}</ul>
</div>
</li>
`);
panelObj.type = 'month';
panelObj.headEl = panelObj.panelEl.querySelector(`[${ax.alias}="head"]`);
panelObj.yearEl = panelObj.headEl.querySelector(`[${ax.alias}="year"]`);
panelObj.listEl = panelObj.panelEl.querySelector(`[${ax.alias}="list"]`);
panelObj.list = this.createPanelMonthList(panelObj.listEl, curDate);
}
else if (this.data.type === 'year') {
curDate.setFullYear(curDate.getFullYear() + 18 * index - 7);
panelObj.year = curDate.getFullYear();
panelObj.panelEl = tplToEl(`
<li panel='year'>
<div ${ax.alias}="head">
<span ${ax.alias}="year"><i>${panelObj.year}</i>${this.options.lang.unit.Y}~<i>${panelObj.year + 17}</i>${this.options.lang.unit.Y}</span>
</div>
<div ${ax.alias}="body">
<ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3"></ul>
</div>
</li>
`);
panelObj.type = 'year';
panelObj.headEl = panelObj.panelEl.querySelector(`[${ax.alias}="head"]`);
panelObj.listEl = panelObj.panelEl.querySelector(`[${ax.alias}="list"]`);
panelObj.list = this.createPanelYearList(panelObj.listEl, curDate);
}
panelObj.bodyEl = panelObj.panelEl.querySelector(`[${ax.alias}="body"]`);
this.data.panels.push(panelObj);
this.panelsEl.appendChild(panelObj.panelEl);
}
createPanels(dateObj, force = false, cb) {
if (this.destroyed)
return;
let index = this.options.rows * this.options.cols, startDate = dateTools.getDate(dateObj || this.data.startDate, this.data.type, this.options.lang);
if (!force && this.inCurPanels(startDate))
return;
this.data.panels = [];
this.panelsEl.innerHTML = '';
for (let k = 0; k < index; k++) {
this.createPanel(k, startDate);
}
this.data.startDate = startDate;
let curItems = this.getCurGrids();
curItems.forEach((k) => {
this.inSelectedDate(k) && !k.selected && this.selectedAttrToggle(k, true);
});
this.options.mode === 'range' && this.setRangeAttr(curItems);
let nowObj = dateTools.getDateObj(new Date(), this.data.type), nowItem = curItems.find((k) => JSON.stringify(k.value) == JSON.stringify(nowObj));
nowItem && nowItem.wrapEl.setAttribute('now', '');
this.afterCreatePanels();
super.listen({ name: 'createPanels', cb });
return this;
}
inSelectedDate(data) {
let value = this.getDateVal(data, this.data.type);
return this.selecteds.some((k) => {
let { hh, mm, ss, ...rest } = k;
return JSON.stringify(rest) == JSON.stringify(value);
});
}
showEvent(obj) {
this.headingEl.innerHTML = dateTools.fillFormat(obj.value, this.options.events.heading, this.options.lang);
if (this.options.lunar.enable && this.options.lunar.handler) {
let lunarObj = { ...this.options.lunar.map }, lunarVal = this.options.lunar.handler(obj.value.YYYY, obj.value.MM + 1, obj.value.DD);
for (let k in lunarObj) {
if (lunarObj.hasOwnProperty(k)) {
lunarObj[k] = lunarVal[lunarObj[k]];
}
}
this.lunarEl.innerHTML = super.getTplcont(lunarObj, this.options.lunar.tplStr, this.options.lunar.tplEng);
}
let item = this.options.events.list.find((k) => dateTools.isSameDay(dateTools.getDateObj(k.date, 'date'), dateTools.getDateObj(obj.value, 'date')));
this.eventEl.innerHTML = item && item.content ? super.getTplcont(item, this.options.events.tplStr, this.options.events.tplEng) : this.options.lang.noEvent;
}
inCurPanels(dateObj, curGrids) {
let type = this.data.type === 'datetime' ? 'date' : this.data.type, date = getDataType(dateObj) === 'Object' ? { ...dateObj } : dateObj, obj = dateTools.getDateObj(date, type), grids = curGrids || this.getCurGrids(), result;
result = grids.some((k) => JSON.stringify(k.value) == JSON.stringify(obj));
return result;
}
inputVal2Dates(toDate = true) {
let str = this.getValFromTgt();
return this.str2Dates(str, toDate);
}
str2Dates(str, toDate = true) {
if (str) {
return str.split(this.separator).map((k) => toDate ? dateTools.getDate(k, this.data.type, this.options.lang) : k);
}
else {
return [];
}
}
getValFromTgt() {
if (!this.inputEl)
return '';
return ('value' in this.inputEl ? this.inputEl.value : this.childEl ? this.childEl.textContent : this.inputEl.textContent).trim();
}
setValFromTgt(value) {
value = value || '';
if (['INPUT', 'TEXTAREA'].includes(this.inputEl.nodeName)) {
this.inputEl.value = value;
}
else if (['AX-INPUT', 'AX-TEXTAREA'].includes(this.inputEl.nodeName)) {
this.inputEl.setAttribute('value', value);
}
else {
this.childEl ? this.childEl.innerHTML = value : this.inputEl.innerHTML = value;
}
}
vals2Arr() {
let type = getDataType(this.options.value), result = [];
if (!isEmpty(this.options.value)) {
if (type === 'Array') {
result = this.options.value.map((k) => dateTools.getDate(k, this.data.type, this.options.lang));
}
else if (type === 'String') {
result = this.str2Dates(this.options.value, true);
}
else {
result = [dateTools.getDate(this.options.value, this.data.type, this.options.lang)];
}
}
else {
if (this.options.autoCorrect) {
let value = this.getValFromTgt();
if (value) {
result = this.inputVal2Dates();
}
else {
result = this.options.fillNow ? [dateTools.getDate(new Date(), this.data.type, this.options.lang)] : [];
}
}
else {
result = [];
}
}
return result;
}
handleDayCont() {
this.value = this.vals2Arr();
if (this.value.length > 1 && this.options.mode === 'range') {
dateTools.sort(this.value);
this.value.length > 2 && (this.value = this.value.slice(0, 2));
}
this.data.startDate = this.value.length === 0 ? dateTools.getDate(new Date(), this.data.type, this.options.lang) : this.value[0];
let selectedContent = this.dates2Objs(this.value);
this.selecteds.splice(0, this.data.selecteds.length, ...selectedContent);
this.raw = [...selectedContent];
if (this.inputEl) {
let value = this.selecteds.map((k) => dateTools.fillFormat(k, this.format, this.options.lang)).join(this.separator);
this.handleVal(value);
}
}
stdTimeStr(data, type = 'object') {
let objArr = [], dataFn = (obj) => dateTools.getDateObj(obj, 'daytime');
if (Array.isArray(data)) {
for (let k of data)
objArr.push(dataFn(k));
}
else {
objArr.push(dataFn(data));
}
return (type === 'string') ? objArr.map((k) => `${dateTools.fillZero(k.hh)}:${dateTools.fillZero(k.mm)}:${dateTools.fillZero(k.ss)}`) : objArr;
}
handleTimeCont() {
this.value = this.stdTimeStr(this.vals2Arr());
if (this.options.mode === 'range') {
if (this.value.length === 0) {
this.setDaytime([{ hh: 0, mm: 0, ss: 0 }, { hh: 0, mm: 0, ss: 0 }]);
}
else if (this.value.length === 1) {
this.setDaytime([this.value[0], { hh: 0, mm: 0, ss: 0 }]);
}
else {
this.setDaytime(this.value);
}
}
else {
if (this.value.length === 0) {
this.setDaytime({ hh: 0, mm: 0, ss: 0 });
}
else {
this.setDaytime(this.value[0]);
}
}
this.raw = [...this.value];
if (this.inputEl && !isEmpty(this.options.value)) {
let value = this.stdTimeStr(this.value, 'string').join(this.separator);
this.fillVals(value);
}
}
dates2Objs(dates) {
let selectedContent = [];
if (this.data.type === 'year') {
selectedContent = dates.map((k) => {
return { YYYY: k.getFullYear() };
});
}
else if (this.data.type === 'month') {
selectedContent = dates.map((k) => {
return { YYYY: k.getFullYear(), MM: k.getMonth() };
});
}
else if (this.data.type === 'daytime') {
selectedContent = dates.map((k) => {
return { hh: k.getHours(), mm: k.getMinutes(), ss: k.getSeconds() };
});
}
else if (this.data.type === 'date') {
selectedContent = dates.map((k) => {
return { YYYY: k.getFullYear(), MM: k.getMonth(), DD: k.getDate() };
});
}
else if (this.data.type === 'datetime') {
selectedContent = dates.map((k) => {
return { YYYY: k.getFullYear(), MM: k.getMonth(), DD: k.getDate(), hh: k.getHours(), mm: k.getMinutes(), ss: k.getSeconds() };
});
}
return selectedContent;
}
checkB4Show() {
if (this.data.type !== 'daytime') {
let value = this.inputVal2Dates(), selecteds = this.dates2Objs(value), isSame = JSON.stringify(selecteds) == JSON.stringify(this.data.selecteds);
if (!isSame) {
this.data.startDate = value.length > 0 ? value[0] : dateTools.getDate(this.data.selecteds[0], this.data.type, this.options.lang);
this.createPanels();
this.clear();
this.setVals(selecteds);
}
}
else {
let timeObj = this.stdTimeStr(this.inputVal2Dates());
this.setDaytime(timeObj);
}
}
createSkeleton() {
let outerHTML = '', footHTML = '';
if (this.data.type !== 'daytime') {
outerHTML = `
<div ${ax.alias}="outer">
<div ${ax.alias}="prev"></div>
<div ${ax.alias}="next"></div>
<ul ${ax.alias}="panels" class="${ax.prefix}reset ${ax.prefix}grid ${ax.screen === 'xxs' ? ax.prefix + 'avg-1' : this.spreadFooter ? ax.prefix + 'fence ' + ax.prefix + 'avg-' + this.options.cols : ax.prefix + 'avg-1'}" ></ul>
</div>`;
}
if (this.options.footer.enable) {
footHTML = `<div ${ax.alias}="foot"></div>`;
}
this.bubbleEl = tplToEl(`
<div class="${ax.prefix}datetime">
<div ${ax.alias}="wrap">
${this.options.menu.length > 0 ? '<ul ' + ax.alias + '="menu" class="' + ax.prefix + 'reset"></ul>' : ''}
<div ${ax.alias}="main">
${this.options.resultShow && this.data.type !== 'daytime' ? '<div ' + ax.alias + '="result"></div>' : ''}
${outerHTML}
${footHTML}
</div>
</div>
</div>
`);
this.wrapEl = this.bubbleEl.querySelector(`[${ax.alias}="wrap"]`);
this.menuEl = this.bubbleEl.querySelector(`[${ax.alias}="menu"]`);
this.resultEl = this.bubbleEl.querySelector(`[${ax.alias}="result"]`);
this.outerEl = this.bubbleEl.querySelector(`[${ax.alias}="outer"]`);
this.prevEl = this.bubbleEl.querySelector(`[${ax.alias}="prev"]`);
this.nextEl = this.bubbleEl.querySelector(`[${ax.alias}="next"]`);
this.mainEl = this.bubbleEl.querySelector(`[${ax.alias}="main"]`);
this.panelsEl = this.mainEl.querySelector(`[${ax.alias}="panels"]`);
if (this.options.footer.enable) {
this.footEl = this.bubbleEl.querySelector(`[${ax.alias}="foot"]`);
if (this.spreadFooter) {
this.bubbleFootEl = createFooter(Object.assign(this.options.footer, { layout: 'right' }), this.footEl, this);
this.footBtnsEl = this.bubbleFootEl.querySelector(`.${ax.prefix}box-btns`);
let tmp = this.bubbleFootEl.querySelector(`[${ax.alias}="tips"]`);
if (tmp) {
this.footTipsEl = tmp;
}
else {
this.footTipsEl = createEl('div', { [ax.alias]: 'tips' });
this.footBtnsEl.insertAdjacentElement('afterend', this.footTipsEl);
}
}
else {
this.bubbleFootEl = createFooter(Object.assign(this.options.footer, { layout: 'plain' }), this.footEl, this);
this.footBtnsEl = this.bubbleFootEl.querySelector(`.${ax.prefix}box-btns`);
this.footTipsEl = this.footBtnsEl;
}
this.confirmEl = this.bubbleFootEl.querySelector(`[${ax.alias}="confirm"]`);
this.clearEl = this.bubbleFootEl.querySelector(`[${ax.alias}="clear"]`);
this.closeEl = this.bubbleFootEl.querySelector(`[${ax.alias}="close"]`);
this.cancelEl = this.bubbleFootEl.querySelector(`[${ax.alias}="cancel"]`);
this.nowEl = this.bubbleFootEl.querySelector(`[${ax.alias}="now"]`);
this.daytimeBtnEl = this.data.type.includes('time') ? createEl('ax-btn', { type: 'plain', [ax.alias]: 'daytime', label: this.options.lang.daytime.select }) : null;
this.yearSearchEl = this.data.type === 'year' ? createEl('ax-input', { [ax.alias]: 'search', placeholder: this.options.lang.year.placeholder, btn: `<i class="${ax.prefix}icon-arrow-right"></i>` }) : null;
this.rangeChkEl = this.options.mode === 'range' && this.data.type === 'datetime' ? createEl('ax-checkbox', { disabled: '', [ax.alias]: 'checkbox', label: this.options.lang.range.checkbox }) : null;
this.daytimeBtnEl && this.footTipsEl.insertAdjacentElement('afterbegin', this.daytimeBtnEl);
this.yearSearchEl && this.footTipsEl.insertAdjacentElement('afterbegin', this.yearSearchEl);
if (this.rangeChkEl) {
this.footTipsEl.insertAdjacentElement('afterbegin', this.rangeChkEl);
this.rangeChkEl.on('check', (data) => {
if (data.checked) {
if (this.selecteds.length === 1) {
this.selecteds.push({ ...this.selecteds[0] });
this.setRange(this.selecteds);
}
}
else {
if (this.selecteds.length === 2 && dateTools.isSameDay(this.selecteds[0], this.selecteds[1])) {
let tmp = { ...this.selecteds[0] };
this.clear(false);
this.select(tmp);
}
}
});
}
}
if (this.options.events.enable) {
this.detailEl = createEl('div', { [ax.alias]: 'detail' });
this.headingEl = createEl('div', { [ax.alias]: 'heading' });
this.eventEl = createEl('div', { [ax.alias]: 'event' }, this.options.lang.noEvent);
this.detailEl.appendChild(this.headingEl);
this.detailEl.appendChild(this.eventEl);
if (this.options.lunar.enable && this.options.lunar.handler) {
this.lunarEl = createEl('div', { [ax.alias]: 'lunar' });
this.headingEl.insertAdjacentElement('afterend', this.lunarEl);
}
if (this.options.events.display === 'inline') {
this.wrapEl.appendChild(this.detailEl);
}
else if (this.options.events.display === 'popup') {
this.detailIns = this.detailIns || new Popup(this.panelsEl, {
content: this.detailEl,
trigger: 'click',
placement: 'bottom',
size: 'md',
footer: false,
});
}
}
this.data.type.includes('time') && this.options.footer.enable && this.createTimeSelectPanel();
this.createMenu();
if (this.data.type !== 'daytime') {
if (this.resultEl) {
this.resultIns = this.resultIns || new Tags(this.resultEl, {
content: '',
removable: true,
empty: { enable: true, content: this.options.lang.empty },
});
}
if (this.data.type === 'year' || this.data.type === 'month') {
this.prevEl.innerHTML = `<i ${ax.alias}="prevYear" class= "${ax.prefix}icon-left-double"></i> `;
this.nextEl.innerHTML = `<i ${ax.alias}="nextYear" class= "${ax.prefix}icon-right-double"></i> `;
}
else if (this.data.type.includes('date')) {
this.prevEl.innerHTML = `<i ${ax.alias}="prevYear" class= "${ax.prefix}icon-left-double"></i> <i ${ax.alias}="prevMonth" class="${ax.prefix}icon-left"></i>`;
this.nextEl.innerHTML = `<i ${ax.alias}="nextYear" class= "${ax.prefix}icon-right-double"></i> <i ${ax.alias}="nextMonth" class="${ax.prefix}icon-right"></i>`;
}
this.prevYearEl = this.prevEl.querySelector(`[${ax.alias}="prevYear"]`);
this.prevMonthEl = this.prevEl.querySelector(`[${ax.alias}="prevMonth"]`);
this.nextYearEl = this.mainEl.querySelector(`[${ax.alias}="nextYear"]`);
this.nextMonthEl = this.mainEl.querySelector(`[${ax.alias}="nextMonth"]`);
if (this.data.type === 'month' || this.data.type.includes('date')) {
this.createYearPanel();
}
if (this.data.type.includes('date')) {
this.createMonthPanel();
}
}
}
createMenu() {
if (this.options.menu.length > 0) {
this.data.menu = this.options.menu;
let fragment = document.createDocumentFragment();
this.data.menu.forEach((k) => {
k.el = createEl('li', '', k.label);
fragment.appendChild(k.el);
});
this.menuEl.appendChild(fragment);
this.data.menu.forEach((k) => {
k.el.onclick = () => {
k.action && k.action.call(this, k);
k.el.setAttribute('selected', '');
k.selected = true;
this.data.menu.filter((i) => i !== k).forEach((o) => {
Reflect.deleteProperty(o, 'selected');
o.el.removeAttribute('selected');
});
};
});
}
}
createMonthPanel(cb) {
this.data.month.panelEl = createEl('div', { panel: 'month' }, `<div ${ax.alias}="body"><ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3">${this.monthStr}</ul></div>`);
this.data.month.listEl = this.data.month.panelEl.querySelector(`[${ax.alias}="list"]`);
[...this.data.month.listEl.children].forEach((k, i) => {
let obj = {
wrapEl: k,
contEl: k.querySelector(`[${ax.alias}="content"]`),
value: i,
};
this.data.month.list.push(obj);
});
this.panelsEl.insertAdjacentElement('afterend', this.data.month.panelEl);
cb && cb();
}
createYearPanel(cb) {
this.data.year.panelEl = createEl('div', { panel: 'year' }, `
<div ${ax.alias}="body">
<ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3"></ul>
<ul ${ax.alias}="pages" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3">
<li><i ${ax.alias}="prev">${this.options.lang.year.prev}</i></li>
<li><ax-input placeholder="${this.options.lang.year.placeholder}" size="sm" btn="<i class='${ax.prefix}icon-arrow-right'></i>"></ax-input></li>
<li><i ${ax.alias}="next">${this.options.lang.year.next}</i></li>
</ul>
</div>
`);
this.data.year.listEl = this.data.year.panelEl.querySelector(`[${ax.alias}="list"]`);
this.data.year.prevEl = this.data.year.panelEl.querySelector(`[${ax.alias}="prev"]`);
this.data.year.nextEl = this.data.year.panelEl.querySelector(`[${ax.alias}="next"]`);
this.data.year.searchEl = this.data.year.panelEl.querySelector('ax-input');
this.data.year.inputEl = this.data.year.searchEl.inputEl;
this.data.year.btnEl = this.data.year.searchEl.btnEl;
this.panelsEl.insertAdjacentElement('afterend', this.data.year.panelEl);
cb && cb();
}
createYearList(panel, start, index) {
if (!panel)
return;
this.data.year.listEl.innerHTML = '';
this.data.year.list = [];
this.panelIdx = index || 0;
for (let k = 0; k < 15; k++) {
let year = start || start === 0 ? start + k : panel.year - 7 + k, obj = {
wrapEl: createEl('li', '', `<span ${ax.alias}="content"> <i ${ax.alias}="label">${year}${this.options.lang.unit.Y}</i></span> `),
value: year,
};
obj.contEl = obj.wrapEl.querySelector(`[${ax.alias}="content"]`);
obj.labelEl = obj.wrapEl.querySelector(`[${ax.alias}="label"]`);
this.data.year.listEl.appendChild(obj.wrapEl);
this.data.year.list.push(obj);
}
this.data.year.list.forEach((k) => {
if (panel.year === k.value) {
this.selectedAttrToggle(k, true);
}
else {
this.selectedAttrToggle(k, false);
}
k.contEl.onclick = () => {
if (k.disabled)
return;
if (panel.year !== k.value) {
let startValue = k.value;
if (this.data.type === 'month') {
startValue = k.value - this.panelIdx;
}
else if (this.data.type.includes('date')) {
startValue = k.value - (this.data.panels[this.panelIdx].year - this.data.panels[0].year);
}
this.data.startDate.setFullYear(startValue);
this.createPanels(null, true);
hide({ el: this.data.year.panelEl });
}
};
});
}
goto(dateObj, select = false, cb) {
if (this.destroyed)
return;
let date = dateTools.getDate(dateObj, this.data.type, this.options.lang);
if (select) {
this.setVals(date);
}
else {
this.createPanels(date);
}
cb && cb.call(this);
}
offset(dateObj, cb) {
if (this.destroyed)
return;
if (this.data.selecteds.length > 0) {
let dates = this.data.selecteds.map((k) => dateTools.getDateObj(dateTools.getOffsetDate(k, dateObj), this.data.type));
this.setVals(dates);
}
else {
this.data.startDate = dateTools.getOffsetDate(dateTools.getDateObj(new Date(), this.data.type), dateObj);
this.setVals(this.data.startDate);
}
cb && cb.call(this);
}
selectedAttrToggle(obj, state) {
if (state) {
if (!obj.selected) {
Reflect.set(obj, 'selected', true);
obj.wrapEl.setAttribute('selected', '');
}
}
else {
if (obj.selected) {
Reflect.deleteProperty(obj, 'selected');
obj.wrapEl.removeAttribute('selected');
}
}
}
select(data, curGrid, curGrids) {
let curObj = this.findFromPanels(data, curGrid, curGrids), curItems = curObj.list, curItem = curObj.target, fillTime = (dateObj) => {
let obj = {};
if (this.options.mode === 'range') {
obj = this.data.type.includes('time') ? { ...dateObj, ...this.data.daytime[this.selecteds.length === 1 ? 1 : 0].value } : dateObj;
}
else {
obj = this.data.daytime.length > 0 && this.data.type.includes('time') ? { ...dateObj, ...this.data.daytime[0].value } : dateObj;
}
return obj;
}, selectedFun = (obj) => {
if (obj.disabled)
return;
let value;
if (this.data.type.includes('time')) {
value = (data.hasOwnProperty('hh') && data.hasOwnProperty('mm') && data.hasOwnProperty('ss')) ? data : fillTime(obj.value);
}
else {
value = data.value || data;
}
if (this.options.mode === 'range') {
let length = this.selecteds.length;
if (length < 2) {
this.selecteds.push(value);
if (length === 1) {
let rangeStart = { ...this.data.selecteds[0] }, rangeEnd = { ...this.data.selecteds[1] };
if (dateTools.getDate(rangeStart, this.data.type, this.options.lang) > dateTools.getDate(rangeEnd, this.data.type, this.options.lang)) {
this.selecteds.sort((a, b) => dateTools.getDate(a, this.data.type, this.options.lang) - dateTools.getDate(b, this.data.type, this.options.lang));
this.assignDaytime();
}
this.rangeChkEl && this.rangeChkEl.setAttribute('disabled', '');
this.rangeChkEl && this.rangeChkEl.setAttribute('check', '');
this.setRange(this.selecteds);
}
else {
this.rangeChkEl && this.rangeChkEl.removeAttribute('disabled');
}
}
else {
this.clear(false);
this.selecteds.splice(0, this.selecteds.length, value);
this.rangeChkEl && this.rangeChkEl.removeAttribute('disabled');
this.rangeChkEl && this.rangeChkEl.setAttribute('check', '');
}
}
else {
if (this.options.mode === 'multiple') {
!this.inSelectedDate(value) && this.selecteds.push(value);
}
else {
if (this.inSelectedDate(value))
return;
this.clear(false);
this.selecteds.splice(0, this.selecteds.length, value);
}
}
this.selectedAttrToggle(obj, true);
};
if (!curItems.includes(data) && !curItem) {
this.createPanels(data.hasOwnProperty('value') ? data.value : data);
curItem = this.findFromPanels(data).target;
}
if (curItem.disabled)
return;
!curItem?.selected && selectedFun(curItem);
this.options.events.enable && curItem && this.showEvent(curItem);
}
deselect(dateObj, curGrid, curGrids) {
if (isEmpty(dateObj))
return;
let curItems = curGrids || this.getCurGrids(), curItem = this.findFromPanels(dateObj, curGrid, curItems).target, selecteds = [];
curItem && this.selectedAttrToggle(curItem, false);
selecteds = this.data.selecteds.filter((k) => !dateTools.isSameDay(k, dateObj.hasOwnProperty('value') ? dateObj.value : dateObj));
this.selecteds.splice(0, this.data.selecteds.length, ...selecteds);
if (this.options.mode === 'range' && this.data.selecteds.length < 2) {
curItems.forEach((k) => {
this.removeRangeAttr(k);
});
}
}
setRangeAttr(grids) {
if (this.data.selecteds.length !== 2)
return;
let curGrids = grids || this.getCurGrids(), type = this.data.type === 'datetime' ? 'date' : this.data.type;
curGrids.forEach((k) => {
this.removeRangeAttr(k);
this.selectedAttrToggle(k, false);
if (dateTools.getDate(k.value, type, this.options.lang) > dateTools.getDate(this.data.selecteds[0], type, this.options.lang) && dateTools.getDate(k.value, type, this.options.lang) < dateTools.getDate(this.data.selecteds[1], type, this.options.lang)) {
k.wrapEl.setAttribute('contain', '');
}
});
let gridStart = this.findFromPanels(this.data.selecteds[0], null, curGrids).target, gridEnd = this.findFromPanels(this.data.selecteds[1], null, curGrids).target;
if (gridStart) {
gridStart.wrapEl.setAttribute('start', '');
this.selectedAttrToggle(gridStart, true);
}
if (gridEnd) {
gridEnd.wrapEl.setAttribute('end', '');
this.selectedAttrToggle(gridEnd, true);
}
}
removeRangeAttr(dateObj) {
if (dateObj.wrapEl.hasAttribute('start')) {
dateObj.wrapEl.removeAttribute('start');
}
if (dateObj.wrapEl.hasAttribute('end')) {
dateObj.wrapEl.removeAttribute('end');
}
if (dateObj.wrapEl.hasAttribute('contain')) {
dateObj.wrapEl.removeAttribute('contain');
}
}
getDatespan() {
this.datespan = [];
if (isEmpty(this.options.datespan))
return;
let spanType = getDataType(this.options.datespan), getVal = (obj) => {
let objType = getDataType(obj), result = {};
if (objType !== 'Object') {
return result;
}
if (obj.hasOwnProperty('min')) {
result.min = {
Date: dateTools.getDate(obj.min, this.data.type, this.options.lang),
Object: dateTools.getDateObj(obj.min, this.data.type, this.options.lang)
};
}
obj.hasOwnProperty('min') && (result.min = dateTools.getDate(obj.min, this.data.type, this.options.lang));
obj.hasOwnProperty('max') && (result.max = dateTools.getDate(obj.max, this.data.type, this.options.lang));
if (obj.hasOwnProperty('max')) {
result.max = {
Date: dateTools.getDate(obj.max, this.data.type, this.options.lang),
Object: dateTools.getDateObj(obj.max, this.data.type, this.options.lang)
};
}
return result;
};
if (spanType === 'Object') {
this.datespan.push(getVal(this.options.datespan));
}
else if (spanType === 'Array') {
this.datespan = this.options.datespan.map((k) => getVal(k)).filter((k) => !isEmpty(k));
}
}
getTimespan() {
this.timespan = [];
if (isEmpty(this.options.timespan))
return;
let spanType = getDataType(this.options.timespan), getVal = (obj) => {
let objType = getDataType(obj), result = {};
if (objType !== 'Object') {
return result;
}
obj.hasOwnProperty('min') && (result.min = dateTools.getDateObj(obj.min, this.data.type, this.options.lang));
obj.hasOwnProperty('max') && (result.max = dateTools.getDateObj(obj.max, this.data.type, this.options.lang));
return result;
};
if (spanType === 'Object') {
this.timespan.push(getVal(this.options.timespan));
}
else if (spanType === 'Array') {
this.timespan = this.options.timespan.map((k) => getVal(k)).filter((k) => !isEmpty(k));
}
}
getDateTimeSpan() {
let hander = (type = 'timespan') => {
if (isEmpty(this.options[type]))
return [];
let spanType = getDataType(this.options[type]), dateProp = type === 'datespan' ? 'getDate' : 'getDateObj', getVal = (obj) => {
let objType = getDataType(obj), result = {};
if (objType !== 'Object')
return result;
obj.hasOwnProperty('min') && (result.min = dateTools[dateProp](obj.min, this.data.type, this.options.lang));
obj.hasOwnProperty('max') && (result.max = dateTools[dateProp](obj.max, this.data.type, this.options.lang));
return result;
};
if (spanType === 'Object') {
return [getVal(this.options[type])];
}
else if (spanType === 'Array') {
return this.options[type].map((k) => getVal(k)).filter((k) => !isEmpty(k));
}
};
this.datespan = hander('datespan');
this.timespan = hander('timespan');
}
setWrapDisabled(obj) {
obj.disabled = true;
obj.wrapEl.setAttribute('disabled', '');
}
compareVal(data, range, prop) {
let min = range.hasOwnProperty('min') ? prop ? range.min[prop] : range.min : null, max = range.hasOwnProperty('max') ? prop ? range.max[prop] : range.max : null, result;
if (isNull(min) && isNull(max)) {
result = false;
}
else if (isNull(min)) {
result = data <= max;
}
else if (isNull(max)) {
result = data >= min;
}
else {
result = data >= min && data <= max;
}
return result;
}
setDatespanDisabled(dateObj) {
if (!this.datespan.length || dateObj.disabled)
return;
let condition;
let valDate = dateTools.getDate(dateObj.value, this.data.type, this.options.lang);
let tmp = this.datespan.find((k) => {
return this.compareVal(valDate, k);
});
condition = tmp ? false : true;
condition && this.setWrapDisabled(dateObj);
}
setTimespanDisabled(timeObj, prop) {
if (!this.timespan.length || timeObj.disabled)
return;
let condition;
let tmp = this.timespan.find((k) => {
return this.compareVal(timeObj.value, k, prop);
});
condition = tmp ? false : true;
condition && this.setWrapDisabled(timeObj);
}
getDateVal(dateObj, type) {
let objType = getDataType(dateObj), value = {}, result;
if (objType === 'String' || objType === 'Date') {
result = dateTools.getDateObj(dateObj, 'date');
}
else {
if (objType === 'Object') {
if (dateObj.hasOwnProperty('value')) {
value = dateObj.value;
}
else {
value = dateObj;
}
}
else if (objType === 'Number') {
value = this.data.selecteds[dateObj];
}
result = dateTools.getDateObj(value, 'date');
}
if (type === 'year') {
Reflect.deleteProperty(result, 'DD');
Reflect.deleteProperty(result, 'MM');
}
else if (type === 'month') {
Reflect.deleteProperty(result, 'DD');
}
return result;
}
getCurGrids() {
return this.data.panels.map((k) => k.list).flat(Infinity).filter((k) => !k.exceed);
}
findFromPanels(dateObj, grid, grids) {
let value = this.getDateVal(dateObj, this.data.type), curItems = grids || this.getCurGrids(), curItem = grid || curItems.find((k) => JSON.stringify(k.value) == JSON.stringify(value));
return { target: curItem, list: curItems };
}
afterCreatePanels() {
if (this.data.type !== 'daytime') {
let curGrids = this.getCurGrids();
this.data.panels.forEach((o) => {
o.list.forEach((k) => {
k.contEl.onclick = () => {
if (k.disabled)
return;
if (this.data.selecteds.length > this.options.maxSelection) {
console.warn(`The selected items have exceeded the ${this.options.maxSelection} limit!`);
return;
}
let curItem = curGrids.find((i) => JSON.stringify(i.value) == JSON.stringify(k.value));
if (this.options.mode === 'multiple') {
if (curItem) {
curItem.selected ? this.deselect(k, curItem, curGrids) : this.select(k, curItem, curGrids);
}
else {
this.select(k, curItem, curGrids);
}
}
else {
this.select(k, curItem, curGrids);
}
super.listen({ name: 'set', params: [k] });
};
if (this.detailIns) {
k.contEl.onmouseenter = () => {
this.showEvent(k);
this.detailIns.transfer(k.contEl, () => {
this.detailIns.show();
});
};
}
});
});
this.data.panels.forEach((k, i) => {
if (k.yearEl) {
k.yearEl.onclick = () => {
this.data.year.panelEl.style.top = k.panelEl.offsetTop + k.headEl.clientHeight + 'px';
this.data.year.panelEl.style.left = k.panelEl.offsetLeft + 'px';
this.data.month.panelEl && elState(this.data.month.panelEl).isVisible && hide({ el: this.data.month.panelEl });
this.createYearList(k, null, i);
toggle({
el: this.data.year.panelEl,
done: {
show: () => {
k.yearEl.classList.add(`${ax.prefix}opened`);
},
hide: () => {
k.yearEl.classList.remove(`${ax.prefix}opened`);
}
}
});
};
this.data.year.prevEl.onclick = () => {
this.createYearList(k, this.data.year.list[0].value - 15, i);
};
this.data.year.nextEl.onclick = () => {
this.createYearList(k, this.data.year.list[14].value + 1, i);
};
this.data.year.btnEl.onclick = () => {
this.searchYear2Update(this.data.year.inputEl);
};
this.data.year.inputEl.onkeyup = (e) => {
(e.code === 'Enter') && this.searchYear2Update(this.data.year.inputEl);
};
}
if (k.monthEl) {
k.monthEl.onclick = () => {
this.data.month.panelEl.style.top = k.panelEl.offsetTop + k.headEl.clientHeight + 'px';
this.data.month.panelEl.style.left = k.panelEl.offsetLeft + 'px';
if (elState(this.data.year.panelEl).isVisible) {
hide({ el: this.data.year.panelEl });
}
this.data.month.list.forEach((o) => {
if (k.month === o.value) {
this.selectedAttrToggle(o, true);
}
else {
this.selectedAttrToggle(o, false);
}
o.contEl.onclick = () => {
if (k.month !== o.value) {
this.data.startDate.setMonth(o.value - i);
this.createPanels('', true);
hide({ el: this.data.month.panelEl });
}
};
});
toggle({
el: this.data.month.panelEl,
done: {
show: () => {
k.monthEl.classList.add(`${ax.prefix}opened`);
},
hide: () => {
k.monthEl.classList.remove(`${ax.prefix}opened`);
}
}
});
};
}
});
this.data.selecteds.forEach((k, i) => {
let item = this.findFromPanels(k, null, curGrids).target;
if (item) {
this.selectedAttrToggle(item, true);
(i === 0 && this.options.events.enable) && this.showEvent(item);
}
});
}
}
renderFinish() {
if (this.data.type !== 'daytime') {
if (this.resultIns) {
this.resultIns.on('removed', (items) => {
for (let k of items) {
this.deselect(k.source);
}
});
this.resultIns.on('updated', () => {
this.resultIns.data.forEach((k) => {
k.wrapEl.onclick = (e) => {
e.target.getAttribute(ax.alias) !== 'remove' && !this.findFromPanels(k.label).target && this.createPanels(k.label);
};
});
});
}
if (this.prevYearEl) {
this.prevYearEl.onclick = () => {
let years = (this.data.type === 'year') ? -18 * this.options.cols * this.options.rows :
(this.data.type === 'month') ? -this.options.cols * this.options.rows : -1;
this.createPanels(dateTools.getOffsetDate(this.data.startDate, { YYYY: years }), true);
this.data.year.panelEl && this.createYearList(this.data.panels[this.panelIdx], null, this.panelIdx);
};
}
if (this.nextYearEl) {
this.nextYearEl.onclick = () => {
let years = (this.data.type === 'year') ? 18 * this.options.cols * this.options.rows :
(this.data.type === 'month') ? this.options.cols * this.options.rows : 1;
this.createPanels(dateTools.getOffsetDate(this.data.startDate, { YYYY: years }), true);
this.data.year.panelEl && this.createYearList(this.data.panels[this.panelIdx], null, this.panelIdx);
};
}
if (this.data.type.includes('date')) {
this.prevMonthEl.onclick = () => {
this.createPanels(dateTools.getOffsetDate(this.data.startDate, { MM: -1 }), true);
};
this.nextMonthEl.onclick = () => {
this.createPanels(dateTools.getOffsetDate(this.data.startDate, { MM: 1 }), true);
};
}
if (this.yearSearchEl) {
this.yearSearchEl.btnEl.onclick = () => {
this.searchYear2Update(this.yearSearchEl.inputEl, false);
};
this.yearSearchEl.inputEl.onkeyup = (e) => {
(e.code === 'Enter') && this.searchYear2Update(this.yearSearchEl.inputEl, false);
};
}
if (this.timePanelsEl) {
if (this.options.mode === 'range') {
if (this.data.selecteds.length === 0) {
this.setDaytime([{ hh: 0, mm: 0, ss: 0 }, { hh: 0, mm: 0, ss: 0 }]);
}
else if (this.data.selecteds.length === 1) {
this.setDaytime([this.data.selecteds[0], { hh: 0, mm: 0, ss: 0 }]);
}
else {
this.setDaytime(this.data.selecteds);
}
}
else {
if (this.data.selecteds.length === 0) {
this.setDaytime({ hh: 0, mm: 0, ss: 0 });
}
else {
this.setDaytime(this.data.selecteds[0]);
}
}
if (this.daytimeBtnEl) {
this.daytimeBtnEl.onclick = () => {
slideToggle({
el: this.timePanelsEl,
display: 'grid',
before: (e) => {
e.for === 'show' && this.openTime2Scroll();
}
});
};
}
}
}
if (this.options.footer.enable) {
if (this.confirmEl) {
this.confirmEl.onclick = () => this.confirm();
}
if (this.nowEl) {
this.nowEl.onclick = () => this.setNow();
}
if (this.clearEl) {
this.clearEl.onclick = () => this.clear(true);
}
if (this.cancelEl) {
this.cancelEl.onclick = () => this.cancel();
}
if (this.closeEl) {
this.closeEl.onclick = () => this.hide();
}
}
if (this.data.type.includes('time') && this.data.daytime.length > 0) {
let timeCols = this.data.daytime.map((k) => k.colsEl).flat(Infinity);
if (this.options.display === 'inline') {
this.openTime2Scroll(timeCols);
}
else {
if (this.bubbleIns) {
this.bubbleIns.on('show', () => {
this.openTime2Scroll(timeCols);
});
}
}
}
if (this.bubbleIns) {
this.bubbleIns.on('show', () => {
this.setResultWidth();
});
}
else {
this.setResultWidth();
}
}
setResultWidth() {
this.resultEl && (this.resultEl.style.maxWidth = this.panelsEl.getBoundingClientRect().width + 'px');
}
openTime2Scroll(cols) {
let timeCols = cols || this.data.daytime.map((k) => k.colsEl).flat(Infinity);
timeCols.forEach((k) => {
this.showForemost(k);
});
}
searchYear2Update(input, isHide = true) {
let value = input.value;
if (value && !isNaN(value)) {
this.data.startDate.setFullYear(~~value);
this.createPanels();
isHide && hide({ el: this.data.year.panelEl });
this.data.type === 'year' && this.select({ YYYY: ~~value });
}
else {
new Message({
status: 'error',
iconShow: true,
content: this.options.lang.message.requireYearFormat,
}).show();
}
}
createPanelDayList(elem, dateObj) {
elem.innerHTML = '';
let curDate = dateTools.getDate(dateObj, this.data.type, this.options.lang);
curDate.setDate(1);
let list = [], startIndex, curMonth = curDate.getMonth(), curYear = curDate.getFullYear(), monthDays = dateTools.getCurDays(curDate), preDate = dateTools.getOffsetDate(curDate, { MM: -1 }), prevMonth = preDate.getMonth(), prevYear = preDate.getFullYear(), nextDate = dateTools.getOffsetDate(curDate, { MM: 1 }), nextMonth = nextDate.getMonth(), nextYear = nextDate.getFullYear(), fragment = document.createDocumentFragment();
if (this.options.weekStart === 'monday') {
startIndex = (curDate.getDay() === 0) ? 7 : curDate.getDay();
}
else {
startIndex = (curDate.getDay() === 0) ? 1 : curDate.getDay() + 1;
}
let day = 1;
for (let gridIndex = 1; gridIndex <= 42;) {
let dayObj = {
wrapEl: createEl('li'),
contEl: createEl('span', { [ax.alias]: 'content' }),
labelEl: createEl('i', { [ax.alias]: 'label' }),
}, label;
dayObj.wrapEl.appendChild(dayObj.contEl);
dayObj.contEl.appendChild(dayObj.labelEl);
if (gridIndex < startIndex) {
label = dateTools.getCurDays({ YYYY: prevYear, MM: prevMonth }) - startIndex + gridIndex + 1;
dayObj.value = { YYYY: prevYear, MM: prevMonth, DD: label };
dayObj.exceed = true;
dayObj.wrapEl.setAttribute('exceed', '');
}
else if (gridIndex >= startIndex + monthDays) {
label = gridIndex - startIndex - monthDays + 1;
dayObj.value = { YYYY: nextYear, MM: nextMonth, DD: label };
dayObj.exceed = true;
dayObj.wrapEl.setAttribute('exceed', '');
}
else {
label = day;
dayObj.value = { YYYY: curYear, MM: curMonth, DD: label };
day++;
}
dayObj.label = label;
dayObj.labelEl.textContent = label;
this.setDatespanDisabled(dayObj);
if (this.options.lunar && this.options.lunar.handler) {
let lunarObj = this.options.lunar.handler(dayObj.value.YYYY, dayObj.value.MM + 1, dayObj.value.DD);
if (lunarObj && lunarObj != -1) {
let lunarContent = '', attr = '';
for (let v of this.options.lunar.arrange) {
if (this.options.lunar.map.hasOwnProperty(v) && lunarObj[this.options.lunar.map[v]]) {
lunarContent = lunarObj[this.options.lunar.map[v]];
if (v.includes('Festival')) {
attr = 'festival';
}
else if (v === 'term') {
attr = v;
}
break;
}
}
dayObj.lunarEl = createEl('u', '', lunarContent);
attr ? dayObj.lunarEl.setAttribute(ax.alias, attr) : null;
dayObj.labelEl.insertAdjacentElement('afterend', dayObj.lunarEl);
}
if (this.options.lunar.tags.length > 0) {
for (let v of this.options.lunar.tags) {
let date = dateTools.getDateObj(v.date, this.data.type), tagEl = createEl('s', v.attr ? { [ax.alias]: v.attr } : {}, v.content);
if (dateTools.isSameDay(date, dayObj.value)) {
dayObj.contEl.appendChild(tagEl);
break;
}
}
}
}
if (this.options.events.enable) {
for (let v of this.options.events.list) {
let date = dateTools.getDateObj(v.date, this.data.type);
if (dateTools.isSameDay(date, dayObj.value)) {
dayObj.busy = true;
dayObj.wrapEl.setAttribute('busy', '');
break;
}
}
}
gridIndex++;
fragment.appendChild(dayObj.wrapEl);
list.push(dayObj);
}
elem.appendChild(fragment);
return list;
}
createPanelMonthList(elem, dateObj) {
let list = [];
[...elem.children].forEach((k, i) => {
let obj = {
wrapEl: k,
contEl: k.querySelector(`[${ax.alias}="content"]`),
value: { YYYY: dateObj.getFullYear(), MM: i }
};
this.setDatespanDisabled(obj);
list.push(obj);
});
return list;
}
createPanelYearList(elem, dateObj) {
let list = [], fragment = document.createDocumentFragment();
for (let k = 0; k < 18; k++) {
let year = dateObj.getFullYear() + k, wrap = createEl('li', '', `<span ${ax.alias}="content"><i ${ax.alias}="label">${year}${this.options.lang.unit.Y}</i></span>`), obj = {
wrapEl: wrap,
value: { YYYY: year },
};
obj.contEl = obj.wrapEl.querySelector(`[${ax.alias}="content"]`);
this.setDatespanDisabled(obj);
list.push(obj);
fragment.appendChild(wrap);
}
elem.appendChild(fragment);
return list;
}
createLoopStr(max) {
let str = '<li>';
for (let n = 0; n < max; n++) {
str += `<div> <span ${ax.alias}="content"><i ${ax.alias}="label">${dateTools.fillZero(n)}</i></span></div> `;
}
str += '</li>';
return str;
}
createTimeList(label) {
return `
<li panel="daytime">
<span ${ax.alias}="tools"><i ${ax.alias}="restore" title='${this.options.lang.toolTip.restore}'></i><i ${ax.alias}="reset" title='${this.options.lang.toolTip.reset}'></i><i ${ax.alias}="now" title='${this.options.lang.toolTip.now}'></i><i ${ax.alias}="close" title='${this.options.lang.toolTip.close}'></i></span>
<div ${ax.alias}="head">
<span ${ax.alias}="time">${label}</span>
</div>
<div ${ax.alias}="body">
<ul ${ax.alias}="column" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3">
<li>${this.options.lang.unit.h}</li>
<li>${this.options.lang.unit.m}</li>
<li>${this.options.lang.unit.s}</li>
</ul>
<ul ${ax.alias}="list" class="${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}avg-3">
${this.createLoopStr(24)}
${this.createLoopStr(60)}
${this.createLoopStr(60)}
</ul>
</div>
</li>
`;
}
toggleTimeList(item, list) {
this.selectedAttrToggle(item, true);
let selectedItem = list.find((k) => k != item && k.selected);
selectedItem && this.selectedAttrToggle(selectedItem, false);
}
getTimeListArr(parent, type) {
let children = parent.children, arr = [];
[...children].forEach((k, i) => {
let obj = {
wrapEl: k,
contEl: k.querySelector(`[${ax.alias}="content"]`),
value: i
};
if (!this.format.includes(type)) {
obj.disabled = true;
obj.wrapEl.setAttribute('disabled', '');
}
else {
this.setTimespanDisabled(obj, type);
}
arr.push(obj);
});
return arr;
}
showForemost(parent) {
let fun = (elem) => {
let selectedItem = elem.querySelector('[selected]'), toTop = selectedItem.getBoundingClientRect().height * Math.floor((~~selectedItem.textContent) / 2);
selectedItem && (elem.scrollTop = toTop);
};
if (Array.isArray(parent)) {
parent.forEach((k) => {
fun(k);
});
}
else {
fun(parent);
}
}
createTimeSelectPanel() {
this.timePanelsEl = createEl('UL', { class: `${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}fence ${ax.screen === 'xxs' ? ax.prefix + 'avg-1' : ax.prefix + 'avg-' + this.options.cols}`, panels: 'hms' });
if (this.options.mode === 'range') {
this.timePanelsEl.innerHTML = this.createTimeList(this.options.lang.daytime.start) + this.createTimeList(this.options.lang.daytime.end);
}
else {
this.timePanelsEl.innerHTML = this.createTimeList(this.options.lang.daytime.select);
}
[...this.timePanelsEl.querySelectorAll(`[panel]`)].forEach((k) => {
let liArr = [...k.querySelectorAll(`[${ax.alias}="list"] li`)], panelObj = {
panelEl: k,
colsEl: liArr,
restoreEl: k.querySelector(`[${ax.alias}="restore"]`),
resetEl: k.querySelector(`[${ax.alias}="reset"]`),
nowEl: k.querySelector(`[${ax.alias}="now"]`),
closeEl: k.querySelector(`[${ax.alias}="close"]`),
value: {},
hh: this.getTimeListArr(liArr[0], 'hh'),
mm: this.getTimeListArr(liArr[1], 'mm'),
ss: this.getTimeListArr(liArr[2], 'ss'),
};
this.data.daytime.push(panelObj);
});
this.footEl.insertAdjacentElement('beforebegin', this.timePanelsEl);
this.data.daytime.forEach((k, n) => {
k.closeEl.onclick = () => {
slideUp({ el: this.timePanelsEl, display: 'inline-grid' });
};
k.restoreEl.onclick = () => {
this.raw[n] && this.setDaytime(this.raw[n], n, true);
};
k.resetEl.onclick = () => {
this.setDaytime({ hh: 0, mm: 0, ss: 0 }, n, true);
};
k.nowEl.onclick = () => {
let time = dateTools.getDateObj(new Date(), this.data.type);
this.setDaytime({ hh: time.hh, mm: time.mm, ss: time.ss }, n, true);
};
k.hh.forEach((i) => {
i.contEl.onclick = () => {
if (i.selected || i.disabled)
return;
this.toggleTimeList(i, k.hh);
k.value.hh = i.value;
this.timeToUpdate(k, n, true);
super.listen({ name: 'updatedTime', params: [i] });
};
});
k.mm.forEach((i) => {
i.contEl.onclick = () => {
if (i.selected || i.disabled)
return;
this.toggleTimeList(i, k.mm);
k.value.mm = i.value;
this.timeToUpdate(k, n, true);
super.listen({ name: 'updatedTime', params: [i] });
};
});
k.ss.forEach((i) => {
i.contEl.onclick = () => {
if (i.selected || i.disabled)
return;
this.toggleTimeList(i, k.ss);
k.value.ss = i.value;
this.timeToUpdate(k, n, true);
super.listen({ name: 'updatedTime', params: [i] });
};
});
});
}
timeToUpdate(parent, index = 0, updateHTML = false) {
updateHTML ? this.setTimeBtnHTML() : null;
if (this.data.type !== 'daytime' && (this.options.mode === 'single' || this.options.mode === 'range')) {
(this.data.selecteds.length >= index + 1) && Object.assign(this.selecteds[index], parent.value);
}
this.data.type === 'daytime' && this.options.autoFill && this.confirm(false);
}
setTimeBtnHTML() {
if (!this.data.type.includes('time') || !this.daytimeBtnEl)
return;
let timeStr = this.data.daytime.map((k) => {
return isEmpty(k.value) ? this.options.lang.daytime.select : `${dateTools.fillZero(k.value.hh)}:${dateTools.fillZero(k.value.mm)}:${dateTools.fillZero(k.value.ss)}`;
});
this.daytimeBtnEl.setAttribute('label', timeStr.join('~'));
}
setDaytime(timeObj, index = 0, update = false, cb) {
if (isEmpty(timeObj) || !this.data.type.includes('time') || this.destroyed)
return;
let type = getDataType(timeObj);
let setFun = (k, i) => {
let time = (typeof k === 'string') ? dateTools.getTimeObj(timeObj) : k;
this.data.daytime[i].value.hh = time.hh;
this.toggleTimeList(this.data.daytime[i].hh[time.hh], this.data.daytime[i].hh);
this.data.daytime[i].value.mm = time.mm;
this.toggleTimeList(this.data.daytime[i].mm[time.mm], this.data.daytime[i].mm);
this.data.daytime[i].value.ss = time.ss;
this.toggleTimeList(this.data.daytime[i].ss[time.ss], this.data.daytime[i].ss);
update && this.data.type === 'datetime' ? this.timeToUpdate(this.data.daytime[i], i) : null;
};
if (type === 'Array') {
timeObj.forEach((k, i) => {
(this.data.daytime.length > i) && setFun(k, i);
});
}
else {
setFun(timeObj, index);
}
this.setTimeBtnHTML();
super.listen({ name: 'updatedTime', cb, params: [timeObj] });
}
assignDaytime() {
this.selecteds.forEach((k, i) => {
this.data.daytime[i] && Object.assign(k, this.data.daytime[i].value);
});
}
async cancel(cb) {
this.options.b4Cancel && await this.options.b4Cancel.call(this);
this.hide();
this.clear(true);
this.handleVal('');
super.listen({ name: 'canceled', cb });
}
hide(cb) {
this.bubbleIns && this.bubbleIns.hide(() => {
super.listen({ name: 'hidden', cb });
});
}
show(cb) {
this.bubbleIns && this.bubbleIns.show(() => {
super.listen({ name: 'shown', cb });
});
}
async confirm(hide = this.options.confirmHide, cb) {
if (this.destroyed)
return;
this.options.b4Confirm && await this.options.b4Confirm.call(this);
let result = '';
if (this.data.type !== 'daytime') {
if (this.options.mode === 'range') {
if (this.data.selecteds.length === 0) {
result = '';
}
else if (this.data.selecteds.length === 2) {
let startStr = dateTools.fillFormat(this.data.selecteds[0], this.format, this.options.lang), endStr = dateTools.fillFormat(this.data.selecteds[1], this.format, this.options.lang);
result = `${startStr}${this.options.lang.range.hyphen}${endStr} `;
}
else {
new Message({
status: 'error',
iconShow: true,
content: this.options.lang.message.requireTwoValue,
}).show();
return false;
}
}
else {
result = this.data.selecteds.map((k) => dateTools.fillFormat(k, this.format, this.options.lang)).join(this.options.separator);
if (this.options.required && !result) {
new Message({
status: 'error',
iconShow: true,
content: this.options.lang.message.requireOneSelected,
}).show();
return false;
}
}
}
else {
result = this.data.daytime.map((k) => dateTools.fillFormat(k.value, this.format, this.options.lang)).join(this.separator);
}
await this.handleVal(result);
if (hide && this.bubbleIns) {
this.hide();
let nextIns = this.options.next && instance.find(this.options.next, 'datetime');
nextIns?.bubbleIns && nextIns.show();
}
super.listen({ name: 'confirmed', cb, params: [result] });
}
fillVals(value) {
if (!this.inputEl || this.options.feature === 'static')
return;
let oldVal = this.inputEl.value;
this.setValFromTgt(value);
super.listen({ name: 'filled', params: [value] });
this.output = { value, raw: oldVal, items: this.data.selecteds };
super.listen({ name: 'output', params: [this.output] });
super.updateCache({ content: value });
}
async handleVal(value) {
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, value, this.separator);
resp && (value = resp);
}
this.value = value;
!this.options.manual && this.fillVals(value);
}
setNow(hide = this.options.nowHide) {
if (this.destroyed)
return;
let date = dateTools.getDateObj(new Date(), this.data.type);
if (this.data.type === 'daytime') {
this.setDaytime(date);
}
else {
this.timePanelsEl && this.options.mode !== 'range' && this.setDaytime(date);
this.select(date);
}
if (hide) {
this.confirm();
this.hide();
}
}
removeIns() {
this.bubbleEl.remove();
this.bubbleIns && (this.bubbleIns.destroy(), this.bubbleIns = null);
this.detailIns && (this.detailIns.destroy(), this.detailIns = null);
this.resultIns && (this.resultIns.destroy(), this.resultIns = null);
}
async update(settings, cb) {
if (this.destroyed)
return;
this.removeIns();
if (!isEmpty(settings)) {
this.updateCache && this.updateCache(settings);
extend({ target: this.options, source: settings });
await this.init();
}
super.listen({ name: 'updated', cb, params: [this.options] });
return this;
}
setVals2Objs(data) {
let dataType = getDataType(data), arr = [];
if (dataType === 'Array') {
arr = data;
}
if (dataType === 'Date') {
arr = [data];
}
else if (dataType === 'Object') {
arr = [data];
}
else if (dataType === 'String') {
let separator;
if (data.includes(this.options.separator)) {
separator = this.options.separator;
}
else {
separator = this.separator;
}
arr = data.split(separator);
}
if (arr.length === 0) {
return [];
}
else {
return arr.map((k) => dateTools.getDateObj(k, this.data.type));
}
}
getVals() {
return { value: this.value, separator: this.separator };
}
async setVals(data, cb) {
if (isEmpty(data) || this.destroyed)
return;
let objArr = this.setVals2Objs(data);
if (objArr.length === 0)
return;
if (this.options.b4Set) {
let resp = await this.options.b4Set.call(this, objArr);
!isEmpty(resp) && (objArr = resp);
}
super.listen({ name: 'set', cb, params: [objArr] });
if (this.options.mode === 'range') {
if (objArr.length >= 2) {
objArr.splice(2, objArr.length - 2);
this.setRange(objArr);
}
else {
this.select(objArr[0]);
}
this.setDaytime(objArr, 0, true);
}
else {
if (this.options.mode === 'single') {
this.select(objArr[0]);
this.setDaytime(objArr[0], 0, true);
}
else if (this.options.mode === 'multiple') {
objArr.forEach((k) => {
this.select(k);
});
}
}
super.listen({ name: 'set', cb, params: [objArr] });
return this;
}
setRange(data, cb) {
if (isEmpty(data) || data.length !== 2 || this.destroyed)
return;
let objArr = data.map((k) => dateTools.getDateObj(k, this.data.type)), curGrids = this.getCurGrids();
dateTools.sort(objArr);
this.selecteds.splice(0, this.selecteds.length, ...objArr);
if (!this.inCurPanels(objArr[0], curGrids) && !this.inCurPanels(objArr[1], curGrids)) {
this.createPanels(objArr[0]);
}
else {
this.setDaytime(objArr);
}
this.setRangeAttr();
super.listen({ name: 'ranged', cb, params: [objArr] });
return this;
}
async removeVals(data, cb) {
if (isEmpty(data) || this.destroyed)
return;
let objArr = this.setVals2Objs(data);
if (objArr.length === 0)
return;
this.options.b4Remove && await this.options.b4Remove.call(this, objArr);
objArr.forEach((k) => {
this.deselect(k);
});
super.listen({ name: 'removed', cb, params: [objArr] });
return this;
}
async clear(resetTime = true, cb) {
if (this.destroyed)
return;
this.options.b4Clear && await this.options.b4Clear.call(this);
if (this.data.type !== 'daytime') {
this.selecteds.splice(0);
this.resultIns && this.resultIns.clear();
let curGrids = this.getCurGrids();
curGrids.forEach((k) => {
if (k.selected) {
this.selectedAttrToggle(k, false);
}
this.removeRangeAttr(k);
});
}
if (resetTime && this.timePanelsEl) {
for (let k in this.data.daytime) {
this.setDaytime({ hh: 0, mm: 0, ss: 0 }, k);
}
}
super.listen({ name: 'cleared', cb, });
return this;
}
async transfer(input, pos, cb) {
if (this.destroyed)
return;
let tmpPos = getEl(pos), tmpInput = getEl(input);
if (this.options.display === 'popup' && tmpPos) {
this.positionEl = tmpPos;
await this.bubbleIns.transfer(pos);
}
if (tmpInput) {
this.inputEl = tmpInput;
this.inputEl.readOnly = true;
this.options.autoCorrect && this.checkB4Show();
}
super.listen({ name: 'transferred', cb, params: [tmpInput, tmpPos] });
}
disable() {
if (this.destroyed)
return;
this.inputEl && this.inputEl.toggleAttribute('inert', true);
this.bubbleEl.toggleAttribute('inert', true);
super.listen({ name: 'disabled' });
}
enable() {
if (this.destroyed)
return;
this.inputEl && this.inputEl.removeAttribute('inert');
this.bubbleEl.removeAttribute('inert');
super.listen({ name: 'enabled' });
}
destroy(cb) {
if (this.destroyed)
return;
this.removeIns();
this.confirmEl && (this.confirmEl.onclick = null);
this.nowEl && (this.nowEl.onclick = null);
this.clearEl && (this.clearEl.onclick = null);
this.cancelEl && (this.cancelEl.onclick = null);
this.closeEl && (this.closeEl.onclick = null);
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_tipTpl = config.lang.rate.template.tooltip, AXTMP_resultTpl = config.lang.rate.template.result;
const optRate = [
{
attr: 'name',
prop: 'name',
value: ''
},
{
attr: 'value',
prop: 'value',
value: 0,
},
{
attr: 'fill',
prop: 'fill',
value: 'value',
},
{
attr: 'heading',
prop: 'heading',
value: ''
},
{
attr: 'half',
prop: 'half',
value: false,
},
{
attr: 'count',
prop: 'count',
value: 5,
},
{
attr: 'increment',
prop: 'increment',
value: 1,
},
{
attr: 'tooltip',
prop: 'tooltip',
value: {
enable: false,
format: AXTMP_tipTpl,
},
},
{
attr: 'result',
prop: 'result',
value: {
enable: false,
format: AXTMP_resultTpl,
},
},
{
attr: 'label',
prop: 'label',
value: {
enable: false,
format: '',
},
},
{
attr: 'clearable',
prop: 'clearable',
value: false,
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'star',
prop: 'star',
value: `${ax.prefix}icon-star-f`,
},
{
attr: 'type',
prop: 'type',
value: 'icon',
},
{
attr: 'map',
prop: 'map',
value: [],
},
{
attr: 'highlight',
prop: 'highlight',
value: false,
},
{
attr: 'omitted',
prop: 'omitted',
value: false,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'disabled',
prop: 'disabled',
value: false,
},
{
attr: 'readonly',
prop: 'readonly',
value: false,
},
{
attr: 'on-set',
prop: 'onSet',
value: null,
},
{
attr: 'on-changed',
prop: 'onChanged',
value: null,
},
{
attr: 'on-restored',
prop: 'onRestored',
value: null,
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null,
},
...optBase
];
class Rate extends ModBaseListenCache {
options = {};
inputEl;
current;
evtMap;
useMap;
outputIns;
output;
rawVal;
wrapEl;
tooltipIns;
tooltipEl;
clearEl;
items;
legends;
headEl;
resultEl;
static hostType = 'node';
static optMaps = optRate;
constructor(elem, options = {}, initial = true) {
super();
let tmp = getEl(elem), host;
if (!tmp)
return this;
if (tmp.nodeName === 'INPUT') {
this.inputEl = tmp;
this.inputEl.type = 'range';
host = createEl('div', { class: `${ax.prefix}rate` });
tmp.insertAdjacentElement('beforebegin', host);
}
else {
host = tmp;
host.classList.add(`${ax.prefix}rate`);
this.inputEl = createEl('input', { type: 'range' });
}
super.ready({
options,
maps: Rate.optMaps,
host,
component: true,
spread: ['tooltip', 'result', 'lable']
});
this.current = { place: 'full', legend: null, value: 0, stars: 0 };
this.evtMap = ax.isTouchScr ? { move: 'ontouchmove', end: 'ontouchend' } : { move: 'onmousemove', end: 'onmouseleave' };
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.useMap = !isEmpty(this.options.map) && Array.isArray(this.options.map);
this.options.count = this.useMap ? this.options.map.length : ~~this.options.count;
this.createOutputIns();
this.legends = [];
this.renderMain();
this.renderFormat();
this.getDirRtl();
this.setAttrs();
this.options.value = parseFloat(this.options.value || this.rawHtml || this.inputEl.value);
this.rawVal = this.options.value;
this.setVals(this.options.value);
this.createTooltip();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
createOutputIns() {
this.outputIns = new Observe({ stars: 0, value: 0, title: this.options.lang.title.dft, count: this.options.count, total: this.options.count * this.options.increment }, {
onSet: (data) => {
if (data.key === 'value') {
let oldVal = parseFloat(this.inputEl.value), newVal = this.output[this.options.fill || 'value'];
this.inputEl.value = newVal;
oldVal !== newVal && super.listen({ name: 'changed', params: [newVal, oldVal] });
}
},
onCompleted: () => {
this.renderFormat();
}
});
this.output = this.outputIns.proxy;
}
renderFinish() {
if (this.options.readonly || this.options.disabled)
return;
this.wrapEl[this.evtMap.move] = (e) => {
let legend = this.findLegend(e);
if (!legend)
return;
let place = this.getStarPoint(e, legend), { stars, value } = this.updateStarsState({ legend, place });
if (this.tooltipIns) {
this.tooltipIns.transfer(legend, () => this.tooltipIns.show());
this.renderFormat('tooltip', { ...this.output, stars, value });
}
this.current = { place, legend, stars, value };
};
this.wrapEl.onclick = (e) => {
let legend = this.findLegend(e);
if (!legend)
return;
this.setVals({ legend, place: this.getStarPoint(e, legend) });
};
this.wrapEl[this.evtMap.end] = (e) => {
this.tooltipIns && this.tooltipIns.hide();
if (ax.isTouchScr) {
this.setVals(this.current);
}
else {
this.updateStarsState(this.output.value);
}
};
this.clearEl.onclick = () => {
this.clear();
};
}
renderFormat(type, data = { ...this.output }) {
let el = type === 'result' ? this.resultEl : type === 'tooltip' ? this.tooltipEl : null;
if (el) {
this.options[type].enable && (el.innerHTML = renderTpl(this.options[type].format, data));
}
else {
this.options.result.enable && (this.resultEl.innerHTML = renderTpl(this.options.result.format, data));
this.options.tooltip.enable && (this.tooltipEl.innerHTML = renderTpl(this.options.tooltip.format, data));
}
}
findLegend(e) {
return this.legends.find((k) => contains(getEvtTarget(e), k));
}
getStarPoint(e, node) {
if (!this.options.half)
return 'full';
let tmp = getRectPoints(e, node), dir = this.isRtl ? 'r' : 'l';
return tmp.length <= 1 ? '' : tmp.includes(`${dir}/3`) || tmp.includes(`${dir}/2`) ? 'half' : 'full';
}
createTooltip() {
if (!this.options.tooltip.enable)
return;
this.tooltipIns = new Tooltip(this.wrapEl, extend({
target: {
content: this.tooltipEl,
size: '',
theme: 'text-lt',
keepShow: true,
},
source: this.options.tooltip,
}));
}
getStarsHtml() {
let getStar = (val) => this.options.type === 'image' ? `<i><img src="${val}"/></i>` : `<i class="${val}"></i>`, result = '', tpl = '', data, getHtml = (cont) => this.options.label.enable ? `<span ${ax.alias}="label">${cont}</span>` : '';
if (this.useMap) {
for (let [i, k] of this.options.map.entries()) {
data = { id: i + 1, title: k.title, count: this.options.map.length };
tpl = this.options.label.format ? renderTpl(this.options.label.format, data) : data.title;
result += `<li ${k.title ? 'title="' + k.title + '"' : ''}>
<span ${ax.alias}="legend">${getStar(k.on)}${getStar(k.off || k.on)}</span>
${getHtml(tpl)}
</li>`;
}
}
else {
for (let i = 0; i < this.options.count; i++) {
data = { id: i + 1, title: '', count: this.options.count };
tpl = this.options.label.format ? renderTpl(this.options.label.format, data) : data.id + this.options.lang.star;
result += `<li>
<span ${ax.alias}="legend">${getStar(this.options.star).repeat(2)}</span>
${getHtml(tpl)}
</li>`;
}
}
return result;
}
renderMain() {
this.targetEl.innerHTML = '';
let fragment = document.createDocumentFragment();
fragment.appendChild(this.inputEl);
this.wrapEl = createEl('ul', { class: `${ax.prefix}reset` }, this.getStarsHtml());
this.resultEl = createEl('div', { [ax.alias]: 'result' });
this.tooltipEl = createEl('div', { [ax.alias]: 'tooltip' });
this.clearEl = createEl('i', { class: `${ax.prefix}icon-close-o-f`, [ax.alias]: 'clear', title: this.options.lang.title.clear });
this.items = [...this.wrapEl.children];
this.legends = this.items.map((k) => getEl(`[${ax.alias}="legend"]`, k));
this.headEl = createEl('i', { [ax.alias]: 'head' }, this.options.heading);
this.options.heading && fragment.appendChild(this.headEl);
this.options.clearable && fragment.appendChild(this.clearEl);
fragment.appendChild(this.wrapEl);
this.options.result.enable && fragment.appendChild(this.resultEl);
this.targetEl.appendChild(fragment);
super.listen({ name: 'rendered', params: [{ targetEl: this.targetEl, headEl: this.headEl, wrapEl: this.wrapEl, resultEl: this.resultEl, clearEl: this.clearEl, items: this.items, legends: this.legends }] });
}
setAttrs() {
this.options.size ? this.targetEl.setAttribute('size', this.options.size) : this.targetEl.removeAttribute('size');
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.setAttribute('type', this.options.type);
this.targetEl.toggleAttribute('disabled', this.options.disabled);
this.targetEl.toggleAttribute('readonly', this.options.readonly);
this.targetEl.toggleAttribute('omitted', this.options.omitted);
this.inputEl.step = (this.options.half ? 0.5 : 1) * (this.options.fill === 'value' ? this.options.increment : 1);
this.inputEl.max = this.options.count * (this.options.fill === 'value' ? this.options.increment : 1);
this.inputEl.min = 0;
this.inputEl.disabled = true;
this.inputEl.name = this.options.name;
!this.inputEl.hasAttribute('value') && (this.inputEl.value = 0);
this.options.rtl ? this.targetEl.setAttribute('dir', 'rtl') : this.targetEl.removeAttribute('dir');
}
getVals() {
return { ...this.output };
}
correctVal(val) {
let valType = getDataType(val), value = 0;
if (valType === 'Object') {
let idx = this.legends.findIndex((k) => k === val.legend);
if (idx === -1) {
value = 0;
}
else {
let tmp = val.place === 'half' ? 0.5 : val.place === 'full' ? 1 : 0;
value = (idx + tmp) * this.options.increment;
}
}
else {
let tmp = clampVal({ min: 0, max: this.options.increment * this.options.count, val: parseFloat(val) }), stars = tmp / this.options.increment, integer = Math.floor(stars), float = stars - integer, rest = this.getFloatStar(float);
value = (integer + rest) * this.options.increment;
}
return value;
}
getFloatStar(float) {
if (this.options.half) {
return !float ? 0 : float > 0 && float <= 0.5 ? 0.5 : 1;
}
else {
return !float ? 0 : 1;
}
}
toggleSelected(li) {
let other = [...this.wrapEl.children].find((k) => k !== li && k.hasAttribute('selected'));
other && other.toggleAttribute('selected', false);
li.toggleAttribute('selected', true);
}
updateStarsState(val = 0) {
let value = this.correctVal(val), stars = value / this.options.increment, b4Stars = Math.floor(stars), curStar = stars - b4Stars, item, map = [`${ax.prefix}half`, `${ax.prefix}full`];
curStar = this.getFloatStar(curStar);
for (let i = 0; i < this.legends.length; i++) {
let el = this.legends[i].firstElementChild, li = el.closest('li');
if (!value) {
classes(el).remove(map.join());
}
else {
if (i < b4Stars) {
if (this.options.highlight) {
if (!curStar && i === b4Stars - 1) {
classes(el).replace(...map);
this.toggleSelected(li);
item = li;
}
else {
classes(el).remove(map.join());
}
}
else {
classes(el).replace(...map);
if (!curStar && i === b4Stars - 1) {
this.toggleSelected(li);
item = li;
}
}
}
else if (i === b4Stars) {
if (curStar === 0) {
classes(el).remove(map.join());
}
else {
if (curStar === 0.5) {
classes(el).replace(...[...map].reverse());
}
else {
classes(el).replace(...map);
}
this.toggleSelected(li);
item = li;
}
}
else {
classes(el).remove(map.join());
}
}
}
return { stars: b4Stars + curStar, value, item };
}
setVals(val, cb) {
let { stars, value, item } = this.updateStarsState(val);
if (value === this.output.value)
return;
this.output.stars = stars;
this.output.value = value;
this.output.item = item;
this.useMap && (this.output.title = this.options.map[Math.ceil(stars) - 1].title);
super.updateCache({ value });
super.listen({ name: 'set', cb, params: [{ ...this.output }] });
}
restore(cb) {
if (this.destroyed)
return this;
this.setVals(this.rawVal);
super.listen({ name: 'restored', cb, params: [this.rawVal] });
return this;
}
clear(cb) {
if (this.destroyed)
return this;
this.setVals(0);
super.listen({ name: 'cleared', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.wrapEl[this.evtMap.move] = null;
this.wrapEl.onclick = null;
this.wrapEl[this.evtMap.end] = null;
this.clearEl.onclick = null;
this.tooltipIns && this.tooltipIns.destroy();
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_separator$1 = config.splitHyphen;
const optAccordion = [
{
attr: 'name',
prop: 'name',
value: '',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'passive',
prop: 'passive',
value: false,
},
{
attr: 'disable',
prop: 'disable',
value: '',
},
{
attr: 'readonly',
prop: 'readonly',
value: '',
},
{
attr: 'expand',
prop: 'expand',
value: {
value: '',
all: false,
only: true,
linkage: false,
},
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: true,
show: `${ax.prefix}icon-down`,
hide: `${ax.prefix}icon-down`,
anim: `${ax.prefix}rotate180`,
type: 'icon',
trigger: 'click',
},
},
{
attr: 'check',
prop: 'check',
value: {
enable: false,
type: 'checkbox',
value: '',
},
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
trigger: 'hover',
children: ['add', 'edit', 'remove'],
},
},
{
attr: 'output',
prop: 'output',
value: {
enable: true,
target: '',
separator: AXTMP_separator$1,
prop: 'label',
},
},
{
attr: 'click-line',
prop: 'clickLine',
value: 'none',
},
{
attr: 'deferred',
prop: 'deferred',
value: false,
},
{
attr: 'delay',
prop: 'delay',
value: 100,
},
{
attr: 'drag',
prop: 'drag',
value: {
enable: false,
exclude: '',
},
},
{
attr: 'drop',
prop: 'drop',
value: {
attr: 'dropnode',
global: false,
},
},
{
attr: 'lamp',
prop: 'lamp',
value: {
enable: false,
placement: 'bottom',
},
},
{
attr: 'duration',
prop: 'duration',
value: 0,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'layout',
prop: 'layout',
value: 'check(icon|disk|cube|label|tips)custom|tools|badge|arrow',
},
{
attr: 'appear',
prop: 'appear',
value: {
rounded: true,
bordered: true,
divided: true,
gapped: false,
},
},
{
attr: 'b4-expand',
prop: 'b4Expand',
value: null,
},
{
attr: 'b4-collapse',
prop: 'b4Collapse',
value: null,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-edit',
prop: 'b4Edit',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-graft',
prop: 'b4Graft',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null
},
{
attr: 'on-added',
prop: 'onAdded',
value: null
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null
},
{
attr: 'on-disabledall',
prop: 'onDisabledAll',
value: null
},
{
attr: 'on-enabledall',
prop: 'onEnabledAll',
value: null
},
{
attr: 'on-readonly',
prop: 'onReadonly',
value: null
},
{
attr: 'on-readonlyall',
prop: 'onReadonlyAll',
value: null
},
{
attr: 'on-expand',
prop: 'onExpand',
value: null
},
{
attr: 'on-expanded',
prop: 'onExpanded',
value: null
},
{
attr: 'on-collapse',
prop: 'onCollapse',
value: null
},
{
attr: 'on-collapsed',
prop: 'onCollapsed',
value: null
},
{
attr: 'on-expandall',
prop: 'onExpandAll',
value: null
},
{
attr: 'on-expandedAll',
prop: 'onExpandedAll',
value: null
},
{
attr: 'on-collapsedall',
prop: 'onCollapsedAll',
value: null
},
{
attr: 'on-selected',
prop: 'onSelected',
value: null
},
{
attr: 'on-deselected',
prop: 'onDeselected',
value: null
},
{
attr: 'on-selectedall',
prop: 'onSelectedAll',
value: null
},
{
attr: 'on-checked',
prop: 'onChecked',
value: null
},
{
attr: 'on-unchecked',
prop: 'onUnchecked',
value: null
},
{
attr: 'on-checkedall',
prop: 'onCheckedAll',
value: null
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-turned',
prop: 'onTurned',
value: null
},
{
attr: 'on-got',
prop: 'onGot',
value: null
},
{
attr: 'on-set',
prop: 'onSet',
value: null
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-grafted',
prop: 'onGrafted',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-toofew',
prop: 'onTooFew',
value: null
},
{
attr: 'on-toomany',
prop: 'onTooMany',
value: null
},
{
attr: 'on-locked',
prop: 'onLocked',
value: null
},
{
attr: 'on-unlocked',
prop: 'onUnlocked',
value: null
},
...optBase
];
class Accordion extends ModBaseListenCacheNest {
expandEvt;
lineEvt;
treeDataOrig;
receiver;
rawData;
observeIns;
chainChecking;
hoverIns;
inputEl;
value;
contXhr;
static hostType = 'node';
static optMaps = optAccordion;
static dependencies = [BadgeElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Accordion.optMaps,
component: true,
spread: ['output', 'arrow', 'check', 'lamp', 'tools', 'drag']
});
let _this = this;
this.expandEvt = debounce(function () {
let attr = this.getAttribute(ax.alias) === 'arrow' ? 'arrowEl' : 'headEl', item = findItem(this, _this.flatData, attr);
_this.toggleExpanded(item);
}, this.options.delay);
this.lineEvt = debounce(function (e) {
let item = findItem(this, _this.flatData, 'headEl');
if (!item)
return;
if ((['group', 'gap', 'holder'].includes(e.target.getAttribute(ax.alias)) || e.target === item.headEl)) {
if (_this.options.clickLine === 'expanded') {
_this.toggleExpanded(item);
}
else if (_this.options.clickLine === 'checked') {
_this.toggleCheck(item);
}
}
}, this.options.delay);
this.treeDataOrig = [];
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.receiver = getEl(this.options.output.target);
super.useTpl();
await this.getDataToRender();
this.setAttrs();
this.renderFinish();
super.initCheckeds();
this.initExpandeds();
super.initDisableds();
super.initReadonlys();
super.listen({ name: 'initiated', cb });
return this;
}
async getDataToRender() {
let base = {
nodeType: 'accordion',
}, promise;
if (this.options.content) {
promise = treeTools.allToTree({
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: { spinSel: this.targetEl, xhrName: 'contXhr' },
ins: this,
...base
});
}
else {
promise = treeTools.allToTree({
content: this.targetEl.innerHTML,
...base
});
}
await promise.then((res) => {
this.treeDataOrig = res.data && Array.isArray(res.data) ? res.data : res;
this.rawData = res;
});
this.targetEl.innerHTML = '';
this.renderData(this.treeDataOrig);
this.getTreeFlat();
super.listen({ name: 'rendered', params: [this.treeData, this.flatData] });
return this;
}
getTreeFlat() {
this.treeData = this.getObserver(this.treeDataOrig).proxy;
this.flatData = this.treeData;
}
getObserver(data) {
this.observeIns = new Observe(data, {
deep: {
enable: true,
exclude: ['tools'],
},
onSet: (obj) => {
if (obj.key === 'icon' && obj.proxy.iconEl) {
classes(obj.proxy.iconEl).replace(obj.raw, obj.value);
}
else if (obj.key === 'cube' && obj.proxy.cubeEl) {
obj.proxy.cubeEl.src = obj.value;
}
else if (obj.key === 'disk' && obj.proxy.diskEl) {
obj.proxy.diskEl.src = obj.value;
}
else if (obj.key === 'label') {
obj.proxy.labelEl.innerHTML = obj.value;
}
else if (obj.key === 'tips' && obj.proxy.tipsEl) {
obj.proxy.tipsEl.innerHTML = obj.value;
}
else if (obj.key === 'content') {
super.updateElCont(obj.proxy, obj.value, 'content');
}
else if (obj.key === 'extra') {
super.updateElCont(obj.proxy, obj.value, 'extra');
}
else if (obj.key === 'custom' && obj.proxy.customEl) {
super.updateElCont(obj.proxy, obj.value, 'custom');
}
else if (obj.key === 'badge' && obj.proxy.badgeEl) {
obj.proxy.badgeEl.setAttribute('label', obj.value);
}
else if (obj.key === 'href' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.href = obj.value;
}
else if (obj.key === 'rel' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.rel = obj.value;
}
else if (obj.key === 'target' && obj.proxy.labelEl.nodeName === 'A') {
obj.proxy.labelEl.target = obj.value;
}
else if (obj.key === 'expanded') {
super.toggleArrow(attrValBool(obj.value), obj.proxy);
}
else if (obj.key === 'disabled') {
obj.proxy.wrapEl.toggleAttribute('disabled', attrValBool(obj.value));
}
else if (obj.key === 'readonly') {
obj.proxy.headEl.toggleAttribute('readonly', attrValBool(obj.value));
}
else if (obj.key === 'checked') {
let tmp = attrValBool(obj.value);
obj.proxy.headEl.toggleAttribute('checked', tmp);
obj.proxy.checkEl.setAttribute('check', tmp ? 'ed' : '');
}
else if (obj.key === 'children') {
if (!obj.raw && obj.value) ;
else if (obj.raw && !obj.value) ;
}
},
onDeleted: (obj) => {
if (obj.key === 'children') {
treeTools.parentToChild(obj.proxy);
}
},
onCompleted: (data) => {
data.keys.set.includes('checked') && this.updateVals();
if (this.options.storName) {
let tmp = {
check: { value: treeTools.getBoolItems(this.flatData, 'checked').map((k) => k.id) },
expand: treeTools.getBoolItems(this.flatData, 'expanded').map((k) => k.id),
disable: treeTools.getBoolItems(this.flatData, 'disabled').map((k) => k.id),
readonly: treeTools.getBoolItems(this.flatData, 'readonly').map((k) => k.id),
content: !isEmpty(this.options.content) ? deepClone(this.treeDataOrig) : '',
};
super.updateCache(tmp);
}
}
});
return this.observeIns;
}
initExpandeds() {
let vals = valToArr(this.options.expand.value).map((k) => findItem(k, this.flatData)).filter(Boolean), items = this.flatData.filter((k) => attrValBool(k.expanded)), tmp = [...items, ...vals];
for (let k of items)
k.expanded = false;
if (this.options.expand.all) {
super.expandAll();
}
else {
super.expand(tmp);
}
}
renderData(data) {
for (let k of data) {
this.createHeadEl(k);
this.createBodyEl(k);
k.wrapEl.append(k.headEl, k.bodyEl);
this.targetEl.appendChild(k.wrapEl);
}
this.inputEl = createEl('input', { type: 'hidden', name: this.options.name });
this.options.name && this.targetEl.insertAdjacentElement('afterbegin', this.inputEl);
}
updateArrowEl(item) {
if (!item.arrowEl)
return;
item.arrowEl.setAttribute('type', this.options.arrow.type);
this.options.lang.title.arrow && item.arrowEl.setAttribute('title', this.options.lang.title.arrow);
if (this.options.arrow.type === 'image') {
this.options.arrow.hide && (item.arrowEl.style.backgroundImage = `url("${this.options.arrow.hide}")`);
}
else {
item.arrowEl.classList.remove(`${ax.prefix}none`);
this.options.arrow.hide && item.arrowEl.classList.add(this.options.arrow.hide);
}
}
createHeadEl(item) {
if (item.wrapEl)
return;
item.wrapEl = createEl('section', { class: `${ax.prefix}accordion-wrap` });
if (item.headEl) {
if (!item.labelEl) {
item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [ax.alias]: 'label' }, item.label);
item.headEl.appendChild(item.labelEl);
}
}
else {
item.headEl = createEl('div', { class: `${ax.prefix}accordion-head` });
!item.labelEl && (item.labelEl = createEl(item.hasOwnProperty('href') ? 'a' : 'i', { [ax.alias]: 'label' }, item.label));
item.headEl.appendChild(item.labelEl);
}
item.wrapEl.appendChild(item.headEl);
item.href && (item.labelEl.href = item.href);
item.target && (item.labelEl.target = item.target);
item.groupEl = createEl('div', { [ax.alias]: 'group' });
super.getArrowEl(item);
if (!item.iconEl) {
item.iconEl = item.hasOwnProperty('icon') ? createEl('i', { [ax.alias]: 'icon', class: item.icon }) : null;
}
if (!item.diskEl) {
item.diskEl = item.hasOwnProperty('disk') ? createEl('img', { [ax.alias]: 'disk', src: item.disk || ax.images.none }) : null;
}
if (!item.cubeEl) {
item.cubeEl = item.hasOwnProperty('cube') ? createEl('img', { [ax.alias]: 'cube', src: item.cube || ax.images.none }) : null;
}
if (!item.imageEl) {
item.imageEl = item.hasOwnProperty('image') ? createEl('img', { [ax.alias]: 'image', src: item.image || ax.images.none }) : null;
}
if (!item.badgeEl) {
item.badgeEl = item.badge ? createEl('ax-badge', { [ax.alias]: 'badge', label: item.badge.toString().trim() }) : null;
}
if (!item.tipsEl) {
item.tipsEl = item.tips ? createEl('i', { [ax.alias]: 'tips' }, item.tips) : null;
}
if (!item.customEl) {
item.customEl = item.custom ? createEl('div', { [ax.alias]: 'custom' }, item.custom) : null;
}
attrValBool(item.expanded) && item.headEl.toggleAttribute('expanded', true);
attrValBool(item.disabled) && item.headEl.toggleAttribute('disabled', true);
attrValBool(item.readonly) && item.headEl.toggleAttribute('readonly', true);
attrValBool(item.checked) && item.headEl.toggleAttribute('checked', true);
if (this.options.check.enable) {
item.checkEl = createEl(`ax-${this.options.check.type}`, { [ax.alias]: 'check' });
}
if (this.options.tools.enable) {
item.toolsEl = createTools(this.options.tools.children, item.headEl);
item.toolsEl.setAttribute(ax.alias, 'tools');
item.tools = deepClone(this.options.tools.children);
for (let k of item.tools) {
this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
if (k.name === 'add') {
item.addEl = k.wrapEl;
}
else if (k.name === 'remove') {
item.removeEl = k.wrapEl;
}
else if (k.name === 'edit') {
item.editEl = k.wrapEl;
}
}
}
super.parseLayout(item.headEl, this.options.layout, {
arrow: item.arrowEl,
label: item.labelEl,
check: item.checkEl,
icon: item.iconEl,
disk: item.diskEl,
cube: item.cubeEl,
badge: item.badgeEl,
tips: item.tipsEl,
custom: item.customEl,
tools: item.toolsEl,
group: item.groupEl
});
}
createBodyEl(item) {
item.bodyEl = createEl('div', { class: `${ax.prefix}accordion-body` });
!item.contEl && (item.contEl = createEl('div', { class: `${ax.prefix}accordion-cont` }));
item.bodyEl.appendChild(item.contEl);
if (!item.extraEl && item.hasOwnProperty('extra')) {
item.extraEl = createEl('div', { class: `${ax.prefix}accordion-extra` });
}
item.extraEl && item.bodyEl.appendChild(item.extraEl);
!this.options.deferred && this.setContExtra(item, true);
item.headEl.insertAdjacentElement('afterend', item.bodyEl);
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}accordion`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.toggleAttribute('inert', this.options.passive);
this.targetEl.setAttribute('tools-trigger', this.options.tools.trigger);
this.options.lamp.enable ? this.targetEl.setAttribute('lamp', this.options.lamp.placement) : this.targetEl.removeAttribute('lamp');
for (let k in this.options.appear) {
let val = this.options.appear[k];
this.targetEl.toggleAttribute(k, val);
}
}
updateExpandEvt(k) {
if (!this.options.arrow.enable)
return;
if (this.options.arrow.trigger === 'click') {
k.arrowEl.removeEventListener('click', this.expandEvt);
k.arrowEl.addEventListener('click', this.expandEvt, false);
}
else if (this.options.arrow.trigger === 'hover') {
k.hoverIns && k.hoverIns.destroy();
k.hoverIns = new Hover(k.arrowEl, {
onMove: (isIn) => {
!isIn && this.options.expand.only ? super.collapse(k) : null;
},
onEnter: () => {
super.expand(k);
},
onLeave: () => {
super.collapse(k);
}
});
}
}
updateEvt(k) {
this.updateExpandEvt(k);
if (k.toolsEl) {
if (k.removeEl) {
k.removeEl.onclick = () => {
if (attrValBool(k.readonly))
return;
this.remove(k);
};
}
if (k.editEl) {
k.editEl.onclick = () => {
if (attrValBool(k.readonly))
return;
this.inputLabelCont(k);
};
}
if (k.addEl) {
k.addEl.onclick = () => {
if (attrValBool(k.readonly))
return;
this.add({ target: k });
};
}
for (let [i, o] of this.options.tools.children.entries()) {
let tool = k.tools[i], refer = { ins: this, item: k };
o.action && o.action.call(refer, tool);
tool.action && tool.action.call(refer, tool);
}
}
if (['expanded', 'checked'].includes(this.options.clickLine)) {
k.headEl.removeEventListener('click', this.lineEvt);
k.headEl.addEventListener('click', this.lineEvt, false);
}
attrValBool(k.disabled) && k.headEl.toggleAttribute('disabled', true);
attrValBool(k.readonly) && k.headEl.toggleAttribute('readonly', true);
if (this.options.check.enable) {
k.checkEl.on('check', (val) => {
let tmp = attrValBool(val.checked);
!this.chainChecking && tmp !== attrValBool(k.checked) && this.check(k, tmp);
});
}
if (this.options.drag.enable) ;
k.action && k.action.call(this, k);
}
renderFinish() {
for (let k of this.flatData) {
this.updateEvt(k);
}
}
getTriggerEl(item) {
return (item.href && item.arrowEl ? item.arrowEl : item.headEl);
}
addTrigger(item, target) {
if (attrValBool(item.disabled))
return;
let triggerEl = target || this.getTriggerEl(item);
if (this.options.arrow.trigger === 'click') {
triggerEl.removeEventListener('click', this.expandEvt);
triggerEl.addEventListener('click', this.expandEvt, false);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns ? this.hoverIns.destroy() : null;
this.hoverIns = new Hover(item.wrapEl, {
onEnter: () => {
super.expand(item);
super.listen({ name: 'trigger', params: [item] });
},
onLeave: () => {
super.collapse(item);
}
});
}
}
removeTrigger(item, target) {
if (attrValBool(item.disabled))
return;
let triggerEl = target || this.getTriggerEl(item);
if (this.options.arrow.trigger === 'click') {
triggerEl.removeEventListener('click', this.expandEvt);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns ? this.hoverIns.destroy() : null;
}
}
toggleExpanded(data) {
if (this.destroyed)
return;
let item = findItem(data, this.flatData);
if (!item)
return;
attrValBool(item.expanded) ? super.collapse(item) : super.expand(item);
super.listen({ name: 'trigger', params: [item] });
}
async setContExtra(item, force = false) {
await super.getElCont({
target: item,
data: item.content,
prop: 'content',
cb: (cont) => {
if (cont !== item.content) {
item.content = cont;
force && super.updateElCont(item, cont, 'content');
}
else {
super.updateElCont(item, cont, 'content');
}
}
});
if (item.extraEl) {
await super.getElCont({
target: item,
data: item.extra,
prop: 'extra',
cb: (cont) => {
if (cont !== item.extra) {
item.extra = cont;
force && super.updateElCont(item, cont, 'extra');
}
else {
super.updateElCont(item, cont, 'extra');
}
}
});
}
}
async eachCollapse(data, cb) {
if (isNull(data))
return;
try {
if (this.options.b4Collapse) {
let resp = await this.options.b4Collapse.call(this, data);
resp && (data = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Branch collapsing has been prevented!');
return;
}
let item = findItem(data, this.flatData);
if (!item)
return;
super.listen({ name: 'collapse', cb, params: [item] });
item.expanded = false;
slideUp({
el: item.bodyEl,
duration: this.options.duration,
done: () => {
super.listen({ name: 'collapsed', cb, params: [item] });
}
});
}
async eachExpand(data, cb) {
if (isNull(data))
return;
try {
if (this.options.b4Expand) {
let resp = await this.options.b4Expand.call(this, data);
resp && (data = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Branch expansion has been prevented!');
return;
}
let item = findItem(data, this.flatData);
if (!item)
return;
super.listen({ name: 'expand', cb, params: [item] });
if (this.options.deferred && !item.contEl.innerHTML) {
item.arrowEl && item.arrowEl.toggleAttribute('spinning', true);
await this.setContExtra(item);
item.arrowEl && item.arrowEl.removeAttribute('spinning');
}
item.expanded = true;
slideDown({
el: item.bodyEl,
duration: this.options.duration,
done: () => {
super.listen({ name: 'expanded', cb, params: [item] });
}
});
if (this.options.expand.only) {
let others = this.flatData.filter((k) => k !== item && attrValBool(k.expanded));
for (let k of others)
super.collapse(k);
}
}
uncheckSibings(item) {
this.chainChecking = true;
let siblings = super.getSiblings(item).filter((k) => attrValBool(k.checked));
for (let k of siblings)
k.checked = false;
this.chainChecking = false;
}
check(data, flag = true, cb) {
if (this.destroyed)
return;
let tmp = Array.isArray(data) ? data : [data], filters = tmp.map((k) => findItem(k, this.flatData)), items = filters.filter((k) => k && !attrValBool(k.checked) === flag), fn = (obj) => {
obj.checked = flag;
flag && this.options.check.type === 'radio' && this.uncheckSibings(obj);
};
if (!items.length)
return;
for (let k of items)
fn(k);
super.listen({ name: flag ? 'checked' : 'unchecked', cb, params: [items] });
return this;
}
checkAll(cb) {
if (this.destroyed || !this.options.check.enable || this.options.check.type !== 'checkbox')
return;
if (this.options.check.type === 'checkbox') {
this.check(this.flatData, true);
}
else {
let checkedItem = this.flatData.find((k) => attrValBool(k.checked));
!checkedItem && this.check(this.flatData[0], true);
}
super.listen({ name: 'checkedAll', cb });
return this;
}
async add(options) {
if (this.destroyed)
return;
let opts = Object.assign({ repeat: true, autoFill: true, isFront: false }, options), type = getDataType(opts.data), target = findItem(opts.target, this.flatData), tmp = [], items = [], appendFun = (data) => {
let obj = treeTools.createBranchObj({
source: data,
flatData: this.flatData,
target,
isLeaf: true,
isChild: false
});
this.createHeadEl(obj);
this.createBodyEl(obj);
treeTools.addBranch({
source: obj,
rootEl: this.targetEl,
flatData: this.flatData,
treeData: this.treeData,
brother: target,
isFront: opts.isFront,
repeat: opts.repeat,
autoFill: opts.autoFill,
cb: (item) => {
items.push(item);
this.updateEvt(item);
}
});
};
tmp = isNull(opts.data) ? [null] : ((type === 'Array' && opts.data.length > 0) ? opts.data : [opts.data]);
for (let k of tmp) {
try {
if (this.options.b4Add) {
let resp = await this.options.b4Add.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Adding new branche (${JSON.stringify(k)}) has been prevented!`);
continue;
}
appendFun(k);
}
super.listen({ name: 'added', cb: opts.cb, params: [items] });
return this;
}
async remove(data, cb) {
if (this.destroyed || isNull(data))
return;
if (this.flatData.length === 0) {
console.warn('The source data is already empty!');
return;
}
let tmp = [], items = [], removeItem = (child) => {
treeTools.removeBranch({
source: child,
flatData: this.flatData,
treeData: this.treeData,
remove: false,
cb: (obj) => {
items.push(obj);
}
});
};
tmp = Array.isArray(data) ? data : [data];
for (let k of tmp) {
try {
if (this.options.b4Remove) {
let resp = await this.options.b4Remove.call(this, k);
resp && (k = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn(`Removing old branch (${JSON.stringify(k)}) has been prevented!`);
continue;
}
removeItem(k);
}
super.listen({ name: 'removed', cb, params: [items] });
return this;
}
inputLabelCont(item) {
}
async edit(item, data, cb) {
if (this.destroyed || isNull(item) || isEmpty(data)) {
return this;
}
let source = findItem(item, this.flatData);
if (!source)
return this;
for (let k in data) {
let val = data[k];
try {
if (this.options.b4Edit) {
let resp = await this.options.b4Edit.call(this, { key: k, value: val }, source);
resp && (val = resp);
}
if (k === 'action') {
source[k] = val.call({ ins: this, item: k }, source);
}
else if (['icon', 'disk', 'cube', 'href', 'target', 'rel', 'label', 'content', 'tips', 'badge'].includes(k)) {
source[k] = val;
}
}
catch (err) {
err ? console.error(err) : console.warn(`No changes have been made to the ${k} property!`);
return this;
}
}
super.listen({ name: 'edited', cb, params: [source] });
return this;
}
async graft({ source, target, isFront = true, isChild = true, cb }) {
if (this.destroyed || isNull(source))
return;
try {
if (this.options.b4Graft) {
let resp = await this.options.b4Graft.call(this, source, target);
resp && resp.source && (source = resp.source);
resp && resp.target && (source = resp.target);
}
}
catch (err) {
err ? console.error(err) : console.warn(`The branch relationship between source and target in the tree remains unchanged!`);
return this;
}
let sourceObj = findItem(source, this.flatData, '', { node: 'wrapEl' }), targetObj = findItem(target, this.flatData);
if (!sourceObj)
return;
treeTools.graftBranch({
source: sourceObj,
target: targetObj,
isFront,
isChild,
flatData: this.flatData,
treeData: this.treeData,
rootEl: this.targetEl,
cb: (obj) => {
super.listen({ name: 'grafted', cb, params: [obj] });
return this;
}
});
return this;
}
updateVals() {
if (!this.options.output.enable)
return;
let val = this.getVals();
this.options.name && (this.inputEl.value = val);
fieldTools.setVals({ target: this.receiver, value: val });
}
setVals(target = this.receiver, cb) {
if (this.destroyed)
return;
let receiver = getEl(target), val = this.getVals();
fieldTools.setVals({ target: receiver, value: val });
super.listen({ name: 'set', cb, params: [val] });
return this;
}
clearVals(cb) {
if (this.destroyed)
return this;
super.uncheckAll();
this.value = '';
fieldTools.setVals({ target: this.receiver, value: '' });
this.options.name && (this.inputEl.value = '');
super.listen({ name: 'cleared', cb });
return this;
}
getVals(opt = {}, cb) {
if (this.destroyed)
return this;
let options = Object.assign({ ...this.options.output, isStr: true }, opt), items = super.getCheckeds(), result = items.map((k) => k[options.prop]);
let val = options.isStr ? result.join(options.separator) : result;
super.listen({ name: 'got', cb, params: [val] });
return val;
}
async setContent(item, data = {}, cb) {
if (this.destroyed)
return;
await super.setElCont({
item,
data,
prop: 'content',
cb: (cont, target) => {
super.listen({ name: 'filled', cb, params: [cont, target] });
}
});
return this;
}
async updateCont(content, cb) {
if (this.destroyed)
return this;
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
},
cb: (data) => {
if (Array.isArray(data)) {
this.treeDataOrig = deepClone(data);
treeTools.addIdPath({ source: this.treeDataOrig });
this.targetEl.innerHTML = '';
this.renderData(this.treeDataOrig);
this.getTreeFlat();
this.renderFinish();
super.updateCache({ content });
super.listen({ name: 'updatedCont', cb, params: [this.treeDataOrig] });
}
}
});
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
for (let k of this.flatData) {
if (this.options.arrow.trigger === 'click') {
let triggerEl = k.hasOwnProperty('href') && k.arrowEl ? k.arrowEl : k.headEl;
triggerEl.removeEventListener('click', this.expandEvt);
}
else if (this.options.arrow.trigger === 'hover') {
this.hoverIns.destroy();
}
['expanded', 'checked'].includes(this.options.clickLine) && k.headEl.removeEventListener('click', this.lineEvt);
this.options.drag.enable && k.dragIns.destroy();
}
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optEditor = [
{
attr: 'name',
prop: 'name',
value: '',
},
{
attr: 'value',
prop: 'value',
value: '',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'disabled',
prop: 'disabled',
value: false,
},
{
attr: 'readonly',
prop: 'readonly',
value: false,
},
{
attr: 'deferred',
prop: 'deferred',
value: false,
},
{
attr: 'delay',
prop: 'delay',
value: 200,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'appear',
prop: 'appear',
value: {
rounded: true,
bordered: true,
},
},
{
attr: 'mode',
prop: 'mode',
value: 'editor',
},
{
attr: 'header',
prop: 'header',
value: {
enable: true,
children: [],
},
},
{
attr: 'footer',
prop: 'footer',
value: {
enable: true,
},
},
{
attr: 'min-height',
prop: 'minHeight',
value: '',
},
{
attr: 'max-height',
prop: 'maxHeight',
value: '',
},
{
attr: 'feature',
prop: 'feature',
value: 'simple',
},
{
attr: 'b4-paste',
prop: 'b4Paste',
value: null,
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null
},
{
attr: 'on-readonly',
prop: 'onReadonly',
value: null
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-set',
prop: 'onSet',
value: null
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-output',
prop: 'onOutput',
value: null
},
...optBase
];
class Editor extends ModBaseListenCache {
options = {};
flatData;
treeData;
inputEl;
headEl;
bodyEl;
contEl;
footEl;
pathEl;
stateEl;
maskEl;
toolsEl;
output;
tmpRaw;
contXhr;
keyupEvt;
pointerEvt;
inputEvt;
pasteEvt;
readonlyEvt;
tools;
static hostType = 'node';
static optMaps = optEditor;
constructor(elem, options = {}, initial = true) {
super();
let tmp = getEl(elem), host;
if (!tmp)
return this;
if (['TEXTAREA'].includes(tmp.nodeName)) {
this.inputEl = tmp;
this.inputEl.classList.add(`${ax.prefix}editor-source`);
host = createEl('div', { class: `${ax.prefix}editor` });
tmp.insertAdjacentElement('afterend', host);
}
else {
host = tmp;
host.classList.add(`${ax.prefix}editor`);
this.inputEl = createEl('textarea', { class: `${ax.prefix}editor-source` });
}
super.ready({
options,
host,
maps: Editor.optMaps,
component: true,
spread: ['header', 'footer']
});
this.rawHtml = this.inputEl.value || this.targetEl.innerHTML;
this.contEl = createEl('div', { class: `${ax.prefix}editor-cont`, placeholder: this.options.lang.placeholder, contenteditable: true });
let _this = this;
this.keyupEvt = debounce((e) => {
let code = e.key;
if (code === 'Backspace') {
([`<br>`, `<p><br></p>`, `<div><br></div>`].includes(trim(this.contEl.innerHTML, 'global'))) && (this.contEl.innerHTML = '');
this.updateInputVal();
}
}, this.options.delay);
this.pointerEvt = () => {
this.setPathInfo();
};
this.inputEvt = debounce(function (e) {
if (this === _this.contEl) {
_this.inputEl.value = _this.contEl.innerHTML;
}
else if (this === _this.inputEl) {
_this.contEl.innerHTML = _this.inputEl.value;
}
_this.output.value = _this.inputEl.value;
_this.updateInfo();
}, {
delay: this.options.delay,
});
this.pasteEvt = async function (e) {
let text = '';
if (_this.options.b4Paste) {
e.preventDefault();
text = await _this.options.b4Paste.call(_this, await navigator.clipboard.readText());
if (text) {
let selection = window.getSelection();
if (selection.rangeCount > 0) {
let range = selection.getRangeAt(0), textNode = document.createTextNode(text);
range.insertNode(textNode);
range.setStartAfter(textNode);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}
}
}
else {
text = await navigator.clipboard.readText();
}
_this.listen({ name: 'pasted', params: [text] });
if (this === _this.contEl) {
_this.inputEl.value = _this.contEl.innerHTML;
}
else if (this === _this.inputEl) {
_this.contEl.innerHTML = _this.inputEl.value;
}
_this.output.value = _this.inputEl.value;
_this.updateInfo();
};
this.readonlyEvt = (e) => {
e.preventDefault();
};
this.tools = [
...this.createToggleItems([
{ name: 'bold', icon: `${ax.prefix}icon-bold`, key: 'fontWeight', value: 'bold', tips: this.options.lang.tips.bold },
{ name: 'italic', icon: `${ax.prefix}icon-italic`, key: 'fontStyle', value: 'italic', tips: this.options.lang.tips.italic },
{ name: 'underline', icon: `${ax.prefix}icon-underline`, key: 'textDecorationLine', value: 'underline', tips: this.options.lang.tips.underline },
{ name: 'through', icon: `${ax.prefix}icon-through`, key: 'textDecorationLine', value: 'line-through', tips: this.options.lang.tips.through },
]),
...this.createFontsizeItems([
{ name: 'fontsize-dft', label: this.options.lang.fontsizeDft, value: '' },
{ name: '1.2rem', label: '12px/1.2rem', value: '1.2rem' },
{ name: '1.4rem', label: '14px/1.4rem', value: '1.4rem' },
{ name: '1.6rem', label: '16px/1.6rem', value: '1.6rem' },
{ name: '1.8rem', label: '18px/1.8rem', value: '1.8rem' },
{ name: '2.2rem', label: '22px/2.2rem', value: '2.2rem' },
{ name: '2.8rem', label: '2.8px/2.8rem', value: '2.8rem' },
{ name: '3.2rem', label: '32px/3.2rem', value: '3.2rem' },
{ name: '3.8rem', label: '38px/3.8rem', value: '3.8rem' },
{ name: '4.2rem', label: '42px/4.2rem', value: '4.2rem' },
{ name: '4.8rem', label: '48px/4.8rem', value: '4.8rem' },
]),
...this.createAlignItems([
{ name: 'align-dft', label: this.options.lang.alignDft, value: '' },
{ name: 'align-left', icon: `${ax.prefix}icon-align-left`, value: 'left', tips: this.options.lang.tips.alignLeft },
{ name: 'align-center', icon: `${ax.prefix}icon-align-center`, value: 'center', tips: this.options.lang.tips.alignCenter },
{ name: 'align-right', icon: `${ax.prefix}icon-align-right`, value: 'right', tips: this.options.lang.tips.alignRight },
{ name: 'align-justify', icon: `${ax.prefix}icon-align-justify`, value: 'justify', tips: this.options.lang.tips.alignJustify },
]),
...this.createSpanTags([
{ name: 'sup', icon: `${ax.prefix}icon-superscript`, value: 'sup', tips: this.options.lang.tips.sup },
{ name: 'sub', icon: `${ax.prefix}icon-subscript`, value: 'sub', tips: this.options.lang.tips.sub },
{ name: 'highlight', icon: `${ax.prefix}icon-highlight`, value: 'mark', tips: this.options.lang.tips.highlight },
{ name: 'cite', icon: `${ax.prefix}icon-quote-left`, value: 'cite', tips: this.options.lang.tips.cite },
{ name: 'code-inline', icon: `${ax.prefix}icon-code-inline`, value: 'code', tips: this.options.lang.tips.codeInline },
{ name: 'em', label: this.options.lang.tips.em, value: 'em', },
{ name: 'address', label: this.options.lang.tips.address, value: 'address', },
{ name: 'time', label: this.options.lang.tips.time, value: 'time', },
{ name: 'ruby', label: this.options.lang.tips.ruby, value: 'ruby', },
{ name: 'rt', label: this.options.lang.tips.rt, value: 'rt', },
]),
...this.createLineTags([
{ name: 'p', icon: `${ax.prefix}icon-article`, value: 'p', tips: this.options.lang.tips.text, },
{ name: 'h1', icon: `${ax.prefix}icon-heading-1`, value: 'h1', tips: this.options.lang.tips.h1 },
{ name: 'h2', icon: `${ax.prefix}icon-heading-2`, value: 'h2', tips: this.options.lang.tips.h2 },
{ name: 'h3', icon: `${ax.prefix}icon-heading-3`, value: 'h3', tips: this.options.lang.tips.h3 },
{ name: 'h4', icon: `${ax.prefix}icon-heading-4`, value: 'h4', tips: this.options.lang.tips.h4 },
{ name: 'h5', icon: `${ax.prefix}icon-heading-5`, value: 'h5', tips: this.options.lang.tips.h5 },
{ name: 'h6', icon: `${ax.prefix}icon-heading-6`, value: 'h6', tips: this.options.lang.tips.h6 },
{ name: 'blockquote', icon: `${ax.prefix}icon-quote-left-f`, value: 'blockquote', tips: this.options.lang.tips.blockquote },
]),
...this.createCloseTags([
{ name: 'hr', icon: `${ax.prefix}icon-line-h`, value: 'hr', tips: this.options.lang.tips.hr },
{ name: 'br', icon: `${ax.prefix}icon-br`, value: 'br', tips: this.options.lang.tips.br },
]),
...this.createNestTags([
{ name: 'code-block', icon: `${ax.prefix}icon-code-block`, value: ['pre', 'code'], tips: this.options.lang.tips.codeBlock, },
{ name: 'list-ul', icon: `${ax.prefix}icon-list-ul`, value: ['ul', 'li', 'br'], tips: this.options.lang.tips.listUl },
{ name: 'list-ol', icon: `${ax.prefix}icon-list-ol`, value: ['ol', 'li', 'br'], tips: this.options.lang.tips.listOl },
{ name: 'paragraph', icon: `${ax.prefix}icon-paragraph`, value: ['div', 'br'], tips: this.options.lang.tips.paragraph, isRoot: true },
]),
{
name: 'indent-more',
icon: `${ax.prefix}icon-indent-more`,
tips: this.options.lang.tips.indentMore,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.setLineStyles('', '', (el) => {
let now = style(el).textIndent;
el.style.textIndent = `${toPixel(now) + toPixel('2.8rem')}px`;
});
};
}
},
{
name: 'indent-less',
icon: `${ax.prefix}icon-indent-less`,
tips: this.options.lang.tips.indentLess,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.setLineStyles('', '', (el) => {
let now = style(el).textIndent, val = Math.max(0, toPixel(now) - toPixel('2.8rem'));
el.style.textIndent = `${val}px`;
});
};
}
},
{
name: 'dropdown-fontsize',
label: this.options.lang.fontsizeDft,
extendable: true,
action: (resp) => {
let content = [
{ label: this.options.lang.fontsizeDft, value: '' },
{ label: '12px/1.2rem', value: '1.2rem' },
{ label: '14px/1.4rem', value: '1.4rem' },
{ label: '16px/1.6rem', value: '1.6rem' },
{ label: '18px1.8rem', value: '1.8rem' },
{ label: '22px/2.2rem', value: '2.2rem' },
{ label: '28px/2.8rem', value: '2.8rem' },
{ label: '32px/3.2rem', value: '3.2rem' },
{ label: '38px/3.8rem', value: '3.8rem' },
{ label: '42px/4.2rem', value: '4.2rem' },
{ label: '48px/4.8rem', value: '4.8rem' },
];
new Dropdown(resp.wrapEl, {
content: content.map((k) => k.label),
feature: 'select',
popup: {
onTargetSet: (value) => {
this.setStyles('fontSize', content.find((k) => k.label === value).value);
}
}
});
}
},
{
name: 'dropdown-align',
label: this.options.lang.alignDft,
extendable: true,
action: (resp) => {
let content = [
{ label: this.options.lang.alignDft, value: '' },
{ label: this.options.lang.tips.alignLeft, icon: `${ax.prefix}icon-align-left`, value: 'left' },
{ label: this.options.lang.tips.alignCenter, icon: `${ax.prefix}icon-align-center`, value: 'center' },
{ label: this.options.lang.tips.alignRight, icon: `${ax.prefix}icon-align-right`, value: 'right' },
{ label: this.options.lang.tips.alignJustify, icon: `${ax.prefix}icon-align-justify`, value: 'justify' },
];
new Dropdown(resp.wrapEl, {
content: content.map((k) => k.label),
feature: 'select',
popup: {
onTargetSet: (value) => {
this.setLineStyles('textAlign', content.find((k) => k.label === value).value);
}
}
});
}
},
{
name: 'dropdown-heading',
label: this.options.lang.tips.text,
extendable: true,
action: (resp) => {
let content = [
{ label: this.options.lang.tips.text, value: 'p' },
{ label: this.options.lang.tips.h1, icon: `${ax.prefix}icon-heading-1`, value: 'h1' },
{ label: this.options.lang.tips.h2, icon: `${ax.prefix}icon-heading-2`, value: 'h2' },
{ label: this.options.lang.tips.h3, icon: `${ax.prefix}icon-heading-3`, value: 'h3' },
{ label: this.options.lang.tips.h4, icon: `${ax.prefix}icon-heading-1`, value: 'h4' },
{ label: this.options.lang.tips.h5, icon: `${ax.prefix}icon-heading-5`, value: 'h5' },
{ label: this.options.lang.tips.h6, icon: `${ax.prefix}icon-heading-6`, value: 'h6' },
];
new Dropdown(resp.wrapEl, {
content: content.map((k) => k.label),
feature: 'select',
popup: {
onTargetSet: (value) => {
this.replaceLineTag(content.find((k) => k.label === value).value);
}
}
});
}
},
{
name: 'dropdown-tags',
label: this.options.lang.tagsDft,
extendable: true,
action: (resp) => {
let content = [
{ label: this.options.lang.tips.em, value: 'em' },
{ label: this.options.lang.tips.address, value: 'address' },
{ label: this.options.lang.tips.time, value: 'time' },
{ label: this.options.lang.tips.ruby, value: 'ruby' },
{ label: this.options.lang.tips.rt, value: 'rt' },
];
new Dropdown(resp.wrapEl, {
content: content.map((k) => k.label),
feature: 'button',
popup: { trigger: 'hover' },
action: (resp) => {
resp.el.onclick = (e) => {
e.preventDefault();
this.addWraps(content.find((k) => k.label === resp.data.label).value);
};
}
});
}
},
{
name: 'source',
icon: `${ax.prefix}icon-code-box`,
swap: `${ax.prefix}icon-html-box`,
tips: this.options.lang.tips.source,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
if (this.targetEl.getAttribute('mode') === 'source') {
this.targetEl.setAttribute('mode', 'editor');
resp.wrapEl.toggleAttribute('focused', false);
classes(resp.iconEl).replace(resp.icon, resp.swap);
}
else {
this.targetEl.setAttribute('mode', 'source');
resp.wrapEl.toggleAttribute('focused', true);
classes(resp.iconEl).replace(resp.swap, resp.icon);
}
};
}
},
];
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.output = { value: '', raw: '' };
this.tmpRaw = '';
super.useTpl();
this.renderMain();
this.setAttrs();
!this.options.deferred && await this.fillCont(this.options.content || this.options.value || this.rawHtml);
this.renderFinish();
this.contEl.addEventListener("input", this.inputEvt, false);
this.inputEl.addEventListener("input", this.inputEvt, false);
this.contEl.addEventListener("paste", this.pasteEvt, false);
this.inputEl.addEventListener("paste", this.pasteEvt, false);
this.contEl.addEventListener("keyup", this.keyupEvt, false);
this.contEl.addEventListener("pointerdown", this.pointerEvt, false);
super.listen({ name: 'initiated', cb });
return this;
}
insertNewPara(parentEl, newPara, startNode) {
if (parentEl === this.contEl) {
this.contEl.insertBefore(newPara, startNode === this.contEl || !startNode ? null : startNode.nextSibling);
}
else {
parentEl.parentNode.insertBefore(newPara, parentEl.nextSibling);
}
}
getTools() {
if (!isEmpty(this.options.header.children)) {
return this.options.header.children.map((k) => {
let tmp = this.tools.find((i) => i.name === k);
return tmp || k;
});
}
else {
if (this.options.feature === 'simple') {
return ['bold', 'align-left', 'align-center', 'align-right', 'highlight', 'p', 'h1', 'h2', 'h3', 'hr', 'br', 'paragraph', 'indent-more', 'indent-less', 'source']
.map((k) => this.tools.find((i) => i.name === k));
}
else if (this.options.feature === 'comm') {
return ['bold', 'italic', 'underline', 'through', 'align-left', 'align-center', 'align-right', 'highlight', 'cite', 'blockquote',
'code-inline', 'code-block', 'p', 'h1', 'h2', 'h3', 'hr', 'br', 'list-ul', 'list-ol', 'paragraph', 'indent-more', 'indent-less', 'source']
.map((k) => this.tools.find((i) => i.name === k));
}
else if (this.options.feature === 'flat') {
return this.tools.filter((k) => !k.name.includes('dropdown-') && !k.name.includes('group-'));
}
else if (this.options.feature === 'group') {
return this.tools.filter((k) => k.name.includes('dropdown-') || k.name.includes('group-'));
}
else {
return this.tools;
}
}
}
renderMain() {
this.targetEl.innerHTML = '';
this.headEl = createEl('div', { class: `${ax.prefix}editor-head` });
this.inputEl.placeholder = this.options.lang.placeholder;
this.options.name && (this.inputEl.name = this.options.name);
this.bodyEl = createEl('div', { class: `${ax.prefix}editor-body` });
this.bodyEl.append(this.contEl, this.inputEl);
this.pathEl = createEl('div', { class: `${ax.prefix}editor-path` });
this.stateEl = createEl('div', { class: `${ax.prefix}editor-state` });
this.footEl = createEl('div', { class: `${ax.prefix}editor-foot` });
this.footEl.append(this.pathEl, this.stateEl);
this.maskEl = createEl('div', { class: `${ax.prefix}editor-mask` }, this.options.lang.defer);
if (this.options.header.enable) {
this.toolsEl = createTools(this.getTools(), this.headEl);
this.targetEl.appendChild(this.headEl);
}
this.targetEl.appendChild(this.bodyEl);
this.options.footer.enable && this.targetEl.appendChild(this.footEl);
this.options.deferred && this.bodyEl.appendChild(this.maskEl);
this.updateInfo();
}
updateInfo() {
this.setPathInfo();
this.setStateInfo();
this.output = { value: this.inputEl.value, raw: this.tmpRaw };
super.listen({ name: 'output', params: [this.output] });
this.tmpRaw = this.inputEl.value;
}
setPathInfo(selection = document.getSelection()) {
if (!selection.rangeCount) {
this.pathEl.innerHTML = this.options.lang.path + ' -';
return;
}
let range = selection.getRangeAt(0), startNode = range.startContainer, parNames = [];
if (!this.isValidRange(startNode))
return;
while (startNode && this.isValidRange(startNode)) {
parNames.unshift(startNode.nodeName.toLowerCase());
startNode = startNode.parentNode;
}
this.pathEl.innerHTML = this.options.lang.path + ' ' + parNames.join(' › ');
}
setStateInfo() {
let charCount = this.contEl.textContent.replace(/\s/g, '').length, paraCount = this.contEl.childNodes.length, html = this.contEl.innerHTML;
this.stateEl.innerHTML = this.options.lang.chars + ' ' + +charCount + ' , ' + this.options.lang.paras + ' ' + +paraCount;
super.updateCache({ content: html });
super.listen({ name: 'edited', params: [html] });
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}editor`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.options.readonly ? this.readonly() : this.enable();
this.targetEl.toggleAttribute('inert', this.options.disabled);
this.targetEl.setAttribute('mode', this.options.mode);
this.options.minHeight ? addStyle(this.contEl, 'max-height', this.options.minHeight) : removeStyle(this.contEl, 'max-height');
for (let k in this.options.appear) {
let val = this.options.appear[k];
this.targetEl.toggleAttribute(k, val);
}
this.targetEl.toggleAttribute('deferred', this.options.deferred);
}
readonly() {
this.headEl.toggleAttribute('inert', true);
this.contEl.addEventListener('keydown', this.readonlyEvt);
this.contEl.addEventListener('paste', this.readonlyEvt);
this.contEl.addEventListener('drop', this.readonlyEvt, false);
this.inputEl.addEventListener('keydown', this.readonlyEvt, false);
this.inputEl.addEventListener('paste', this.readonlyEvt, false);
this.inputEl.addEventListener('drop', this.readonlyEvt, false);
this.inputEl.readOnly = true;
super.listen({ name: 'readonly' });
}
disable() {
this.headEl.toggleAttribute('inert', true);
this.targetEl.toggleAttribute('inert', true);
this.contEl.addEventListener('keydown', this.readonlyEvt, false);
this.contEl.addEventListener('paste', this.readonlyEvt, false);
this.contEl.addEventListener('drop', this.readonlyEvt, false);
this.inputEl.addEventListener('keydown', this.readonlyEvt, false);
this.inputEl.addEventListener('paste', this.readonlyEvt, false);
this.inputEl.addEventListener('drop', this.readonlyEvt, false);
this.inputEl.readOnly = true;
super.listen({ name: 'disabled' });
}
enable() {
this.headEl.toggleAttribute('inert', false);
this.targetEl.toggleAttribute('inert', false);
this.contEl.removeEventListener('keydown', this.readonlyEvt);
this.contEl.removeEventListener('paste', this.readonlyEvt);
this.contEl.removeEventListener('drop', this.readonlyEvt);
this.inputEl.removeEventListener('keydown', this.readonlyEvt);
this.inputEl.removeEventListener('paste', this.readonlyEvt);
this.inputEl.removeEventListener('drop', this.readonlyEvt);
this.inputEl.readOnly = false;
super.listen({ name: 'enabled' });
}
renderFinish() {
if (this.options.deferred) {
this.maskEl.onclick = async () => {
await this.fillCont(this.options.content || this.options.value);
this.targetEl.removeAttribute('deferred');
this.maskEl.remove();
};
}
}
fullTextNode(range) {
let startNode = range.startContainer, endNode = range.endContainer;
if (startNode === endNode) {
if (startNode.nodeType === 3) {
const text = startNode.textContent;
return range.startOffset === 0 && range.endOffset === text.length;
}
else if (startNode.nodeType === 1) {
return range.startOffset === 0 && range.endOffset === 1;
}
else {
return false;
}
}
else {
return false;
}
}
setChildRange(wrap, selection = document.getSelection()) {
let newRange = document.createRange();
if (!wrap.firstChild || !wrap.lastChild)
return;
newRange.setStartBefore(wrap.firstChild);
newRange.setEndAfter(wrap.lastChild);
selection.removeAllRanges();
selection.addRange(newRange);
}
setStyles(key, value, selection = document.getSelection()) {
if (selection.rangeCount > 0) {
for (let i = 0; i < selection.rangeCount; i++) {
let range = selection.getRangeAt(i), startNode = range.startContainer;
if (!this.isValidRange(startNode))
continue;
let wrap = this.fullTextNode(range) ? (startNode.nodeType === 1 ? startNode : startNode.parentNode) : this.addOneWrap('i', range);
wrap.style[key] = value;
this.setChildRange(wrap, selection);
}
this.updateInputVal();
}
}
getParentNode(range) {
let parent = range.commonAncestorContainer;
return (parent.nodeType !== 1) ? parent.parentNode : parent;
}
removeStyles(key, selection = document.getSelection()) {
if (selection.rangeCount > 0) {
for (let i = 0; i < selection.rangeCount; i++) {
let range = selection.getRangeAt(i), startNode = range.startContainer;
if (!this.isValidRange(startNode))
continue;
let parent = this.getParentNode(range);
if (parent) {
parent.style[key] = null;
}
}
}
}
toggleStyles(key, value, selection = document.getSelection()) {
if (selection.rangeCount > 0) {
for (let i = 0; i < selection.rangeCount; i++) {
let range = selection.getRangeAt(i), startNode = range.startContainer;
if (!this.isValidRange(startNode))
continue;
let parent = this.getParentNode(range);
if (parent && parent.style[key]) {
parent.style[key] = null;
}
else {
let wrap = this.fullTextNode(range) ? (startNode.nodeType === 1 ? startNode : startNode.parentNode) : this.addOneWrap('i', range);
wrap.style[key] = value;
this.setChildRange(wrap, selection);
}
}
this.updateInputVal();
}
}
addOneWrap(tagName, range) {
let text = range.extractContents(), wrap = document.createElement(tagName);
wrap.appendChild(text);
range.insertNode(wrap);
return wrap;
}
addWraps(tagName, selection = document.getSelection()) {
if (!selection.rangeCount)
return;
let last;
for (let i = 0; i < selection.rangeCount; i++) {
let range = selection.getRangeAt(i), startNode = range.startContainer;
if (!this.isValidRange(startNode))
continue;
let parent = this.getParentNode(range);
if (parent && parent.nodeName === tagName.toUpperCase()) {
continue;
}
let wrap = this.addOneWrap(tagName, range);
if (i === selection.rangeCount - 1) {
last = wrap;
}
}
last && this.setChildRange(last, selection);
this.updateInputVal();
}
replaceLineTag(tagName, selection = document.getSelection()) {
if (!selection.rangeCount)
return;
let range = selection.getRangeAt(0), startNode = range.startContainer, newTag = document.createElement(tagName), startOffset = range.startOffset, newRange = document.createRange();
if (!this.isValidRange(startNode))
return;
while (startNode && startNode.nodeType === 3 && startNode.parentNode !== this.contEl)
startNode = startNode.parentNode;
if (startNode?.tagName?.toLowerCase() === tagName)
return;
newTag.innerHTML = startNode.innerHTML || startNode.textContent;
startNode.parentNode.replaceChild(newTag, startNode);
let start = newTag.firstChild || newTag;
try {
newRange.setStart(start, startOffset);
}
catch {
newRange.setStart(start, 0);
}
newRange.collapse(true);
selection.removeAllRanges();
selection.addRange(newRange);
this.updateInputVal();
}
setLineStyles(key, value, cb) {
let selection = document.getSelection(), range = selection.getRangeAt(0), startNode = range.startContainer, parEl = startNode?.parentNode;
if (!selection.rangeCount || !this.isValidRange(startNode) || parEl === this.contEl)
return;
key && (parEl.style[key] = value);
this.updateInputVal();
cb && cb(parEl);
}
createNestWrap(tags) {
let root = document.createElement(tags[0]), leaf;
tags.slice(1).reduce((parent, tag, idx) => {
let newNode = document.createElement(tag);
if (idx === tags.length - 2)
leaf = newNode;
parent.appendChild(newNode);
return newNode;
}, root);
return { root, leaf };
}
insertNestNodes(tags, isRoot = false) {
if (!Array.isArray(tags) || !tags.length)
return;
let selection = document.getSelection();
if (!selection)
return;
let range = selection.getRangeAt(0), startNode = range.startContainer, { root, leaf } = this.createNestWrap(tags), newRange = document.createRange();
if (!selection.rangeCount || !this.isValidRange(startNode, false))
return;
if (isRoot) {
let parNode = startNode, curNode = startNode;
while (parNode !== this.contEl) {
curNode = parNode;
parNode = parNode.parentNode;
}
this.contEl.insertBefore(root, curNode === this.contEl ? null : curNode.nextSibling);
}
else {
range.insertNode(root);
}
newRange.setStart(leaf, 0);
newRange.collapse(true);
selection.removeAllRanges();
selection.addRange(newRange);
this.updateInputVal();
}
insertTag(tag) {
let selection = document.getSelection();
if (!selection.rangeCount || !this.isValidRange(null, false))
return;
let range = selection.getRangeAt(0), node = document.createElement(tag);
this.clearRanges(selection);
range.insertNode(node);
range.setStartAfter(node);
range.setEndAfter(node);
selection.removeAllRanges();
selection.addRange(range);
this.updateInputVal();
}
clearRanges(selection = document.getSelection()) {
if (selection.rangeCount > 0) {
for (let i = 0; i < selection.rangeCount; i++) {
let range = selection.getRangeAt(i);
range.deleteContents();
}
}
}
isValidRange(node, exact = true) {
let startNode;
if (!node) {
let selection = document.getSelection(), range = selection.getRangeAt(0);
startNode = range.startContainer;
}
else {
startNode = node;
}
return this.contEl.contains(startNode) && (exact ? this.contEl !== startNode : true);
}
createFontsizeItems(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.setStyles('fontSize', k.value);
};
}
};
});
}
createToggleItems(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.toggleStyles(k.key, k.value);
};
}
};
});
}
createAlignItems(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.setLineStyles('textAlign', k.value);
};
}
};
});
}
createLineTags(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.replaceLineTag(k.value);
};
}
};
});
}
createSpanTags(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.addWraps(k.value);
};
}
};
});
}
createCloseTags(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.insertTag(k.value);
};
}
};
});
}
createNestTags(arr) {
return arr.map((k) => {
return {
name: k.name,
label: k.label,
tips: k.tips,
icon: k.icon,
action: (resp) => {
resp.wrapEl.onpointerdown = (e) => {
e.preventDefault();
this.insertNestNodes(k.value, k.isRoot);
};
}
};
});
}
async fillCont(content = this.options.content, cb) {
if (isEmpty(content))
return;
let result, spinProp = elState(this.maskEl).isVisible ? { target: this.maskEl } : { spinSel: this.bodyEl };
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
...spinProp,
...this.options.ajax
},
request: (data) => {
super.listen({ name: 'request', params: [data] });
},
cb: async (resp) => {
result = resp;
setContent({
content: resp,
template: content?.tplStr || this.tplStr,
engine: content?.tplEng || this.tplEng,
target: this.contEl,
prevent: (result) => {
if (getDataType(result).includes('HTML')) {
this.contEl.appendChild(result);
}
else {
this.contEl.innerHTML = result;
}
this.inputEl.value = this.output.value = this.contEl.innerHTML;
this.updateInfo();
}
});
}
});
super.listen({ name: 'filled', cb, params: [result] });
}
updateInputVal() {
this.inputEl.value = this.output.value = this.contEl.innerHTML;
this.updateInfo();
}
setVals(value, cb) {
if (this.destroyed)
return this;
this.inputEl.value = this.contEl.innerHTML = value;
this.updateInfo();
super.listen({ name: 'set', cb, params: [value] });
return this;
}
getVals() {
if (this.destroyed)
return;
return this.contEl.innerHTML;
}
clearVals(cb) {
if (this.destroyed)
return;
this.inputEl.value = this.contEl.innerHTML = '';
this.updateInfo();
super.listen({ name: 'cleared', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.contEl.removeEventListener("input", this.inputEvt);
this.inputEl.removeEventListener("input", this.inputEvt);
this.contEl.removeEventListener("keyup", this.keyupEvt);
this.enable();
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optSelect = [
{
attr: 'name',
prop: 'name',
value: '',
},
{
attr: 'value',
prop: 'value',
value: '',
},
{
attr: 'field',
prop: 'field',
value: 'label',
},
{
attr: 'type',
prop: 'type',
value: 'dropdown',
},
{
attr: 'manual',
prop: 'manual',
value: false,
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'disabled',
prop: 'disabled',
value: false,
},
{
attr: 'multiple',
prop: 'multiple',
value: false,
},
{
attr: 'exclude',
prop: 'exclude',
value: '',
},
{
attr: 'readonly',
prop: 'readonly',
value: false,
},
{
attr: 'full',
prop: 'full',
value: false,
},
{
attr: 'min',
prop: 'min',
value: 0,
},
{
attr: 'max',
prop: 'max',
value: 0,
},
{
attr: 'sliced',
prop: 'sliced',
value: true,
},
{
attr: 'removable',
prop: 'removable',
value: true,
},
{
attr: 'max-height',
prop: 'maxHeight',
value: '',
},
{
attr: 'span',
prop: 'span',
value: 'leaf',
},
{
attr: 'unique',
prop: 'unique',
value: true,
},
{
attr: 'collapse',
prop: 'collapse',
value: false,
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'search',
prop: 'search',
value: {
enable: false,
value: '',
fuzzy: true,
ignore: true,
result: true,
},
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
children: ['close']
},
},
{
attr: 'auto-width',
prop: 'autoWidth',
value: true,
},
{
attr: 'status',
prop: 'status',
value: false,
},
{
attr: 'tags',
prop: 'tags',
value: {},
},
{
attr: 'popup',
prop: 'popup',
value: {
enable: true,
},
},
{
attr: 'tree',
prop: 'tree',
value: {},
},
{
attr: 'b4-expand',
prop: 'b4Expand',
value: null,
},
{
attr: 'b4-collapse',
prop: 'b4Collapse',
value: null,
},
{
attr: 'b4-add',
prop: 'b4Add',
value: null,
},
{
attr: 'b4-edit',
prop: 'b4Edit',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-graft',
prop: 'b4Graft',
value: null,
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-trigger',
prop: 'onTrigger',
value: null
},
{
attr: 'on-added',
prop: 'onAdded',
value: null
},
{
attr: 'on-edited',
prop: 'onEdited',
value: null
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null
},
{
attr: 'on-disabled',
prop: 'onDisabled',
value: null
},
{
attr: 'on-enabled',
prop: 'onEnabled',
value: null
},
{
attr: 'on-disabledall',
prop: 'onDisabledAll',
value: null
},
{
attr: 'on-enabledall',
prop: 'onEnabledAll',
value: null
},
{
attr: 'on-readonly',
prop: 'onReadonly',
value: null
},
{
attr: 'on-readonlyall',
prop: 'onReadonlyAll',
value: null
},
{
attr: 'on-expand',
prop: 'onExpand',
value: null
},
{
attr: 'on-expanded',
prop: 'onExpanded',
value: null
},
{
attr: 'on-collapse',
prop: 'onCollapse',
value: null
},
{
attr: 'on-collapsed',
prop: 'onCollapsed',
value: null
},
{
attr: 'on-expandall',
prop: 'onExpandAll',
value: null
},
{
attr: 'on-expandedAll',
prop: 'onExpandedAll',
value: null
},
{
attr: 'on-collapsedall',
prop: 'onCollapsedAll',
value: null
},
{
attr: 'on-selected',
prop: 'onSelected',
value: null
},
{
attr: 'on-deselected',
prop: 'onDeselected',
value: null
},
{
attr: 'on-selectedall',
prop: 'onSelectedAll',
value: null
},
{
attr: 'on-checked',
prop: 'onChecked',
value: null
},
{
attr: 'on-unchecked',
prop: 'onUnchecked',
value: null
},
{
attr: 'on-checkedall',
prop: 'onCheckedAll',
value: null
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-turned',
prop: 'onTurned',
value: null
},
{
attr: 'on-got',
prop: 'onGot',
value: null
},
{
attr: 'on-set',
prop: 'onSet',
value: null
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-grafted',
prop: 'onGrafted',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-toofew',
prop: 'onTooFew',
value: null
},
{
attr: 'on-toomany',
prop: 'onTooMany',
value: null
},
{
attr: 'on-locked',
prop: 'onLocked',
value: null
},
{
attr: 'on-unlocked',
prop: 'onUnlocked',
value: null
},
{
attr: 'on-output',
prop: 'onOutput',
value: null
},
...optBase
];
class Select extends ModBaseListenCache {
options = {};
flatData;
selectData;
inputEl;
tagsEl;
arrowEl;
toolsEl;
listEl;
wrapEl;
searchEl;
resultEl;
keysEl;
checkEl;
statsEl;
statusEl;
statusHolderEl;
popupIns;
tagsIns;
treeIns;
output;
rawHmtl;
clearVals;
outputEvt;
static hostType = 'node';
static optMaps = optSelect;
static dependencies = [InputElem, CheckboxElem];
constructor(elem, options = {}, initial = true) {
super();
let tmp = getEl(elem), host;
if (!tmp)
return this;
if (['SELECT', 'INPUT'].includes(tmp.nodeName)) {
this.inputEl = tmp;
host = createEl('div', { class: `${ax.prefix}select` });
tmp.insertAdjacentElement('afterend', host);
host.appendChild(this.inputEl);
}
else {
host = tmp;
host.classList.add(`${ax.prefix}select`);
this.inputEl = createEl('input', { type: 'hidden' });
}
super.ready({
options,
host,
maps: Select.optMaps,
component: true,
spread: ['popup', 'search', 'tools']
});
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.correctOpts();
super.useTpl();
this.renderMain();
this.setAttrs();
this.output = { value: '', raw: '', items: [] };
if (this.options.popup.enable && !this.options.readonly) {
this.setPopup();
await this.popupIns.init();
}
else {
this.popupIns && this.popupIns.destroy();
}
this.setTags();
await this.tagsIns.init();
this.setTree();
await this.treeIns.init();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
renderMain() {
this.targetEl.innerHTML = '';
this.inputEl.setAttribute(ax.alias, 'input');
let nameTmp = this.options.name;
if (this.inputEl.nodeName === 'SELECT' && this.options.multiple)
nameTmp += `[]`;
this.options.name && (this.inputEl.name = nameTmp);
this.targetEl.appendChild(this.inputEl);
this.tagsEl = createEl('div', { [ax.alias]: 'tags' });
this.arrowEl = createEl('i', { [ax.alias]: 'arrow' });
this.targetEl.appendChild(this.tagsEl);
if (this.options.tools.enable) {
this.toolsEl = createTools(this.options.tools.children, null, this);
this.tagsEl.insertAdjacentElement('afterend', this.toolsEl);
this.toolsEl.setAttribute(ax.alias, 'tools');
for (let k of this.options.tools.children) {
!k.tips && !k.title && this.options.lang.title[k.name] && k.wrapEl.setAttribute('title', this.options.lang.title[k.name]);
if (k.name === 'close') {
k.wrapEl.onclick = () => {
this.clearVals();
};
}
}
}
this.options.popup.enable && this.targetEl.appendChild(this.arrowEl);
this.listEl = createEl('div', { class: `${ax.prefix}select-list` });
this.wrapEl = createEl('div', { class: `${ax.prefix}select-wrap` }, this.listEl);
if (this.options.popup.enable && this.options.search.enable) {
this.searchEl = createEl('div', { class: `${ax.prefix}select-search` });
this.resultEl = createEl('div', { [ax.alias]: 'result' }, this.options.lang.search.start);
if (!this.options.manual) {
this.keysEl = createEl('ax-input', { tools: true, placeholder: this.options.lang.search.placeholder, [ax.alias]: 'keys' });
this.searchEl.appendChild(this.keysEl);
}
this.options.search.result && this.searchEl.appendChild(this.resultEl);
this.wrapEl.insertAdjacentElement('afterbegin', this.searchEl);
}
if (this.options.popup.enable && this.options.status) {
this.checkEl = createEl('ax-checkbox', { label: this.options.lang.check.all, [ax.alias]: 'check' });
!this.options.multiple && this.checkEl.toggleAttribute('disabled', true);
this.statsEl = createEl('span', { [ax.alias]: 'stats' });
this.statusEl = createEl('div', { class: `${ax.prefix}select-status` });
this.statusEl.append(this.checkEl, this.statsEl);
this.wrapEl.appendChild(this.statusEl);
this.checkEl.on('check', (data) => {
if (data.value === 'ed') {
this.treeIns.checkAll();
this.checkEl.setAttribute('label', this.options.lang.check.none);
}
else if (data.value === 'ing') {
this.checkEl.setAttribute('label', this.options.lang.check.ing);
}
else {
this.treeIns.uncheckAll();
this.checkEl.setAttribute('label', this.options.lang.check.ed);
}
});
this.statusHolderEl = createEl('div', { class: `${ax.prefix}select-holder` });
this.wrapEl.appendChild(this.statusHolderEl);
}
}
updateResult(value, keys) {
if (!this.options.popup.enable || !this.options.search.enable)
return;
this.resultEl.innerHTML = renderTpl(value ? this.options.lang.search.succ : (keys.length ? this.options.lang.search.fail : this.options.lang.search.start), { value, keys: keys.toString() });
}
updateStatus() {
if (!this.options.popup.enable || !this.options.status)
return;
let total = this.treeIns.flatData.length, value = this.treeIns.getCheckeds().length;
this.statsEl.innerHTML = renderTpl(this.options.lang.stats, { value, total });
this.checkEl.setAttribute('check', !value ? '' : (total === value ? 'ed' : 'ing'));
}
setPopup() {
let footer = this.options.multiple && !this.options.manual ? {
children: [
{
name: 'clear',
action: (resp) => {
resp.el.onclick = () => {
this.treeIns.clearVals();
};
},
},
'confirm',
]
} : false, targetObj = {
trigger: 'click',
content: this.wrapEl,
contType: 'node',
placement: 'bottom-start',
padding: false,
arrow: false,
tools: false,
footer,
canClick: (el) => {
let arr = [];
if (this.options.manual) {
arr = [this.arrowEl, this.targetEl, this.tagsEl];
}
else {
let dft = [this.arrowEl, this.targetEl, this.tagsEl, this.tagsEl.emptyEl], tmp = this.tagsIns.data.map((k) => [k.wralEl, k.labelEl, k.iconEl, k.diskEl, k.cubeEl, k.imageEl]).flat().filter(Boolean);
arr = !this.options.multiple ? [...tmp, ...dft] : dft;
}
return arr.includes(el) ? true : false;
},
onInitiated: () => {
this.popupIns.mainEl.classList.add(`${ax.prefix}select-popup`);
if (this.options.autoWidth && !(this.popupIns.options.adaptive && ax.screen === 'xxs')) {
this.popupIns.positionIns.on('changed', () => {
this.popupIns.mainEl.style.width = this.popupIns.positionIns.targetData.width + 'px';
});
}
}
}, params = extend({ target: targetObj, source: this.options.popup });
this.popupIns && this.popupIns.destroy();
this.popupIns = new Popup(this.targetEl, params, false);
}
setTags() {
let content = this.options.popup.enable ?
{ content: '' } :
{
content: this.rawHmtl || this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajx: this.options.ajax,
}, opts = {
...content,
field: this.options.field,
min: this.options.multiple ? this.options.min : 0,
max: this.options.multiple ? this.options.max : 1,
sliced: this.options.sliced,
compact: true,
size: this.options.size,
unique: { enable: this.options.manual ? this.options.unique : true },
editor: !this.options.manual || this.options.readonly ? false : true,
removable: this.options.readonly || !this.options.removable ? false : true,
empty: { enable: !this.options.manual ? true : false, content: this.options.lang.placeholder },
onRemoved: (items) => {
for (let k of items) {
this.treeIns.check(k[this.options.field], false);
}
},
onOutput: (data) => {
super.updateCache({ value: data.value });
this.output = data;
super.listen({ name: 'output', params: [this.output] });
}
};
if (this.options.manual) {
opts.b4Add = (data) => {
return new Promise(async (resolve, reject) => {
let rest = [];
for (let k of data) {
let tmp = this.treeIns.flatData.find((i) => k[this.options.field] === i[this.options.field]);
if (tmp) {
if (tmp.checked) {
rest.push(k);
}
else {
await this.treeIns.check(tmp, true);
}
}
else {
rest.push(k);
}
}
resolve(rest);
});
};
opts.onAdded = () => {
this.tagsIns.editEl.focus();
};
}
this.tagsIns && this.tagsIns.initiated && this.tagsIns.destroy();
this.tagsIns = new Tags(this.tagsEl, extend({
target: opts,
source: this.options.tags,
}), false);
}
setTree() {
this.listEl.innerHTML = this.rawHtml;
let targetObj = {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: this.options.ajax,
passive: this.options.disabled,
lang: {
empty: this.options.lang.empty,
},
search: {
target: this.options.search.enable ? (this.options.manual ? this.tagsIns.editEl : this.keysEl) : null,
trigger: this.options.manual ? 'input' : 'changed',
ignore: this.options.search.ignore,
fuzzy: this.options.search.fuzzy,
value: this.options.search.value,
},
disable: this.options.exclude,
check: {
type: this.options.multiple ? 'checkbox' : 'radio',
value: this.options.value,
sliced: this.options.sliced,
},
feature: {
type: this.options.type,
check: {
linkage: false,
span: this.options.span,
only: this.options.multiple ? false : true,
},
expand: {
all: !this.options.collapse,
}
},
output: {
field: this.options.field,
},
onInitiated: () => {
this.updateStatus();
},
onChecked: (items) => {
if (!this.options.manual)
return;
this.tagsIns.add(items.map((k) => k[this.options.field]));
if (this.tagsIns.editEl.value) {
this.treeIns.search();
this.tagsIns.editEl.value = '';
}
},
onUnchecked: (items) => {
if (!this.options.manual)
return;
this.tagsIns.remove(items.map((k) => k[this.options.field]));
},
onCheckedAll: () => {
if (!this.options.manual)
return;
let tmp = this.treeIns.getCheckeds();
this.tagsIns.add(filterPrims(tmp));
},
onOutput: (data) => {
if (!this.options.manual) {
let vals = filterPrims(data.items);
this.popupIns && this.popupIns.state === 'shown' && !this.options.multiple && this.popupIns.hide();
this.tagsIns.updateCont(vals);
this.updateStatus();
}
fieldTools.setVals({
target: this.inputEl,
value: data.value.split(this.treeIns.options.output.separator),
separator: this.treeIns.options.output.separator
});
},
onSearched: (searchs, keys) => {
this.options.manual && this.popupIns && this.popupIns.show();
this.updateResult(searchs.length, keys);
},
}, params = extend({ target: targetObj, source: this.options.tree, });
this.treeIns && this.treeIns.initiated && this.treeIns.destroy();
this.treeIns = new Tree(this.listEl, params, false);
}
correctOpts() {
if (this.inputEl.nodeName === 'SELECT') {
this.options.manual = false;
this.options.multiple = this.inputEl.multiple;
this.options.span = 'leaf';
}
this.inputEl.disabled && (this.options.disabled = true);
this.options.autoWidth && (this.options.popup.size = '');
this.options.manual === false && (this.options.popup.enable = true);
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}select`);
this.targetEl.setAttribute('tabindex', 0);
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.targetEl.toggleAttribute('inert', this.options.disabled);
this.inputEl.disabled = this.options.disabled;
this.targetEl.setAttribute('size', this.options.size);
this.targetEl.toggleAttribute('readonly', this.options.readonly);
this.targetEl.toggleAttribute('full', this.options.full);
this.targetEl.toggleAttribute('manual', this.options.manual);
this.targetEl.toggleAttribute('multiple', this.options.multiple);
this.options.maxHeight ? addStyle(this.listEl, 'max-height', this.options.maxHeight) : removeStyle(this.listEl, 'max-height');
}
renderFinish() {
}
getVals(cb) {
if (this.destroyed)
return this;
return this.tagsIns.getVals((data) => {
super.listen({ name: 'got', cb, params: [data] });
});
}
async select(vals, cb) {
if (this.destroyed)
return this;
let resp;
if (this.options.manual) {
await this.tagsIns.add(vals, (data) => {
resp = data;
});
}
else {
await this.treeIns.check(vals, true, (data) => {
resp = data;
});
}
super.listen({ name: 'selected', cb, params: [resp] });
return this;
}
async deselect(vals, cb) {
if (this.destroyed || !this.tagsIns.data.length)
return this;
await this.tagsIns.remove(vals, (data) => {
super.listen({ name: 'deselected', cb, params: [data] });
});
return this;
}
clear(cb) {
if (this.destroyed)
return this;
this.treeIns.uncheckAll();
this.options.manual && this.tagsIns.clear();
super.listen({ name: 'cleared', cb });
return this;
}
selectAll(cb) {
if (this.destroyed)
return this;
this.treeIns.checkAll();
super.listen({ name: 'selectedAll', cb });
return this;
}
disable(cb) {
this.treeIns.lock();
this.targetEl.toggleAttribute('inert', true);
this.inputEl.disabled = true;
super.listen({ name: 'disabled', cb });
return this;
}
enable(cb) {
this.treeIns.unlock();
this.targetEl.toggleAttribute('inert', false);
this.inputEl.disabled = false;
super.listen({ name: 'enabled', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
if (this.options.popup.enable && !this.options.readonly) {
this.popupIns.destroy();
}
this.treeIns.destroy();
this.tagsIns.destroy();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let AXTMP_separator = config.splitHyphen;
const optUpload = [
{
attr: 'name',
prop: 'name',
value: '',
},
{
attr: 'value',
prop: 'value',
value: '',
},
{
attr: 'url',
prop: 'url',
value: '',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'disabled',
prop: 'disabled',
value: false,
},
{
attr: 'readonly',
prop: 'readonly',
value: false,
},
{
attr: 'multiple',
prop: 'multiple',
value: true,
},
{
attr: 'manual',
prop: 'manual',
value: false,
},
{
attr: 'type',
prop: 'type',
value: 'text',
},
{
attr: 'icons',
prop: 'icons',
value: {},
},
{
attr: 'cols',
prop: 'cols',
value: 4,
},
{
attr: 'type-getter',
prop: 'typeGetter',
value: null,
},
{
attr: 'feature',
prop: 'feature',
value: '',
},
{
attr: 'limit',
prop: 'limit',
value: {
min: 0,
max: 0,
size: 0,
suffix: '',
},
},
{
attr: 'accept',
prop: 'accept',
value: '',
},
{
attr: 'size',
prop: 'size',
value: 'md',
},
{
attr: 'table',
prop: 'table',
value: {
header: true,
},
},
{
attr: 'pastable',
prop: 'pastable',
value: true,
},
{
attr: 'choose-btn',
prop: 'chooseBtn',
value: {
target: '',
icon: `${ax.prefix}icon-plus`,
attrs: {},
},
},
{
attr: 'upload-btn',
prop: 'uploadBtn',
value: {
enable: false,
target: '',
icon: `${ax.prefix}icon-upload`,
attrs: {},
},
},
{
attr: 'clear-btn',
prop: 'clearBtn',
value: {
enable: false,
target: '',
icon: `${ax.prefix}icon-trash`,
attrs: {},
},
},
{
attr: 'picture-btn',
prop: 'pictureBtn',
value: {
icon: `${ax.prefix}icon-plus`,
attrs: {},
},
},
{
attr: 'gallery-btn',
prop: 'galleryBtn',
value: {
icon: `${ax.prefix}icon-addpic`,
attrs: {},
},
},
{
attr: 'separator',
prop: 'separator',
value: AXTMP_separator,
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'status',
prop: 'status',
value: '',
},
{
attr: 'success',
prop: 'success',
value: (data) => data.code == 200,
},
{
attr: 'cloud',
prop: 'cloud',
value: {
enable: false,
field: '',
server: '',
domain: '',
map: { name: '', url: '', size: '', time: '' }
},
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'b4-remove',
prop: 'b4Remove',
value: null,
},
{
attr: 'b4-upload',
prop: 'b4Upload',
value: null,
},
{
attr: 'b4-uploadall',
prop: 'b4UploadAll',
value: null,
},
{
attr: 'on-output',
prop: 'onOutput',
value: null,
}, {
attr: 'on-rendered',
prop: 'onRendered',
value: null,
},
{
attr: 'on-added',
prop: 'onAdded',
value: null
},
{
attr: 'on-removed',
prop: 'onRemoved',
value: null
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-pasted',
prop: 'onPasted',
value: null
},
{
attr: 'on-dropped',
prop: 'onDropped',
value: null
},
{
attr: 'on-uploading',
prop: 'onUploading',
value: null
},
{
attr: 'on-uploaded',
prop: 'onUploaded',
value: null
},
{
attr: 'on-received',
prop: 'onReceived',
value: null
},
{
attr: 'on-receivedAll',
prop: 'onReceivedAll',
value: null
},
{
attr: 'on-uploadAll',
prop: 'onUploadAll',
value: null
},
{
attr: 'on-uploadedAll',
prop: 'onUploadedAll',
value: null
}, {
attr: 'on-failed',
prop: 'onFailed',
value: null
},
{
attr: 'on-error',
prop: 'onError',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
{
attr: 'on-locked',
prop: 'onLocked',
value: null
},
{
attr: 'on-unlocked',
prop: 'onUnlocked',
value: null
},
...optBase
];
class Upload extends ModBaseListenCache {
options = {};
flatData;
treeData;
dftTypes;
fileChangeEvt;
chooseEvt;
clearEvt;
uploadEvt;
dragLeaveEvt;
dragOverEvt;
dragEnterEvt;
dropEvt;
tipsEl;
summaryEl;
infoEl;
listEl;
tableEl;
theadEl;
fileEl;
inputEl;
footEl;
headEl;
chooseBtn;
uploadBtn;
clearBtn;
ctrlvEl;
tipsText;
name;
singleSizeLimit;
fileTypes;
passedItems;
allItems;
output;
files;
value;
validItems;
fileInputEvt;
static hostType = 'node';
static optMaps = optUpload;
static dependencies = [ProgressElem, BtnElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Upload.optMaps,
component: true,
spread: ['cloud', 'uploadBtn', 'clearBtn']
});
this.dftTypes = {
'image': `${ax.prefix}icon-image`,
'video': `${ax.prefix}icon-video`,
'audio': `${ax.prefix}icon-music`,
'file': `${ax.prefix}icon-file-text`,
};
let _this = this;
this.fileChangeEvt = function (e) {
e.stopPropagation();
let files = [...this.files];
_this.renderList(files);
this.value = '';
_this.listen({ name: 'changed', params: [files] });
};
this.fileInputEvt = function (e) {
e.stopPropagation();
};
this.chooseEvt = () => {
let globalValid = this.globalValid();
if (!globalValid.passed) {
new Message({
content: globalValid.msg,
status: 'error',
}).show();
return;
}
this.fileEl.click();
};
this.clearEvt = () => {
this.clear.call(this);
};
this.uploadEvt = () => {
this.uploadAll();
};
this.dragLeaveEvt = (e) => {
e.preventDefault();
this.targetEl.removeAttribute('dragging');
};
this.dragOverEvt = (e) => {
e.preventDefault();
this.targetEl.toggleAttribute('dragging', true);
};
this.dragEnterEvt = (e) => {
e.preventDefault();
};
this.dropEvt = async (e) => {
e.preventDefault();
this.targetEl.removeAttribute('dragging');
let items = e.dataTransfer.items;
for (let k of items) {
if (k.kind === "file") {
let entry = k.webkitGetAsEntry();
this.getEntries(entry);
}
}
super.listen({ name: 'dropped', params: [items] });
};
this.tipsEl = createEl('div', { [ax.alias]: 'tips' });
this.summaryEl = createEl('div', { [ax.alias]: 'summary' });
this.infoEl = createEl('div', { class: `${ax.prefix}upload-info` });
this.createSetList();
super.listen({ name: 'constructed' });
initial && this.init();
}
createSetList() {
let classes = ax.prefix + 'reset';
if (this.options.type === 'card') {
classes += ` ${ax.prefix}grid ${ax.prefix}g-xs`;
this.options.cols && (classes += ` ${ax.prefix}avg-${this.options.cols}`);
}
this.listEl = createEl(this.options.type === 'table' ? 'table' : 'ul', { class: `${this.options.type !== 'table' ? classes : ''} ${ax.prefix}upload-list` });
if (this.options.type === 'table') {
this.tableEl = createEl('table');
this.listEl = createEl('tbody', { class: `${ax.prefix}upload-list` });
if (this.options.table.header) {
this.theadEl = createEl('thead', {}, this.options.lang.thead.map((k) => `<th>${k}</th>`).join(''));
this.tableEl.appendChild(this.theadEl);
}
this.tableEl.appendChild(this.listEl);
}
else {
this.listEl = createEl('ul', { class: `${classes} ${ax.prefix}upload-list` });
}
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
this.passedItems = [];
this.allItems = [];
this.output = { value: '', raw: '', items: [] };
this.singleSizeLimit = this.options.limit.size * 1024 * 1024;
this.setFeature();
this.getFileTypes();
this.name = this.targetEl.name || this.options.name;
this.createSkeleton();
this.setAttrs();
this.renderFinish();
this.initShow();
super.listen({ name: 'initiated', cb });
return this;
}
initShow() {
if (!isEmpty(this.options.value)) {
this.add(this.options.value);
}
else {
let tmp = this.rawHtml.trim();
tmp && this.add(tmp);
}
}
setFeature() {
if (this.options.feature === 'picture') {
this.options.type = 'cube';
}
}
getFileTypes() {
this.fileTypes = { ...this.dftTypes, ...this.options.icons };
}
getTips() {
this.tipsText = [this.options.lang.tips.free];
this.options.limit.suffix && this.tipsText.push(renderTpl(this.options.lang.tips.suffix, { value: this.options.limit.suffix }));
this.options.limit.size && this.tipsText.push(renderTpl(this.options.lang.tips.size, { value: this.options.limit.size }));
this.options.limit.min && this.tipsText.push(renderTpl(this.options.lang.tips.min, { value: this.options.limit.min }));
this.options.limit.max && this.tipsText.push(renderTpl(this.options.lang.tips.max, { value: this.options.limit.max }));
return this.tipsText.join(',');
}
createStart() {
if (this.options.feature === 'gallery') {
this.chooseBtn = this.createBox(this.options.feature, 'div');
}
else if (this.options.feature === 'picture') {
this.chooseBtn = this.createBox(this.options.feature, 'li');
}
else {
this.chooseBtn = getEl(this.options.chooseBtn.target) || this.createBtn('choose');
}
}
createBox(type, node = 'li') {
let iconStr = this.options[type + 'Btn'].icon ? `<i ${ax.alias}="icon" class="${this.options[type + 'Btn'].icon}"></i>` : '', textStr = this.options.lang.button[type] ? `<div ${ax.alias}="text">${this.options.lang.button[type]}</div>` : '';
return createEl(node, Object.assign({ [ax.alias]: ['picture', 'gallery'].includes(type) ? 'choose' : type }, type !== 'gallery' ? { tabindex: 0 } : {}, this.options[type + 'Btn'].attrs), `${iconStr}${textStr}`);
}
createBtn(type) {
return createEl('ax-btn', Object.assign({ [ax.alias]: type, size: this.options.size, tabindex: 0, icon: this.options[type + 'Btn'].icon, label: this.options.lang.button[type] }, this.options[type + 'Btn'].attrs));
}
createInput(hasText = true, hasFile = true) {
if (hasText) {
this.inputEl = createEl('input', { type: 'hidden', readonly: '', name: this.name });
}
if (hasFile) {
this.fileEl = createEl('input', { type: 'file', readonly: '' });
}
}
createSkeleton() {
if (this.targetEl) {
if (this.targetEl.nodeName === 'INPUT') {
let tmp = this.targetEl;
if (tmp.type === 'file') {
this.fileEl = tmp;
this.fileEl.readOnly = true;
this.createInput(true, false);
}
else {
this.inputEl = tmp;
this.inputEl.type = 'hidden';
this.inputEl.name = this.name;
this.inputEl.readOnly = true;
this.createInput(false, true);
}
this.targetEl = createEl('div');
tmp.insertAdjacentElement('beforeBegin', this.targetEl);
}
else {
this.createInput(true, true);
}
}
else {
this.targetEl = createEl('div');
this.createInput(true, true);
}
this.inputEl.toggleAttribute(ax.embedSign, true);
this.fileEl.toggleAttribute(ax.embedSign, true);
this.targetEl.innerHTML = this.listEl.innerHTML = '';
this.options.accept && this.fileEl.setAttribute('accept', this.options.accept);
if (this.fileEl.multiple) {
this.options.multiple = true;
}
else {
this.options.multiple && (this.fileEl.toggleAttribute('multiple', true));
}
!this.fileEl.multiple && (this.options.limit.min = 0, this.options.limit.max = 1);
this.targetEl.append(this.inputEl, this.fileEl);
this.targetEl.appendChild(this.options.type === 'table' ? this.tableEl : this.listEl);
this.footEl = createEl('div', { class: `${ax.prefix}upload-foot` }, this.infoEl);
if (this.options.status) {
this.targetEl.setAttribute('status', this.options.status);
if (this.options.status.includes('tips')) {
this.tipsEl.innerHTML = this.getTips();
this.infoEl.appendChild(this.tipsEl);
}
if (this.options.status.includes('summary')) {
this.summaryEl.innerHTML = this.getSummary();
this.infoEl.appendChild(this.summaryEl);
}
}
if (this.options.feature === 'gallery') {
this.createCtrlv();
this.targetEl.appendChild(this.footEl);
this.chooseBtn = this.createBox(this.options.feature, 'div');
this.targetEl.insertAdjacentElement('afterBegin', this.chooseBtn);
this.targetEl.setAttribute('tabindex', 0);
if (this.options.clearBtn.enable) {
this.clearBtn = this.createBtn('clear');
this.footEl.appendChild(this.clearBtn);
}
if (this.options.uploadBtn.enable) {
this.uploadBtn = this.createBtn('upload');
this.footEl.appendChild(this.uploadBtn);
}
}
else if (this.options.feature === 'picture') {
this.targetEl.appendChild(this.footEl);
this.chooseBtn = this.createBox(this.options.feature, 'li');
this.listEl.appendChild(this.chooseBtn);
if (this.options.clearBtn.enable) {
this.clearBtn = this.createBox('clear', 'li');
this.chooseBtn.insertAdjacentElement('afterEnd', this.clearBtn);
}
if (this.options.uploadBtn.enable) {
this.uploadBtn = this.createBox('upload', 'li');
this.chooseBtn.insertAdjacentElement('afterEnd', this.uploadBtn);
}
}
else {
this.headEl = createEl('div', { class: `${ax.prefix}upload-head` });
this.listEl.insertAdjacentElement('beforeBegin', this.footEl);
let btn = getEl(this.options.chooseBtn.target);
if (btn) {
this.chooseBtn = btn;
}
else {
this.chooseBtn = this.createBtn('choose');
this.headEl.appendChild(this.chooseBtn);
}
if (this.options.uploadBtn.enable) {
let tmp = getEl(this.options.uploadBtn.target);
if (tmp) {
this.uploadBtn = tmp;
}
else {
this.uploadBtn = this.createBtn('upload');
this.headEl.appendChild(this.uploadBtn);
}
}
if (this.options.clearBtn.enable) {
let tmp = getEl(this.options.clearBtn.target);
if (tmp) {
this.clearBtn = tmp;
}
else {
this.clearBtn = this.createBtn('clear');
this.headEl.appendChild(this.clearBtn);
}
}
this.targetEl.insertAdjacentElement('afterBegin', this.headEl);
}
}
addEvts() {
this.chooseBtn.addEventListener('click', this.chooseEvt, false);
this.uploadBtn && this.uploadBtn.addEventListener('click', this.uploadEvt, false);
this.clearBtn && this.clearBtn.addEventListener('click', this.clearEvt, false);
this.fileEl.addEventListener('change', this.fileChangeEvt, false);
this.fileEl.addEventListener('input', this.fileInputEvt, true);
this.targetEl.addEventListener("dragleave", this.dragLeaveEvt, false);
this.targetEl.addEventListener("dragover", this.dragOverEvt, false);
this.targetEl.addEventListener("dragenter", this.dragEnterEvt, false);
this.targetEl.addEventListener("drop", this.dropEvt, false);
}
removeEvts() {
this.chooseBtn.removeEventListener('click', this.chooseEvt);
this.uploadBtn && this.uploadBtn.removeEventListener('click', this.uploadEvt);
this.clearBtn && this.clearBtn.removeEventListener('click', this.clearEvt);
this.fileEl.removeEventListener('change', this.fileChangeEvt);
this.fileEl.removeEventListener('input', this.fileInputEvt);
this.targetEl.removeEventListener("dragleave", this.dragLeaveEvt);
this.targetEl.removeEventListener("dragover", this.dragOverEvt);
this.targetEl.removeEventListener("dragenter", this.dragEnterEvt);
this.targetEl.removeEventListener("drop", this.dropEvt);
}
renderFinish() {
this.removeEvts();
this.addEvts();
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}upload`);
this.options.type ? this.targetEl.setAttribute('type', this.options.type) : this.targetEl.removeAttribute('type');
this.targetEl.toggleAttribute('pastable', this.options.pastable);
this.targetEl.toggleAttribute('inert', this.options.disabled);
this.options.feature ? this.targetEl.setAttribute('feature', this.options.feature) : this.targetEl.removeAttribute('feature');
this.targetEl.setAttribute('size', this.options.size);
this.updateInsProg('ready');
}
createCtrlv() {
if (this.options.pastable) {
this.ctrlvEl = createEl('i', { [ax.alias]: 'ctrlv' }, this.options.lang.paste.before);
this.targetEl.appendChild(this.ctrlvEl);
this.ctrlvEl.onclick = () => {
this.ctrlvEl.innerHTML = this.options.lang.paste.ing;
this.ctrlvEl.toggleAttribute('contenteditable', true);
this.ctrlvEl.focus();
};
this.ctrlvEl.onpaste = (e) => {
e.preventDefault();
this.ctrlvEl.toggleAttribute('contenteditable', false);
let data = e.clipboardData;
if (data) {
let item = data.items[0];
if (item && item.kind === 'file' && item.type.includes('image')) {
this.renderList([item.getAsFile()]);
this.ctrlvEl && (this.ctrlvEl.innerHTML = this.options.lang.paste.after);
}
super.listen({ name: 'pasted', params: [item] });
}
};
this.targetEl.onmouseleave = () => {
this.ctrlvEl.innerHTML = this.options.lang.paste.before;
};
}
}
getSummary() {
let originalSize = 0, realSize, totalNum = this.passedItems.length, receivedItems = this.passedItems.filter((i) => i.progress == 'received'), okNum = receivedItems.length;
for (let k of receivedItems) {
originalSize += k.file.size;
}
realSize = convertByte({ val: originalSize }).str;
return renderTpl(this.options.lang.summary, { total: totalNum, count: okNum, size: realSize });
}
createItem(item) {
let name = item.file.name, size = item.file.size, passed = item.valid.passed, msg = item.valid.msg, tpl = '', part1 = `
<div class="${ax.prefix}upload-mask">
${this.options.manual ? '<i ' + ax.alias + '="upload" class="' + ax.prefix + 'icon-upload"></i>' : ''}
<i ${ax.alias}="view" class="${ax.prefix}icon-zoomin"></i>
<a ${ax.alias}="download" href="###" class="${ax.prefix}icon-download"></a>
<i ${ax.alias}="remove" class="${ax.prefix}icon-trash"></i>
</div>
<ax-progress ${ax.alias}="progress" thk="xs" size="sm" type="circle"></ax-progress>
<i ${ax.alias}="state"></i>
<i ${ax.alias}="sign" class="${ax.prefix}icon-check"></i>
<div ${ax.alias}="message">${passed ? msg : ''}</div>
`, part2 = `
<div class="${ax.prefix}upload-info">
<a href="###" ${ax.alias}="title">${name}</a>
${this.options.type === 'bullet' ? '<div ' + ax.alias + '="size">' + convertByte({ val: size }).str + '</div>' : ''}
</div>
<ax-progress ${ax.alias}="progress" label="false" thk="xs"></ax-progress>
<i ${ax.alias}="message">${passed ? msg : ''}</i>
<i ${ax.alias}="percent"></i>
<i ${ax.alias}="state"></i>
<i ${ax.alias}="sign" class="${ax.prefix}icon-check"></i>
${this.options.manual ? '<i ' + ax.alias + '="upload" class="' + ax.prefix + 'icon-upload"></i>' : ''}
<i ${ax.alias}="remove" class="${ax.prefix}icon-trash"></i>
`;
if (this.options.type === 'card') {
tpl = `
<li valid=${passed ? 'success' : 'failed'}>
<div class="${ax.prefix}upload-file">
${part1}
</div>
<div class="${ax.prefix}upload-info">
<div ${ax.alias}="title">${name}</div>
<div ${ax.alias}="size">${convertByte({ val: size }).str}</div>
<div ${ax.alias}="url"></div>
</div>
</li>
`;
}
else if (this.options.type === 'cube') {
tpl = `
<li valid=${passed ? 'success' : 'failed'}>
<div class="${ax.prefix}upload-file"></div>
${part1}
</li>
`;
}
else if (this.options.type == 'bullet') {
tpl = `
<li valid=${passed ? 'success' : 'failed'}>
<a href="###" class="${ax.prefix}upload-file"></a>
${part2}
</li>
`;
}
else if (this.options.type === 'table') {
let btns = `
${this.options.manual ? '<i ' + ax.alias + '="upload" class="' + ax.prefix + 'icon-upload"></i>' : ''}
<i ${ax.alias}="remove" class="${ax.prefix}icon-trash"></i>
`;
tpl = `
<tr valid=${passed ? 'success' : 'failed'}>
<td><div class="${ax.prefix}upload-file"></div></td>
<td><div class="${ax.prefix}upload-info"><a href="###" ${ax.alias}="title">${name}</a></div></td>
<td>${convertByte({ val: size }).str}</td>
<td><ax-progress ${ax.alias}="progress" thk="sm"></ax-progress></td>
<td><i ${ax.alias}="message">${passed ? msg : ''}</i></td>
<td><span ${ax.alias}="state">${passed ? this.options.lang.progress.passed : this.options.lang.progress.notPassed}</span></td>
<td>${btns}</td>
</tr>
`;
}
else {
tpl = `
<li valid=${passed ? 'success' : 'failed'}>
<i ${ax.alias}="icon" class="${ax.prefix}icon-attach"></i>
${part2}
</li>
`;
}
item.wrapEl = tplToEl(tpl);
item.fileEl = item.wrapEl.querySelector(`.${ax.prefix}upload-file`);
item.fileEl && this.fillHeader(item);
if (this.options.feature === 'picture') {
this.chooseBtn.insertAdjacentElement('beforeBegin', item.wrapEl);
}
else {
this.listEl.appendChild(item.wrapEl);
}
}
updateInsProg(prog) {
this.targetEl.setAttribute('progress', prog);
}
updateItemProg(item, prog) {
item.progress = prog;
item.wrapEl.setAttribute('progress', prog);
item.stateEl && (item.stateEl.innerHTML = this.options.lang.progress[prog]);
}
updateItemValid(item, valid) {
item.wrapEl.setAttribute('valid', valid);
}
renderItem(file) {
let fileValid = this.fileValid(file), item = { file, valid: fileValid };
this.createItem(item);
item.uploadEl = item.wrapEl.querySelector(`[${ax.alias}="upload"]`);
item.removeEl = item.wrapEl.querySelector(`[${ax.alias}="remove"]`);
item.stateEl = item.wrapEl.querySelector(`[${ax.alias}="state"]`);
item.msgEl = item.wrapEl.querySelector(`[${ax.alias}="message"]`);
item.progEl = item.wrapEl.querySelector(`ax-progress`);
if (item.uploadEl) {
item.uploadEl.onclick = async () => {
try {
this.options.b4Upload && await this.options.b4Upload.call(this, item);
}
catch (err) {
err ? console.error(err) : console.warn('The "upload" operation has been blocked!');
return this;
}
this.upload(item);
};
}
if (item.removeEl) {
item.removeEl.onclick = async () => {
try {
this.options.b4Remove && await this.options.b4Remove.call(this, item);
}
catch (err) {
err ? console.error(err) : console.warn('The "remove" operation has been blocked!');
return this;
}
this.remove(item);
};
}
this.allItems.push(item);
fileValid.passed && this.passedItems.push(item);
this.updateItemProg(item, 'rendered');
super.listen({ name: 'rendered', params: [item] });
return item;
}
getEntries(entry) {
if (entry.isFile) {
entry.file((i) => this.renderList([i]));
}
else {
entry.createReader().readEntries((k) => k.forEach((i) => this.getEntries(i)));
}
}
hasSame(file) {
return this.allItems.length ? this.allItems.some((i) => (i.file.name === file.name && i.file.size === file.size)) : false;
}
renderList(files) {
if (!files.length)
return;
for (let k of files) {
!this.hasSame(k) && this.renderItem(k);
}
!this.options.manual && this.uploadAll();
this.updateInsProg('processing');
}
async uploadAll(cb) {
if (!this.options.url)
throw new Error('The parameter "url" (the address of the page to send data) is required!');
let globalValid = this.globalValid();
if (!globalValid.passed) {
new Message({
content: globalValid.msg,
status: 'error',
}).show();
return this;
}
else {
if (this.allItems.length < this.options.limit.min) {
new Message({
content: globalValid.msg,
status: 'warn',
}).show();
}
}
let items = this.getUploadingItems();
try {
this.options.b4UploadAll && await this.options.b4UploadAll.call(this, items);
}
catch (err) {
err ? console.error(err) : console.warn('The "upload all files" operation has been blocked!');
return this;
}
super.listen({ name: 'uploadAll', cb, params: [items] });
this.saveRaw();
await Promise.all(items.map((k) => this.upload(k, true)));
this.setInputVal();
this.listenReceivedAll();
return this;
}
getUploadingItems() {
return this.passedItems.filter((i) => this.canUpload(i));
}
actOpt(item) {
let file = item.file, dom = item.wrapEl, url = item.data.url; item.file.name;
if (this.options.cloud.enable)
url = url ? this.options.cloud.domain + url : 'javascript:void(0);';
let downloadBtn = dom.querySelector(`[${ax.alias}="download"]`), viewBtn = dom.querySelector(`[${ax.alias}="view"]`);
if (downloadBtn) {
if (this.options.cloud.enable) {
downloadBtn.onclick = () => fileTools.download(url, file.name);
}
else {
downloadBtn.setAttribute('download', '');
downloadBtn.setAttribute('href', url);
}
}
if (viewBtn) {
this.getFileType(file);
}
if (['text', 'bullet', 'table'].includes(this.options.type)) {
let titleEl = dom.querySelector(`[${ax.alias}="title"]`), fileEl = dom.querySelector(`.${ax.prefix}upload-file`);
titleEl.setAttribute('href', url);
titleEl.setAttribute('target', '_blank');
if (fileEl) {
fileEl.setAttribute('href', url);
fileEl.setAttribute('target', '_blank');
}
}
}
canUpload(item) {
return item.valid.passed && !['uploading', 'uploaded', 'received'].includes(item.progress);
}
async upload(item, eager = false) {
let data = new FormData(), file = item.file, dom = item.wrapEl, fixEl = (flag, message) => {
if (flag) {
this.actOpt(item);
this.updateItemProg(item, 'received');
}
else {
this.updateItemProg(item, 'failed');
this.updateItemValid(item, 'failed');
item.msgEl.innerText = message;
this.passedItems = this.allItems.filter((i) => i.valid.passed);
}
this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
};
if (!this.canUpload(item))
return this;
try {
this.options.b4Upload && await this.options.b4Upload.call(this, item);
}
catch (err) {
err ? console.error(err) : console.warn('The "upload" operation has been blocked!');
return this;
}
data.append(this.name || 'file', file);
if (this.options.cloud.enable) {
await ajax({
url: this.options.url,
before: () => {
this.updateItemProg(item, 'getAuth');
},
success: (resp) => {
for (let k in resp.content)
data.append(k, resp.content[k]);
this.options.cloud.append && this.options.cloud.append(data, file);
this.updateItemProg(item, 'authorized');
},
error: () => {
this.updateItemProg(item, 'unauthorized');
this.updateItemValid(item, 'failed');
this.validItems = this.allItems.filter((i) => i.valid.passed);
return;
}
});
}
this.updateItemProg(item, 'uploading');
!eager && this.saveRaw();
await ajax({
url: this.options.cloud.enable ? this.options.cloud.server : this.options.url,
data,
uploading: (resp) => {
item.abort = resp.abort;
item.progEl.setAttribute('value', resp.percent);
if (['text', 'bullet'].includes(this.options.type)) {
dom.querySelector(`[${ax.alias}="percent"]`).innerHTML = resp.result;
}
if (resp.percent >= 100) {
this.updateItemProg(item, 'uploaded');
super.listen({ name: 'uploaded', params: [item] });
if (this.passedItems.every((i) => i.valid.passed && ['uploaded', 'received'].includes(i.progress))) {
super.listen({ name: 'uploadedAll' });
}
}
else {
this.updateItemProg(item, 'uploading');
super.listen({ name: 'uploading', params: [{ item, content: resp }] });
}
},
success: async (resp) => {
let name = '', msg = '', url = '', size = 0, time = 0, passed, map = this.options.cloud.map, forceMsg = (item, msg, type) => {
if (msg) {
item.valid.msg = msg;
}
else {
item.valid.msg = this.options.lang.message.single[type];
}
}, getKeys = (obj, str) => {
if (!str)
return '';
if (!str.includes('.'))
return obj[str];
let arr = str.split("."), len = arr.length, value = len === 1 ? obj[arr[0]] : len === 2 ? obj[arr[0]][arr[1]] : '';
return value;
};
if (this.options.cloud.enable) {
name = getKeys(resp.content, map.name || 'name');
url = getKeys(resp.content, map.url || 'url');
size = getKeys(resp.content, map.size || 'size');
time = getKeys(resp.content, map.time || 'time');
msg = getKeys(resp.content, map.msg || 'msg');
}
else {
name = resp.content.name || item.file.name;
url = resp.content.url;
size = file.size;
time = resp.content.time;
msg = resp.content.msg;
}
passed = (this.options.success && this.options.success(resp.content)) || !!url;
item.resp = resp.content;
item.data = { name, url, size, time };
item.valid.passed = passed;
if (!passed) {
forceMsg(item, msg, 'failed');
super.listen({ name: 'failed', params: [{ item, content: resp.content }] });
}
else {
forceMsg(item, msg, 'success');
super.listen({ name: 'received', params: [{ item, content: resp.content }] });
}
fixEl(passed, item.valid.msg);
},
error: (resp) => {
fixEl(false, this.options.lang.message.single.failed);
super.listen({ name: 'error', params: [{ item, content: resp.content }] });
}
});
if (!eager) {
this.setInputVal();
this.listenReceivedAll();
}
}
listenReceivedAll() {
if (this.passedItems.every((i) => i.valid.passed && i.progress == 'received')) {
super.listen({ name: 'receivedAll' });
}
}
items2Vals(vals = this.passedItems) {
let items = vals.map((k) => k.data).filter(Boolean), arr = [];
for (let k of items)
arr.push(k.url);
return { value: arr.join(this.options.separator), items };
}
saveRaw(items = this.passedItems) {
this.output.raw = this.items2Vals(items).value;
}
setInputVal(value = this.passedItems) {
Object.assign(this.output, this.items2Vals(value));
if (this.inputEl) {
this.inputEl.value = this.output.value;
this.inputEl.onchange && this.inputEl.onchange();
}
super.listen({ name: 'output', params: [this.output] });
}
getFileType(file) {
let type = file.type, sfx = fileTools.getSuffix(file).toLowerCase(), tmp = '';
if (type.startsWith('image')) {
tmp = 'image';
}
else if (type.startsWith('video')) {
tmp = 'video';
}
else if (type.startsWith('audio')) {
tmp = 'audio';
}
else {
tmp = this.options.typeGetter ? this.options.typeGetter(file, sfx) : 'file';
}
return tmp;
}
async fillHeader(item) {
let file = item.file, type = this.getFileType(file), elem;
if (type === 'image') {
await fileTools.getBase64(file, (data) => { elem = createEl('img', { src: data }); });
}
else if (['video', 'audio'].includes(type)) {
await fileTools.getBase64(file, (data) => elem = createEl(type, { src: data, controls: '' }));
}
else {
elem = createEl('i', { class: this.fileTypes[type] || this.fileTypes.file, [ax.alias]: 'icon' });
}
item.fileEl.appendChild(elem);
}
fileValid(file) {
let msg = this.options.lang.message.single.passed, passed = true, suffix = fileTools.getSuffix(file);
if (this.allItems.length > this.options.limit.max && this.options.limit.max) {
msg = this.options.lang.message.single.max;
passed = false;
}
else if (this.singleSizeLimit && (file.size > this.singleSizeLimit)) {
msg = this.options.lang.message.single.size;
passed = false;
}
else if (this.options.limit.suffix && !this.options.limit.suffix.includes(suffix)) {
msg = this.options.lang.message.single.suffix;
passed = false;
}
return { passed, msg };
}
globalValid() {
let msg = this.options.lang.message.global.passed, passed = true;
if (this.allItems.length < this.options.limit.min) {
msg = renderTpl(this.options.lang.message.global.min, { value: this.options.limit.min });
passed = true;
}
else if (this.options.limit.max && this.allItems.length > this.options.limit.max) {
msg = renderTpl(this.options.lang.message.global.max, { value: this.options.limit.max });
passed = false;
}
return { passed, msg };
}
findItem(data) {
let type = getDataType(data), result;
if (type === 'String') {
result = this.allItems.find((i) => i.file.name === data);
}
else if (type === 'Number') {
result = this.allItems[data];
}
else if (type === 'File') {
result = this.allItems.find((i) => i.file === data);
}
else if (type === 'Object' && data.wrapEl) {
result = this.allItems.find((i) => i === data);
}
return result;
}
async remove(data, cb) {
if (this.destroyed)
return this;
let item = this.findItem(data);
if (!item)
return this;
try {
this.options.b4Remove && await this.options.b4Remove.call(this, item);
}
catch (err) {
err ? console.error(err) : console.warn('The "remove" operation has been blocked!');
return this;
}
this.saveRaw();
item.abort && item.abort();
item.wrapEl.remove();
this.allItems = this.allItems.filter((i) => i !== item);
this.passedItems = this.passedItems.filter((i) => i !== item);
if (this.passedItems.length) {
this.setInputVal();
}
else {
this.updateInsProg('ready');
this.setInputVal();
}
this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
super.listen({ name: 'removed', cb, params: [item] });
return this;
}
async clear(cb) {
if (this.destroyed)
return this;
try {
this.options.b4Clear && await this.options.b4Clear.call(this);
}
catch (err) {
err ? console.error(err) : console.warn('The "clear" operation has been blocked!');
return this;
}
this.saveRaw();
for (let k of this.passedItems) {
k.abort && k.abort();
k.wrapEl.remove();
}
this.passedItems = [];
this.allItems = [];
this.setInputVal();
this.updateInsProg('ready');
this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
super.listen({ name: 'cleared', cb });
return this;
}
getVals() {
if (this.destroyed)
return this;
return this.inputEl.value;
}
async add(data, cb) {
if (this.destroyed)
return this;
let newData = valToArr(data).map((k) => { return typeof k === 'string' ? { url: k, name: '' } : k; }).filter(Boolean), result = [];
if (!newData.length)
return;
this.updateInsProg('processing');
this.saveRaw();
for (let k of newData) {
try {
await fileTools.urlToFile(k.url, k.name, (file) => {
if (this.hasSame(file))
return;
let item = this.renderItem(file);
item.valid = {
passed: true,
msg: this.options.lang.message.single.success
};
item.data = {
name: file.name,
url: k.url,
time: k.time || file.lastModified,
size: file.size,
};
this.updateItemProg(item, 'received');
this.actOpt(item);
result.push(item);
});
}
catch {
console.error(`File address error, or the file may be blocked due to cross-origin restrictions:${k.url}`);
continue;
}
}
this.options.status.includes('summary') && (this.summaryEl.innerHTML = this.getSummary());
this.setInputVal();
super.listen({ name: 'added', cb, params: [result] });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.removeEvts();
for (let k of this.passedItems) {
k.abort && k.abort();
k.uploadEl && (k.uploadEl.onclick = null);
k.removeEl && (k.removeEl.onclick = null);
}
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optPanel = [
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'tpl-str',
prop: 'tplStr',
value: '',
},
{
attr: 'tpl-eng',
prop: 'tplEng',
value: null,
},
{
attr: 'label',
prop: 'label',
value: '',
},
{
attr: 'tips',
prop: 'tips',
value: '',
},
{
attr: 'cube',
prop: 'cube',
value: '',
},
{
attr: 'disk',
prop: 'disk',
value: '',
},
{
attr: 'image',
prop: 'image',
value: '',
},
{
attr: 'icon',
prop: 'icon',
value: '',
},
{
attr: 'badge',
prop: 'badge',
value: null,
},
{
attr: 'annot',
prop: 'annot',
value: '',
},
{
attr: 'lamp',
prop: 'lamp',
value: '',
},
{
attr: 'custom',
prop: 'custom',
value: '',
},
{
attr: 'brief',
prop: 'brief',
value: '',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: false,
show: `${ax.prefix}icon-up`,
hide: `${ax.prefix}icon-up`,
anim: `${ax.prefix}rotate180`,
type: 'icon',
placement: 'end',
},
},
{
attr: 'tab',
prop: 'tab',
value: {
enable: true,
},
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: false,
children: ['toggle']
},
},
{
attr: 'deferred',
prop: 'deferred',
value: false,
},
{
attr: 'feature',
prop: 'feature',
value: '',
},
{
attr: 'dividable',
prop: 'dividable',
value: false,
},
{
attr: 'collapsed',
prop: 'collapsed',
value: false,
},
{
attr: 'head-closable',
prop: 'headClosable',
value: false,
},
{
attr: 'padded',
prop: 'padded',
value: true,
},
{
attr: 'theme',
prop: 'theme',
value: '',
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'b4-expand',
prop: 'b4Expand',
value: null,
},
{
attr: 'b4-collapse',
prop: 'b4Collapse',
value: null,
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-rendered',
prop: 'onRendered',
value: null
},
{
attr: 'on-expand',
prop: 'onExpand',
value: null
},
{
attr: 'on-expanded',
prop: 'onExpanded',
value: null
},
{
attr: 'on-collapse',
prop: 'onCollapse',
value: null
},
{
attr: 'on-collapsed',
prop: 'onCollapsed',
value: null
},
{
attr: 'on-updatedcont',
prop: 'onUpdatedCont',
value: null
},
{
attr: 'on-request',
prop: 'onRequest',
value: null
},
...optBase
];
class LineElem extends CompBaseComm {
labelEl;
startEl;
endEl;
contRaw;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'theme', 'size', 'align', 'dir', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, LineElem);
}
getRawData() {
this.getRawProps(LineElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.labelEl);
this.startEl = createEl('i', { [ax.alias]: 'start' });
this.endEl = createEl('i', { [ax.alias]: 'end' });
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label);
this.wrapEl.appendChild(this.startEl);
data.label ? this.wrapEl.append(this.labelEl, this.endEl) : null;
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
};
changedLabel(opt) {
this.labelEl.innerHTML = opt.newVal;
if (opt.newVal) {
(elState(this.labelEl).isVirtual) && this.wrapEl.append(this.labelEl, this.endEl);
}
else {
this.labelEl.remove();
this.endEl.remove();
}
}
}
class Panel extends ModBaseListenCache {
options = {};
flatData;
treeData;
wrapEl;
headEl;
innerEl;
titleEl;
groupEl;
labelEl;
iconEl;
diskEl;
cubeEl;
imageEl;
briefEl;
annotEl;
badgeEl;
tipsEl;
customEl;
toolsEl;
arrowEl;
bodyEl;
contEl;
closeEl;
tabIns;
contXhr;
transmitioned;
data;
closeEvt;
static hostType = 'node';
static optMaps = optPanel;
static dependencies = [LineElem, BadgeElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Panel.optMaps,
component: true,
spread: ['arrow', 'tab', 'tools']
});
this.transmitioned = true;
this.closeEvt = () => {
if (!this.transmitioned)
return;
if (elState(this.bodyEl).isHidden) {
this.expand();
}
else {
this.collapse();
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
super.useTpl();
this.renderMain();
this.setAttrs();
await this.getDataToRender();
this.renderFinish();
super.listen({ name: 'initiated', cb });
return this;
}
correctOpts() {
if (this.options.feature === 'window') {
this.options.dividable = false;
}
}
async fillBody(content, cb) {
if (this.destroyed)
return this;
try {
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, content);
resp && (content = resp);
}
}
catch (err) {
err ? console.error(err) : console.warn('Body filling has been prevented!');
return;
}
setContent({
content,
target: this.contEl,
template: this.tplStr,
engine: this.tplEng
});
if ((this.options.deferred || this.options.collapsed) && !this.options.arrow.enable && !this.options.headClosable) {
await this.expand();
}
super.listen({ name: 'filled', cb, params: [content] });
return this;
}
async getDataToRender(force = false) {
let allow = force || !this.options.deferred;
if (!allow)
return;
if (this.options.content) {
this.data = await getContent.call(this, {
content: this.options.content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.arrowEl,
...this.options.ajax
},
request: (data) => {
this.listen({ name: 'request', params: [data] });
}
});
}
else {
this.data = this.rawEl || this.rawHtml;
}
this.data && await this.fillBody(this.data);
}
toggleArrow(val) {
if (!this.arrowEl)
return;
let map = val ? { new: 'show', old: 'hide', action: 'remove' } : { new: 'hide', old: 'show', action: 'add' };
if (this.options.arrow.type === 'image') {
this.arrowEl.style.backgroundImage = `url("${this.options.arrow[map.new]}")`;
}
else {
if (this.options.arrow.show === this.options.arrow.hide) {
this.arrowEl.classList[map.action](this.options.arrow.anim);
}
else {
classes(this.arrowEl).replace(this.options.arrow[map.old], this.options.arrow[map.new]);
}
}
}
setArrow() {
if (!this.arrowEl)
return;
let prop = this.options.collapsed || this.options.deferred ? 'hide' : 'show';
if (this.options.arrow.type === 'image') {
this.options.arrow[prop] && (this.arrowEl.style.backgroundImage = `url("${this.options.arrow[prop]}")`);
}
else {
this.options.arrow[prop] && this.arrowEl.classList.add(this.options.arrow[prop]);
(this.options.arrow.show === this.options.arrow.hide) && prop === 'hide' && this.arrowEl.classList.add(this.options.arrow.anim);
}
}
createHeadEl() {
let tpl = `
<div class="_panel-head">
<div class="_panel-inner">
<div class="_panel-title">
<div rep="group">
<i rep="label">${this.options.label}</i>
</div>
</div>
</div>
</div>
`;
this.headEl = tplToEl(tpl);
this.innerEl = this.headEl.querySelector(`.${ax.prefix}panel-inner`);
this.titleEl = this.headEl.querySelector(`.${ax.prefix}panel-title`);
this.groupEl = this.headEl.querySelector(`[${ax.alias}="group"]`);
this.labelEl = this.headEl.querySelector(`[${ax.alias}="label"]`);
if (this.options.icon) {
this.iconEl = createEl('i', { [ax.alias]: `icon`, class: this.options.icon });
(this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.iconEl);
}
if (this.options.disk) {
this.diskEl = createEl('img', { [ax.alias]: `disk`, src: this.options.disk });
(this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.diskEl);
}
if (this.options.cube) {
this.cubeEl = createEl('img', { [ax.alias]: `cube`, src: this.options.cube });
(this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.cubeEl);
}
if (this.options.image) {
this.imageEl = createEl('img', { [ax.alias]: `image`, src: this.options.image });
(this.options.feature === 'loose' ? this.innerEl : this.groupEl).insertAdjacentElement('beforebegin', this.imageEl);
}
if (this.options.brief) {
this.briefEl = createEl('div', { class: `${ax.prefix}panel-brief` }, this.options.brief);
this.titleEl.insertAdjacentElement('afterend', this.briefEl);
}
if (this.options.annot) {
this.annotEl = createEl('span', { [ax.alias]: `annot` }, this.options.annot);
this.labelEl.insertAdjacentElement('afterend', this.annotEl);
}
if (!isNull(this.options.badge)) {
this.badgeEl = createEl('ax-badge', { label: this.options.badge });
this.groupEl.insertAdjacentElement('afterend', this.badgeEl);
}
if (this.options.tips) {
this.tipsEl = createEl('span', { [ax.alias]: `tips` }, this.options.tips);
this.groupEl.insertAdjacentElement('afterend', this.tipsEl);
}
if (this.options.custom) {
this.customEl = createEl('div', { [ax.alias]: `custum` }, this.options.custom);
this.groupEl.insertAdjacentElement('afterend', this.customEl);
}
if (this.options.tools.enable) {
this.toolsEl = createTools(this.options.tools.children, this.titleEl);
this.toolsEl.setAttribute(ax.alias, 'tools');
}
if (this.options.arrow.enable) {
this.arrowEl = createEl('i', { [ax.alias]: `arrow` });
this.setArrow();
if (this.options.arrow.placement === 'end') {
this.titleEl.appendChild(this.arrowEl);
}
else {
(this.options.feature === 'loose' ? this.headEl : this.titleEl).insertAdjacentElement('afterbegin', this.arrowEl);
}
}
this.wrapEl.insertAdjacentElement('afterbegin', this.headEl);
this.options.dividable && this.headEl.insertAdjacentHTML('afterend', `<ax-line ${this.options.theme ? 'theme="' + this.options.theme + '"' : ''}></ax-line>`);
}
createBodyEl() {
this.bodyEl = createEl('div', { class: `${ax.prefix}panel-body` });
if (this.options.padded) {
this.contEl = createEl('div', { class: `${ax.prefix}panel-inner` });
this.bodyEl.appendChild(this.contEl);
}
else {
this.contEl = this.bodyEl;
}
this.wrapEl.appendChild(this.bodyEl);
}
renderMain() {
this.targetEl.innerHTML = '';
this.wrapEl = createEl('div', { class: `${ax.prefix}panel-wrap` });
this.targetEl.appendChild(this.wrapEl);
this.createHeadEl();
this.createBodyEl();
super.listen({ name: 'rendered' });
}
setAttrs() {
this.targetEl.classList.add(`${ax.prefix}panel`);
this.options.classes && classes(this.targetEl).add(this.options.classes);
(this.options.collapsed || this.options.deferred) && this.targetEl.toggleAttribute('collapsed', true);
this.options.headClosable && this.targetEl.toggleAttribute('headclosable', true);
this.options.feature && this.targetEl.setAttribute('feature', this.options.feature);
this.options.lamp && this.targetEl.setAttribute('lamp', this.options.lamp);
this.options.theme && this.targetEl.setAttribute('theme', this.options.theme);
}
renderFinish() {
this.closeEl = this.options.headClosable ? this.headEl : this.arrowEl;
if (this.closeEl) {
this.closeEl.removeEventListener('click', this.closeEvt);
this.closeEl.addEventListener('click', this.closeEvt, false);
}
for (let k of this.options.tools.children) {
if (k.name === 'toggle') {
k.wrapEl.onclick = () => {
if (k.iconEl.classList.contains(k.icon)) {
this.targetEl.toggleAttribute('max', true);
classes(k.iconEl).replace(k.icon, k.swap);
}
else {
this.targetEl.toggleAttribute('max', false);
classes(k.iconEl).replace(k.swap, k.icon);
}
};
}
else {
k.action && k.action.call(this, k);
}
}
if (this.options.tab.enable && this.headEl.querySelector(`.${ax.prefix}tab-head`) && this.bodyEl.querySelector(`.${ax.prefix}tab-body`)) {
this.tabIns = new Tab(this.targetEl, this.options.tab);
}
}
async expand(cb) {
if (this.destroyed || !this.transmitioned || elState(this.bodyEl).isVisible)
return this;
try {
if (this.options.b4Expand) {
await this.options.b4Expand.call(this);
}
}
catch (err) {
err ? console.error(err) : console.warn('Body expanding has been prevented!');
return;
}
this.options.deferred && !this.contEl.innerHTML && await this.getDataToRender(true);
slideDown({
el: this.bodyEl,
before: () => {
this.transmitioned = false;
super.listen({ name: 'expand' });
},
doing: () => {
this.toggleArrow(true);
},
done: () => {
this.transmitioned = true;
super.listen({ name: 'expanded', cb });
super.updateCache({ collapsed: false });
}
});
return this;
}
async collapse(cb) {
if (this.destroyed || !this.transmitioned || elState(this.bodyEl).isHidden)
return this;
try {
if (this.options.b4Collapse) {
await this.options.b4Collapse.call(this);
}
}
catch (err) {
err ? console.error(err) : console.warn('Body collapsing has been prevented!');
return;
}
slideUp({
el: this.bodyEl,
before: () => {
this.transmitioned = false;
super.listen({ name: 'collapse' });
},
doing: () => {
this.toggleArrow(false);
},
done: () => {
this.transmitioned = true;
super.listen({ name: 'collapsed', cb });
super.updateCache({ collapsed: true });
}
});
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.closeEl && this.closeEl.removeEventListener('click', this.closeEvt);
this.contXhr && this.contXhr.abort();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optRouter = [
{
attr: 'routes',
prop: 'routes',
value: [],
},
{
attr: 'current',
prop: 'current',
value: '',
},
{
attr: 'redirect',
prop: 'redirect',
value: [],
},
{
attr: 'before-check',
prop: 'beforeCheck',
value: null,
},
{
attr: 'after-check',
prop: 'afterCheck',
value: null,
},
{
attr: 'purpose',
prop: 'purpose',
value: 'sort',
},
{
attr: 'point',
prop: 'point',
value: {
before: ['t/3'],
after: ['b/3'],
},
},
{
attr: 'holder',
prop: 'holder',
value: {
from: false,
to: false,
},
},
{
attr: 'arrow',
prop: 'arrow',
value: {
enable: false,
icon: `${ax.prefix}icon-right`,
placement: 'left',
selector: '',
},
},
{
attr: 'gesture',
prop: 'gesture',
value: {},
},
{
attr: 'delay',
prop: 'delay',
value: 50,
},
{
attr: 'duration',
prop: 'duration',
value: 200,
},
{
attr: 'b4-drop',
prop: 'b4Drop',
value: null,
},
{
attr: 'on-dropping',
prop: 'onDropping',
value: null,
},
{
attr: 'on-dropped',
prop: 'onDropped',
value: null,
},
{
attr: 'on-dragstart',
prop: 'onDragStart',
value: null,
},
{
attr: 'on-dragmove',
prop: 'onDragMove',
value: null,
},
{
attr: 'on-dragend',
prop: 'onDragEnd',
value: null,
},
{
attr: 'on-located',
prop: 'onLocated',
value: null,
},
...optBase
];
class Router extends ModBaseListen {
options = {};
routes;
current;
stateEvt;
static hostType = 'none';
constructor(options = {}, initial = true) {
super();
super.ready({
options,
maps: optRouter,
});
this.routes = this.options.routes || [];
this.current = this.options.current;
this.stateEvt = (evt) => {
if (!evt.state) ;
else {
if (this.current !== evt.state.path) {
let toRoute = this.getRoute(evt.state.path), fromRoute = this.getRoute();
if (this.options.beforeCheck) {
let resp = this.options.beforeCheck(toRoute, fromRoute);
if (typeof resp === 'string') {
let reRoute = this.getRoute(resp);
if (reRoute) {
this.push(reRoute);
}
else {
return;
}
}
else if (!resp) {
return;
}
}
this.current = evt.state.path;
toRoute.action && toRoute.action.call(this, toRoute);
super.listen({ name: 'located', params: [toRoute] });
}
}
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
window.addEventListener('popstate', this.stateEvt);
this.current = this.getUrlPath();
this.add({ path: this.current, action: null });
super.listen({ name: 'initiated', cb });
return this;
}
getUrlPath() {
let pathname = window.location.pathname, search = window.location.search, hash = window.location.hash;
return pathname + search + hash;
}
getRoute(path = this.current) {
return this.routes.find((k) => k.path === path);
}
;
add(state) {
let item = this.routes.find((k) => k.path === state.path);
item ? Object.assign(item, state) : this.routes.push(state);
}
remove(path) {
this.routes.filter((k) => k.path !== path);
}
push(state, cb) {
if (isNull(state) || this.destroyed)
return;
if (this.options.beforeCheck) {
let resp = this.options.beforeCheck(state, this.getRoute());
if (typeof resp === 'string') {
state = this.getRoute(state.resp);
if (!state)
window.location.href = resp;
}
else if (!resp) {
return;
}
}
let route = this.getRoute(state.path);
if (route) {
this.replace(state);
Object.assign(route, state);
return this;
}
this.add(state);
history.pushState({ path: state.path }, Date.now() + '', state.path);
this.current = state.path;
state.action && state.action.call(this, state);
super.listen({ name: 'located', cb, params: [state] });
return this;
}
replace(state, cb) {
if (isNull(state) || this.destroyed)
return;
let route = this.getRoute(state.path);
if (!route) {
this.push(state);
return this;
}
Object.assign(route, state);
if (this.options.beforeCheck) {
let resp = this.options.beforeCheck(route, this.getRoute());
if (typeof resp === 'string') {
state = this.getRoute(state.resp);
if (!state)
return;
}
else if (!resp) {
return;
}
}
history.replaceState({ path: state.path }, Date.now() + '', state.path);
this.current = state.path;
state.action && state.action.call(this, state);
super.listen({ name: 'located', cb, params: [state] });
return this;
}
back() {
if (this.destroyed)
return;
history.go(-1);
return this;
}
forward() {
if (this.destroyed)
return;
history.go(1);
return this;
}
go(path) {
if (this.destroyed)
return;
if (typeof path === 'string') {
this.push(this.getRoute(path));
}
else {
history.go(path);
}
return this;
}
clear() {
this.routes = [];
return this;
}
routeChange(path) {
if (!path)
return;
let action = this.routes[path];
if (action) {
this.current = path;
action.call(this);
}
else {
console.error(`No route found for path: ${path}`);
}
}
beforeCheck(to, from, next) {
}
afterCheck() {
}
restore() {
return this;
}
destroy(cb) {
if (this.destroyed)
return;
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
let OCTMP_actClass = config.actClass;
const optViewer = [
{
attr: 'target',
prop: 'target',
value: ''
},
{
attr: 'auto-idx',
prop: 'autoIdx',
value: false,
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'gallery',
prop: 'gallery',
value: true,
},
{
attr: 'autoplay',
prop: 'autoplay',
value: false,
},
{
attr: 'thumb',
prop: 'thumb',
value: {
enable: false,
show: true,
placement: 'bottom',
size: 70,
gap: 8,
divide: 1,
}
}, {
attr: 'aside',
prop: 'aside',
value: {
enable: false,
expanded: true,
placement: 'end',
title: '',
closable: true,
delay: 0,
getter: null,
template: '',
engine: renderTpl,
}
},
{
attr: 'mode',
prop: 'mode',
value: 'fixed',
},
{
attr: 'inverted',
prop: 'inverted',
value: false,
},
{
attr: 'width',
prop: 'width',
value: 0,
},
{
attr: 'height',
prop: 'height',
value: 0,
},
{
attr: 'swipe',
prop: 'swipe',
value: {},
},
{
attr: 'active',
prop: 'active',
value: 0,
},
{
attr: 'z-index',
prop: 'zIndex',
value: 0,
},
{
attr: 'tools',
prop: 'tools',
value: {
enable: true,
children: ['close'],
}
},
{
attr: 'total',
prop: 'total',
value: {
enable: true,
format: '',
}
},
{
attr: 'act-class',
prop: 'actClass',
value: OCTMP_actClass,
},
{
attr: 'cont-type',
prop: 'contType',
value: 'text',
},
{
attr: 'cont-data',
prop: 'contData',
value: {},
},
{
attr: 'ajax',
prop: 'ajax',
value: {},
},
{
attr: 'on-changed',
prop: 'onChanged',
value: null,
},
{
attr: 'on-filledaside',
prop: 'onFilledAside',
value: null,
},
...optBase
];
const init = (type, parent) => {
let parentEl = getEl(parent) || document.body, evalFn = new Function('el', 'module', `"use strict";try {return new module(el)} catch {return null}`), moduleNodeMaps = [], setProp = (node, module) => {
storeNode(node)?.addModule(module);
}, getUsableModules = () => {
let result = [];
for (let [key, value] of Object.entries(ax)) {
value?.hostType === 'node' ? result.push(key) : null;
}
return result;
}, getNodeList = (types) => {
let allModules = getUsableModules(), modules = !isEmpty(types) ? types.filter(k => allModules.includes(k)) : allModules, modulesNodes = modules.map(k => {
let nodes = getEls(`[ax-${k}]`, parentEl).filter((i) => !i.ax || (i.ax && !i.ax[k]));
return nodes.map((i) => { return { module: k, node: i }; });
});
return modulesNodes;
}, activeFn = (obj) => {
if (['Dialog', 'Drawer', 'Popup'].includes(obj.module)) {
higherParent(obj.module, obj.node);
}
else {
let ins = evalFn(obj.node, ax[obj.module]);
ins ? setProp(obj.node, obj.module) : null;
}
}, higherParent = (module, node) => {
let eachInstance = (host, parent) => {
let ins = evalFn(host, ax[module]), children;
if (ins) {
host[module] = true;
parent ? ins.targetEl.style.zIndex = parseInt(getComputedStyle(parent.targetEl).zIndex) + 1 : null;
children = getEls(`[ax-${module}]`, ins.contEl);
if (children.length > 0) {
for (let k of children)
eachInstance(k, ins);
}
}
};
eachInstance(node);
};
if (!isEmpty(type)) {
let moduleType = getDataType(type), types;
types = (moduleType === 'String') ? [type] :
(moduleType === 'Array') ? type : [];
moduleNodeMaps = types.length > 0 ? getNodeList(types) : [];
}
else {
moduleNodeMaps = getNodeList();
}
let flatArr = moduleNodeMaps.flat();
if (flatArr.length) {
decompTask({
tasks: flatArr,
count: 4,
type: 'idle',
done: () => {
console.info(`Initialization finished, all tasks of axui are done!`);
},
run: (task) => activeFn(task),
});
}
if (isEmpty(type) || type?.includes('lazy')) {
let lazySrcs = getEls('[lazy-src]', parentEl), lazyAsyncs = getEls('[lazy-async]', parentEl);
for (let k of lazySrcs) {
if (k?.ax?.lazy)
continue;
new Lazy(k, {
content: k.getAttribute('lazy-src'),
type: 'src'
});
}
for (let k of lazyAsyncs) {
if (k?.ax?.lazy)
continue;
new Lazy(k, {
content: k.getAttribute('lazy-async'),
contType: k.getAttribute('lazy-type'),
contData: strToJson(k.getAttribute('lazy-data')),
tplStr: k.getAttribute('lazy-tpl'),
type: 'async'
});
}
}
if (isEmpty(type) || type?.includes('viewer')) {
let viewers = getEls('[ax-viewer]', parentEl), viewerData = [];
for (let k of viewers) {
let options = attrToJson(k, 'ax-viewer'), name = options.insName, child = getEl(`[src]`, k), node = k.hasAttribute('src') ? k : child, nodename = node?.nodeName?.toLocaleLowerCase() || '', caption = node?.getAttribute('alt') || node?.getAttribute('title') || '', type = ['video', 'audio', 'iframe'].includes(nodename) ? nodename : 'image', tmp = node ? { media: node.getAttribute('src'), caption, type } : '', content = [options.content || tmp].flat();
options.content = content;
options.target = [];
if (!name) {
options.content = content;
options.target.push(k);
}
else {
let existObj = viewerData.find((k) => k.name === name), idx = 0;
if (existObj) {
Reflect.deleteProperty(options, 'content');
Reflect.deleteProperty(options, 'target');
deepMerge(existObj, options);
idx = existObj.options.content.length;
storeNode(k).addData('viewer', idx);
existObj.options.target.push(k);
existObj.options.content.push(...content);
}
else {
options.target.push(k);
}
storeNode(k).addData('viewer', idx);
}
viewerData.push({ name, options });
}
for (let k of viewerData)
new Viewer(k.options);
}
return ax;
};
class Viewer extends ModBaseListen {
data;
maskEl;
headEl;
totalEl;
toolsEl;
bodyEl;
stageEl;
thumbEl;
footEl;
viewerEl;
hideEvt;
shown;
stageIns;
thumbIns;
showEvt;
targetEls;
locateIdx;
asideEl;
titleEl;
closeEl;
contEl;
overwritable;
change2FillEvt;
static hostType = 'none';
static optMaps = optViewer;
constructor(options = {}, initial = true) {
super();
super.ready({
options,
maps: Viewer.optMaps,
spread: ['total', 'tools', 'thumb']
});
let _this = this;
this.data = [];
this.shown = false;
this.overwritable = true;
this.targetEls = getEls(this.options.target);
this.hideEvt = () => {
if (this.options.mode === 'inline')
return;
!this.viewerEl.hasAttribute('show') && this.viewerEl.remove();
if (this.targetEls.length) {
for (let k of this.targetEls)
k.classList.remove(this.options.actClass);
}
};
this.showEvt = debounce(function (evt) {
if (_this.options.mode === 'inline')
return;
preventDft(evt);
!_this.shown && _this.show();
this.classList.add(_this.options.actClass);
_this.locateIdx = !isNull(this?.ax?.viewer) ? this?.ax?.viewer :
_this.options.autoIdx ? _this.targetEls.findIndex((k) => k === this) : null;
!isNull(_this.locateIdx) && _this.stageIns.prepared && _this.stageIns.toLocate(_this.locateIdx);
});
this.change2FillEvt = debounce((params) => {
if (this.overwritable) {
this.fillAside(null, params);
}
else {
!this.contEl.innerHTML && this.fillAside(null, params);
}
}, this.options.aside.delay);
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
if (ax.isPortraitScr) {
this.options.thumb.enable && (this.options.thumb.placement = 'bottom');
this.options.aside.enable && (this.options.aside.expanded = false);
}
this.data = await this.getStdData();
this.getStructure();
this.setThumbIns();
this.setStageIns();
this.setAttrs();
this.setTools();
if (this.targetEls.length && this.options.mode !== 'inline') {
for (let k of this.targetEls)
k.addEventListener('click', this.showEvt, false);
}
if (this.options.aside.enable) {
this.options.aside.expanded ? this.expand() : this.collapse();
}
this.options.mode === 'inline' && this.targetEls[0] && this.show();
super.listen({ name: 'initiated', cb });
}
setTools() {
if (!this.options.tools.enable)
return;
createTools(this.options.tools.children, this.toolsEl, this);
for (let k of this.options.tools.children) {
if (k.name === 'close') {
k.wrapEl.setAttribute('title', this.options.lang.close);
k.wrapEl.onclick = () => {
this.hide();
};
}
else if (k.name === 'zoom') {
k.wrapEl.setAttribute('title', this.options.lang.zoom);
k.wrapEl.onclick = debounce(() => {
this.stageIns.enable2Init(this.stageIns.snapSlider);
this.stageIns.toggleZoom(this.stageIns.snapSlider);
});
}
else if (k.name === 'zoomin') {
k.wrapEl.setAttribute('title', this.options.lang.zoomin);
k.wrapEl.onclick = debounce(() => {
this.stageIns.enable2Init(this.stageIns.snapSlider);
this.stageIns.snapSlider.zoomIns.stepFn(null, 1, 'keyboard');
});
}
else if (k.name === 'zoomout') {
k.wrapEl.setAttribute('title', this.options.lang.zoomout);
k.wrapEl.onclick = debounce(() => {
if (!this.stageIns?.snapSlider?.zoomIns)
return;
this.stageIns.snapSlider.zoomIns.stepFn(null, -1, 'keyboard');
this.stageIns.snapSlider.zoomIns.nowVals.scale.x === this.stageIns.snapSlider.rawTrans.scale.x && this.stageIns.snapSlider.zoomIns.destroy();
});
}
else if (k.name === 'play') {
k.wrapEl.onclick = debounce(() => {
if (this.stageIns.paused) {
this.options.autoplay ? this.stageIns.autoPlay() : this.stageIns.play();
}
else {
this.options.autoplay ? this.stageIns.autoPause() : this.stageIns.pause();
}
});
}
else if (k.name === 'flipv' || k.name === 'fliph') {
k.wrapEl.setAttribute('title', this.options.lang[k.name]);
k.wrapEl.onclick = debounce(() => {
let mediaEl = this.stageIns.snapSlider.slider.querySelector(`.${ax.prefix}viewer-media`), scaleVal = transformTools.get(mediaEl, ['scale']).scale, setVal = {
x: scaleVal.x * (k.name === 'fliph' ? -1 : 1),
y: scaleVal.y * (k.name === 'flipv' ? -1 : 1)
};
transformTools.set({
el: mediaEl,
data: {
scale: setVal,
}
});
});
}
else if (k.name === 'download') {
k.wrapEl.setAttribute('title', this.options.lang.download);
k.wrapEl.onclick = debounce(() => {
let sliderData = this.data.find((k) => k.wrapEl === this.stageIns.snapSlider.slider), href = sliderData?.source || sliderData?.media;
if (!sliderData || !href || (sliderData.type && !['image', 'video', 'audio'].includes(sliderData.type)))
return;
let tmp = createEl('a', { download: '', style: 'display:none', target: '_blank', href });
document.body.appendChild(tmp);
tmp.click();
setTimeout(() => tmp.remove(), 1000);
});
}
else if (k.name === 'thumb') {
k.wrapEl.setAttribute('title', this.options.lang.thumb);
k.wrapEl.onclick = debounce(() => {
let tmp = this.viewerEl.hasAttribute('nonthumb');
this.viewerEl.toggleAttribute('nonthumb', !tmp);
});
}
else if (k.name === 'fullscr') {
k.wrapEl.setAttribute('title', this.options.lang.fullscrOn);
k.wrapEl.onclick = debounce(() => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen()
.then(() => {
this.toggleScreenAttr(k, 'off');
});
}
else {
document.exitFullscreen()
.then(() => {
this.toggleScreenAttr(k, 'on');
});
}
});
}
else if (k.name === 'rotatel' || k.name === 'rotater') {
k.wrapEl.setAttribute('title', this.options.lang[k.name]);
k.wrapEl.onclick = debounce(() => {
let tmp = this.stageIns.snapSlider.slider.querySelector(`.${ax.prefix}viewer-media`), rotateVal = transformTools.get(tmp, ['rotate']).rotate;
transformTools.set({
el: tmp,
data: {
rotate: rotateVal + 90 * (k.name === 'rotatel' ? -1 : 1),
}
});
});
}
else if (k.name === 'more') {
k.wrapEl.setAttribute('title', this.options.lang.expand);
k.wrapEl.onclick = debounce(() => {
if (!this.options.aside.enable)
return;
if (this.viewerEl.hasAttribute('expanded')) {
this.collapse();
}
else {
this.expand();
}
});
}
}
}
toggleMoreAttr(status) {
let tools = this.options.tools.children.find((k) => k.name === 'more');
if (!tools)
return;
let iconClass = classes(tools.iconEl);
if (status === 'off') {
tools.wrapEl.setAttribute('title', this.options.lang.collapse);
iconClass.replace(tools.icon, tools.swap);
}
else {
tools.wrapEl.setAttribute('title', this.options.lang.expand);
iconClass.replace(tools.swap, tools.icon);
}
}
toggleScreenAttr(tools, status) {
let iconClass = classes(tools.iconEl);
if (status === 'off') {
tools.wrapEl.setAttribute('title', this.options.lang.fullscrOff);
iconClass.replace(tools.icon, tools.swap);
}
else {
tools.wrapEl.setAttribute('title', this.options.lang.fullscrOn);
iconClass.replace(tools.swap, tools.icon);
}
}
togglePlayAttr(tools, status) {
let iconClass = classes(tools.iconEl);
if (status === 'play') {
tools.wrapEl.setAttribute('title', this.options.lang.play);
iconClass.replace(tools.swap, tools.icon);
}
else {
tools.wrapEl.setAttribute('title', this.options.lang.pause);
iconClass.replace(tools.icon, tools.swap);
}
}
getCurData(from = this.stageIns.actIdx, opts = {}) {
let index = opts.index, slider = opts.slider, thumb = opts.thumb;
if (isEmpty(opts)) {
let fromType = getDataType(from);
if (fromType === 'Number') {
index = from;
}
else if (fromType === 'Object') {
index = this.stageIns.sliders.findIndex((k) => k === from);
}
else if (fromType.includes('HTML')) {
index = this.stageIns.sliders.findIndex((k) => k.slider === from);
}
if (index > -1) {
slider = this.stageIns.sliders[index];
thumb = this.thumbIns?.sliders[index];
}
}
return { index, slider, thumb, content: opts.content || this.data[index] };
}
async fillAside(from = this.stageIns.actIdx, opts = {}) {
if (!this.options.aside.enable || !this.options.aside.getter)
return;
let params = this.getCurData(from, opts), tmp = await this.options.aside.getter.call(this, params);
!isNull(tmp) && this.setAsideCont(tmp);
}
setAsideCont(content) {
if (!this.options.aside.enable)
return;
setContent({
content,
target: this.contEl,
template: this.options.aside.template,
engine: this.options.aside.engine,
});
super.listen({ name: 'filledAside', params: [content] });
}
setStageIns() {
this.stageIns = new Swipe(this.stageEl, deepMerge({
thumb: {
content: this.thumbIns,
mode: 'locate'
},
zoom: {
enable: true,
},
nav: {
fill: true,
},
total: {
enable: true,
selector: this.totalEl,
},
keyboard: true,
active: this.options.active,
autoplay: this.options.autoplay,
onChanged: (slider, index) => {
let params = { index, slider, thumb: this.thumbIns?.sliders[index], content: this.data[index] };
this.change2FillEvt(params);
super.listen({ name: 'changed', params: [params] });
},
onPaused: () => {
let playTools = this.options.tools.children.find((k) => k.name === 'play');
playTools && this.togglePlayAttr(playTools, 'play');
},
onPlayed: () => {
let playTools = this.options.tools.children.find((k) => k.name === 'play');
playTools && this.togglePlayAttr(playTools, 'pause');
},
onPrepared: () => {
if (!isNull(this.locateIdx)) {
this.stageIns.scrollIns.tmpTarget = this.stageIns.sliders[this.locateIdx].slider;
}
}
}, this.options.swipe));
}
setThumbIns() {
if (!this.options.thumb.enable)
return;
let opts = {
slides: 'auto',
nav: {
enable: false,
},
flow: this.options.thumb.placement === 'bottom' ? 'h' : 'v',
scroll: {
resizeThr: 2,
},
};
opts[this.options.thumb.placement === 'bottom' ? 'height' : 'width'] = this.options.thumb.size;
this.thumbIns = new Swipe(this.thumbEl, deepMerge(opts, this.options.thumb));
}
setAttrs() {
this.viewerEl.toggleAttribute('nonthumb', !this.options.thumb.show);
this.options.zIndex && (this.viewerEl.style.zIndex = this.options.zIndex);
this.options.thumb.enable && this.viewerEl.setAttribute('thumb', this.options.thumb.placement);
this.options.classes && classes(this.viewerEl).add(this.options.classes);
this.viewerEl.setAttribute('mode', this.options.mode);
this.viewerEl.toggleAttribute('inverted', this.options.inverted);
if (this.options.aside.enable) {
this.viewerEl.setAttribute('aside', this.options.aside.placement);
}
else {
this.viewerEl.removeAttribute('aside');
}
}
getStageSlideStr(data) {
if (data.type == 'video') {
return `<video controls lazy-src="${data.media}"></video>`;
}
else if (data.type == 'audio') {
return `<audio controls lazy-src="${data.media}"></audio>`;
}
else if (data.type == 'iframe') {
return `<iframe lazy-src="${data.media}" frameborder="0" width="100%" height="100%"></iframe>`;
}
else if (data.type == 'html') {
let tmp = getEl(data.media);
return `<div class="${ax.prefix}viewer-text" ${data.unfenced ? 'unfenced' : ''}>${tmp?.innerHTML || ''}</div>`;
}
else if (data.type == 'text') {
return `<div class="${ax.prefix}viewer-text" ${data.unfenced ? 'unfenced' : ''}>${data.media}</div>`;
}
else {
return `<img lazy-src="${data.media}"/>`;
}
}
fillStage() {
let ul = getEl('ul', this.stageEl), fragment = document.createDocumentFragment();
for (let k of this.data) {
k.mediaEl = createEl('div', { class: `${ax.prefix}viewer-media` });
k.captionEl = createEl('div', { class: `${ax.prefix}viewer-caption` }, k.caption);
k.wrapEl = createEl('li', {}, k.mediaEl);
if (k.type === 'dom') {
let dom = getEl(k.media);
let tmp = createEl('div', { class: `${ax.prefix}viewer-dom` }, dom);
k.unfenced && tmp.toggleAttribute('unfenced', true);
k.mediaEl.appendChild(tmp);
}
else {
k.mediaEl.innerHTML = this.getStageSlideStr(k);
}
k.srcEl = k.mediaEl.firstElementChild;
k.caption && k.wrapEl.appendChild(k.captionEl);
if (k.attrs) {
for (let i in k.attrs)
k.srcEl.setAttribute(i, k.attrs[i]);
}
fragment.appendChild(k.wrapEl);
}
ul.appendChild(fragment);
}
fillThumb() {
if (!this.options.thumb.enable)
return;
let ul = getEl('ul', this.thumbEl), fragment = document.createDocumentFragment();
for (let k of this.data) {
let src = k.cover || (k.type === 'image' ? k.media : '') || ax.images.none;
k.coverEl = createEl('li', {}, `<img lazy-src="${src}"/>`);
fragment.appendChild(k.coverEl);
}
ul.appendChild(fragment);
}
getStructure() {
let asideArrow = this.options.aside.placement === 'end' ? 'right' : 'left', asideCont = `<div class="${ax.prefix}viewer-aside">
${this.options.aside.closable ? '<i ' + ax.alias + '="close" class="' + ax.prefix + 'icon-arrow-' + asideArrow + '" title="' + this.options.lang.collapse + '"></i>' : ''}
${this.options.aside.title ? '<div class="' + ax.prefix + 'viewer-title"><span ' + ax.alias + '="title">' + this.options.aside.title + '</span></div>' : ''}
<div class="${ax.prefix}viewer-wrap">
<div class="${ax.prefix}viewer-cont"></div>
</div>
</div>
`;
this.viewerEl = createEl('div', { class: `${ax.prefix}viewer` }, `
<div class="${ax.prefix}viewer-mask"></div>
<div class="${ax.prefix}viewer-body">
<div class="${ax.prefix}viewer-head">
<div class="${ax.prefix}viewer-total"></div>
<div class="${ax.prefix}viewer-tools"></div>
</div>
<div class="${ax.prefix}viewer-stage"><ul class="${ax.prefix}reset"></ul></div>
<div class="${ax.prefix}viewer-foot">
<div class="${ax.prefix}viewer-thumb"><ul class="${ax.prefix}reset"></ul></div>
</div>
</div>
${this.options.aside.enable ? asideCont : ''}
`);
this.maskEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-mask`);
this.headEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-head`);
this.totalEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-total`);
this.toolsEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-tools`);
this.bodyEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-body`);
this.stageEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-stage`);
this.thumbEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-thumb`);
this.footEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-foot`);
this.asideEl = this.viewerEl.querySelector(`.${ax.prefix}viewer-aside`);
this.titleEl = this.asideEl?.querySelector(`[${ax.alias}="title]"`);
this.closeEl = this.asideEl?.querySelector(`:scope > [${ax.alias}="close"]`);
this.contEl = this.asideEl?.querySelector(`.${ax.prefix}viewer-cont`);
if (this.options.mode !== 'fixed') {
this.options.width && this.viewerEl.style.setProperty(`--${ax.prefix}viewer-w`, isNaN(this.options.width) ? this.options.width : this.options.width + 'px');
this.options.height && this.viewerEl.style.setProperty(`--${ax.prefix}viewer-h`, isNaN(this.options.height) ? this.options.height : this.options.height + 'px');
}
this.fillStage();
this.fillThumb();
this.viewerEl.addEventListener('transitionend', this.hideEvt, false);
this.stageEl.onclick = (event) => {
let target = getEvtTarget(event);
if ([this.maskEl, this.stageEl].includes(target)) {
this.hide();
}
};
if (this.closeEl) {
this.closeEl.onclick = () => {
this.collapse();
};
}
init('lazy', this.viewerEl);
}
getDataFromFigure(target) {
let result = [];
if (getEl('figure', target)) {
result = getEls('figure', target);
return result.map((k) => {
let img = getEl('img', k), src = img?.getAttribute('src') || '', caption = k.querySelector('figcaption')?.innerHTML || img?.getAttribute('alt') || img?.getAttribute('title') || '';
return { media: src, cover: src, caption, type: 'image', };
});
}
else {
result = getEls('img', target);
return result.map((k) => {
let src = k.getAttribute('src') || '', caption = k.getAttribute('alt') || k.getAttribute('title') || '';
return { media: src, cover: src, caption, type: 'image' };
});
}
}
getDataFromStr(str) {
str = str.trim();
let tmp = getEl(str);
return tmp ? this.getDataFromFigure(tmp) : valToArr(str).map((k) => { return { media: k, cover: k, type: 'image' }; });
}
async getStdData(content = this.options.content) {
if (this.options.contType === 'async') {
await getContent.call(this, {
content,
contType: this.options.contType,
contData: this.options.contData,
ajax: {
xhrName: 'contXhr',
spinSel: this.targetEl,
...this.options.ajax
},
cb: async (data) => {
content = data;
}
});
}
let getDataFromSingle = (cont) => {
let contType = getDataType(cont);
if (contType === 'String') {
return this.getDataFromStr(cont);
}
else if (contType.includes('HTML')) {
return this.getDataFromFigure(cont);
}
else if (contType === 'Object') {
return [cont];
}
else if (contType === 'Array') {
return cont.map((k) => getDataFromSingle(k)).flat();
}
}, data = getDataFromSingle(content);
return data.filter((k) => k.media);
}
show(cb) {
if (this.destroyed)
return this;
super.listen({ name: 'show' });
(this.options.mode === 'inline' && this.targetEls[0] ? this.targetEls[0] : document.body).appendChild(this.viewerEl);
this.viewerEl.setAttribute('show', '');
this.shown = true;
super.listen({ name: 'shown', cb });
return this;
}
hide(cb) {
if (this.destroyed || this.options.mode === 'inline')
return this;
super.listen({ name: 'hide' });
this.viewerEl.removeAttribute('show');
this.viewerEl.addEventListener('transitionend', this.hideEvt, false);
for (let k of getEls('video,audio', this.stageEl))
k.pause();
this.shown = false;
super.listen({ name: 'hiddden', cb });
return this;
}
expand(cb) {
if (this.destroyed)
return this;
this.viewerEl.toggleAttribute('expanded', true);
this.toggleMoreAttr('off');
super.listen({ name: 'expanded', cb });
return this;
}
collapse(cb) {
if (this.destroyed)
return this;
this.viewerEl.toggleAttribute('expanded', false);
this.toggleMoreAttr('on');
super.listen({ name: 'expanded', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.viewerEl.removeEventListener('transitionend', this.hideEvt);
if (this.targetEls.length && this.options.mode !== 'inline') {
for (let k of this.targetEls)
k.removeEventListener('click', this.showEvt);
}
if (this.options.tools.enable) {
for (let k of this.options.tools.children)
k.wrapEl.onclick = null;
}
if (this.closeEl) {
this.closeEl.onclick = null;
}
this.stageEl.onclick = null;
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optToast = [
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'placement',
prop: 'placement',
value: 'bottom',
},
{
attr: 'content',
prop: 'content',
value: '',
},
{
attr: 'status',
prop: 'status',
value: 'info',
},
{
attr: 'delay',
prop: 'delay',
value: 3000,
},
{
attr: 'iconized',
prop: 'iconized',
value: false,
},
{
attr: 'eager',
prop: 'eager',
value: false,
},
{
attr: 'feature',
prop: 'feature',
value: '',
},
{
attr: 'z-index',
prop: 'zIndex',
value: 0,
},
{
attr: 'on-shown',
prop: 'onShown',
value: null,
},
{
attr: 'on-hidden',
prop: 'onHidden',
value: null,
},
...optBase
];
class Toast extends ModBaseListen {
options = {};
hideEvt;
template;
shown;
contEl;
static hostType = 'none';
static optMaps = optToast;
constructor(options, initial = true) {
super();
super.ready({
options,
type: Toast.hostType,
maps: Toast.optMaps,
});
this.hideEvt = () => {
!this.shown && this.targetEl.remove();
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch {
console.warn(config.warn.init);
return this;
}
this.shown = false;
this.createSection();
this.setAttrs();
this.options.eager && this.show();
super.listen({ name: 'initiated', cb });
return this;
}
setAttrs() {
this.options.classes && classes(this.targetEl).add(this.options.classes);
this.options.zIndex && (this.targetEl.style.zIndex = this.options.zIndex);
this.options.feature && this.targetEl.setAttribute('feature', this.options.feature);
}
createSection() {
let icon = this.options.iconized ? `<i rep="icon"></i>` : '', template = `
<div class="${ax.prefix}toast" placement="${this.options.placement}" status="${this.options.status}" ${this.options.iconized ? 'iconized' : ''}>
<div rep="wrap">
${icon}<div rep="cont">${this.options.content || this.options.lang.content[this.options.status]}</div>
</div>
</div>
`;
this.targetEl = tplToEl(template);
this.contEl = getEl(`[${ax.alias}="cont"]`, this.targetEl);
this.targetEl.addEventListener('transitionend', this.hideEvt, false);
}
hideOthers() {
if (this.options.zIndex)
return;
let others = instance.findAll('toast').filter((k) => k.shown);
for (let k of others)
k.hide();
}
show(cb) {
if (this.destroyed || this.shown)
return this;
this.hideOthers();
document.body.appendChild(this.targetEl);
this.targetEl.toggleAttribute('show', true);
this.shown = true;
setTimeout(() => {
this.hide();
}, this.options.delay);
super.listen({ name: 'shown', cb });
return this;
}
hide(cb) {
if (this.destroyed || !this.shown)
return this;
this.targetEl.toggleAttribute('show', false);
this.shown = false;
super.listen({ name: 'hidden', cb });
return this;
}
updateCont(content, cb) {
if (this.destroyed)
return this;
this.contEl.innerHTML = content;
this.options.content = content;
super.listen({ name: 'updatedCont', cb, params: [content] });
return this;
}
async update(settings, cb) {
if (this.destroyed)
return this;
this.targetEl.remove();
this.options = extend({ target: this.options, source: settings });
await this.init();
super.listen({ name: 'updated', cb, params: [settings] });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.targetEl.remove();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
const optColor = [
{
attr: 'value',
prop: 'value',
value: '',
},
{
attr: 'layout',
prop: 'layout',
value: 'picker',
},
{
attr: 'classes',
prop: 'classes',
value: '',
},
{
attr: 'popup',
prop: 'popup',
value: {},
},
{
attr: 'canvas',
prop: 'canvas',
value: {
showLabel: true,
showTools: true,
width: 370,
height: 180,
mode: 'hsv',
hue: 0,
},
},
{
attr: 'output',
prop: 'output',
value: {
alpha: true,
mode: 'hsl',
format: 'hsla',
child: '',
manual: true,
},
},
{
attr: 'b4-assign',
prop: 'b4Assign',
value: null,
},
{
attr: 'b4-clear',
prop: 'b4Clear',
value: null,
},
{
attr: 'b4-fill',
prop: 'b4Fill',
value: null,
},
{
attr: 'b4-restore',
prop: 'b4Restore',
value: null,
},
{
attr: 'on-assigned',
prop: 'onAssigned',
value: null,
},
{
attr: 'on-cleared',
prop: 'onCleared',
value: null
},
{
attr: 'on-restored',
prop: 'onRestored',
value: null
},
{
attr: 'on-filled',
prop: 'onFilled',
value: null
},
{
attr: 'on-output',
prop: 'onOutput',
value: null
},
...optBase
];
class RadiosElem extends CompBaseCommField {
labelEl;
legendEl;
inputs;
setVals;
setLabels;
check;
type;
valMap;
constructor() {
super();
this.type = 'radios-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.reset = () => {
if (this.propsRaw.content != this.propsRaw.content)
this.updateInputs(this.propsRaw.content, this.propsRaw);
for (let k in this.propsRaw) {
if (k === 'content')
continue;
(this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
}
this.listen({ name: 'reset' });
};
this.clear = () => {
this.removeAttribute('checked');
this.listen({ name: 'cleared' });
};
this.check = (value, type = 'ed', from = 'value') => {
let val = Array.isArray(value) ? value[0] : value;
if (!val && val !== 0) {
this.setAttribute('checked', '');
return;
}
let input = this.inputs.find((i) => i.propsProxy[from] == val);
if (input) {
if (type === 'ing') {
input.checked && this.setAttribute('checked', '');
input.setAttribute('check', type);
}
else if (type === 'ed') {
this.setAttribute('checked', input.propsProxy.value);
}
else {
input.checked && this.setAttribute('checked', '');
}
}
};
this.propsObs.on('set', (data) => {
data.key === 'value' && (this.valMap = { newVal: data.value, oldVal: data.raw || '' });
});
this.propsObs.on('completed', (data) => {
if (data.keys.set.includes('value')) {
this.updateCache({ check: data.proxy.value });
this.listen({ name: 'changed', params: [this.valMap] });
}
});
}
static dependencies = [{ tag: 'ax-radio', comp: RadioElem }];
static custAttrs = ['size', 'name', 'type', 'layout', 'cols', 'checked', 'disable', 'content', 'wrap-classes', 'item-classes', 'input-classes', 'on-checked', ...this.evtsArr];
static boolAttrs = ['disabled', 'inverted'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, RadiosElem);
}
getRawData() {
this.getRawProps(RadiosElem);
!this.propsRaw.name && (this.propsRaw.name = ax.namePfx + Date.now());
this.propsRaw.content = super.getItemsData();
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
data['wrap-classes'] && classes(this.wrapEl).add(data['wrap-classes']);
if (data.layout === 'grid') {
this.wrapEl.classList.add(`${ax.prefix}grid`);
data.cols && this.wrapEl.classList.add(`${ax.prefix}avg-${data.cols}`);
}
else if (data.layout === 'flex') {
this.wrapEl.classList.add(`${ax.prefix}row`);
}
this.updateInputs(data.content, data);
}
updateInputs(data, host = this.propsProxy) {
this.inputs = [];
this.wrapEl.innerHTML = '';
let tmp = super.getItemsData(data);
for (let k of tmp) {
let parent = createEl('div'), input = createEl('ax-radio', { label: k.label, value: isNull(k.value) ? k.label : k.value, [ax.embedSign]: '' });
host.name ? input.setAttribute('name', host.name) : input.removeAttribute('name');
host.type ? input.setAttribute('type', host.type) : input.removeAttribute('type');
k.checked ? input.setAttribute('check', 'ed') : input.removeAttribute('check');
input.toggleAttribute('disabled', !!k.disabled);
host['input-classes'] && classes(input).add(host['input-classes']);
this.inputs.push(input);
if (host.layout) {
host.layout === 'flex' && parent.classList.add(`${ax.prefix}flex`);
host['item-classes'] && classes(parent).add(host['item-classes']);
parent.appendChild(input);
this.wrapEl.appendChild(parent);
}
else {
this.wrapEl.appendChild(input);
}
input.on('changed', (data) => {
let eds = this.inputs.find((i) => i.propsProxy.check === 'ed');
this.propsProxy.value = eds ? eds.propsProxy.value : '';
this.value = this.propsProxy.value;
data.newVal && this.listen({ name: 'checked', params: [input] });
});
}
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
content: this.changedMultiCont,
disabled: this.changedMultiDisabled,
inverted: this.changedInverted,
name: this.changedMultiName,
type: this.changedMultiName,
size: this.changedMultiName,
checked: this.changedChecked,
disable: this.changedMultiDisable,
};
changedChecked(opt) {
for (let k of this.inputs) {
if (opt.newVal === null) {
k.check('');
}
else {
k.check(k.propsProxy.value === opt.newVal ? 'ed' : '');
}
}
}
changedInverted(opt) {
for (let k of this.inputs) {
k.toggleAttribute('inverted', this.propsProxy.inverted);
}
}
}
class NumberElem extends CompBaseCommField {
labelEl;
tipsEl;
incrEl;
decrEl;
type;
select;
oldVal;
constructor() {
super();
this.type = 'number-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.select = () => this.inputEl.select();
this.oldVal = this.value = '';
this.on('input', (value) => {
let step = parseFloat(this.propsProxy.step) || 1, val = parseFloat(value), max = parseFloat(this.propsProxy.max), min = parseFloat(this.propsProxy.min);
if (!isNull(this.propsProxy.max)) {
if (val + step > max) {
this.incrEl.toggleAttribute('disabled', true);
}
else {
this.incrEl.removeAttribute('disabled');
}
}
if (!isNull(this.propsProxy.min)) {
if (val - step < min) {
this.decrEl.toggleAttribute('disabled', true);
}
else {
this.decrEl.removeAttribute('disabled');
}
}
});
}
static custAttrs = ['name', 'placeholder', 'layout', 'size', 'max', 'min', 'step', 'label', 'attrs', 'on-exceeded', ...this.evtsArr];
static boolAttrs = ['tips', 'disabled', 'readonly', 'full'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, NumberElem);
if (oldVal !== newVal) {
this.listen({ name: 'changed', params: [{ oldVal, newVal }] });
}
}
getRawData() {
this.getRawProps(NumberElem);
this.propsRaw.value = parseFloat(this.getAttribute('value') || this.getConnCont('text'));
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.inputEl = createEl('input', { type: 'number', name: data.name, placeholder: data.placeholder || config.lang.form.placeholder, [ax.embedSign]: '' });
(data.value || data.value == 0) && (this.inputEl.value = data.value);
this.decrEl = createEl('i', { [ax.alias]: 'decrease' }, 'minus');
this.incrEl = createEl('i', { [ax.alias]: 'increase' }, 'plus');
this.labelEl = createEl('span', { [ax.alias]: 'label' });
this.wrapEl.append(this.decrEl, this.inputEl, this.incrEl);
this.tipsEl = createEl('div', { [ax.alias]: 'tips' });
}
updateTips() {
let val = parseFloat(this.value);
if (isNaN(val))
return;
let max = isNull(this.propsProxy.max) ? '+∞' : parseFloat(this.propsProxy.max), min = isNull(this.propsProxy.min) ? '-∞' : parseFloat(this.propsProxy.min), old = this.oldVal === '' ? '' : parseFloat(this.oldVal), str = '';
if (max === '+∞' && min === '-∞') {
return this;
}
if (max !== '+∞' && min !== '-∞') {
str = renderTpl(this.propsProxy.lang?.limit || config.lang.form.limitNumber, { max, min });
if (val >= min && val <= max) {
this.removeAttribute('exceeded');
}
else {
this.setAttribute('exceeded', '');
str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
val = (val < min) ? min : (val > max) ? max : val;
this.listen({ name: 'exceeded', params: [val, old] });
}
}
else if (max !== '+∞') {
str = renderTpl(this.propsProxy.lang?.max || config.lang.form.maxNumber, { max });
if (val > max) {
val = max;
this.setAttribute('exceeded', '');
str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
this.listen({ name: 'exceeded', params: [val, old] });
}
else {
this.removeAttribute('exceeded');
}
}
else if (min !== '-∞') {
str = renderTpl(this.propsProxy.lang?.min || config.lang.form.minNumber, { min });
if (val < min) {
val = min;
this.setAttribute('exceeded', '');
str += (this.propsProxy.lang?.exceed || config.lang.form.exceed);
this.listen({ name: 'exceeded', params: [val, old] });
}
else {
this.removeAttribute('exceeded');
}
}
if (val !== old) {
this.setAttribute('value', val + '');
}
this.tipsEl.innerHTML = str;
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
(this.propsProxy.tips && (this.propsProxy.max || this.propsProxy.min) && elState(this.tipsEl).isVirtual) ? this.appendChild(this.tipsEl) : null;
let inputEvt = new Event('input', { bubbles: true });
this.decrEl.onclick = () => {
this.inputEl.stepDown();
this.inputEl.dispatchEvent(inputEvt);
};
this.incrEl.onclick = () => {
this.inputEl.stepUp();
this.inputEl.dispatchEvent(inputEvt);
};
this.inputEl.addEventListener('input', debounce((e) => {
this.setBtnDisabled();
if (this.propsProxy.value == this.inputEl.value)
return;
this.value = this.inputEl.value;
this.updateTips();
this.oldVal = this.value;
this.listen({ name: 'input', params: [this.inputEl.value] });
}), false);
this.setBtnDisabled();
}
setBtnDisabled(value = this.inputEl.value) {
let tmp = parseFloat(value);
if (isNaN(tmp))
return;
this.decrEl.toggleAttribute('disabled', this.propsProxy.min && tmp <= parseFloat(this.propsProxy.min) ? true : false);
this.incrEl.toggleAttribute('disabled', this.propsProxy.max && tmp >= parseFloat(this.propsProxy.max) ? true : false);
}
changedMaps = {
disabled: this.changedBool,
readonly: this.changedBool,
blocked: this.changedBool,
tips: this.changedBool,
name: this.changedName,
placeholder: this.changedName,
value: this.changedValue,
min: this.changedValue,
max: this.changedValue,
step: this.changedValue,
label: this.changedLabel,
attrs: this.changedAttrs,
};
changedBool(opt) {
this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
if (opt.name === 'tips') {
if (this.propsProxy.tips) {
elState(this.tipsEl).isVirtual && this.appendChild(this.tipsEl);
}
else {
this.tipsEl.remove();
}
}
}
changedValue(opt) {
this.inputEl[opt.name] = opt.newVal;
if (opt.name === 'value') {
this.inputEl.dispatchEvent(new Event('input'));
}
['min', 'max'].includes(opt.name) && this.updateTips();
}
changedName(opt) {
this.inputEl.setAttribute(opt.name, opt.newVal);
opt.name === 'name' && (this.name = opt.newVal);
}
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal;
elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
this.setAttribute('layout', 'embed');
}
else {
this.labelEl.remove();
}
}
}
class Color extends ModBaseListenCache {
spaceEl;
outputEl;
toolsEl;
canvasEl;
canvasModeEl;
randomEl;
previewEl;
hRangeEl;
aRangeEl;
alphaEl;
strawEl;
restoreEl;
clearEl;
confirmEl;
copyEl;
indEl;
valueEl;
changeEl;
hexEl;
hexaEl;
rgbrEl;
rgbgEl;
rgbbEl;
rgbaEl;
hslhEl;
hslsEl;
hsllEl;
hslaEl;
hwbhEl;
hwbwEl;
hwbbEl;
hwbaEl;
wrapEl;
schemeEl;
pickerEl;
paletteEl;
outputHexEl;
outputRgbEl;
outputHwbEl;
outputHslEl;
outputBodyEl;
axisyEl;
canvasCtx;
curColors;
indCoord;
gestureIns;
canvasRect;
previewChildEl;
canvasMode;
canvasHue;
hRangeEvt;
aRangeEvt;
alphaEvt;
modeEvt;
showAlpha;
outputMode;
outputMap;
changeEvt;
randomEvt;
canvasWidth;
canvasHeight;
copyEvt;
previewEvt;
colorEvt;
coloraEvt;
colorhEvt;
eyeDropper;
strawEvt;
stopOutput;
themeColorsEl;
themeWrapEl;
historyColorsEl;
historyWrapEl;
presets1El;
presets2El;
colorEl;
popupIns;
fillEl;
value;
dialogEl;
static hostType = 'node';
static optMaps = optColor;
static dependencies = [RadiosElem, InputElem, NumberElem, BtnElem, CheckboxElem];
constructor(elem, options = {}, initial = true) {
super();
super.ready({
options,
host: elem,
maps: Color.optMaps,
component: true,
spread: ['output', 'arrow', 'check', 'lamp', 'tools', 'drag']
});
this.curColors = { rgb: { r: 255, g: 0, b: 0 }, hwb: { h: 0, w: 0, b: 0 }, hsl: { h: 0, s: 100, l: 50 }, hex: '#ff0000', a: 1, a16: 'ff' };
this.indCoord = { x: 0, y: 0 };
this.hRangeEvt = (e) => {
this.canvasHue = this.curColors.hsl.h = this.curColors.hwb.h = parseFloat(e.target.value);
this.curColors.rgb = hsl2Rgb(this.curColors.hsl, false);
this.curColors.hex = rgb2Hex(this.curColors.rgb, false);
this.updateReverse();
this.updatePreviewOutput();
};
this.aRangeEvt = (e) => {
this.curColors.a = parseFloat(e.target.value);
this.curColors.a16 = alpha2Hex(this.curColors.a);
this.updatePreviewOutput();
};
this.modeEvt = debounce((data) => {
this.canvasMode = data.newVal;
this.drawCanvas();
this.setAxisLabel();
});
this.alphaEvt = debounce((data) => {
this.showAlpha = data.newVal;
this.aRangeEl.toggleAttribute('disabled', !data.newVal);
this.hexaEl.toggleAttribute('disabled', !data.newVal);
this.rgbaEl.toggleAttribute('disabled', !data.newVal);
this.hslaEl.toggleAttribute('disabled', !data.newVal);
this.hwbaEl.toggleAttribute('disabled', !data.newVal);
this.updatePreviewOutput();
});
this.changeEvt = debounce(() => {
this.toggleOutputAct();
});
this.randomEvt = debounce(() => {
this.canvasRect = this.canvasEl.getBoundingClientRect();
this.setValFromCanvas({ x: Math.random() * this.canvasWidth, y: Math.random() * this.canvasHeight });
});
this.copyEvt = debounce(() => {
navigator.clipboard.writeText(this.valueEl.textContent).then(() => new Toast({ content: this.options.lang.message.copy, status: 'succ', eager: true }));
});
this.previewEvt = debounce(() => {
navigator.clipboard.writeText(this.previewChildEl.style.backgroundColor).then(() => new Toast({ content: this.options.lang.message.copy, status: 'succ', eager: true }));
});
let _this = this;
this.colorEvt = debounce(function (e) {
_this.stopOutput = true;
let value = {};
if (this === _this.hexEl) {
if (e.target.value.length !== 7)
return;
value.hex = e.target.value;
}
else {
let tmp = parseFloat(e.target.value);
if (isNaN(tmp))
return;
if (this === _this.rgbrEl) {
value = { ..._this.curColors.rgb };
value.r = tmp;
}
else if (this === _this.rgbgEl) {
value = { ..._this.curColors.rgb };
value.g = tmp;
}
else if (this === _this.rgbbEl) {
value = { ..._this.curColors.rgb };
value.b = tmp;
}
else if (this === _this.hslsEl) {
value = { ..._this.curColors.hsl };
value.s = tmp;
}
else if (this === _this.hsllEl) {
value = { ..._this.curColors.hsl };
value.l = tmp;
}
else if (this === _this.hwbwEl) {
value = { ..._this.curColors.hwb };
value.w = tmp;
}
else if (this === _this.hwbbEl) {
value = { ..._this.curColors.hwb };
value.b = tmp;
}
}
value.a = _this.curColors.a;
_this.assignVals(value);
_this.stopOutput = false;
}, 500);
this.coloraEvt = debounce((e) => {
_this.stopOutput = true;
let tmp = parseFloat(e.target.value);
if (isNaN(tmp))
return;
let value = this.outputMode === 'hex' ? { hex: this.curColors[this.outputMode] } : { ...this.curColors[this.outputMode] };
value.a = tmp;
this.assignVals(value);
_this.stopOutput = false;
}, 500);
this.colorhEvt = debounce((e) => {
_this.stopOutput = true;
let tmp = parseFloat(e.target.value);
if (isNaN(tmp))
return;
let value = { ...this.curColors[this.outputMode] };
value.a = this.curColors.a;
value.h = tmp;
this.assignVals(value);
_this.stopOutput = false;
}, 500);
this.strawEvt = async () => {
try {
let result = await this.eyeDropper.open(), hex = result.sRGBHex;
this.assignVals(hex);
}
catch { }
};
super.listen({ name: 'constructed' });
initial && this.init();
}
async init(cb) {
super.listen({ name: 'initiate' });
try {
this.options.b4Init && await this.options.b4Init.call(this);
}
catch (err) {
err ? console.error(err) : console.warn(config.warn.init);
return this;
}
!['picker', 'full'].includes(this.options.layout) && (this.options.output.manual = false);
this.canvasMode = this.options.canvas.mode;
this.canvasHue = this.options.canvas.hue;
this.showAlpha = this.options.output.alpha;
this.outputMode = this.options.output.mode;
this.canvasWidth = toPixel(ax.screen === 'xxs' ? 300 : this.options.canvas.width);
this.canvasHeight = toPixel(ax.screen === 'xxs' ? 150 : this.options.canvas.height);
this.fillEl = getEl(this.options.fillEl, this.targetEl) || this.targetEl;
this.setAttrs();
this.createPanel();
this.drawCanvas();
this.setGesture();
this.setPopup();
this.canvasModeEl.on('changed', this.modeEvt);
this.alphaEl.on('changed', this.alphaEvt);
this.hRangeEl.addEventListener('input', this.hRangeEvt, false);
this.aRangeEl.addEventListener('input', this.aRangeEvt, false);
this.changeEl.addEventListener('click', this.changeEvt, false);
this.randomEl.addEventListener('click', this.randomEvt, false);
this.hexEl.addEventListener('input', this.colorEvt, false);
this.rgbrEl.addEventListener('input', this.colorEvt, false);
this.rgbgEl.addEventListener('input', this.colorEvt, false);
this.rgbbEl.addEventListener('input', this.colorEvt, false);
this.hslsEl.addEventListener('input', this.colorEvt, false);
this.hsllEl.addEventListener('input', this.colorEvt, false);
this.hwbwEl.addEventListener('input', this.colorEvt, false);
this.hwbbEl.addEventListener('input', this.colorEvt, false);
this.hexaEl.addEventListener('input', this.coloraEvt, false);
this.rgbaEl.addEventListener('input', this.coloraEvt, false);
this.hslaEl.addEventListener('input', this.coloraEvt, false);
this.hwbaEl.addEventListener('input', this.coloraEvt, false);
this.hwbhEl.addEventListener('input', this.colorhEvt, false);
this.hslhEl.addEventListener('input', this.colorhEvt, false);
this.copyEl.addEventListener('click', this.copyEvt, false);
this.previewEl.addEventListener('click', this.previewEvt, false);
this.eyeDropper = new window.EyeDropper();
this.strawEl.onclick = async () => {
try {
let result = await this.eyeDropper.open(), hex = result.sRGBHex;
this.assignVals(hex);
}
catch { }
};
this.restoreEl.onclick = () => {
this.restoreVals();
};
this.confirmEl.onclick = () => {
!this.value ? this.popupIns.hide() : this.fillVals();
};
this.clearEl.onclick = () => {
this.clearVals();
};
this.initVals();
super.listen({ name: 'initiated', cb });
return this;
}
updateReverse() {
this.canvasHue = this.curColors.hsl.h;
this.drawCanvas();
this.updateHueSlider();
this.updateAlphaSlider();
}
setAttrs() {
this.options.classes && this.colorEl && classes(this.colorEl).add(this.options.classes);
}
toggleOutputAct() {
let keys = Object.keys(this.outputMap), curKey = keys.find(key => this.outputMap[key].active), curIdx = keys.indexOf(curKey), nextIdx = (curIdx + 1) % keys.length;
for (let k in this.outputMap) {
if (keys[nextIdx] === k) {
this.outputMode = k;
this.outputBodyEl.innerHTML = '';
this.outputBodyEl.appendChild(this.outputMap[k].el);
this.setOutputStr();
this.setOutputVals();
}
this.outputMap[k].active = keys[nextIdx] === k ? true : false;
}
}
updateHueSlider() {
this.colorEl.style.setProperty(`--${ax.prefix}color-thumb`, `hsl(${this.curColors.hsl.h}, 100%, 50%)`);
}
updateAlphaSlider() {
this.colorEl.style.setProperty(`--${ax.prefix}color-from`, `hsla(${this.curColors.hsl.h}, 100%, 50%,0)`);
this.colorEl.style.setProperty(`--${ax.prefix}color-to`, `hsla(${this.curColors.hsl.h}, 100%, 50%,1)`);
}
drawCanvas(hue = this.canvasHue, mode = this.canvasMode) {
this.canvasCtx = drawColor({
el: this.canvasEl,
width: this.canvasWidth,
height: this.canvasHeight,
hue,
mode,
});
}
getColorFromCanvas(x, y) {
let pixel = this.canvasCtx.getImageData(x, y, 1, 1).data;
return {
r: pixel[0],
g: pixel[1],
b: pixel[2]
};
}
canvasInteraction(data) {
let x = data.x, y = data.y, boundedX = Math.max(0, Math.min(x, this.canvasEl.width - 1)), boundedY = Math.max(0, Math.min(y, this.canvasEl.height - 1)), rgb = this.getColorFromCanvas(boundedX, boundedY), hex = rgb2Hex(rgb, false), hsl = rgb2Hsl(rgb, false), hwb = rgb2Hwb(rgb, false), isInverted = (rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114) > 150 ? true : false;
if (rgb.r === rgb.g && rgb.g === rgb.b) {
hsl.h = hwb.h = this.curColors.hsl.h;
}
this.curColors.rgb = rgb;
this.curColors.hex = hex;
this.curColors.hsl = hsl;
this.curColors.hwb = hwb;
this.indEl.toggleAttribute('inverted', isInverted);
this.updatePreviewOutput();
}
updatePreview() {
this.previewChildEl.style.backgroundColor = this.valueEl.textContent;
}
updatePreviewOutput() {
this.setOutputStr();
this.setOutputVals();
this.updatePreview();
}
setOutputStr(mode = this.outputMode) {
let val, a, result;
if (mode === 'hex') {
val = this.curColors[mode];
a = this.curColors.a16;
result = `${val}${this.showAlpha ? a : ''}`;
}
else {
let tmp = deepClone(this.curColors[mode]);
if (mode !== 'rgb') {
tmp.hasOwnProperty('s') && (tmp.s += '%');
tmp.hasOwnProperty('l') && (tmp.l += '%');
tmp.hasOwnProperty('w') && (tmp.w += '%');
tmp.hasOwnProperty('b') && (tmp.b += '%');
}
val = Object.values(tmp).join(',');
a = this.curColors.a;
result = `${mode}${this.showAlpha ? 'a' : ''}(${val}${this.showAlpha ? ',' + a : ''})`;
}
this.valueEl.innerHTML = result;
this.value = this.getVals();
if (!this.options.output.manual)
this.fillVals();
super.listen({ name: 'output', params: [this.value] });
}
setOutputVals() {
for (let k in this.outputMap[this.outputMode].children) {
let item = this.outputMap[this.outputMode].children[k];
item.setAttribute('value', k === 'a' ? this.curColors.a : this.outputMode === 'hex' ? this.curColors[this.outputMode] : this.curColors[this.outputMode][k]);
}
}
setPopup() {
this.popupIns && this.popupIns.destroy();
let opts = deepMerge({
content: this.colorEl,
footer: false,
padding: false,
tools: false,
trigger: 'click',
size: '',
adaptive: false,
canClose: (target) => {
return this.dialogEl && this.dialogEl.contains(target) ? false : true;
},
}, this.options.popup);
this.popupIns = new Popup(this.targetEl, opts);
}
createPanel() {
this.wrapEl = createEl('div', { class: `${ax.prefix}color-wrap` });
this.colorEl = createEl('div', { class: `${ax.prefix}color` }, this.wrapEl);
this.pickerEl = createEl('div', { class: `${ax.prefix}color-picker`, style: `width:${this.canvasWidth}px` });
this.schemeEl = createEl('div', { class: `${ax.prefix}color-scheme` });
this.paletteEl = createEl('div', { class: `${ax.prefix}color-palette` }, `
<div class="${ax.prefix}color-presets">
<div class="${ax.prefix}color-regular">
<div ${ax.alias}="body">
<ul class="${ax.prefix}color-preset-1 ${ax.prefix}grid ${ax.prefix}g-xs ${ax.prefix}avg-10">
</ul>
</div>
</div>
<ax-br></ax-br>
<ul class="${ax.prefix}color-preset-2 ${ax.prefix}reset ${ax.prefix}grid ${ax.prefix}g-sm"></ul>
</div>
`);
this.presets1El = getEl(`.${ax.prefix}color-preset-1`, this.paletteEl);
this.presets2El = getEl(`.${ax.prefix}color-preset-2`, this.paletteEl);
this.presets1El.appendChild(this.getRegularPresets());
this.presets2El.append(this.getThemePresets(), this.getHistoryPresets());
if (this.options.layout === 'picker') {
this.wrapEl.append(this.pickerEl);
}
else if (this.options.layout === 'palette') {
this.wrapEl.append(this.paletteEl);
}
else if (this.options.layout === 'scheme') {
this.wrapEl.append(this.schemeEl);
}
else {
this.wrapEl.append(this.pickerEl, this.paletteEl);
}
let labelX = this.options.canvas.showLabel ? `<div class="${ax.prefix}color-canvas-x">${this.options.lang.label.s}</div>` : '', labelY = this.options.canvas.showLabel ? `<div class="${ax.prefix}color-canvas-y">${this.options.canvas.mode === 'hsv' ? this.options.lang.label.v : this.options.lang.label.h}</div>` : '', spaceTools = this.options.canvas.showTools ? `
<div class="${ax.prefix}color-mode">
<div class="${ax.prefix}flex">
<ax-radios content="[{label:'${this.options.lang.label.hsv}',value:'hsv'},{label:'${this.options.lang.label.hsl}',value:'hsl'}]" checked="${this.options.canvas.mode}"></ax-radios>
</div>
<span ${ax.alias}="random" title="${this.options.lang.btn.random}"><i class="${ax.prefix}icon-random"></i></span>
<span ${ax.alias}="straw" title="${this.options.lang.btn.straw}"><i class="${ax.prefix}icon-straw"></i></span>
</div>` : '', spaceControl = `
<div class="${ax.prefix}color-control">
<span class="${ax.prefix}color-preview"><i></i><s>${this.options.lang.btn.copy}</s></span>
<div class="${ax.prefix}color-sliders">
<div class="${ax.prefix}color-slider" title="${this.options.lang.label.h}">
<input type="range" class="${ax.prefix}color-hue" min="0" max="360" value="0" step="1">
</div>
<div class="${ax.prefix}color-break"></div>
<div class="${ax.prefix}color-slider" title="${this.options.lang.label.a}">
<input type="range" class="${ax.prefix}color-alpha" min="0" max="1" value="1" step="0.01" ${!this.showAlpha ? 'disabled' : ''}>
</div>
</div>
</div>
`;
this.spaceEl = createEl('div', { class: `${ax.prefix}color-space` }, `
<div class="${ax.prefix}color-canvas">
<canvas></canvas>
<i class="${ax.prefix}color-canvas-ind"></i>
${labelX}
${labelY}
</div>
${spaceTools}
<ax-br></ax-br>
${spaceControl}
`);
this.canvasEl = getEl(`canvas`, this.spaceEl);
this.indEl = getEl(`.${ax.prefix}color-canvas-ind`, this.spaceEl);
this.canvasModeEl = getEl(`AX-RADIOS`, this.spaceEl);
this.randomEl = getEl(`[${ax.alias}="random"]`, this.spaceEl);
this.strawEl = getEl(`[${ax.alias}="straw"]`, this.spaceEl);
this.previewEl = getEl(`.${ax.prefix}color-preview`, this.spaceEl);
this.previewChildEl = getEl(`i`, this.previewEl);
this.hRangeEl = getEl(`.${ax.prefix}color-hue`, this.spaceEl);
this.aRangeEl = getEl(`.${ax.prefix}color-alpha`, this.spaceEl);
this.axisyEl = getEl(`.${ax.prefix}color-canvas-y`, this.spaceEl);
this.outputEl = createEl('div', { class: `${ax.prefix}color-output` }, `
<div class="${ax.prefix}color-output-head">
<div class="${ax.prefix}flex">
<span ${ax.alias}="value">-</span><span ${ax.alias}="copy" class="${ax.prefix}icon-copy" title="${this.options.lang.btn.copy}"></span>
</div>
<span ${ax.alias}="change" title="${this.options.lang.btn.change}"><i class="${ax.prefix}icon-change"></i></span>
</div>
<div class="${ax.prefix}color-output-body"></div>
`);
this.outputBodyEl = getEl(`.${ax.prefix}color-output-body`, this.outputEl);
this.valueEl = getEl(`[${ax.alias}="value"]`, this.outputEl);
this.copyEl = getEl(`[${ax.alias}="copy"]`, this.outputEl);
this.changeEl = getEl(`[${ax.alias}="change"]`, this.outputEl);
this.outputHexEl = createEl('div', { class: `${ax.prefix}row ${ax.prefix}g-xs` }, `
<div class="${ax.prefix}flex">
<ax-input size="sm" full>${this.curColors.hex}</ax-input>
<div ${ax.alias}="label">HEX (000000~ffffff)</div>
</div>
<div style="width:fit-content">
<ax-number size="sm" step="0.01" min="0" max="1" full layout="embed" ${!this.showAlpha ? 'disabled' : ''}>${this.curColors.a}</ax-number>
<div ${ax.alias}="label">A (0~1)</div>
</div>
`);
this.hexEl = getEl('AX-INPUT', this.outputHexEl);
this.hexaEl = getEl('AX-NUMBER', this.outputHexEl);
this.outputRgbEl = createEl('ul', { class: `${ax.prefix}grid ${ax.prefix}avg-4 ${ax.prefix}xxs-2 ${ax.prefix}g-xs` }, `
<li>
<ax-number size="sm" step="1" min="0" max="255" full layout="embed">${this.curColors.rgb.r}</ax-number>
<div ${ax.alias}="label">R (0~255)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="255" full layout="embed">${this.curColors.rgb.g}</ax-number>
<div ${ax.alias}="label">G (0~255)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="255" full layout="embed">${this.curColors.rgb.b}</ax-number>
<div ${ax.alias}="label">B (0~255)</div>
</li>
<li>
<ax-number size="sm" step="0.01" min="0" max="1" full layout="embed" ${!this.showAlpha ? 'disabled' : ''}>${this.curColors.a}</ax-number>
<div ${ax.alias}="label">A (0~1)</div>
</li>
`);
this.rgbrEl = getEls('AX-NUMBER', this.outputRgbEl)[0];
this.rgbgEl = getEls('AX-NUMBER', this.outputRgbEl)[1];
this.rgbbEl = getEls('AX-NUMBER', this.outputRgbEl)[2];
this.rgbaEl = getEls('AX-NUMBER', this.outputRgbEl)[3];
this.outputHwbEl = createEl('ul', { class: `${ax.prefix}grid ${ax.prefix}avg-4 ${ax.prefix}xxs-2 ${ax.prefix}g-xs` }, `
<li>
<ax-number size="sm" step="1" min="0" max="360" value="0" full layout="embed">${this.curColors.hwb.h}</ax-number>
<div ${ax.alias}="label">H (0~360°)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="100" full layout="embed">${this.curColors.hwb.w}</ax-number>
<div ${ax.alias}="label">W (0~100%)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="100" full layout="embed">${this.curColors.hwb.b}</ax-number>
<div ${ax.alias}="label">B (0~100%)</div>
</li>
<li>
<ax-number size="sm" step="0.01" min="0" max="1" full layout="embed" ${!this.showAlpha ? 'disabled' : ''}>${this.curColors.a}</ax-number>
<div ${ax.alias}="label">A (0~1)</div>
</li>
`);
this.hwbhEl = getEls('AX-NUMBER', this.outputHwbEl)[0];
this.hwbwEl = getEls('AX-NUMBER', this.outputHwbEl)[1];
this.hwbbEl = getEls('AX-NUMBER', this.outputHwbEl)[2];
this.hwbaEl = getEls('AX-NUMBER', this.outputHwbEl)[3];
this.outputHslEl = createEl('ul', { class: `${ax.prefix}grid ${ax.prefix}avg-4 ${ax.prefix}xxs-2 ${ax.prefix}g-xs` }, `
<li>
<ax-number size="sm" step="1" min="0" max="360" full layout="embed">${this.curColors.hsl.h}</ax-number>
<div ${ax.alias}="label">H (0~360°)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="100" full layout="embed">${this.curColors.hsl.s}</ax-number>
<div ${ax.alias}="label">S (0~100%)</div>
</li>
<li>
<ax-number size="sm" step="1" min="0" max="100" full layout="embed">${this.curColors.hsl.l}</ax-number>
<div ${ax.alias}="label">L (0~100%)</div>
</li>
<li>
<ax-number size="sm" step="0.01" min="0" max="1" full layout="embed" ${!this.showAlpha ? 'disabled' : ''}>${this.curColors.a}</ax-number>
<div ${ax.alias}="label">A (0~1)</div>
</li>
`);
this.hslhEl = getEls('AX-NUMBER', this.outputHslEl)[0];
this.hslsEl = getEls('AX-NUMBER', this.outputHslEl)[1];
this.hsllEl = getEls('AX-NUMBER', this.outputHslEl)[2];
this.hslaEl = getEls('AX-NUMBER', this.outputHslEl)[3];
this.outputMap = {
hsl: {
el: this.outputHslEl,
active: this.outputMode === 'hsl',
children: {
h: this.hslhEl,
s: this.hslsEl,
l: this.hsllEl,
a: this.hslaEl,
}
},
hwb: {
el: this.outputHwbEl,
active: this.outputMode === 'hwb',
children: {
h: this.hwbhEl,
w: this.hwbwEl,
b: this.hwbbEl,
a: this.hwbaEl,
}
},
rgb: {
el: this.outputRgbEl,
active: this.outputMode === 'rgb',
children: {
r: this.rgbrEl,
g: this.rgbgEl,
b: this.rgbbEl,
a: this.rgbaEl,
}
},
hex: {
el: this.outputHexEl,
active: this.outputMode === 'hex',
children: {
hex: this.hexEl,
a: this.hexaEl,
}
},
};
this.outputBodyEl.appendChild(this.outputMap[this.outputMode].el);
this.toolsEl = createEl('div', { class: `${ax.prefix}color-tools` }, `
<div class="${ax.prefix}flex"><ax-checkbox check="ed">${this.options.lang.label.a}</ax-checkbox></div>
<ax-btn ${ax.alias}="restore" size="sm" type="plain">${this.options.lang.btn.restore}</ax-btn>
<ax-btn ${ax.alias}="clear" size="sm" type="plain">${this.options.lang.btn.clear}</ax-btn>
`);
this.alphaEl = getEl(`AX-CHECKBOX`, this.toolsEl);
this.clearEl = getEl(`[${ax.alias}="clear"]`, this.toolsEl);
this.restoreEl = getEl(`[${ax.alias}="restore"]`, this.toolsEl);
this.confirmEl = createEl('ax-btn', { [ax.alias]: 'confirm', size: 'sm', theme: 'prim', label: this.options.lang.btn.confirm });
this.options.output.manual && this.toolsEl.appendChild(this.confirmEl);
this.pickerEl.appendChild(this.spaceEl);
this.pickerEl.appendChild(this.outputEl);
this.pickerEl.appendChild(this.toolsEl);
}
getThemePresets() {
this.themeColorsEl = createEl('li', '', `<div ${ax.alias}="head">${this.options.lang.theme}</div><div ${ax.alias}="body"><ul class="${ax.prefix}grid ${ax.prefix}g-xs ${ax.prefix}avg-10"></ul></div>`);
this.themeWrapEl = getEl('ul', this.themeColorsEl);
let arrSuffix = ['', '-dp', '-tl', '-fg', '-ht', '-aj', '-sd', '-fc', '-bd', '-bs'], arrTheme = ['prim', 'error', 'succ', 'issue', 'info', 'warn', 'text'], fragment = document.createDocumentFragment();
for (let k of arrTheme) {
for (let i of arrSuffix) {
let color = `var(--${ax.prefix}c-${k}${i})`, grid = this.createColorGrid(color);
i === '-bs' && grid.toggleAttribute('bordered', true);
fragment.appendChild(grid);
}
}
this.themeWrapEl.appendChild(fragment);
return this.themeColorsEl;
}
getHistoryPresets() {
this.historyColorsEl = createEl('li', '', `<div ${ax.alias}="head">${this.options.lang.history}</div><div ${ax.alias}="body"><ul class="${ax.prefix}grid ${ax.prefix}g-xs ${ax.prefix}avg-10"></ul></div>`);
this.historyWrapEl = getEl('ul', this.historyColorsEl);
return this.historyColorsEl;
}
addHistory(color) {
let grid = this.createColorGrid(color);
this.historyWrapEl.insertAdjacentElement('afterbegin', grid);
let children = this.historyWrapEl.children;
Array.from(children).slice(10).forEach((k) => k.remove());
}
storColor(color) {
let tmp = storage.get(ax.colorStor);
if (!tmp)
tmp = [];
tmp.unshift(color);
storage.set(ax.colorStor, tmp);
}
getRegularPresets() {
let fragment = document.createDocumentFragment(), addCustom = createEl('li', { title: this.options.lang.btn.add, class: `${ax.prefix}color-add`, bordered: '' }, `<i class="${ax.prefix}icon-plus"></i>`);
['picker', 'full'].includes(this.options.layout) && fragment.appendChild(addCustom);
addCustom.onclick = debounce(() => {
let color = this.value, grid = this.createColorGrid(color);
ax.confirm({
heading: this.options.lang.add.heading,
content: `${renderTpl(this.options.lang.add.content, { value: color })}<ax-br></ax-br><div class="${ax.prefix}h-2 ${ax.prefix}r" style="background-color:${color}"></div>`,
dialog: {
zIndex: 881,
},
init: (dialog) => {
this.dialogEl = dialog.mainEl;
},
yes: () => {
addCustom.insertAdjacentElement('afterend', grid);
this.storColor(color);
}
});
});
let storColor = storage.get(ax.colorStor), colors = storColor ? [...storColor, ...ax.swatches] : ax.swatches;
for (let k of colors) {
let grid = this.createColorGrid(k);
k === '#ffffff' && grid.toggleAttribute('bordered', true);
fragment.appendChild(grid);
}
return fragment;
}
createColorGrid(color) {
let tmp = createEl('li', { title: color }, `<i style="background-color:${color}"></i>`);
tmp.onclick = () => {
this.assignVals(style(tmp.querySelector('i')).backgroundColor);
};
return tmp;
}
setAxisLabel(mode = this.canvasMode) {
this.axisyEl.innerHTML = mode === 'hsv' ? this.options.lang.label.v : this.options.lang.label.l;
}
getIndCoord(data) {
let x = Math.max(0, Math.min(data.x, this.canvasEl.width - 1)), y = Math.max(0, Math.min(data.y, this.canvasEl.height - 1));
return { x, y };
}
updateIndCoord() {
this.indEl.style.left = `${this.indCoord.x}px`;
this.indEl.style.top = `${this.indCoord.y}px`;
}
getCanvasPos(coord) {
return {
x: coord.x - this.canvasRect.left,
y: coord.y - this.canvasRect.top,
};
}
setValFromCanvas(data) {
this.canvasInteraction(data);
this.indCoord = this.getIndCoord(data);
this.updateIndCoord();
}
setGesture() {
this.gestureIns = new ax.Gesture(this.canvasEl, {
onTranslate: (data) => {
this.canvasRect = this.canvasEl.getBoundingClientRect();
this.setValFromCanvas(this.getCanvasPos(data.coord));
},
onTranslating: (data) => {
this.setValFromCanvas(this.getCanvasPos(data.coord));
},
onTranslated: (data) => {
}
});
}
parseVals(value = this.options.value) {
let result = {
rgb: {
r: 0,
g: 0,
b: 0,
},
hwb: {
h: 0,
w: 0,
b: 0,
},
hsl: {
h: 0,
s: 0,
l: 0,
},
hex: '#ffffff',
a: 1,
a16: 'ff'
};
if (typeof value === 'string') {
let rgba = value.startsWith('#') ? hex2Rgb(value) :
value.startsWith('rgb') ? parseRgb(value) :
value.startsWith('hsl') ? hsl2Rgb(value) :
value.startsWith('hwb') ? hwb2Rgb(value) : { r: 0, g: 0, b: 0, a: 1 };
result.rgb = { r: rgba.r, g: rgba.g, b: rgba.b };
result.a = rgba.a;
result.a16 = alpha2Hex(rgba.a);
result.hwb = rgb2Hwb(result.rgb, false);
result.hsl = rgb2Hsl(result.rgb, false);
result.hex = rgb2Hex(result.rgb, false);
}
else {
if (value.hasOwnProperty('hex')) {
result.hex = value.hex.trim().slice(0, 7);
if (typeof value.a === 'number') {
result.a = value.a;
result.a16 = alpha2Hex(result.a);
}
else {
result.a16 = value.a;
result.a = hex2Alpha(result.a16);
}
result.rgb = hex2Rgb(value, false);
result.hwb = rgb2Hwb(result.rgb, false);
result.hsl = rgb2Hsl(result.rgb, false);
}
else if (value.hasOwnProperty('r')) {
result.rgb = { r: value.r, g: value.g, b: value.b };
result.a = value.hasOwnProperty('a') ? value.a : 1;
result.a16 = alpha2Hex(result.a);
result.hwb = rgb2Hwb(result.rgb, false);
result.hsl = rgb2Hsl(result.rgb, false);
result.hex = rgb2Hex(result.rgb, false);
}
else if (value.hasOwnProperty('l')) {
result.hsl = { h: value.h, s: value.s, l: value.l };
result.hwb = hsl2Hwb(result.hsl, false);
result.a = value.hasOwnProperty('a') ? value.a : 1;
result.a16 = alpha2Hex(result.a);
result.rgb = hsl2Rgb(result.hsl, false);
result.hex = rgb2Hex(result.rgb, false);
}
else if (value.hasOwnProperty('w')) {
result.hwb = { h: value.h, w: value.w, b: value.b };
result.hsl = hwb2Hsl(result.hwb, false);
result.a = value.hasOwnProperty('a') ? value.a : 1;
result.a16 = alpha2Hex(result.a);
result.rgb = hwb2Rgb(result.hwb, false);
result.hex = rgb2Hex(result.rgb, false);
}
}
if (result.rgb.r === result.rgb.g && result.rgb.g === result.rgb.b) {
result.hsl.h = result.hwb.h = this.curColors.hsl.h;
}
return result;
}
getCoordFromVal(hsl) {
let x = hsl.s, y = hsl.l;
if (this.canvasMode === 'hsv') {
let tmpS = hsl.s / 100, tmpL = hsl.l / 100, tmpV = tmpL + tmpS * Math.min(tmpL, 1 - tmpL), tmpS2 = tmpV === 0 ? 0 : 2 * (1 - tmpL / tmpV);
x = Math.round(tmpS2 * 100);
y = Math.round(tmpV * 100);
}
return {
x: (x / 100) * this.canvasWidth,
y: (1 - y / 100) * this.canvasHeight
};
}
async assignVals(value = this.options.value, cb) {
if (this.destroyed)
return this;
if (!value)
return this;
if (this.options.b4Assign) {
let resp = await this.options.b4Assign.call(this, value);
resp && (value = resp);
}
let tmp = this.parseVals(value);
deepMerge(this.curColors, tmp);
this.hRangeEl.value = this.curColors.hsl.h;
this.aRangeEl.value = this.curColors.a;
this.updateReverse();
this.setOutputStr();
this.updatePreview();
!this.stopOutput && this.setOutputVals();
let { x, y } = this.getCoordFromVal(this.curColors.hsl);
this.indCoord = {
x: Math.max(0, Math.min(x, this.canvasWidth - 1)),
y: Math.max(0, Math.min(y, this.canvasHeight - 1))
};
this.updateIndCoord();
super.listen({ name: 'assigned', cb, params: [value] });
return this;
}
initVals(value = this.options.value) {
if (value) {
this.assignVals(value);
}
else {
this.indCoord = { x: this.canvasWidth / 2, y: this.canvasHeight / 2 };
this.updateIndCoord();
this.canvasRect = this.canvasEl.getBoundingClientRect();
this.canvasInteraction({
x: this.canvasRect.left + this.canvasWidth / 2,
y: this.canvasRect.top + this.canvasHeight / 2,
});
this.updateHueSlider();
this.updateAlphaSlider();
}
}
getVals() {
if (this.destroyed)
return this;
let result = this.curColors.hex;
if (this.options.output.format.startsWith('hex')) {
result + (this.options.output.format.endsWith('a') ? this.curColors.a16 : '');
}
else {
let aVal = this.options.output.format.endsWith('a') ? ',' + this.curColors.a : '';
if (this.options.output.format.startsWith('rgb')) {
result = `${this.options.output.format}(${this.curColors.rgb.r},${this.curColors.rgb.g},${this.curColors.rgb.b}${aVal})`;
}
else if (this.options.output.format.startsWith('hwb')) {
result = `${this.options.output.format}(${this.curColors.hwb.h},${this.curColors.hwb.w}%,${this.curColors.hwb.b}%${aVal})`;
}
else {
result = `${this.options.output.format}(${this.curColors.hsl.h},${this.curColors.hsl.s}%,${this.curColors.hsl.l}%${aVal})`;
}
}
return result;
}
async fillVals(value = this.value, cb) {
if (this.destroyed)
return this;
if (this.options.b4Fill) {
let resp = await this.options.b4Fill.call(this, value);
resp && (value = resp);
}
if (['INPUT', 'TEXTAREA'].includes(this.fillEl.nodeName)) {
this.fillEl.value = value;
}
else if (['AX-INPUT', 'AX-TEXTAREA'].includes(this.fillEl.nodeName)) {
this.fillEl.setAttribute('value', value);
}
else {
this.fillEl.innerHTML = value;
}
this.addHistory(value);
super.listen({ name: 'filled', cb, params: [value] });
return this;
}
async clearVals(cb) {
if (this.destroyed)
return this;
this.options.b4Clear && await this.options.b4Clear.call(this);
this.value = '';
if (['INPUT', 'TEXTAREA'].includes(this.fillEl.nodeName)) {
this.fillEl.value = '';
}
else if (['AX-INPUT', 'AX-TEXTAREA'].includes(this.fillEl.nodeName)) {
this.fillEl.removeAttribute('value');
}
else {
this.fillEl.innerHTML = '';
}
super.listen({ name: 'cleared', cb });
return this;
}
async restoreVals(cb) {
if (this.destroyed)
return this;
this.options.b4Clear && await this.options.b4Clear.call(this);
this.assignVals(this.options.value);
super.listen({ name: 'restored', cb });
return this;
}
destroy(cb) {
if (this.destroyed)
return this;
this.canvasModeEl.off('changed', this.modeEvt);
this.alphaEl.off('changed', this.alphaEvt);
this.hRangeEl.removeEventListener('input', this.hRangeEvt);
this.aRangeEl.removeEventListener('input', this.aRangeEvt);
this.changeEl.removeEventListener('click', this.changeEvt);
this.randomEl.removeEventListener('click', this.randomEvt);
this.hexEl.removeEventListener('input', this.colorEvt);
this.rgbrEl.removeEventListener('input', this.colorEvt);
this.rgbgEl.removeEventListener('input', this.colorEvt);
this.rgbbEl.removeEventListener('input', this.colorEvt);
this.hslsEl.removeEventListener('input', this.colorEvt);
this.hsllEl.removeEventListener('input', this.colorEvt);
this.hwbwEl.removeEventListener('input', this.colorEvt);
this.hwbbEl.removeEventListener('input', this.colorEvt);
this.hexaEl.removeEventListener('input', this.coloraEvt);
this.rgbaEl.removeEventListener('input', this.coloraEvt);
this.hslaEl.removeEventListener('input', this.coloraEvt);
this.hwbaEl.removeEventListener('input', this.coloraEvt);
this.hwbhEl.removeEventListener('input', this.colorhEvt);
this.hslhEl.removeEventListener('input', this.colorhEvt);
this.copyEl.removeEventListener('click', this.copyEvt);
this.previewEl.removeEventListener('click', this.previewEvt);
this.strawEl.onclick = null;
this.restoreEl.onclick = null;
this.confirmEl.onclick = null;
this.clearEl.onclick = null;
this.popupIns.destroy();
this.gestureIns.destroy();
this.destroyed = true;
super.listen({ name: 'destroyed', cb });
return this;
}
}
class CompBaseCommFieldMixin extends CompBaseCommField {
modsOpts;
canListenkeys;
static custAttrs;
static boolAttrs;
constructor() {
super();
this.modsOpts = {};
this.createShadow();
this.getRawData();
this.fillWrap(this.propsProxy);
this.propsObs.on('completed', (resp) => {
this.ins && this.ins.initialized && resp.keys.set.length && this.completedEvt(resp);
});
}
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.evtsArr];
}
connectedCallback() {
this.addEvts(['blur', 'focus', 'input', 'change']);
this.connectedRender();
}
mapVals(name, newVal, module, opts = []) {
return module.evtsArr.includes(name) ? newVal :
module.boolAttrs.includes(name) ? Object.values(attrJoinVal(name, newVal, opts))[0] :
isNull(newVal) ? null : Object.values(attrJoinVal(name, newVal, opts))[0];
}
saveModsOpts(name, opts = [], module = 'module') {
if (!name || !module)
return;
let tmp = this.propsProxy[name], item = opts.find((k) => k.attr === name);
if (!item)
return;
!this.modsOpts[module] && (this.modsOpts[module] = {});
if (isNull(tmp)) {
this.connected && (this.modsOpts[module][item.prop] = item.value);
}
else {
this.modsOpts[module][item.prop] = tmp;
}
}
getRawProps(comp, opts = []) {
for (let k of [...comp.custAttrs, ...comp.lazyAttrs, ...comp.boolAttrs, ...comp.evtsArr]) {
this.propsRaw[k] = this.mapVals(k, this.getAttribute(k), comp, opts);
}
}
filterModsOpts(opts = []) {
for (let k of Object.keys(this.properties).filter(keyCond))
this.saveModsOpts(k, opts);
}
getListenKeys(comp, exclude = []) {
this.canListenkeys = [...comp.custAttrs, ...comp.boolAttrs].filter((k) => !exclude.includes(k));
}
fillWrap(data) {
this.wrapEl = createEl('div', {}, this.rawHtml);
}
updateProxyOpts(comp, opts = [], name, newVal, oldVal) {
this.propsProxy[name] = name === 'async' ? getAttrBool(newVal) : this.mapVals(name, newVal, comp, opts);
!comp.evtsArr.includes(name) && this.saveModsOpts(name, opts);
this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
getRawPropsOpts(comp, opts) {
this.getRawProps(comp, opts);
this.getProxyProps();
this.filterModsOpts(opts);
}
completedEvt(data) {
let intArr = getIntArr([this.canListenkeys, data.keys.set]);
intArr.length && this.ins.update(this.modsOpts['module']);
}
}
class MoreElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optMore.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
super.updateProxy(name, newVal, optMore);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new More(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class DeformElem extends CompBaseComm {
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'theme', 'shape', 'size', ...this.baseAttrs];
static boolAttrs = ['disabled', 'bordered', 'filled', 'dark'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, DeformElem);
}
getRawData() {
this.getRawProps(DeformElem);
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, '<i></i>'.repeat(3));
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
class: this.changedClass,
};
changedClass(opt) {
let has = opt.newVal.includes(config.actClass), type = this.propsRaw.type;
if (has) {
if (type === 'left') {
this.setAttribute('type', 'right');
}
else if (type === 'right') {
this.setAttribute('type', 'left');
}
else if (type === 'up') {
this.setAttribute('type', 'down');
}
else if (type === 'down') {
this.setAttribute('type', 'up');
}
else {
this.setAttribute('type', 'close');
}
}
else {
this.setAttribute('type', this.propsRaw.type);
}
}
}
class AvatarElem extends CompBaseComm {
mainEl;
badgeEl;
tipsEl;
contRaw;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-badge', comp: BadgeElem }];
static custAttrs = ['type', 'theme', 'tips', 'size', 'src', 'shape', 'badge', 'href', 'target', 'rel', ...this.baseAttrs];
static boolAttrs = ['disabled'];
static get observedAttributes() {
return ['src', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, AvatarElem);
}
getMainEl(type, src) {
return (type === 'text') ? createEl('i', { [ax.alias]: 'main' }, src || 'null') : createEl('img', { [ax.alias]: 'main', src: src || ax.images.avatar });
}
getRawData() {
this.getRawProps(AvatarElem);
this.propsRaw.src = this.getAttribute('src') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('a', { [ax.alias]: 'wrap' });
this.badgeEl = createEl('ax-badge', { [ax.alias]: 'badge', shadowed: '', label: data?.badge?.trim() });
this.tipsEl = createEl('i', { [ax.alias]: 'tips' }, data.tips || '');
this.mainEl = this.getMainEl(data.type, data.src);
this.wrapEl.appendChild(this.mainEl);
this.hasAttribute('badge') && this.wrapEl.appendChild(this.badgeEl);
this.getAttribute('tips') && this.wrapEl.appendChild(this.tipsEl);
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
badge: this.changedBadge,
tips: this.changedTips,
src: this.changedSrc,
href: this.changedHref,
target: this.changedHref,
rel: this.changedHref,
type: this.changedType,
};
changedSrc(opt) {
(this.propsProxy.type === 'text') ? this.mainEl.innerHTML = opt.newVal : this.mainEl.src = opt.newVal;
}
changedHref(opt) {
if (opt.newVal) {
this.wrapEl.setAttribute(opt.name, opt.newVal);
}
else {
this.wrapEl.removeAttribute(opt.name);
}
}
changedBadge(opt) {
if (opt.newVal === null) {
this.badgeEl.remove();
}
else {
this.badgeEl.setAttribute('label', (opt.newVal === '0' || !opt.newVal) ? '' : opt.newVal);
(elState(this.badgeEl).isVirtual) ? this.wrapEl.appendChild(this.badgeEl) : null;
}
}
changedTips(opt) {
if (opt.newVal === null) {
this.tipsEl.remove();
}
else {
this.tipsEl.innerHTML = opt.newVal;
(elState(this.tipsEl).isVirtual) ? this.wrapEl.appendChild(this.tipsEl) : null;
}
}
changedType(opt) {
if ((this.mainEl.nodeName === 'IMG' && opt.newVal === 'text') || (this.mainEl.nodeName === 'I' && (opt.newVal === 'image' || !opt.newVal))) {
this.mainEl.remove();
this.mainEl = this.getMainEl(opt.newVal, this.propsProxy.src);
this.wrapEl.appendChild(this.mainEl);
}
}
}
class FormatElem extends CompBaseComm {
tipsIns;
infoEl;
separator;
locale;
prefixEl;
suffixEl;
prefixTips;
suffixTips;
labelEl;
places;
constructor() {
super();
this.getRawData();
this.locale = navigator.language || 'en-US';
this.getSeparator();
this.places = 2;
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'rts', 'info', 'tips', 'lines', 'size', 'width', 'locale', 'places', ...this.baseAttrs];
static boolAttrs = [];
static jsonAttrs = ['lang', 'prefix', 'suffix'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, FormatElem);
}
getRawData() {
this.getRawProps(FormatElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
let sfxStr = this.getAttribute('suffix')?.trim(), preStr = this.getAttribute('prefix')?.trim();
this.propsRaw.prefix = { content: !preStr?.startsWith('{') && !preStr?.endsWith('}') ? preStr : '', tips: {} };
this.propsRaw.suffix = { content: !sfxStr?.startsWith('{') && !sfxStr?.endsWith('}') ? sfxStr : '', tips: {} };
this.getProxyProps();
}
fillWrap(data) {
this.labelEl = createEl('span', { [ax.alias]: 'label' }, data.label);
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.labelEl);
this.fillCont(data);
}
fillCont(data) {
if (data.type === 'ruby') {
this.labelEl.innerHTML = `<ruby>${this.getRuby(data.label, data.rts)}</ruby>`;
}
else if (data.type === 'latex') {
try {
new Function(`label`, `el`, `"use strict";${data.engin || 'katex.render(label, el)'}`)(data.label, this.labelEl);
}
catch {
console.error('Please introduce a math formula parsing plugin(katex)!');
}
}
else if (data.type === 'break') {
this.labelEl.innerHTML = this.getBrText(data.label, data.lines, data.size);
}
else if (data.type === 'localenum') {
this.labelEl.innerHTML = this.getLocaleNum(data.label);
}
else if (data.type === 'plainnum') {
this.labelEl.innerHTML = this.getPlainNum(data.label);
}
else if (data.type === 'padstart' || data.type === 'padend') {
this.labelEl.innerHTML = this.getPadstr(data.label, data.type);
}
else {
this.labelEl.innerHTML = data.label;
}
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
getRuby(text, rts) {
let result = '';
if (!text) {
return result;
}
if (!rts) {
return text;
}
let chars = text.split(''), hyphen = text.includes(config.splitHyphen) ? config.splitHyphen : config.wordHyphen, rtArr = rts.split(hyphen);
chars = chars.map((k, i) => {
return `${k}<rt>${rtArr[i] || ''}</rt>`;
});
result = chars.join('');
return result;
}
getBrText(text, lines = 2, size) {
if (!text) {
return '';
}
if (lines === 1 || !lines) {
return text;
}
let points = Math.ceil(text.length / lines), fontSize = size ? 'style="font-size:' + size + '"' : '', result = `<i class="${ax.prefix}t-br" ${fontSize}>`, hasBr = text.includes('<br') ? true : false;
if (hasBr) {
result += text;
}
else {
for (let i = 0; i < lines; i++) {
if (i === lines - 1) {
result += text.substring(i * points);
}
else {
result += text.substring(i * points, (i + 1) * points) + '<br/>';
}
}
}
return result + '</i>';
}
getLocaleNum(text) {
let localeObj = new Intl.NumberFormat(this.locale).formatToParts(text.trim()), localeStr = localeObj.map(k => k.value).join('');
return localeStr;
}
getPlainNum(text) {
return text.trim().replaceAll(this.separator[0], '').replaceAll(this.separator[1], '.');
}
getSeparator() {
this.separator = this.locale == 'de-DE' ? ['.', ','] :
this.locale == 'fr-FR' ? [' ', ','] :
this.locale == 'de-CH' ? [`’`, '.'] :
this.locale == 'sv-SE' ? [` `, ','] : [',', '.'];
}
getPadstr(text, placement = 'padend') {
let tmp = text.replaceAll(this.separator[0], ''), split = tmp.split(this.separator[1]), int = split[0], dec = split[1] || '', dot = dec ? this.separator[1] : '';
if (placement === 'padstart') {
return int.length > this.places ? tmp : int.padStart(this.places, '0') + dot + dec;
}
else {
return dec.length > this.places ? tmp : int + dot + dec.padEnd(this.places, '0');
}
}
changedMaps = {
label: this.changedLabel,
type: this.changedLabel,
rts: this.changedRts,
prefix: this.changedEnds,
suffix: this.changedEnds,
lines: this.changedLines,
size: this.changedSize,
width: this.changedWidth,
locale: this.changedLocale,
places: this.changedPlaces,
};
changedLabel(opt) {
this.labelEl.innerHTML = '';
this.fillCont(this.propsProxy);
}
changedRts(opt) {
if (this.propsProxy.type === 'ruby') {
this.labelEl.innerHTML = `<ruby>${this.getRuby(this.propsProxy.label, opt.newVal)}</ruby>`;
}
}
changedEnds(opt) {
if (opt.newVal === null) {
this[`${opt.name}El`].remove();
return;
}
let el = this[`${opt.name}El`], tips = this[`${opt.name}Tips`], data = this.propsProxy[opt.name], content = isNull(data.content) ? this.propsRaw[opt.name].content : data.content;
if (content) {
if (el) {
el.innerHTML = content;
}
else {
this[`${opt.name}El`] = createEl('i', { [ax.alias]: opt.name }, content);
el = this[`${opt.name}El`];
this.wrapEl.insertAdjacentElement(opt.name === 'suffix' ? 'beforeend' : 'afterbegin', el);
}
if (!isEmpty(data.tips)) {
if (typeof data.tips === 'string') {
this.propsProxy[opt.name].tips = { content: data.tips };
}
if (tips) {
tips.update(this.propsProxy[opt.name].tips);
}
else {
this[`${opt.name}Tips`] = new Tooltip(el, this.propsProxy[opt.name].tips);
}
}
else {
tips && tips.update({ asleep: true });
}
}
else {
el && el.remove();
}
}
changedLines(opt) {
if (this.propsProxy.type === 'break') {
this.labelEl.innerHTML = this.getBrText(this.propsProxy.label, ~~opt.newVal, this.propsProxy.size);
}
}
changedSize(opt) {
if (this.propsProxy.type === 'break') {
let tmp = this.labelEl.firstElementChild;
tmp ? tmp.style.fontSize = opt.newVal : null;
}
}
changedWidth(opt) {
if (this.propsProxy.type === 'break') {
let tmp = this.labelEl.firstElementChild;
tmp ? tmp.style.width = opt.newVal : null;
}
}
changedLocale(opt) {
this.locale = !opt.newVal ? navigator.language || 'en-US' : opt.newVal;
this.getSeparator();
if (['localenum', 'plainnum'].includes(this.propsProxy.type)) {
this.labelEl.innerHTML = '';
this.fillCont(this.propsProxy);
}
}
changedPlaces(opt) {
if (!['padstart', 'padend'].includes(this.propsProxy.type))
return;
if (opt.newVal !== null) {
this.places = ~~opt.newVal;
}
this.labelEl.innerHTML = this.getPadstr(this.propsProxy.label, this.propsProxy.type);
}
}
class FlagElem extends CompBaseComm {
labelEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'theme', 'placement', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, FlagElem);
}
getRawData() {
this.getRawProps(FlagElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.labelEl = createEl('i', { [ax.alias]: 'label' }, this.propsProxy.label);
this.wrapEl = createEl('span', { [ax.alias]: 'wrap' }, this.labelEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
};
changedLabel(opt) {
this.labelEl.innerHTML = opt.newVal || '';
}
}
class BuoyElem extends CompBaseComm {
headEl;
labelEl;
iconEl;
arrowEl;
valueEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['icon', 'label', 'theme', 'size', ...this.baseAttrs];
static boolAttrs = ['inverted', 'arrow'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, BuoyElem);
}
getRawData() {
this.getRawProps(BuoyElem);
this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('span', { [ax.alias]: 'wrap' });
this.headEl = createEl('span', { [ax.alias]: 'head' });
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label || '');
this.iconEl = createEl('i', { class: data.icon || '', [ax.alias]: 'icon' });
this.arrowEl = createEl('i', { class: `${ax.prefix}icon-down`, [ax.alias]: 'arrow' });
this.valueEl = createEl('i', { [ax.alias]: 'value' }, data.value || '');
data.label ? this.headEl.appendChild(this.labelEl) : null;
data.icon ? this.headEl.insertAdjacentElement('afterBegin', this.iconEl) : null;
data.arrow ? this.headEl.insertAdjacentElement('beforeEnd', this.arrowEl) : null;
this.wrapEl.append(this.headEl, this.valueEl);
}
render(data) {
this.insertSource();
this.append(this.wrapEl);
}
changedMaps = {
value: this.changedValue,
label: this.changedLabel,
icon: this.changedIcon,
arrow: this.changedArrow,
};
changedValue(opt) {
this.valueEl.innerHTML = opt.newVal || '';
}
changedLabel(opt) {
if (opt.newVal === null) {
this.labelEl.remove();
}
else {
this.labelEl.innerHTML = opt.newVal;
if (elState(this.labelEl).isVirtual) {
if (!elState(this.iconEl).isVirtual) {
this.iconEl.insertAdjacentElement('afterEnd', this.labelEl);
}
else {
this.headEl.insertAdjacentElement('afterBegin', this.labelEl);
}
}
}
}
changedIcon(opt) {
if (opt.newVal === null) {
this.iconEl.remove();
}
else {
this.iconEl.setAttribute('class', opt.newVal);
if (elState(this.iconEl).isVirtual) {
this.headEl.insertAdjacentElement('afterBegin', this.iconEl);
}
}
}
changedArrow(opt) {
if (!attrValBool(opt.newVal)) {
this.arrowEl.remove();
}
else {
if (elState(this.arrowEl).isVirtual) {
this.headEl.appendChild(this.arrowEl);
}
}
}
}
class GoodElem extends CompBaseComm {
labelEl;
iconEl;
tipsEl;
valueEl;
increase;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
this.increase = (step = 1, cb) => {
let value = parseInt(this.properties.value) + step, tips = this.getAttribute('tips');
this.canListen = false;
this.setAttribute('value', String(value));
tips && this.setAttribute('tips', tips);
this.toggleAttribute('increased', true);
cb && cb.call(this, value);
this.canListen = true;
};
}
static custAttrs = ['icon', 'label', 'tips', ...this.baseAttrs];
static boolAttrs = ['disabled', 'increased'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, GoodElem);
}
getRawData() {
this.getRawProps(GoodElem);
this.propsRaw.value = this.getAttribute('value') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('span', { [ax.alias]: 'wrap' });
this.labelEl = createEl('i', { [ax.alias]: 'label' });
this.iconEl = createEl('i', { [ax.alias]: 'icon' });
this.valueEl = createEl('i', { [ax.alias]: 'value' }, data.value || '');
this.tipsEl = createEl('i', { [ax.alias]: 'tips' });
this.wrapEl.appendChild(this.valueEl);
}
render(data) {
this.insertSource();
this.append(this.labelEl, this.wrapEl, this.tipsEl);
}
changedMaps = {
label: this.changedLabel,
value: this.changedLabel,
tips: this.changedLabel,
icon: this.changedIcon,
};
changedLabel(opt) {
this[opt.name + 'El'].innerHTML = opt.newVal || '';
}
changedIcon(opt) {
if (opt.newVal === null) {
this.iconEl.remove();
}
else {
this.iconEl.setAttribute('class', opt.newVal);
elState(this.iconEl).isVirtual && this.wrapEl.insertAdjacentElement('afterBegin', this.iconEl);
}
}
}
class AnchorsElem extends CompBaseComm {
data;
smoothEvent;
interactIns;
constructor() {
super();
this.getRawData();
this.createInteract();
this.fillWrap(this.propsProxy);
this.render(this.propsProxy);
}
static custAttrs = ['root', 'active', 'offset', ...this.baseAttrs];
static boolAttrs = ['smooth'];
static get observedAttributes() {
return ['headings', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, AnchorsElem);
}
getRawData() {
this.getRawProps(AnchorsElem);
this.propsRaw.headings = this.getHeadings(this.getAttribute('headings') || this.rawHtml);
this.getProxyProps();
}
createInteract() {
this.interactIns = new IntersectionObserver(entries => {
for (let k of entries) {
if (k.isIntersecting) {
if (k.intersectionRatio === 1) {
this.activate(k.target, true, false);
}
}
}
}, {
threshold: [1],
});
}
getHeadings(str) {
return valToArr(str).map((k) => {
let tmp = k.split('|');
return { heading: tmp[0], exclude: tmp[1] };
});
}
getData(headings) {
if (headings.length === 0) {
headings = [{ heading: 'h2', exclude: '' }];
}
let result = [], getChildren = (index, current, arr, pNext) => {
let els = getEls(current.heading, this.propsProxy.root), excEls = getEls(current.exclude, this.propsProxy.root), keyNext = headings[index + 1]?.heading;
for (let [y, x] of els.entries()) {
let obj = {
target: x,
label: x.textContent.replace('§', '')
};
let children = getBetweenEls({
selector: keyNext,
start: x,
end: els[y + 1] || pNext,
root: this.propsProxy.root,
});
if (children.length > 0) {
obj.children = [];
getChildren(index + 1, headings[index + 1], obj.children, els[y + 1]);
}
if (excEls.length && excEls.find((i) => i.contains(x)))
continue;
arr.push(obj);
}
};
getChildren(0, headings[0], result);
treeTools.addIdPath({ source: result });
return result;
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.get2FillTreeNodes(data);
}
get2FillTreeNodes(data) {
this.data = this.getData(data.headings);
let plantTree = (parent, data) => {
let ul = createEl('ul', { class: `${ax.prefix}reset` });
for (let k of data) {
k.wrapEl = createEl('li', { [ax.alias]: 'wrap' });
k.labelEl = createEl('a', { [ax.alias]: 'label', href: `#${k.label}` }, k.label);
k.headEl = createEl('div', { [ax.alias]: 'head', id: k.id }, k.labelEl);
k.wrapEl.appendChild(k.headEl);
k.labelEl.onclick = () => this.smoothToActive(k, false);
k.target.id = k.label;
k.target.classList.add(`${ax.prefix}anchor`);
let tmp = k.target.querySelector(`${ax.prefix}hash`);
tmp && tmp.remove();
k.hashEl = createEl('a', { href: `#${k.label}`, class: `${ax.prefix}hash` }, '§');
k.hashEl.onclick = () => this.smoothToActive(k, false);
k.target.appendChild(k.hashEl);
this.interactIns.observe(k.target);
if (k.hasOwnProperty('children')) {
k.bodyEl = plantTree(k.wrapEl, k.children);
k.bodyEl.setAttribute(ax.alias, 'body');
}
ul.appendChild(k.wrapEl);
}
parent.appendChild(ul);
return ul;
};
this.wrapEl.innerHTML = '';
plantTree(this.wrapEl, this.data);
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
activate(data, active = true, smooth = true) {
if (!data) {
return this;
}
let flat = treeTools.toFlat(this.data), dataType = getDataType(data), tmp = Number(data), value = tmp === 0 || !!tmp ? tmp : data, item = dataType.includes('HTML') ? findItem(data, flat, 'target') : findItem(value, flat);
if (item) {
if (!item.active && active) {
item.headEl.setAttribute('active', '');
item.active = true;
let others = flat.filter((k) => k !== item && k.active);
for (let k of others) {
k.headEl.removeAttribute('active');
Reflect.deleteProperty(k, 'active');
}
}
if (smooth) {
if (this.propsProxy.smooth) {
scrollTo(item.target, {
offset: this.propsProxy.offset,
});
}
}
}
}
addSmooth() {
let flat = treeTools.toFlat(this.data);
for (let k of flat) {
k.labelEl.onclick = () => this.smoothToActive(k, false);
k.hashEl.onclick = () => this.smoothToActive(k, false);
}
}
removeSmooth() {
let flat = treeTools.toFlat(this.data);
for (let k of flat) {
k.labelEl.onclick = null;
k.hashEl.onclick = null;
}
}
smoothToActive(obj, active = true) {
this.activate(obj.target, active, this.propsProxy.smooth);
}
changedMaps = {
headings: this.changedRender,
root: this.changedRender,
active: this.changedActive,
offset: this.changedOffset,
smooth: this.changedSmooth,
};
changedRender(opt) {
this.get2FillTreeNodes(this.propsProxy);
}
changedActive(opt) {
this.activate(opt.newVal);
}
changedOffset(opt) {
for (let k of this.data)
k.target.style.scrollMarginTop = opt.newVal;
}
changedSmooth(opt) {
let bool = attrValBool(opt.newVal);
bool ? this.addSmooth() : this.removeSmooth();
}
}
class MenuElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optMenu$1.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'active') {
this.ins && newVal && this.ins.activate(newVal);
}
if (name === 'disable') {
this.ins && newVal && this.ins.treeIns.disable(newVal);
}
else {
super.updateProxy(name, newVal, optMenu$1);
}
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new Menu(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class FileElem extends CompBaseCommField {
holderEl;
meanEl;
clickEvent;
changeEvt;
namesEl;
type;
clickEvt;
labelEl;
constructor() {
super();
this.type = 'file-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.clickEvt = (evt) => {
let target = getEvtTarget(evt);
if (this.toolsEl && this.toolsEl.contains(target))
return;
this.inputEl.click();
};
this.zeroEvt = new Event('change');
}
static custAttrs = ['name', 'value', 'accept', 'size', 'label', 'show', 'tools', 'attrs', ...this.evtsArr];
static boolAttrs = ['disabled', 'readonly', 'multiple', 'full'];
static get observedAttributes() {
return ['placeholder', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, FileElem, { tools: getAttrArr(newVal, 'close') });
}
getRawData() {
this.getRawProps(FileElem);
this.propsRaw.placeholder = this.getAttribute('placeholder') || this.rawHtml || config.lang.form.fileLabel;
this.propsRaw.value = this.propsRaw.multiple ? [] : '';
this.getProxyProps();
this.propsProxy['tools'] = getAttrArr(this.getAttribute('tools'), 'close');
this.value = this.propsProxy.value;
this.setFieldProps(['name', 'value', 'disabled', 'readonly', 'multiple']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.inputEl = createEl('input', { type: 'file', [ax.embedSign]: '' });
this.inputEl.multiple = data.multiple;
this.labelEl = createEl('span', { [ax.alias]: 'label' });
data.name && (this.inputEl.name = (data.name + (this.inputEl.multiple ? `[]` : '')) || '');
super.getToolsEl(data.tools);
this.holderEl = createEl('i', { [ax.alias]: 'placeholder' }, data.placeholder);
this.namesEl = createEl('i', { [ax.alias]: 'names' });
this.meanEl = createEl('i', { [ax.alias]: 'mean' }, 'file');
this.wrapEl.append(this.inputEl, this.namesEl, this.holderEl, this.meanEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.inputEl.addEventListener('change', (e) => {
let files = [...this.inputEl.files], names = files.map((k) => k.name), oldVal = this.value;
this.value = this.propsProxy.multiple ? files : files[0] || '';
files.length > 0 && (this.propsProxy.value = names.join(','));
this.namesEl.innerHTML = (files.length === 0) ? '' : (files.length === 1) ? this.inputEl.value : renderTpl(this.propsProxy.lang?.multi || config.lang.form.fileMulti, { data: files.length }) + this.propsProxy.value;
if (this.mediaEl) {
this.mediaEl.innerHTML = '';
for (let k of Array.from(e.target.files))
this.read2Append(k, this.mediaEl);
}
this.listen({ name: 'changed', params: [{ oldVal, newVal: this.value }] });
}, false);
this.wrapEl.addEventListener('click', this.clickEvt);
}
read2Append(file, box) {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (evt) => {
let src = evt.target.result, el;
if (file.type.startsWith('image/')) {
el = ax.createEl('img', { src });
}
else if (file.type.startsWith('video/')) {
el = ax.createEl('video', { src, controls: true });
}
else if (file.type.startsWith('audio/')) {
el = ax.createEl('audio', { src, controls: true });
}
el && box.appendChild(el);
};
}
changedMaps = {
disabled: this.changedBool,
readonly: this.changedBool,
multiple: this.changedBool,
full: this.changedBool,
name: this.changedName,
value: this.changedValue,
accept: this.changedName,
tools: this.changedTools,
placeholder: this.changedHolder,
label: this.changedLabel,
show: this.changedShow,
attrs: this.changedAttrs,
};
changedBool(opt) {
this.inputEl[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
this[opt.name === 'readonly' ? 'readOnly' : opt.name] = this.propsProxy[opt.name];
}
changedTools(opt) {
this.toolsEl && this.toolsEl.remove();
if (this.propsProxy.tools.length > 0) {
super.getToolsEl(this.propsProxy.tools);
this.propsProxy.tools.forEach((k) => {
if (k.name === 'close') {
k.wrapEl.onclick = () => {
this.clear();
};
}
else {
k.action && k.action.bind(this);
}
});
this.holderEl.insertAdjacentElement('afterEnd', this.toolsEl);
}
}
changedHolder(opt) {
this.holderEl.innerHTML = opt.newVal;
}
changedName(opt) {
this.inputEl.setAttribute(opt.name, opt.newVal);
opt.name === 'name' && (this.name = opt.newVal + (this.propsProxy.multiple ? `[]` : ''));
if (opt.name === 'name') {
this.name = opt.newVal || '';
if (this.name) {
this.inputEl.name = this.propsProxy.multiple ? `${this.name}[]` : this.name;
}
else {
this.inputEl.removeAttribute('name');
}
}
}
changedValue(opt) {
this.clear();
console.warn('The field.files property cannot be changed through scripts,this operation is performed by resetting!');
}
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal;
elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
}
else {
this.labelEl.remove();
}
}
changedShow(opt) {
this.mediaEl && (this.mediaEl.innerHTML = '');
if (opt.newVal) {
this.mediaEl = getEl(opt.newVal);
let arr = Array.from(this.inputEl.files);
if (!this.mediaEl || !arr.length)
return;
for (let k of arr)
this.read2Append(k, this.mediaEl);
}
}
}
class CheckboxesElem extends CompBaseCommField {
labelEl;
legendEl;
inputs;
checkedAll;
switch;
setVals;
check;
setLabels;
switchType;
switchEvt;
valMap;
checkedMore;
checkedLess;
type;
constructor() {
super();
this.type = 'checkboxes-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.reset = () => {
if (this.propsRaw.content != this.propsRaw.content)
this.updateInputs(this.propsRaw.content, this.propsRaw);
for (let k in this.propsRaw) {
if (k === 'content')
continue;
(this.propsRaw[k] !== null && this.propsRaw[k] !== false) ? this.setAttribute(k, this.propsRaw[k]) : this.removeAttribute(k);
}
this.listen({ name: 'reset' });
};
this.clear = () => {
let tmp = this.inputs.every((k) => !k.propsProxy.check);
if (tmp)
return;
this.setAttribute('checked', '');
this.listen({ name: 'cleared' });
};
this.checkedAll = () => {
let vals = this.inputs.
filter((k) => !k.propsProxy.checked && k.propsProxy.value).
map((k) => k.propsProxy.value);
if (!vals.length)
return;
this.setAttribute('checked', vals);
this.listen({ name: 'checkedAll', params: [vals] });
};
this.checkedMore = (data) => {
let vals = valToArr(data), cur = this.value.split(','), value = unique([...cur, ...vals]).filter(Boolean);
this.setAttribute('checked', value.join(','));
};
this.checkedLess = (data) => {
let vals = valToArr(data), cur = this.value.split(','), value = cur.filter((k) => !vals.includes(k));
this.setAttribute('checked', value.join(','));
};
this.check = (value, type = 'ed', from = 'value') => {
let vals = valToArr(value);
if (!vals.length) {
this.setAttribute('checked', '');
return;
}
let inputs = vals.map((k) => this.inputs.find((i) => i.propsProxy[from] == k)).filter(Boolean);
if (!inputs.length)
return;
let val = inputs.map((k) => k.value), cur = this.propsProxy.value.split(','), diff = !type ? cur.filter((k) => !val.includes(k)) : val;
if (type === 'ing') {
inputs[0].checked && this.setAttribute('checked', cur.shift.join(','));
inputs[0].setAttribute('check', type);
}
else {
this.setAttribute('checked', diff.join(','));
}
};
this.propsObs.on('set', (data) => {
data.key === 'value' && (this.valMap = { newVal: data.value, oldVal: data.raw || '' });
});
this.propsObs.on('completed', (data) => {
if (data.keys.set.includes('value')) {
this.referSwitch(data.proxy.value);
this.updateCache({ check: data.proxy.value });
this.listen({ name: 'changed', params: [this.valMap] });
}
});
this.switchEvt = (e) => {
this.switch.value == '1' || this.switch.checked ? this.checkedAll() : this.clear();
};
}
static dependencies = [{ tag: 'ax-checkbox', comp: CheckboxElem }];
static custAttrs = [
'size', 'name', 'type', 'layout', 'cols', 'checked', 'disable', 'content', 'switch', 'wrap-classes', 'item-classes', 'input-classes', 'on-checkedall', ...this.evtsArr
];
static boolAttrs = ['disabled', 'inverted'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, CheckboxesElem);
}
getRawData() {
this.getRawProps(CheckboxesElem);
!this.propsRaw.name && (this.propsRaw.name = ax.namePfx + Date.now());
this.propsRaw.content = super.getItemsData();
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
data['wrap-classes'] && classes(this.wrapEl).add(data['wrap-classes']);
if (data.layout === 'grid') {
this.wrapEl.classList.add(`${ax.prefix}grid`);
data.cols && this.wrapEl.classList.add(`${ax.prefix}avg-${data.cols}`);
}
else if (data.layout === 'flex') {
this.wrapEl.classList.add(`${ax.prefix}row`);
}
this.updateInputs(data.content, data);
}
updateInputs(data, host = this.propsProxy) {
this.inputs = [];
this.wrapEl.innerHTML = '';
let tmp = super.getItemsData(data);
for (let k of tmp) {
let parent = createEl('div'), input = createEl('ax-checkbox', { label: k.label, value: isNull(k.value) ? k.label : k.value, [ax.embedSign]: '' });
host.name ? input.setAttribute('name', `${host.name}[]`) : input.removeAttribute('name');
host.type ? input.setAttribute('type', host.type) : input.removeAttribute('type');
k.checked ? input.setAttribute('check', 'ed') : input.removeAttribute('check');
input.toggleAttribute('disabled', !!k.disabled);
host['input-classes'] && classes(input).add(host['input-classes']);
this.inputs.push(input);
if (host.layout) {
host.layout === 'flex' && parent.classList.add(`${ax.prefix}flex`);
host['item-classes'] && classes(parent).add(host['item-classes']);
parent.appendChild(input);
this.wrapEl.appendChild(parent);
}
else {
this.wrapEl.appendChild(input);
}
}
this.inputs.forEach((k) => {
k.on('changed', () => {
let eds = this.inputs.filter((i) => i.propsProxy.check === 'ed').map((o) => o.propsProxy.value).join(',');
this.propsProxy.value = eds;
this.value = this.propsProxy.value;
});
});
}
referSwitch(val) {
if (!this.switch)
return;
if (!val) {
['AX-CHECKBOXES', 'AX-CHECKBOX', 'AX-RADIO'].includes(this.switchType) ? this.switch.clear() : this.switch.check('0');
}
else {
let tmp = val.split(',').length;
if (tmp > 0 && tmp < this.inputs.length) {
this.switch.clear();
if (['AX-CHECKBOX', 'AX-RADIO'].includes(this.switchType)) {
this.switch.setAttribute('check', 'ing');
}
else {
let tmp = this.switch.inputs.find((k) => k.propsProxy.value == '1');
tmp && tmp.setAttribute('check', 'ing');
}
}
else {
if (['AX-CHECKBOX', 'AX-RADIO'].includes(this.switchType)) {
this.switch.setAttribute('check', 'ed');
}
else {
this.switch.check('1');
}
}
}
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
content: this.changedMultiCont,
disabled: this.changedMultiDisabled,
inverted: this.changedInverted,
name: this.changedMultiName,
type: this.changedMultiName,
size: this.changedMultiName,
checked: this.changedChecked,
disable: this.changedMultiDisable,
switch: this.changedSwitch,
};
changedChecked(opt) {
for (let k of this.inputs) {
if (opt.newVal === null) {
k.check('');
}
else {
let tmp = !opt.newVal ? [''] : getAttrArr(opt.newVal);
k.check(tmp.includes(k.propsProxy.value) ? 'ed' : '');
}
}
}
changedSwitch(opt) {
this.switch = getEl(`[name="${opt.newVal}"]`);
if (this.switch) {
this.switchType = this.switch.nodeName;
this.switch.removeEventListener('change', this.switchEvt);
this.switch.addEventListener('change', this.switchEvt, false);
}
}
changedInverted(opt) {
for (let k of this.inputs) {
k.toggleAttribute('inverted', this.propsProxy.inverted);
}
}
}
class RangeElem extends CompBaseCommFieldMixin {
type;
constructor() {
super();
this.type = 'range-comp';
}
static custAttrs = ['name', 'value', 'step', 'max', 'min', 'flow', 'size', 'classes', 'separator', 'hyphen', 'fence', 'button', 'ruler', 'result', 'lang'];
static boolAttrs = ['async', 'disabled', 'full', 'limit-show', 'tip-show', 'multiple', 'locked', 'rtl'];
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.updateProxyOpts(RangeElem, optRange, name, newVal, oldVal);
}
getRawData() {
this.getRawPropsOpts(RangeElem, optRange);
this.setFieldProps(['name', 'value', 'disabled']);
this.getListenKeys(RangeElem, ['name', 'disabled', 'value', 'size']);
}
createIns() {
if (this.ins)
return;
let params = Object.assign({
onSet: (data) => {
this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
this.canListen = false;
this.setAttribute('value', data.value);
this.canListen = true;
this.dispatchEvent(this.events['input'].event);
this.listen({ name: 'input', params: [data.value] });
if (data.value !== data.raw) {
this.dispatchEvent(this.events['change'].event);
this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
}
},
}, deepClone(this.modsOpts['module']));
this.ins = new Range(this.wrapEl, params);
this.ins.inputEl.setAttribute(ax.embedSign, '');
this.focus = () => {
this.ins.handles[this.propsProxy.multiple ? 'from' : 'single'].focus();
};
this.blur = () => {
if (this.propsProxy.multiple) {
this.ins.handles.from.blur();
this.ins.handles.to.blur();
}
else {
this.ins.handles.single.blur();
}
};
this.clear = () => {
this.ins.clear();
this.listen({ name: 'cleared' });
};
for (let k in this.ins.handles) {
if (this.ins.handles[k]) {
this.ins.handles[k].addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.ins.handles[k].addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
}
}
}
changedMaps = {
size: this.changedSize,
disabled: this.changedDisabled,
name: this.changedName,
value: this.changedValue,
};
changedName(opt) {
let tmp = opt.newVal || '';
this.ins && (this.ins.inputEl.name = tmp);
this.name = tmp;
}
changedValue(opt) {
this.ins && this.ins.setVals(opt.newVal);
this.value = this.ins ? this.ins.output.value : opt.newVal;
}
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.disable() : this.ins.enable();
}
}
changedSize(opt) {
if (this.ins) {
opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
}
}
}
class StatsElem extends CompBaseComm {
mainEl;
badgeEl;
tipsEl;
labelEl;
unitEl;
suffixEl;
prefixEl;
iconEl;
cubeEl;
diskEl;
headEl;
imageEl;
coreEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-badge', comp: BadgeElem }];
static custAttrs = ['unit', 'tips', 'icon', 'disk', 'cube', 'image', 'badge', 'prefix', 'suffix', 'flow', ...this.baseAttrs];
static boolAttrs = ['flipped', 'disabled'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, StatsElem);
}
getRawData() {
this.getRawProps(StatsElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.mainEl = createEl('div', { [ax.alias]: 'main' });
this.iconEl = createEl('i', { [ax.alias]: 'icon', class: data.icon });
this.diskEl = createEl('span', { [ax.alias]: 'disk' }, `<img src="${data.disk}"/>`);
this.cubeEl = createEl('span', { [ax.alias]: 'cube' }, `<img src="${data.cube}"/>`);
this.imageEl = createEl('span', { [ax.alias]: 'image' }, `<img src="${data.image}"/>`);
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label);
this.coreEl = createEl('span', { [ax.alias]: 'core' }, this.labelEl);
this.headEl = createEl('div', { [ax.alias]: 'head' }, this.coreEl);
this.tipsEl = createEl('div', { [ax.alias]: 'tips' }, data.tips);
this.unitEl = createEl('i', { [ax.alias]: 'unit' }, data.unit);
this.suffixEl = createEl('i', { [ax.alias]: 'suffix' }, data.suffix);
this.prefixEl = createEl('i', { [ax.alias]: 'prefix' }, data.prefix);
this.badgeEl = createEl('ax-badge', { [ax.alias]: 'badge', label: data?.badge?.trim() });
this.mainEl.appendChild(this.headEl);
this.wrapEl.appendChild(this.mainEl);
}
render() {
this.insertSource();
!this.hasAttribute('flow') && this.setAttribute('flow', 'v');
this.append(this.wrapEl);
}
changedMaps = {
badge: this.changedBadge,
label: this.changedLabel,
icon: this.changedIcon,
disk: this.changedDisk,
cube: this.changedCube,
image: this.changedImage,
tips: this.changedTips,
unit: this.changedUnit,
suffix: this.changedSuffix,
prefix: this.changedPrefix,
};
changedBadge(opt) {
if (opt.newVal === null) {
this.badgeEl.remove();
}
else {
this.badgeEl.setAttribute('label', opt.newVal.trim());
elState(this.badgeEl).isVirtual && this.coreEl.appendChild(this.badgeEl);
}
}
changedIcon(opt) {
if (opt.newVal === null) {
this.iconEl.remove();
}
else {
this.iconEl.setAttribute('class', opt.newVal);
if (elState(this.iconEl).isVirtual) {
this.diskEl.remove();
this.cubeEl.remove();
this.imageEl.remove();
this.wrapEl.insertAdjacentElement('afterbegin', this.iconEl);
}
}
}
changedDisk(opt) {
if (opt.newVal === null) {
this.diskEl.remove();
}
else {
this.diskEl.querySelector('img').src = opt.newVal;
if (elState(this.diskEl).isVirtual) {
this.iconEl.remove();
this.cubeEl.remove();
this.imageEl.remove();
this.wrapEl.insertAdjacentElement('afterbegin', this.diskEl);
}
}
}
changedCube(opt) {
if (opt.newVal === null) {
this.cubeEl.remove();
}
else {
this.cubeEl.querySelector('img').src = opt.newVal;
if (elState(this.cubeEl).isVirtual) {
this.diskEl.remove();
this.imageEl.remove();
this.iconEl.remove();
this.wrapEl.insertAdjacentElement('afterbegin', this.cubeEl);
}
}
}
changedImage(opt) {
if (opt.newVal === null) {
this.imageEl.remove();
}
else {
this.imageEl.querySelector('img').src = opt.newVal;
if (elState(this.cubeEl).isVirtual) {
this.diskEl.remove();
this.cubeEl.remove();
this.iconEl.remove();
this.wrapEl.insertAdjacentElement('afterbegin', this.imageEl);
}
}
}
changedTips(opt) {
if (opt.newVal === null) {
this.tipsEl.remove();
}
else {
this.tipsEl.innerHTML = opt.newVal;
this.mainEl.appendChild(this.tipsEl);
}
}
changedUnit(opt) {
if (opt.newVal === null) {
this.unitEl.remove();
}
else {
this.unitEl.innerHTML = opt.newVal;
this.headEl.appendChild(this.unitEl);
}
}
changedPrefix(opt) {
if (opt.newVal === null) {
this.prefixEl.remove();
}
else {
this.prefixEl.innerHTML = opt.newVal;
elState(this.prefixEl).isVirtual && this.coreEl.insertAdjacentElement('afterbegin', this.prefixEl);
}
}
changedSuffix(opt) {
if (opt.newVal === null) {
this.suffixEl.remove();
}
else {
this.suffixEl.innerHTML = opt.newVal;
elState(this.suffixEl).isVirtual && this.coreEl.insertAdjacentElement('beforeend', this.suffixEl);
}
}
changedLabel(opt) {
this.labelEl.innerHTML = opt.newVal || '';
}
}
class IconElem extends CompBaseComm {
badgeEl;
tipsEl;
iconEl;
cubeEl;
diskEl;
imageEl;
headEl;
legendEl;
tmp;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-badge', comp: BadgeElem }];
static custAttrs = ['tips', 'type', 'badge', 'dir', 'bg', 'href', 'target', 'rel', 'download', ...this.baseAttrs];
static boolAttrs = ['disabled'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, IconElem);
}
getRawData() {
this.getRawProps(IconElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.headEl = createEl('span', { [ax.alias]: 'head' });
this.wrapEl = createEl(data.href ? 'a' : 'div', { [ax.alias]: 'wrap' }, this.headEl);
this.iconEl = createEl('i', { [ax.alias]: 'icon', class: data.label });
this.diskEl = createEl('span', { [ax.alias]: 'disk' }, `<img src="${data.label}"/>`);
this.cubeEl = createEl('span', { [ax.alias]: 'cube' }, `<img src="${data.label}"/>`);
this.imageEl = createEl('span', { [ax.alias]: 'image' }, `<img src="${data.label}"/>`);
this.tipsEl = createEl('div', { [ax.alias]: 'tips' }, data.tips);
this.toggleLegend('icon');
this.badgeEl = createEl('ax-badge', { [ax.alias]: 'badge', label: data?.badge?.trim() });
}
setLegendBg(theme, old) {
if (theme) {
classes(this.iconEl).replace(`${ax.prefix}bg-${old}`, `${ax.prefix}bg-${theme}`);
classes(this.diskEl).replace(`${ax.prefix}bg-${old}`, `${ax.prefix}bg-${theme}`);
classes(this.cubeEl).replace(`${ax.prefix}bg-${old}`, `${ax.prefix}bg-${theme}`);
}
else {
this.iconEl.classList.remove(`${ax.prefix}bg-${old}`);
this.diskEl.classList.remove(`${ax.prefix}bg-${old}`);
this.cubeEl.classList.remove(`${ax.prefix}bg-${old}`);
}
}
toggleLegend(type) {
let map = [{
type: 'icon',
show: this.iconEl,
hide: [this.diskEl, this.imageEl, this.cubeEl],
}, {
type: 'disk',
show: this.diskEl,
hide: [this.iconEl, this.imageEl, this.cubeEl],
}, {
type: 'cube',
show: this.cubeEl,
hide: [this.diskEl, this.imageEl, this.iconEl],
}, {
type: 'image',
show: this.imageEl,
hide: [this.diskEl, this.cubeEl, this.iconEl],
}];
let item = map.find((k) => k.type === type);
if (item) {
for (let k of item.hide)
k.remove();
elState(item.show).isVirtual && this.headEl.insertAdjacentElement('afterbegin', item.show);
this.legendEl = item.show;
}
else {
this.iconEl.remove();
this.cubeEl.remove();
this.diskEl.remove();
this.imageEl.remove();
}
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
!this.hasAttribute('dir') && this.setAttribute('dir', 'h');
if (!this.hasAttribute('type')) {
this.canListen = false;
this.setAttribute('type', 'icon');
this.canListen = true;
}
}
changedMaps = {
label: this.changedLabel,
href: this.changedHref,
badge: this.changedBadge,
target: this.changedTarget,
rel: this.changedTarget,
download: this.changedTarget,
tips: this.changedTips,
type: this.changedType,
bg: this.changedBg,
};
changedLabel(opt) {
if (opt.newVal === null) {
this.toggleLegend();
}
else {
if (this.legendEl.nodeName === 'I') {
this.legendEl.setAttribute('class', opt.newVal);
}
else {
this.legendEl.querySelector('img').src = opt.newVal;
}
}
}
changedBadge(opt) {
if (opt.newVal === null) {
this.badgeEl.remove();
}
else {
this.badgeEl.setAttribute('label', opt.newVal.trim());
elState(this.badgeEl).isVirtual && this.headEl.appendChild(this.badgeEl);
}
}
changedHref(opt) {
if (opt.newVal === null) {
let children = this.wrapEl.children;
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.wrapEl.append(...children);
this.render();
}
else {
if (this.wrapEl.nodeName !== 'A') {
this.wrapEl = createEl('a', { [ax.alias]: 'wrap' }, [...this.wrapEl.children]);
this.render();
}
this.wrapEl.setAttribute('href', opt.newVal);
}
}
changedTarget(opt) {
opt.newVal ? this.wrapEl[opt.name] = opt.newVal : this.wrapEl.removeAttribute(opt.name);
}
changedTips(opt) {
if (opt.newVal === null) {
this.tipsEl.remove();
}
else {
this.tipsEl.innerHTML = opt.newVal;
this.wrapEl.appendChild(this.tipsEl);
}
}
changedBg(opt) {
this.setLegendBg(opt.newVal, opt.oldVal);
}
changedType(opt) {
this.toggleLegend(opt.newVal);
}
}
class DividerElem extends CompBaseComm {
startEl;
endEl;
labelEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['break', 'size', 'fs', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, DividerElem);
}
getRawData() {
this.getRawProps(DividerElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.startEl = createEl('div', { [ax.alias]: 'start' });
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.startEl);
this.endEl = createEl('div', { [ax.alias]: 'end' });
this.labelEl = createEl('div', { [ax.alias]: 'label' }, this.propsProxy.label);
this.propsProxy.label && this.wrapEl.append(this.labelEl, this.endEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
};
changedLabel(opt) {
if (opt.newVal === null) {
this.labelEl.remove();
this.endEl.remove();
}
else {
this.labelEl.innerHTML = opt.newVal;
elState(this.labelEl).isVirtual && this.wrapEl.append(this.labelEl, this.endEl);
}
}
}
class AlarmElem extends CompBaseComm {
labelEl;
iconEl;
imageEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['icon', 'image', 'theme', 'size', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, AlarmElem);
}
getRawData() {
this.getRawProps(AlarmElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('span', { [ax.alias]: 'wrap' });
this.labelEl = createEl('i', { [ax.alias]: 'label' }, this.propsProxy.label);
this.iconEl = createEl('i', { [ax.alias]: 'icon' });
this.imageEl = createEl('img', { [ax.alias]: 'image' });
this.propsProxy.label && this.wrapEl.appendChild(this.labelEl);
}
render(data) {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
icon: this.changedIcon,
image: this.changedImage,
};
changedLabel(opt) {
if (opt.newVal === null) {
this.labelEl.remove();
}
else {
this.labelEl.innerHTML = opt.newVal;
if (elState(this.labelEl).isVirtual) {
this.wrapEl.appendChild(this.labelEl);
this.iconEl.remove();
this.imageEl.remove();
}
}
}
changedIcon(opt) {
if (opt.newVal === null) {
this.iconEl.remove();
}
else {
this.iconEl.setAttribute('class', opt.newVal);
if (elState(this.iconEl).isVirtual) {
this.wrapEl.appendChild(this.iconEl);
this.labelEl.remove();
this.imageEl.remove();
}
}
}
changedImage(opt) {
if (opt.newVal === null) {
this.imageEl.remove();
}
else {
this.imageEl.src = opt.newVal;
if (elState(this.imageEl).isVirtual) {
this.wrapEl.appendChild(this.imageEl);
this.labelEl.remove();
this.iconEl.remove();
}
}
}
}
class DatetimeElem extends CompBaseCommFieldMixin {
labelEl;
inputEvt;
meanEl;
datetimeIns;
type;
select;
constructor() {
super();
this.type = 'datetime-comp';
this.select = () => this.ins.inputEl.select();
}
static dependencies = [
{ tag: 'ax-input', comp: InputElem },
{ tag: 'ax-btn', comp: BtnElem },
{ tag: 'ax-textarea', comp: TextareaElem },
{ tag: 'ax-checkbox', comp: CheckboxElem }
];
static custAttrs = ['name', 'value', 'size', 'format', 'classes', 'mode', 'feature', 'display', 'placeholder', 'label', 'tools',
'max-selection', 'min-date', 'max-date', 'datespan', 'timespan', 'rows', 'cols', 'week-start', 'separator', 'btn-sel', 'pos-sel', 'input-sel', 'child-sel', 'lunar', 'events', 'menu', 'bubble', 'footer', 'lang', 'attrs'];
static boolAttrs = ['async', 'disabled', 'to-drawer', 'full', 'multiline', 'now-hide', 'now-show', 'clear-show', 'close-show', 'cancel-show', 'confirm-hide', 'auto-fill', 'manual', 'auto-correct', 'required', 'fill-now', 'rtl'];
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.updateProxyOpts(DatetimeElem, optDatetime, name, newVal, oldVal);
}
getRawData() {
this.getRawPropsOpts(DatetimeElem, optDatetime);
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
this.getListenKeys(DatetimeElem, ['name', 'disabled', 'value', 'size']);
}
fillWrap(data) {
this.wrapEl = createEl('div', { class: `${ax.prefix}datetime-wrap` }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
let params = Object.assign(this.modsOpts['module'], {
onOutput: (data) => {
this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
this.canListen = false;
this.setAttribute('value', data.value);
this.canListen = true;
this.dispatchEvent(this.events['input'].event);
this.listen({ name: 'input', params: [data.value] });
if (data.value !== data.raw) {
this.dispatchEvent(this.events['change'].event);
this.listen({ name: 'changed', params: [data] });
}
}
});
this.ins = new Datetime(this.wrapEl, params);
this.ins.inputEl.setAttribute(ax.embedSign, '');
this.focus = () => {
this.ins.inputEl.focus();
};
this.blur = () => {
this.ins.inputEl.blur();
};
this.clear = () => {
this.ins.clear();
this.ins.inputEl.clear();
this.listen({ name: 'cleared' });
};
this.ins.inputEl.addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.ins.inputEl.addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
}
changedMaps = {
disabled: this.changedDisabled,
size: this.changedSize,
name: this.changedName,
value: this.changedValue,
attrs: this.changedAttrs,
};
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.disable() : this.ins.enable();
}
}
changedName(opt) {
let tmp = opt.newVal || '';
this.ins && (this.ins.inputEl.name = tmp);
this.name = tmp;
}
changedValue(opt) {
if (this.ins) {
this.ins.setVals(opt.newVal);
this.ins.confirm();
}
this.value = this.ins ? this.ins.output.value : opt.newVal;
}
changedSize(opt) {
if (this.ins) {
opt.newVal ? this.ins.inputEl.setAttribute('size', opt.newVal) : this.ins.inputEl.removeAttribute('size');
}
}
}
class RateElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optRate.map((k) => k.attr), 'options', 'async', 'attrs'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'value') {
this.ins && newVal && this.ins.setVals(newVal);
}
else {
super.updateProxy(name, newVal, optRate);
}
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new Rate(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class TreeElem extends CompBaseComm {
name;
value;
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optTree.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'name') {
this.name = newVal;
}
else {
super.updateProxy(name, newVal, optTree);
}
}
createIns() {
if (this.ins)
return;
this.ins = this.ins = new Tree(this.wrapEl, {
onInitiated: function () {
this.inputEl && this.inputEl.setAttribute(ax.embedSign, '');
},
onOutput: (data) => {
this.value = data.value;
}
});
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class AccordionElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optAccordion.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'value') {
this.ins && newVal && this.ins.setVals(newVal);
}
else {
super.updateProxy(name, newVal, optAccordion);
}
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new Accordion(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class EditorElem extends CompBaseCommFieldMixin {
type;
select;
constructor() {
super();
this.type = 'editor-comp';
this.select = () => this.ins.inputEl.select();
}
static custAttrs = ['name', 'value', 'delay', 'classes', 'content', 'cont-type',
'cont-data', 'ajax', 'appear', 'header', 'mode', 'min-height', 'max-height', 'feature', 'lang',];
static boolAttrs = ['async', 'disabled', 'readonly', 'deferred'];
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.updateProxyOpts(EditorElem, optEditor, name, newVal, oldVal);
}
getRawData() {
this.getRawPropsOpts(EditorElem, optEditor);
this.propsRaw.value = this.rawHtml || this.propsRaw.value || '';
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
this.getListenKeys(EditorElem, ['name', 'disabled', 'value', 'readonly']);
}
createIns() {
if (this.ins)
return;
let params = Object.assign(this.modsOpts['module'], {
onOutput: (data) => {
this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
this.canListen = false;
this.setAttribute('value', data.value);
this.canListen = true;
this.dispatchEvent(this.events['input'].event);
this.listen({ name: 'input', params: [data.value] });
if (data.value !== data.raw) {
this.dispatchEvent(this.events['change'].event);
this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
}
}
});
this.ins = new Editor(this.wrapEl, params);
this.ins.inputEl.setAttribute(ax.embedSign, '');
this.focus = () => {
(elState(this.ins.inputEl).isVisible ? this.ins.inputEl : this.ins.contEl).focus();
};
this.blur = () => {
(elState(this.ins.inputEl).isVisible ? this.ins.inputEl : this.ins.contEl).blur();
};
this.clear = () => {
this.ins.clearVals();
this.listen({ name: 'cleared' });
};
this.ins.inputEl.addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.ins.contEl.addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.ins.inputEl.addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
this.ins.contEl.addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
this.ins.inputEl.addEventListener('input', (e) => {
e.stopPropagation();
}, false);
this.ins.contEl.addEventListener('input', (e) => {
e.stopPropagation();
}, false);
this.ins.inputEl.addEventListener('change', (e) => {
e.stopPropagation();
}, false);
}
changedMaps = {
readOnly: this.changedReadOnly,
disabled: this.changedDisabled,
name: this.changedName,
value: this.changedValue,
};
changedBool(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.disable() : this.ins.enable();
}
}
changedName(opt) {
let tmp = opt.newVal || '';
this.ins && (this.ins.inputEl.name = tmp);
this.name = tmp;
}
changedValue(opt) {
this.ins && this.ins.setVals(opt.newVal);
}
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.disable() : this.ins.enable();
}
}
changedReadOnly(opt) {
this.readOnly = this.propsProxy[opt.name];
if (this.ins) {
this.readOnly ? this.ins.readonly() : this.ins.enable();
}
}
}
class SelectElem extends CompBaseCommFieldMixin {
type;
constructor() {
super();
this.type = 'select-comp';
}
static custAttrs = ['name', 'value', 'field', 'type', 'exclude', 'min', 'max', 'span', 'content', 'cont-type', 'cont-Data', 'ajax', 'size', 'max-height', 'search', 'tools', 'popup', 'lang', 'attrs'];
static boolAttrs = ['async', 'manual', 'disabled', 'readonly', 'full', 'multiple', 'sliced', 'removable', 'unique', 'collapse', 'status', 'auto-width'];
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.updateProxyOpts(SelectElem, optSelect, name, newVal, oldVal);
}
getRawData() {
this.getRawPropsOpts(SelectElem, optSelect);
this.setFieldProps(['name', 'disabled']);
this.value = '';
this.getListenKeys(SelectElem, ['name', 'disabled', 'value', 'size']);
}
createIns() {
if (this.ins)
return;
let params = Object.assign(this.modsOpts['module'], {
onOutput: (data) => {
this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
this.canListen = false;
this.setAttribute('value', data.value);
this.canListen = true;
this.dispatchEvent(this.events['input'].event);
this.listen({ name: 'input', params: [data.value] });
if (data.value !== data.raw) {
this.dispatchEvent(this.events['change'].event);
this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
}
}
});
this.ins = new Select(this.wrapEl, params);
this.ins.inputEl.setAttribute(ax.embedSign, '');
this.focus = () => {
this.wrapEl.focus();
};
this.blur = () => {
this.wrapEl.blur();
};
this.clear = () => {
this.ins.clear();
this.listen({ name: 'cleared' });
};
this.wrapEl.addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.wrapEl.addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
}
changedMaps = {
size: this.changedSize,
disabled: this.changedDisabled,
name: this.changedName,
value: this.changedValue,
attrs: this.changedAttrs,
};
changedName(opt) {
let tmp = opt.newVal || '';
this.ins && (this.ins.inputEl.name = tmp);
this.name = tmp;
}
changedValue(opt) {
this.ins && this.ins.select(opt.newVal);
}
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.disable() : this.ins.enable();
}
}
changedSize(opt) {
if (this.ins) {
opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
}
}
}
class UploadElem extends CompBaseCommFieldMixin {
type;
focusEl;
constructor() {
super();
this.type = 'upload-comp';
}
static custAttrs = ['name', 'value', 'url', 'content', 'cont-type', 'cont-data', 'ajax', 'limit', 'accept', 'type', 'feature', 'size', 'table', 'classes', 'status', 'choose-btn', 'upload-btn', 'clear-btn', 'cloud', 'attrs'];
static boolAttrs = ['async', 'disabled', 'readonly', 'multiple', 'manual', 'pastable'];
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.updateProxyOpts(UploadElem, optUpload, name, newVal, oldVal);
}
getRawData() {
this.getRawPropsOpts(UploadElem, optUpload);
this.setFieldProps(['name', 'value', 'disabled']);
this.getListenKeys(UploadElem, ['name', 'disabled', 'value', 'size']);
}
createIns() {
if (this.ins)
return;
let params = Object.assign(this.modsOpts['module'], {
onOutput: (data) => {
this.modsOpts['module'].value = this.propsProxy.value = this.value = data.value;
this.canListen = false;
this.setAttribute('value', data.value);
this.canListen = true;
this.dispatchEvent(this.events['input'].event);
this.listen({ name: 'input', params: [data.value] });
if (data.value !== data.raw) {
this.dispatchEvent(this.events['change'].event);
this.listen({ name: 'changed', params: [{ newVal: data.value, oldVal: data.raw }] });
}
}
});
this.ins = new Upload(this.wrapEl, params);
this.ins.inputEl.setAttribute(ax.embedSign, '');
this.focusEl = this.ins.options.feature === 'gallery' ? this.wrapEl : this.ins.chooseBtn;
this.focus = () => {
this.focusEl.focus();
};
this.blur = () => {
this.focusEl.blur();
};
this.clear = () => {
this.ins.clear();
this.listen({ name: 'cleared' });
};
this.focusEl.addEventListener('focus', () => {
this.dispatchEvent(this.events['focus'].event);
}, false);
this.focusEl.addEventListener('blur', () => {
this.dispatchEvent(this.events['blur'].event);
}, false);
}
changedMaps = {
size: this.changedSize,
disabled: this.changedDisabled,
name: this.changedName,
value: this.changedValue,
attrs: this.changedAttrs,
};
changedName(opt) {
let tmp = opt.newVal || '';
this.ins && (this.ins.inputEl.name = tmp);
this.name = tmp;
}
changedValue(opt) {
this.ins && this.ins.add(opt.newVal);
this.value = this.ins ? this.ins.output.value : opt.newVal;
}
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
if (this.ins) {
this.disabled ? this.ins.lock() : this.ins.unlock();
}
}
changedSize(opt) {
if (this.ins) {
opt.newVal ? this.ins.targetEl.setAttribute('size', opt.newVal) : this.ins.targetEl.removeAttribute('size');
}
}
}
class FieldsElem extends CompBaseCommField {
labelEl;
limitEl;
diskEl;
cubeEl;
iconEl;
btnEl;
meanEl;
type;
childEls;
compEls;
fieldsEl;
unitEl;
constructor() {
super();
this.type = 'fields-comp';
this.getRawData();
this.btnEl = getEl(':scope > AX-BTN', this);
this.childEls = [...this.children].filter((k) => k !== this.btnEl);
this.compEls = this.childEls.filter((k) => fieldTypes.includes(k.nodeName.toLowerCase().replace('ax-', '')));
this.fillWrap(this.propsProxy);
}
static custAttrs = ['size', 'label', 'unit', 'connector', 'align', 'shape'];
static boolAttrs = ['disabled', 'full', 'dividable'];
static get observedAttributes() {
return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, FieldsElem);
}
getRawData() {
this.getRawProps(FieldsElem);
this.getProxyProps();
}
fillWrap(data) {
this.fieldsEl = createEl('div', { [ax.alias]: 'fields' });
this.fieldsEl.append(...this.childEls);
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.fieldsEl);
this.btnEl && this.wrapEl.appendChild(this.btnEl);
this.labelEl = createEl('span', { [ax.alias]: 'label' });
this.unitEl = createEl('span', { [ax.alias]: 'unit' });
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
size: this.changedSize,
align: this.changedSize,
label: this.changedLabel,
unit: this.changedUnit,
connector: this.changedConn,
shape: this.changedShape,
};
changedLabel(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = opt.newVal;
elState(this.labelEl).isVirtual && this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
}
else {
this.labelEl.remove();
}
}
changedUnit(opt) {
if (opt.newVal) {
this.unitEl.innerHTML = opt.newVal;
elState(this.unitEl).isVirtual && this.fieldsEl.insertAdjacentElement('afterend', this.unitEl);
}
else {
this.unitEl.remove();
}
}
changedSize(opt) {
if (opt.newVal) {
for (let k of this.compEls)
k.setAttribute(opt.name, opt.newVal);
this.btnEl && opt.name === 'size' && this.btnEl.setAttribute(opt.name, opt.newVal);
}
else {
for (let k of this.compEls)
k.removeAttribute(opt.name);
this.btnEl && opt.name === 'size' && this.btnEl.removeAttribute(opt.name);
}
}
changedConn(opt) {
if (opt.newVal) {
for (let [i, k] of this.childEls.entries())
(i !== this.childEls.length - 1) && k.insertAdjacentHTML('afterend', `<i ${ax.alias}="connector">${opt.newVal}</i>`);
}
else {
let conns = getEls(`[${ax.alias}="connector"]`, this.fieldsEl);
for (let k of conns)
k.remove();
}
}
changedShape(opt) {
if (opt.newVal) {
this.btnEl && this.btnEl.setAttribute('shape', opt.newVal);
}
else {
this.btnEl && this.btnEl.removeAttribute('shape');
}
}
}
class SearchElem extends CompBaseCommField {
labelEl;
limitEl;
diskEl;
cubeEl;
iconEl;
btnEl;
meanEl;
type;
fieldsEl;
constructor() {
super();
this.type = 'search-comp';
this.getRawData();
this.fieldsEl = getEl(':scope > AX-FIELDS', this);
this.fillWrap(this.propsProxy);
}
static dependencies = [{ tag: 'ax-fields', comp: FieldsElem }];
static custAttrs = ['size', 'label', 'feature', 'shape'];
static boolAttrs = ['disabled', 'full', 'notable'];
static get observedAttributes() {
return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.propsProxy[name] = SearchElem.boolAttrs.includes(name) ? getAttrBool(newVal) : newVal;
this.changedMaps[name] && this.changedMaps[name].call(this, { name, newVal, oldVal, proxy: this.propsProxy });
}
getRawData() {
for (let k of [...SearchElem.custAttrs, ...SearchElem.lazyAttrs])
this.propsRaw[k] = this.getAttribute(k);
for (let k of SearchElem.boolAttrs)
this.propsRaw[k] = getAttrBool(this.getAttribute(k));
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.fieldsEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
full: this.changedFull,
size: this.changedSize,
notable: this.changedNotable,
shape: this.changedShape,
};
changedFull(opt) {
if (!this.fieldsEl)
return;
this.fieldsEl.toggleAttribute('full', !!opt.newVal);
}
changedSize(opt) {
if (!this.fieldsEl)
return;
if (opt.newVal) {
this.fieldsEl.setAttribute('size', opt.newVal);
}
else {
this.fieldsEl.removeAttribute('size');
}
}
changedNotable(opt) {
if (!this.fieldsEl?.btnEl)
return;
if (this.propsProxy.notable) {
this.fieldsEl.btnEl.setAttribute('theme', 'prim');
}
else {
this.fieldsEl.btnEl.removeAttribute('theme');
}
}
changedShape(opt) {
if (!this.fieldsEl?.btnEl)
return;
if (opt.newVal) {
this.fieldsEl.setAttribute('shape', opt.newVal);
}
else {
this.fieldsEl.removeAttribute('shape');
}
}
}
class TwilightElem extends CompBaseComm {
labelEl;
legendEl;
targetEl;
labels;
isDay;
toggleEvt;
constructor() {
super();
this.getRawData();
this.labels = [config.lang.twilight.day, config.lang.twilight.night];
this.isDay = true;
this.toggleEvt = () => {
let target = this.targetEl || document.body;
if (target.hasAttribute('scheme')) {
this.labelEl.innerHTML = this.labels[0];
target.removeAttribute('scheme');
this.isDay = true;
}
else {
this.labelEl.innerHTML = this.labels[1];
target.setAttribute('scheme', 'dark');
this.isDay = false;
}
};
this.fillWrap(this.propsProxy);
}
static custAttrs = ['labels', 'target', 'feature', ...this.baseAttrs];
static boolAttrs = [''];
static get observedAttributes() {
return [...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, TwilightElem);
}
getRawData() {
this.getRawProps(TwilightElem);
this.getProxyProps();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' });
this.labelEl = createEl('i', { [ax.alias]: 'label' }, this.labels[0]);
let now = Date.now();
this.legendEl = createEl('i', { [ax.alias]: 'legend' }, `
<svg viewBox="0 0 24 24">
<mask id="mask-${now}">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<circle cy="13" r="6" stroke="none" class="${ax.prefix}twilight-mask" fill="dark" />
</mask>
<circle fill="currentColor" cx="12" cy="12" r="6" class="${ax.prefix}twilight-main" mask="url(#mask-${now})" />
<g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="${ax.prefix}twilight-rays">
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</g>
</svg>
`);
this.wrapEl.append(this.labelEl, this.legendEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.removeEventListener('click', this.toggleEvt);
this.addEventListener('click', this.toggleEvt, false);
}
changedMaps = {
feature: this.changedFeature,
target: this.changedTarget,
labels: this.changedLabels,
};
changedTarget(opt) {
this.targetEl = getEl(opt.newVal);
}
changedFeature(opt) {
opt.newVal ? this.labelEl.remove() : this.wrapEl.insertAdjacentElement('afterbegin', this.labelEl);
}
changedLabels(opt) {
if (opt.newVal) {
this.labels = valToArr(opt.newVal);
this.labelEl.innerHTML = this.labels[this.isDay ? 0 : 1];
}
}
}
class PaginationElem extends CompBaseComm {
constructor() {
super();
this.createShadow();
super.createPropsObs();
this.fillWrap(this.propsProxy);
}
static get observedAttributes() {
return [...optPagination.map((k) => k.attr), 'options', 'async'];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
if (name === 'current') {
this.ins && newVal && this.ins.locate(newVal);
}
else {
super.updateProxy(name, newVal, optPagination);
}
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'slot-host' }, this.rawHtml);
}
createIns() {
if (this.ins)
return;
this.ins = new Pagination(this.wrapEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.propsProxy.async ? requestIdleCallback(() => this.createIns()) : this.createIns();
}
}
class StepElem extends CompBaseComm {
content;
template;
constructor() {
super();
this.template = `
{{let active = this.active?'active':'',
href = this.href ?'href="'+this.href+'"':'',
name = href?'a':'div',
target = href && this.target?'target="'+this.target+'"':'',
rel= href && this.rel?'rel="'+this.rel+'"':'';
/}}
<{{name}} {{href}} {{target}} {{rel}} {{active}} class="_step-item _reset">
<div class="_step-track">
<div></div>
<span ${ax.alias}="node"></span>
<div></div>
</div>
</{{name}}>
`;
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['active', 'type', 'theme', 'dir', 'error', ...this.baseAttrs];
static boolAttrs = ['head-show', 'body-show', 'inverted', 'justify'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, StepElem);
}
getRawData() {
this.getRawProps(StepElem);
this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.content = this.stdContent(this.getArrContent());
let fragment = document.createDocumentFragment();
for (let k of this.content) {
let node = tplToEl(renderTpl(this.template, k));
k.wrapEl = node;
k.wrapEl.querySelector(`[${ax.alias}="node"]`).innerHTML = this.getLegend(k);
k.headEl = createEl('div', { class: `${ax.prefix}step-head` }, k.tips);
k.labelEl = createEl('div', { [ax.alias]: 'label' }, k.label);
k.briefEl = createEl('div', { [ax.alias]: 'brief' }, k.brief);
k.bodyEl = createEl('div', { class: `${ax.prefix}step-body` }, [k.labelEl, k.briefEl]);
fragment.appendChild(node);
}
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, data.label);
this.wrapEl.appendChild(fragment);
}
getArrContent(content = this.propsProxy.content) {
let trim = content.trim(), tmp = createEl('div', {}, trim), firstChild = tmp.firstElementChild, result = [];
if (trim.startsWith('<') && firstChild) {
let nodeName = firstChild.nodeName;
if (nodeName === 'SCRIPT' && firstChild.getAttribute('type').includes('content')) {
result = parseStr({
content: firstChild.textContent,
type: 'array',
error: (err) => {
console.info(config.warn.parse, err);
}
});
}
else {
result = [...tmp.children].map((k, i) => {
let _tmp = {
label: k.getAttribute('label') || k.textContent.trim(),
brief: k.getAttribute('brief'),
tips: k.getAttribute('tips'),
icon: k.getAttribute('icon'),
cube: k.getAttribute('cube'),
image: k.getAttribute('image'),
disk: k.getAttribute('disk'),
};
if (k.nodeName === 'A') {
_tmp.target = k.getAttribute('target');
_tmp.rel = k.getAttribute('rel');
_tmp.href = k.getAttribute('href');
}
return _tmp;
});
}
}
else {
result = parseStr({
content,
type: 'array',
error: (err) => {
console.info(config.warn.parse, err);
}
});
}
return result;
}
stdContent(content) {
if (!Array.isArray(content)) {
console.warn(`The obtained data is not an array, an empty array has been returned!`);
return [];
}
return content.map((k, i) => {
if (typeof k === 'string' || typeof k === 'number') {
return { label: k, index: i + 1 };
}
else {
return Object.assign(k, { index: i + 1 });
}
});
}
getLegend(data) {
let type = this.propsProxy.type, dft = data.icon ? '<i class="' + data.icon + '"></i>' : data.image ? '<img src="' + data.image + '"/>' : data.index, result = '';
if (type?.includes('circle')) {
result = dft;
}
else if (type === 'plain') {
result = data.field ? (data.field === 'icon' ? '<i class="' + data.icon + '"></i>' : data.field === 'image' ? '<img src="' + data.image + '"/>' : data[data.field]) : dft;
}
return result;
}
setLegendType() {
for (let k of this.content) {
let tmp = this.getLegend(k);
k.wrapEl.querySelector(`[${ax.alias}="node"]`).innerHTML = tmp;
}
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
'head-show': this.changedHeadshow,
'body-show': this.changedBodyshow,
active: this.changedActive,
error: this.changedError,
content: this.changedContent,
type: this.changedType,
};
changedHeadshow(opt) {
for (let k of this.content) {
this.propsProxy['head-show'] ? k.wrapEl.insertAdjacentElement('afterbegin', k.headEl) : k.headEl.remove();
}
}
changedBodyshow(opt) {
for (let k of this.content) {
this.propsProxy['body-show'] ? k.wrapEl.insertAdjacentElement('beforeend', k.bodyEl) : k.bodyEl.remove();
}
}
changedActive(opt) {
if (opt.newVal) {
let tmp = Math.min(~~opt.newVal, this.content.length - 1);
for (let [i, k] of this.content.entries()) {
let bool = i === tmp ? true : false;
k.wrapEl.toggleAttribute('active', bool);
k.active = bool;
}
}
}
changedError(opt) {
let tmp = opt.newVal ? valToArr(opt.newVal) : [];
if (!tmp.length) {
for (let k of this.content) {
k.wrapEl.toggleAttribute('error', false);
}
}
else {
for (let [i, k] of this.content.entries()) {
k.wrapEl.toggleAttribute('error', tmp.includes(i) ? true : false);
}
}
}
changedContent(opt) {
if (opt.newVal) {
this.wrapEl.remove();
this.fillWrap(this.propsProxy);
this.appendChild(this.wrapEl);
}
}
changedType(opt) {
this.setLegendType();
}
}
class StatusElem extends CompBaseComm {
lampEl;
labelEl;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'lamp', 'current', ...this.baseAttrs];
static boolAttrs = [];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, StatusElem);
}
getRawData() {
this.getRawProps(StatusElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.lampEl = createEl('i', { [ax.alias]: 'lamp' });
this.labelEl = createEl('i', { [ax.alias]: 'label' }, this.propsProxy.lang?.info || config.lang.status.info);
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.lampEl);
this.propsRaw.label && this.wrapEl.appendChild(this.labelEl);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
lamp: this.changedLamp,
current: this.changedCurrent,
};
changedLabel(opt) {
if (opt.newVal === null) {
this.labelEl.remove();
}
else {
elState(this.labelEl).isVirtual && this.wrapEl.appendChild(this.labelEl);
let tmp = this.propsProxy.current || 'info';
this.labelEl.innerHTML = opt.newVal ? opt.newVal : this.propsProxy.lang?.[tmp] || config.lang.status[tmp];
}
}
changedLamp(opt) {
let attr = this.propsProxy.type === 'circle' ? 'borderColor' : 'background';
this.lampEl.style[attr] = opt.newVal || null;
}
changedCurrent(opt) {
if (opt.newVal) {
this.labelEl.innerHTML = this.propsProxy.lang?.[opt.newVal] || config.lang.status[opt.newVal];
}
}
}
class CategoryElem extends CompBaseComm {
headEl;
iconEl;
diskEl;
cubeEl;
imageEl;
labelEl;
tipsEl;
arrowEl;
legends;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = [...this.baseAttrs, 'size', 'theme', 'icon', 'disk', 'cube', 'image', 'tips', 'arrow'];
static get observedAttributes() {
return ['label', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, CategoryElem);
}
getRawData() {
this.getRawProps(CategoryElem);
this.propsRaw.label = this.getAttribute('label') || this.rawHtml;
this.getProxyProps();
}
fillWrap(data) {
this.labelEl = createEl('i', { [ax.alias]: 'label' }, data.label);
this.headEl = createEl('div', { [ax.alias]: 'head' }, this.labelEl);
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.headEl);
this.arrowEl = createEl('i', { [ax.alias]: 'arrow', class: `${ax.prefix}icon-right` });
this.tipsEl = createEl('i', { [ax.alias]: 'tips' }, data.tips);
this.iconEl = createEl('i', { [ax.alias]: 'icon', class: data.label });
this.diskEl = createEl('img', { [ax.alias]: 'disk', src: data.disk });
this.cubeEl = createEl('img', { [ax.alias]: 'cube', src: data.cube });
this.imageEl = createEl('img', { [ax.alias]: 'image', src: data.image });
this.legends = [
{ name: 'icon', el: this.iconEl, attr: 'class' },
{ name: 'disk', el: this.diskEl, attr: 'src' },
{ name: 'cube', el: this.cubeEl, attr: 'src' },
{ name: 'image', el: this.imageEl, attr: 'src' },
];
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
label: this.changedLabel,
icon: this.changedLegend,
disk: this.changedLegend,
cube: this.changedLegend,
image: this.changedLegend,
tips: this.changedTips,
arrow: this.changedArrow,
};
changedLabel(opt) {
this.labelEl.innerHTML = opt.newVal;
}
changedTips(opt) {
if (opt.newVal === null) {
this.tipsEl.remove();
}
else {
this.tipsEl.innerHTML = opt.newVal;
this.headEl.insertAdjacentElement('afterend', this.tipsEl);
}
}
changedArrow(opt) {
if (opt.newVal === null) {
this.arrowEl.remove();
}
else {
this.arrowEl.setAttribute('class', opt.newVal ? opt.newVal : `${ax.prefix}icon-right`);
this.wrapEl.appendChild(this.arrowEl);
}
}
changedLegend(opt) {
let item = this.legends.find((k) => k.name === opt.name);
if (opt.newVal) {
item.el.setAttribute(item.attr, opt.newVal);
elState(item.el).isVirtual && this.headEl.insertAdjacentElement('beforebegin', item.el);
for (let k of this.legends) {
k !== item && !elState(k.el).isVirtual && k.el.remove();
}
}
else {
item.el.remove();
}
}
}
class SkeletonElem extends CompBaseComm {
headEl;
iconEl;
diskEl;
cubeEl;
imageEl;
labelEl;
tipsEl;
arrowEl;
legends;
cols;
rows;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['type', 'anim', 'cols', 'rows', ...this.baseAttrs];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, SkeletonElem);
}
getRawData() {
this.getRawProps(SkeletonElem);
this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
this.getProxyProps();
this.cols = this.getCols();
this.rows = this.getRows();
}
fillWrap(data) {
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.getSkelStr());
}
getRows(str = this.propsProxy.rows) {
return ~~this.propsProxy.rows || 1;
}
getCols(str = this.propsProxy.cols) {
let val = null, obj;
if (isNull(str))
return val;
if (str?.includes(',')) {
obj = strToJson(str);
val = ~~obj[getScreenSize()];
}
else {
val = ~~str;
}
return val || 4;
}
getSkelStr() {
if (!this.propsProxy.type) {
if (this.propsProxy.content) {
return this.propsProxy.content.repeat((this.cols || 1) * this.rows);
}
else {
return '';
}
}
if (this.propsProxy.type === 'article') {
return `
<section>
<div rep="legend">
</div>
<div rep="text">
${'<div></div>'.repeat(this.rows > 1 ? this.rows : 19)}
</div>
</section>
`;
}
else {
let repeatNum = this.propsProxy.type.includes('avatar') ? 2 :
this.propsProxy.type === 'paragraph' ? 4 : 3, itemStr = `
<section>
<div rep="legend"></div>
<div rep="text">
${'<div></div>'.repeat(repeatNum)}
</div>
</section>
`;
return itemStr.repeat((this.cols || 1) * this.rows);
}
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
}
changedMaps = {
content: this.changedContent,
cols: this.changedCols,
rows: this.changedRows,
type: this.changedType
};
changedContent(opt) {
this.wrapEl.innerHTML = this.getSkelStr();
}
changedType(opt) {
this.wrapEl.innerHTML = this.getSkelStr();
}
changedCols(opt) {
this.cols = this.getCols(opt.newVal);
this.wrapEl.style.gridTemplateColumns = this.cols ? `repeat(${this.cols}, 1fr)` : null;
this.wrapEl.innerHTML = this.getSkelStr();
}
changedRows(opt) {
this.rows = this.getRows(opt.newVal);
this.wrapEl.innerHTML = this.getSkelStr();
}
}
class PillElem extends CompBaseComm {
content;
itemsEl;
thumbEl;
activeItem;
bodyEl;
inputEl;
value;
name;
constructor() {
super();
this.getRawData();
this.fillWrap(this.propsProxy);
}
static custAttrs = ['active', 'disable', 'refer', 'name', 'on-changed', ...this.baseAttrs];
static boolAttrs = ['disabled'];
static get observedAttributes() {
return ['content', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, PillElem);
}
getRawData() {
this.getRawProps(PillElem);
this.propsRaw.content = this.getAttribute('content') || this.rawHtml;
this.propsRaw.active = ~~this.propsRaw.active || 0;
this.getProxyProps();
}
getLegend(data) {
let tmp = (data.disk || data.cube || data.image);
return data.icon ? `<i class="${data.icon}" rep="icon"></i>` : tmp ? `<img src="${tmp}" rep="${tmp}" />` : '';
}
getItemsData(data) {
let content = super.getAttrHtmlData(data);
if (!Array.isArray(content)) {
console.warn(`The obtained data is not an array, an empty array has been returned!`);
return [];
}
return content.map((k, i) => {
return (typeof k === 'string' || typeof k === 'number') ? { label: k, index: i } : Object.assign(k, { index: i });
});
}
getItems(data = this.propsProxy) {
this.content = this.getItemsData(data.content);
let fragment = document.createDocumentFragment();
for (let [i, k] of this.content.entries()) {
let legend = this.getLegend(k), node = tplToEl(renderTpl(`<span ${ax.alias}="item" {{this.selected?'selected':''}} {{this.disabled?'disabled':''}}>${legend}<i rep=label>{{this.label}}</i></span>`, k));
k.wrapEl = node;
fragment.appendChild(node);
k.wrapEl.onclick = () => {
!k.selected && !k.disabled && this.active(i);
};
}
return fragment;
}
active(val = 0) {
let oldVal = this.content.find((k) => k.selected);
let tmp = Math.min(~~val, this.content.length - 1);
for (let [i, k] of this.content.entries()) {
let bool = i === tmp ? true : false;
k.wrapEl.toggleAttribute('selected', bool);
k.selected = bool;
if (bool) {
this.setTranslate(k.wrapEl);
this.activeItem = k;
this.value = k.label;
this.inputEl && (this.inputEl.value = k.label);
this.listen({ name: 'changed', params: [{ oldVal, newVal: k }] });
}
}
if (this.bodyEl) {
for (let [i, k] of [...this.bodyEl.children].entries()) {
let bool = i === tmp ? true : false;
k.toggleAttribute('selected', bool);
}
}
this.updateCache({ active: val });
}
disable(val) {
let arr = valToArr(val);
if (!arr.length)
return;
for (let k of arr) {
let tmp = Math.min(~~k, this.content.length - 1);
for (let [i, o] of this.content.entries()) {
let bool = i === tmp ? true : false;
o.wrapEl.toggleAttribute('disabled', bool);
o.disabled = bool;
}
}
this.updateCache({ disable: val });
this.listen({ name: 'disabled', params: [arr.map((k) => this.content[k])] });
}
setTranslate(el) {
this.style.setProperty(`--${ax.prefix}pill-thumb-offset`, el.offsetLeft + 'px');
this.style.setProperty(`--${ax.prefix}pill-thumb-w`, el.offsetWidth + 'px');
}
fillWrap(data = this.propsProxy) {
this.itemsEl = createEl('div', { [ax.alias]: 'items' });
this.thumbEl = createEl('span', { [ax.alias]: 'thumb' });
this.bodyEl = getEl(data.refer);
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, [this.itemsEl, this.thumbEl]);
this.itemsEl.appendChild(this.getItems(data));
}
render(data = this.propsProxy) {
this.insertSource();
this.appendChild(this.wrapEl);
this.active(data.active);
}
changedMaps = {
active: this.changedActive,
disable: this.changedDisable,
content: this.changedContent,
refer: this.changedRefer,
name: this.changedName,
};
changedActive(opt) {
opt.newVal && this.active(opt.newVal);
}
changedContent(opt) {
if (opt.newVal) {
this.itemsEl.innerHTML = '';
this.itemsEl.appendChild(this.getItems());
this.propsProxy.active && this.active(this.propsProxy.active);
this.propsProxy.disable && this.disable(this.propsProxy.disable);
}
}
changedDisable(opt) {
opt.newVal && this.disable(opt.newVal);
}
changedRefer(opt) {
if (opt.newVal) {
this.bodyEl = getEl(opt.newVal);
this.bodyEl && this.bodyEl.classList.add(`${ax.prefix}pill-body`);
}
}
changedName(opt) {
this.name = opt.newVal || '';
if (opt.newVal) {
if (this.inputEl) {
this.inputEl.setAttribute(opt.name, opt.newVal);
}
else {
this.inputEl = createEl('input', { type: 'text', name: opt.newVal, [ax.embedSign]: '' });
this.wrapEl.appendChild(this.inputEl);
}
}
else {
this.inputEl && this.inputEl.remove();
}
}
}
class ColorElem extends CompBaseCommField {
labelEl;
inputEvt;
meanEl;
colorIns;
type;
select;
updateEvt;
copyEl;
closeEl;
insOpts;
constructor() {
super();
this.type = 'color-comp';
this.getRawData();
this.fillWrap(this.propsProxy);
this.select = () => this.inputEl.inputEl.select();
this.updateEvt = debounce(() => {
this.ins.update(deepMerge(this.insOpts, this.propsProxy.color));
});
this.clear = (cb) => {
this.removeAttribute('value');
this.value = '';
this.setLamp();
this.inputEl.removeAttribute('value');
this.listen({ name: 'cleared', cb });
};
this.insOpts = {
output: {},
};
}
static dependencies = [
{ tag: 'ax-input', comp: InputElem },
{ tag: 'ax-btn', comp: BtnElem },
{ tag: 'ax-textarea', comp: TextareaElem },
{ tag: 'ax-checkbox', comp: CheckboxElem },
{ tag: 'ax-radio', comp: RadioElem },
{ tag: 'ax-radios', comp: RadiosElem }
];
static custAttrs = ['name', 'value', 'size', 'format', 'layout', 'placeholder', 'label', ...this.evtsArr];
static boolAttrs = ['manual', 'disabled', 'readonly', 'full', 'detectable'];
static jsonAttrs = ['color', 'lang'];
static get observedAttributes() {
return ['value', ...this.custAttrs, ...this.boolAttrs, ...this.jsonAttrs];
}
attributeChangedCallback(name, oldVal, newVal) {
if (!this.canListen)
return;
this.savePropsToListen(name, oldVal, newVal, ColorElem);
if (oldVal !== newVal) {
this.listen({ name: 'changed', params: [{ oldVal, newVal }] });
}
}
getRawData() {
this.getRawProps(ColorElem);
this.propsRaw.value = this.value = this.getAttribute('value') || this.rawHtml;
this.getProxyProps();
this.setFieldProps(['name', 'value', 'disabled', 'readOnly']);
}
fillWrap(data) {
this.inputEl = createEl('ax-input', {
value: this.value,
icon: `${ax.prefix}color-lamp`,
tools: "['copy','close']"
});
this.propsProxy.placeholder && this.inputEl.setAttribute('placeholder', this.propsProxy.placeholder);
this.propsProxy.disabled && this.inputEl.setAttribute('disabled', '');
this.propsProxy.readonly && this.inputEl.setAttribute('readonly', '');
this.propsProxy.full && this.inputEl.setAttribute('full', '');
this.wrapEl = createEl('div', { [ax.alias]: 'wrap' }, this.inputEl);
}
createIns() {
if (this.ins)
return;
this.ins = new Color(this.inputEl, deepMerge({
value: this.value,
popup: {
canClick: (target) => {
return this.copyEl.contains(target) || this.closeEl.contains(target) ? false : true;
},
b4Show: () => {
return new Promise((resolve) => {
!this.propsProxy.readonly && resolve();
});
},
onShow: () => {
this.propsProxy.detectable && this.value !== this.ins.value && this.ins.assignVals(this.value);
}
},
onCleared: () => {
this.clear();
},
onFilled: (val) => {
this.setAttribute('value', val);
}
}, this.propsProxy.color));
}
setLamp(value = this.value) {
this.style.setProperty(`--${ax.prefix}color-lamp`, value);
}
render() {
this.insertSource();
this.appendChild(this.wrapEl);
this.copyEl = getEl(`[${ax.alias}="copy"]`, this.inputEl.toolsEl);
this.closeEl = getEl(`[${ax.alias}="close"]`, this.inputEl.toolsEl);
this.closeEl.onclick = () => {
this.clear();
};
this.copyEl.onclick = () => {
if (!this.value)
return;
navigator.clipboard.writeText(this.value).then(() => new Toast({ content: this.ins.options.lang.message.copy, status: 'succ', eager: true }));
};
this.setLamp();
setTimeout(() => {
this.createIns();
}, 0);
}
changedMaps = {
disabled: this.changedDisabled,
readonly: this.changedReadonly,
size: this.changedSize,
label: this.changedSize,
name: this.changedName,
value: this.changedName,
format: this.changedFormat,
manual: this.changedManual,
layout: this.changedLayout,
color: this.changedColor,
};
changedDisabled(opt) {
this.disabled = this.propsProxy[opt.name];
this.inputEl.toggleAttribute(opt.name, this.propsProxy[opt.name]);
}
changedReadonly(opt) {
this.readOnly = this.propsProxy[opt.name];
this.inputEl.toggleAttribute(opt.name, this.propsProxy[opt.name]);
}
changedName(opt) {
this[opt.name] = opt.newVal || '';
this.inputEl.setAttribute(opt.name, this[opt.name]);
if (opt.name === 'value') {
this.setLamp();
}
}
changedSize(opt) {
if (opt.newVal) {
this.inputEl.setAttribute(opt.name, this[opt.name]);
}
else {
this.inputEl.removeAttribute(opt.name);
}
}
changedColor(opt) {
this.updateEvt();
}
changedFormat(opt) {
this.insOpts.output.format = opt.newVal;
this.updateEvt();
}
changedManual(opt) {
this.insOpts.output.manual = this.propsProxy.manual;
this.updateEvt();
}
changedLayout(opt) {
this.insOpts.layout = opt.newVal;
this.updateEvt();
}
}
var modules = {
ax,
config,
fieldTypes,
getDataType,
renderTpl,
getScreenSize,
sliceStrEnd,
delay,
toNumber,
toPixel,
preventDft,
events,
icons,
propsMap,
augment,
privacy,
support,
requireTypes,
trim,
getSelectorType,
isEmpty,
isNull,
getEl,
deepClone,
deepMerge,
strToJson,
attrToJson,
attrJoinVal,
extend,
plan,
instance,
breakpoints,
createEl,
purifyHtml,
startUpper,
storage,
isDateStr,
getExpiration,
ajax,
offset,
elState,
contains,
getEls,
getContent,
setContent,
createBtns,
createFooter,
createTools,
tplToEl,
tplToEls,
getHeights,
getWidths,
getElSpace,
slideDown,
slideUp,
slideToggle,
curveFns,
ease,
easeHeight,
fadeIn,
fadeOut,
fadeToggle,
style,
show,
hide,
toggle,
spreadBool,
getClasses,
classes,
validTools,
toLocalTime,
regExps,
replaceFrag,
combineArr,
sliceFrags,
paramToJson,
getLast,
fieldTools,
isSubset,
debounce,
throttle,
storeNode,
convertByte,
clampVal,
formTools,
fileTools,
unique,
increaseId,
treeTools,
valToArr,
moveItem,
getValsFromAttrs,
dl2Tree,
findItem,
findItems,
getAttrBool,
getAttrArr,
theme,
attrValBool,
getBetweenEls,
scrollTo,
allToEls,
getUTCTimestamp,
setAttr,
setAttrs,
getScrollObj,
transformTools,
isScrollUp,
eventMap,
getClientObj,
bulletTools,
arrSearch,
arrSort,
isProxy,
getNestProp,
getIntArr,
clearRegx,
isOutside,
getRectPoints,
elsSort,
getEvtTarget,
getEvtClient,
getStrFromTpl,
stdParam,
setSingleSel,
splitNum,
parseUrlArr,
getPlaces,
dateTools,
repeatStr,
createModule,
createComp,
getArrMap,
includes,
capStart,
removeItem,
deepEqual,
splice,
appendEls,
decompTask,
filterPrims,
createEvt,
confirm,
alert,
notice,
prompt,
keyCond,
removeStyle,
removeStyles,
addStyle,
addStyles,
regComp,
getComputedVar,
select2Tree,
ul2Tree,
parseStr,
getAutoDur,
getHypotenuse,
promiseRaf,
getRtl,
setRtl,
isChildVisible,
drawColor,
alpha2Hex,
hex2Alpha,
rgb2Hex,
rgb2Hsl,
rgb2Hwb,
hwb2Rgb,
hsl2Rgb,
hex2Rgb,
parseRgb,
hsl2Hwb,
hwb2Hsl,
ModBase,
ModBaseListen,
ModBaseListenCache,
ModBaseListenCacheBubble,
ModBaseListenCacheNest,
More,
Observe,
Position,
Hover,
Popup,
Dodge,
Message,
Valid,
Menu,
Tab,
Drawer,
Dialog,
Spy,
Tooltip,
Dropdown,
Gesture,
Tags,
Retrieval,
Autocomplete,
Scroll,
Drag,
Masonry,
Swipe,
Lazy,
Progress,
Infinite,
Virtualize,
Pagination,
Range,
Datetime,
Tree,
Rate,
Accordion,
Editor,
Select,
Upload,
Panel,
Router,
Flip,
Viewer,
Toast,
Color,
CompBase,
CompBaseComm,
CompBaseCommField,
CompBaseCommFieldMixin,
MoreElem,
ResultElem,
DeformElem,
RadioElem,
CheckboxElem,
BtnElem,
LineElem,
AvatarElem,
FormatElem,
FlagElem,
BuoyElem,
GoodElem,
AnchorsElem,
MenuElem,
FileElem,
InputElem,
TextareaElem,
RadiosElem,
CheckboxesElem,
NumberElem,
RangeElem,
StatsElem,
IconElem,
BadgeElem,
DividerElem,
AlarmElem,
ProgressElem,
DatetimeElem,
RateElem,
TreeElem,
AccordionElem,
EditorElem,
SelectElem,
UploadElem,
FieldsElem,
SearchElem,
CalloutElem,
TwilightElem,
PaginationElem,
StepElem,
StatusElem,
CategoryElem,
SkeletonElem,
PillElem,
ColorElem,
init,
};
var tmp = /*#__PURE__*/Object.freeze({
__proto__: null,
Accordion: Accordion,
AccordionElem: AccordionElem,
AlarmElem: AlarmElem,
AnchorsElem: AnchorsElem,
Autocomplete: Autocomplete,
AvatarElem: AvatarElem,
BadgeElem: BadgeElem,
BtnElem: BtnElem,
BuoyElem: BuoyElem,
CalloutElem: CalloutElem,
CategoryElem: CategoryElem,
CheckboxElem: CheckboxElem,
CheckboxesElem: CheckboxesElem,
Color: Color,
ColorElem: ColorElem,
CompBase: CompBase,
CompBaseComm: CompBaseComm,
CompBaseCommField: CompBaseCommField,
CompBaseCommFieldMixin: CompBaseCommFieldMixin,
Datetime: Datetime,
DatetimeElem: DatetimeElem,
DeformElem: DeformElem,
Dialog: Dialog,
DividerElem: DividerElem,
Dodge: Dodge,
Drag: Drag,
Drawer: Drawer,
Dropdown: Dropdown,
Editor: Editor,
EditorElem: EditorElem,
FieldsElem: FieldsElem,
FileElem: FileElem,
FlagElem: FlagElem,
Flip: Flip,
FormatElem: FormatElem,
Gesture: Gesture,
GoodElem: GoodElem,
Hover: Hover,
IconElem: IconElem,
Infinite: Infinite,
InputElem: InputElem,
Lazy: Lazy,
LineElem: LineElem,
Masonry: Masonry,
Menu: Menu,
MenuElem: MenuElem,
Message: Message,
ModBase: ModBase,
ModBaseListen: ModBaseListen,
ModBaseListenCache: ModBaseListenCache,
ModBaseListenCacheBubble: ModBaseListenCacheBubble,
ModBaseListenCacheNest: ModBaseListenCacheNest,
More: More,
MoreElem: MoreElem,
NumberElem: NumberElem,
Observe: Observe,
Pagination: Pagination,
PaginationElem: PaginationElem,
Panel: Panel,
PillElem: PillElem,
Popup: Popup,
Position: Position,
Progress: Progress,
ProgressElem: ProgressElem,
RadioElem: RadioElem,
RadiosElem: RadiosElem,
Range: Range,
RangeElem: RangeElem,
Rate: Rate,
RateElem: RateElem,
ResultElem: ResultElem,
Retrieval: Retrieval,
Router: Router,
Scroll: Scroll,
SearchElem: SearchElem,
Select: Select,
SelectElem: SelectElem,
SkeletonElem: SkeletonElem,
Spy: Spy,
StatsElem: StatsElem,
StatusElem: StatusElem,
StepElem: StepElem,
Swipe: Swipe,
Tab: Tab,
Tags: Tags,
TextareaElem: TextareaElem,
Toast: Toast,
Tooltip: Tooltip,
Tree: Tree,
TreeElem: TreeElem,
TwilightElem: TwilightElem,
Upload: Upload,
UploadElem: UploadElem,
Valid: Valid,
Viewer: Viewer,
Virtualize: Virtualize,
addStyle: addStyle,
addStyles: addStyles,
ajax: ajax,
alert: alert,
allToEls: allToEls,
alpha2Hex: alpha2Hex,
appendEls: appendEls,
arrSearch: arrSearch,
arrSort: arrSort,
attrJoinVal: attrJoinVal,
attrToJson: attrToJson,
attrValBool: attrValBool,
augment: augment,
ax: ax,
breakpoints: breakpoints,
bulletTools: bulletTools,
capStart: capStart,
clampVal: clampVal,
classes: classes,
clearRegx: clearRegx,
combineArr: combineArr,
config: config,
confirm: confirm,
contains: contains,
convertByte: convertByte,
createBtns: createBtns,
createComp: createComp,
createEl: createEl,
createEvt: createEvt,
createFooter: createFooter,
createModule: createModule,
createTools: createTools,
curveFns: curveFns,
dateTools: dateTools,
debounce: debounce,
decompTask: decompTask,
deepClone: deepClone,
deepEqual: deepEqual,
deepMerge: deepMerge,
default: modules,
delay: delay,
dl2Tree: dl2Tree,
drawColor: drawColor,
ease: ease,
easeHeight: easeHeight,
elState: elState,
elsSort: elsSort,
eventMap: eventMap,
events: events,
extend: extend,
fadeIn: fadeIn,
fadeOut: fadeOut,
fadeToggle: fadeToggle,
fieldTools: fieldTools,
fieldTypes: fieldTypes,
fileTools: fileTools,
filterPrims: filterPrims,
findItem: findItem,
findItems: findItems,
formTools: formTools,
getArrMap: getArrMap,
getAttrArr: getAttrArr,
getAttrBool: getAttrBool,
getAutoDur: getAutoDur,
getBetweenEls: getBetweenEls,
getClasses: getClasses,
getClientObj: getClientObj,
getComputedVar: getComputedVar,
getContent: getContent,
getDataType: getDataType,
getEl: getEl,
getElSpace: getElSpace,
getEls: getEls,
getEvtClient: getEvtClient,
getEvtTarget: getEvtTarget,
getExpiration: getExpiration,
getHeights: getHeights,
getHypotenuse: getHypotenuse,
getIntArr: getIntArr,
getLast: getLast,
getNestProp: getNestProp,
getPlaces: getPlaces,
getRectPoints: getRectPoints,
getRtl: getRtl,
getScreenSize: getScreenSize,
getScrollObj: getScrollObj,
getSelectorType: getSelectorType,
getStrFromTpl: getStrFromTpl,
getUTCTimestamp: getUTCTimestamp,
getValsFromAttrs: getValsFromAttrs,
getWidths: getWidths,
hex2Alpha: hex2Alpha,
hex2Rgb: hex2Rgb,
hide: hide,
hsl2Hwb: hsl2Hwb,
hsl2Rgb: hsl2Rgb,
hwb2Hsl: hwb2Hsl,
hwb2Rgb: hwb2Rgb,
icons: icons,
includes: includes,
increaseId: increaseId,
init: init,
instance: instance,
isChildVisible: isChildVisible,
isDateStr: isDateStr,
isEmpty: isEmpty,
isNull: isNull,
isOutside: isOutside,
isProxy: isProxy,
isScrollUp: isScrollUp,
isSubset: isSubset,
keyCond: keyCond,
moveItem: moveItem,
notice: notice,
offset: offset,
paramToJson: paramToJson,
parseRgb: parseRgb,
parseStr: parseStr,
parseUrlArr: parseUrlArr,
plan: plan,
preventDft: preventDft,
privacy: privacy,
promiseRaf: promiseRaf,
prompt: prompt,
propsMap: propsMap,
purifyHtml: purifyHtml,
regComp: regComp,
regExps: regExps,
removeItem: removeItem,
removeStyle: removeStyle,
removeStyles: removeStyles,
renderTpl: renderTpl,
repeatStr: repeatStr,
replaceFrag: replaceFrag,
requireTypes: requireTypes,
rgb2Hex: rgb2Hex,
rgb2Hsl: rgb2Hsl,
rgb2Hwb: rgb2Hwb,
scrollTo: scrollTo,
select2Tree: select2Tree,
setAttr: setAttr,
setAttrs: setAttrs,
setContent: setContent,
setRtl: setRtl,
setSingleSel: setSingleSel,
show: show,
sliceFrags: sliceFrags,
sliceStrEnd: sliceStrEnd,
slideDown: slideDown,
slideToggle: slideToggle,
slideUp: slideUp,
splice: splice,
splitNum: splitNum,
spreadBool: spreadBool,
startUpper: startUpper,
stdParam: stdParam,
storage: storage,
storeNode: storeNode,
strToJson: strToJson,
style: style,
support: support,
theme: theme,
throttle: throttle,
toLocalTime: toLocalTime,
toNumber: toNumber,
toPixel: toPixel,
toggle: toggle,
tplToEl: tplToEl,
tplToEls: tplToEls,
transformTools: transformTools,
treeTools: treeTools,
trim: trim,
ul2Tree: ul2Tree,
unique: unique,
valToArr: valToArr,
validTools: validTools
});
const _tmp = { ...tmp };
for (let k in _tmp) {
let comp = _tmp[k];
if (typeof comp !== 'function' || !comp?.name?.endsWith(`Elem`))
continue;
_tmp.regComp(comp);
}
document.addEventListener("DOMContentLoaded", () => {
for (let k of ax.tasks)
k();
ax.tasks = [];
});
ax.config.support && _tmp.support(true);
ax.config.privacy && _tmp.privacy({});
Reflect.deleteProperty(_tmp, 'ax');
Object.assign(ax, _tmp);
return ax;
}));