@whitesev/pops
Version:
弹窗库
1,759 lines (1,745 loc) • 89.1 kB
text/typescript
import { pops } from "../../Pops";
import { popsDOMUtils } from "../../utils/PopsDOMUtils";
import { PopsInstanceUtils } from "../../utils/PopsInstanceUtils";
import { PopsMathFloatUtils } from "../../utils/PopsMathUtils";
import { PopsSafeUtils } from "../../utils/PopsSafeUtils";
import { popsUtils } from "../../utils/PopsUtils";
import type { PopsAlertDetails } from "../alert/indexType";
import type { PopsTooltipResult } from "../tooltip";
import type { PopsToolTipDetails } from "../tooltip/indexType";
import type { PopsPanelButtonDetails } from "./buttonType";
import type { PopsPanelRightAsideContainerOptions } from "./commonType";
import type { PopsPanelDeepMenuDetails } from "./deepMenuType";
import type { PopsPanelFormsDetails } from "./formsType";
import type {
PopsPanelContentConfig,
PopsPanelDetails,
PopsPanelFormsTotalDetails,
} from "./indexType";
import type { PopsPanelInputDetails } from "./inputType";
import type { PopsPanelOwnDetails } from "./ownType";
import type {
PopsPanelSelectMultipleDataOption,
PopsPanelSelectMultipleDetails,
} from "./selectMultipleType";
import type { PopsPanelSelectDetails } from "./selectType";
import type { PopsPanelSliderDetails } from "./sliderType";
import type { PopsPanelSwitchDetails } from "./switchType";
import type { PopsPanelTextAreaDetails } from "./textareaType";
export const PanelHandleContentDetails = () => {
return {
/**
* 左侧的ul容器
*/
asideULElement: null as any as HTMLUListElement,
/**
* 右侧主内容的顶部文字ul容器
*/
sectionContainerHeaderULElement: null as any as HTMLUListElement,
/**
* 右侧主内容的ul容器
*/
sectionContainerULElement: null as any as HTMLUListElement,
/**
* 元素
*/
$el: {
/** 内容 */
$content: null as any as HTMLDivElement,
/** 左侧容器 */
$contentAside: null as any as HTMLDivElement,
/** 右侧容器 */
$contentSectionContainer: null as any as HTMLDivElement,
},
/**
* 初始化
* @param details
*/
init(details: {
config: Required<PopsPanelDetails>;
$el: {
$content: HTMLDivElement;
$contentAside: HTMLDivElement;
$contentSectionContainer: HTMLDivElement;
};
}) {
// @ts-ignore
this.$el = null;
this.$el = {
...details.$el,
};
this.asideULElement =
this.$el.$contentAside.querySelector<HTMLUListElement>("ul")!;
this.sectionContainerHeaderULElement =
this.$el.$contentSectionContainer.querySelectorAll<HTMLUListElement>(
"ul"
)[0];
this.sectionContainerULElement =
this.$el.$contentSectionContainer.querySelectorAll<HTMLUListElement>(
"ul"
)[1];
/**
* 默认点击的左侧容器项
*/
let $asideDefaultItemElement: HTMLLIElement | null = null;
/** 是否滚动到默认位置(第一个项) */
let isScrollToDefaultView = false;
details.config.content.forEach((asideItemConfig) => {
let $asideLiElement = this.createAsideItem(asideItemConfig);
this.setAsideItemClickEvent($asideLiElement, asideItemConfig);
this.asideULElement.appendChild($asideLiElement);
if ($asideDefaultItemElement == null) {
let flag = false;
if (typeof asideItemConfig.isDefault === "function") {
flag = Boolean(asideItemConfig.isDefault());
} else {
flag = Boolean(asideItemConfig.isDefault);
}
if (flag) {
$asideDefaultItemElement = $asideLiElement;
isScrollToDefaultView = Boolean(
asideItemConfig.scrollToDefaultView
);
}
}
if (typeof asideItemConfig.afterRender === "function") {
// 执行渲染完毕的回调
asideItemConfig.afterRender({
asideConfig: asideItemConfig,
$asideLiElement: $asideLiElement,
});
}
});
/* 点击左侧列表 */
if (
$asideDefaultItemElement == null &&
this.asideULElement.children.length
) {
/* 默认第一个 */
$asideDefaultItemElement = this.asideULElement
.children[0] as HTMLLIElement;
}
if ($asideDefaultItemElement) {
/* 点击选择的那一项 */
$asideDefaultItemElement.click();
if (isScrollToDefaultView) {
$asideDefaultItemElement?.scrollIntoView();
}
} else {
console.error("pops.panel:左侧容器没有项");
}
},
/**
* 清空container容器的元素
*/
clearContainer() {
PopsSafeUtils.setSafeHTML(this.sectionContainerHeaderULElement, "");
PopsSafeUtils.setSafeHTML(this.sectionContainerULElement, "");
this.$el.$content
?.querySelectorAll("section.pops-panel-deepMenu-container")
.forEach((ele) => ele.remove());
},
/**
* 清空左侧容器已访问记录
*/
clearAsideItemIsVisited() {
this.$el.$contentAside
.querySelectorAll<HTMLDivElement>(".pops-is-visited")
.forEach((element) => {
popsDOMUtils.removeClassName(element, "pops-is-visited");
});
},
/**
* 设置左侧容器已访问记录
* @param element
*/
setAsideItemIsVisited(element: HTMLElement) {
popsDOMUtils.addClassName(element, "pops-is-visited");
},
/**
* 为元素添加自定义属性
* @param element
* @param attributes
*/
setElementAttributes(element: HTMLElement, attributes?: any) {
if (attributes == null) {
return;
}
if (Array.isArray(attributes)) {
attributes.forEach((attrObject) => {
this.setElementAttributes(element, attrObject);
});
} else {
Object.keys(attributes).forEach((attributeName) => {
element.setAttribute(attributeName, attributes[attributeName]);
});
}
},
/**
* 为元素设置(自定义)属性
* @param element
* @param props
*/
setElementProps(element: HTMLElement, props?: any) {
if (props == null) {
return;
}
Object.keys(props).forEach((propName) => {
let value = props[propName];
if (propName === "innerHTML") {
PopsSafeUtils.setSafeHTML(element, value);
return;
}
Reflect.set(element, propName, value);
});
},
/**
* 为元素设置classname
* @param element
* @param className
*/
setElementClassName(
element: HTMLElement,
className?: string | string[] | (() => string | string[])
) {
if (className == null) {
return;
}
if (typeof className === "function") {
className = className();
}
if (typeof className === "string") {
let splitClassName = className.split(" ");
splitClassName.forEach((classNameStr) => {
element.classList.add(classNameStr);
});
} else if (Array.isArray(className)) {
className.forEach((classNameStr) => {
this.setElementClassName(element, classNameStr);
});
}
},
/**
* 创建左侧容器元素<li>
* @param asideConfig
*/
createAsideItem(asideConfig: PopsPanelContentConfig) {
let liElement = document.createElement("li");
liElement.id = asideConfig.id;
// @ts-ignore
liElement["__forms__"] = asideConfig.forms;
PopsSafeUtils.setSafeHTML(liElement, asideConfig.title);
/* 处理className */
this.setElementClassName(liElement, asideConfig.className);
this.setElementAttributes(liElement, asideConfig.attributes);
this.setElementProps(liElement, asideConfig.props);
return liElement;
},
/**
* 创建中间容器的元素<li>
* type ==> switch
* @param formConfig
*/
createSectionContainerItem_switch(formConfig: PopsPanelSwitchDetails) {
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = /*html*/ `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-switch">
<input class="pops-panel-switch__input" type="checkbox">
<span class="pops-panel-switch__core">
<div class="pops-panel-switch__action">
</div>
</span>
</div>`
);
const PopsPanelSwitch = {
[Symbol.toStringTag]: "PopsPanelSwitch",
$data: {
value: Boolean(formConfig.getValue()),
},
$ele: {
switch:
liElement.querySelector<HTMLDivElement>(".pops-panel-switch")!,
input: liElement.querySelector<HTMLInputElement>(
".pops-panel-switch__input"
)!,
core: liElement.querySelector<HTMLSpanElement>(
".pops-panel-switch__core"
)!,
},
init() {
this.setStatus(this.$data.value);
if (formConfig.disabled) {
this.disable();
}
this.setClickEvent();
},
setClickEvent() {
let that = this;
popsDOMUtils.on(this.$ele.core, "click", void 0, function (event) {
if (
that.$ele.input.disabled ||
that.$ele.switch.hasAttribute("data-disabled")
) {
return;
}
that.$data.value = that.getStatus();
that.setStatus(that.$data.value);
if (typeof formConfig.callback === "function") {
formConfig.callback(event, that.$data.value);
}
});
},
/**
* 设置状态
*/
setStatus(isChecked = false) {
isChecked = Boolean(isChecked);
this.$ele.input.checked = isChecked;
if (isChecked) {
popsDOMUtils.addClassName(
this.$ele.switch,
"pops-panel-switch-is-checked"
);
} else {
popsDOMUtils.removeClassName(
this.$ele.switch,
"pops-panel-switch-is-checked"
);
}
},
/**
* 根据className来获取逆反值
*/
getStatus() {
let checkedValue = false;
if (
!popsDOMUtils.containsClassName(
this.$ele.switch,
"pops-panel-switch-is-checked"
)
) {
checkedValue = true;
}
return checkedValue;
},
/**
* 禁用复选框
*/
disable() {
this.$ele.input.disabled = true;
this.$ele.switch.setAttribute("data-disabled", "true");
},
/**
* 启用复选框
*/
notDisable() {
this.$ele.input.disabled = false;
this.$ele.switch.removeAttribute("data-disabled");
},
};
PopsPanelSwitch.init();
(liElement as any)["data-switch"] = PopsPanelSwitch;
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> slider
* @param formConfig
*/
createSectionContainerItem_slider(formConfig: PopsPanelSliderDetails) {
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-slider">
<input type="range" min="${formConfig.min}" max="${formConfig.max}">
</div>
`
);
let rangeInputElement = liElement.querySelector<HTMLInputElement>(
".pops-panel-slider input[type=range]"
)!;
if (formConfig.step) {
rangeInputElement.setAttribute("step", formConfig.step.toString());
}
rangeInputElement.value = formConfig.getValue().toString();
/**
* 获取提示的内容
* @param value
*/
let getToolTipContent = function (value: number | string) {
if (typeof formConfig.getToolTipContent === "function") {
return formConfig.getToolTipContent(value as number);
} else {
return value as string;
}
};
let tooltip = pops.tooltip({
target: rangeInputElement.parentElement!,
content: () => {
return getToolTipContent(rangeInputElement.value);
},
zIndex: () => {
return PopsInstanceUtils.getPopsMaxZIndex().zIndex;
},
className: "github-tooltip",
alwaysShow: false,
only: false,
position: "top",
arrowDistance: 10,
});
popsDOMUtils.on(
rangeInputElement,
["input", "propertychange"],
void 0,
function (event) {
tooltip.toolTip.changeContent(
getToolTipContent(rangeInputElement.value)
);
if (typeof formConfig.callback === "function") {
formConfig.callback(
event as InputEvent,
(event as any).target.value
);
}
}
);
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> slider
* @param formConfig
*/
createSectionContainerItem_slider_new(formConfig: PopsPanelSliderDetails) {
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = /*html*/ `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text" style="flex: 1;">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-slider pops-slider-width">
<div class="pops-slider__runway">
<div class="pops-slider__bar" style="width: 0%; left: 0%"></div>
<div class="pops-slider__button-wrapper" style="left: 0%">
<div class="pops-slider__button"></div>
</div>
</div>
</div>`
);
const PopsPanelSlider = {
[Symbol.toStringTag]: "PopsPanelSlider",
/**
* 值
*/
value: formConfig.getValue(),
/**
* 最小值
*/
min: formConfig.min,
/**
* 最大值
*/
max: formConfig.max,
/**
* 间隔
*/
step: formConfig.step || 1,
$data: {
/**
* 是否正在移动
*/
isMove: false,
/**
* 是否已初始化已拖拽的距离
*/
isInitDragPosition: false,
/**
* 是否正在检测是否停止拖拽
*/
isCheckingStopDragMove: false,
/**
* 总宽度(px)
*/
totalWidth: 0,
/**
* 每一块的间隔(px)
*/
stepPx: 0,
/**
* 已拖拽的距离(px)
*/
dragWidth: 0,
/**
* 已拖拽的百分比
*/
dragPercent: 0,
/**
* 每一次块的信息
* 例如:当最小值是2,最大值是10,step为2
* 那么生成[2,4,6,8,10] 共计5个
* 又获取到当前滑块总长度是200px
* 那么生成映射
* 2 => 0px~40px
* 4 => 40px~80px
* 6 => 80px~120px
* 8 => 120px~160px
* 10 => 160px~200px
*/
stepBlockMap: new Map<
number,
{
value: number;
px: number;
pxLeft: number;
pxRight: number;
percent: number;
}
>(),
tooltip: null as any as PopsTooltipResult<PopsToolTipDetails>,
},
$ele: {
slider: liElement.querySelector<HTMLDivElement>(".pops-slider")!,
runAway: liElement.querySelector<HTMLDivElement>(
".pops-slider__runway"
)!,
bar: liElement.querySelector<HTMLDivElement>(".pops-slider__bar")!,
buttonWrapper: liElement.querySelector<HTMLDivElement>(
".pops-slider__button-wrapper"
)!,
button: liElement.querySelector<HTMLDivElement>(
".pops-slider__button"
)!,
},
$interval: {
isCheck: false,
},
$tooltip: null as any,
init() {
this.initEleData();
this.setToolTipEvent();
this.setPanEvent();
this.setRunAwayClickEvent();
this.intervalInit();
if (formConfig.disabled) {
this.disableDrag();
}
},
/**
* 10s内循环获取slider的宽度等信息
* 获取到了就可以初始化left的值
* @param {number} [checkStepTime=200] 每次检测的间隔时间
* @param {number} [maxTime=10000] 最大的检测时间
*/
intervalInit(checkStepTime = 200, maxTime = 10000) {
if (this.$interval.isCheck) {
return;
}
this.$interval.isCheck = true;
let isSuccess = false;
let oldTotalWidth = this.$data.totalWidth;
let timer: number | undefined = void 0;
let interval = setInterval(() => {
if (isSuccess) {
this.$interval.isCheck = false;
clearTimeout(timer);
clearInterval(interval);
} else {
this.initTotalWidth();
if (this.$data.totalWidth !== 0) {
isSuccess = true;
if (this.$data.totalWidth !== oldTotalWidth) {
/* slider的总宽度改变了 */
if (PopsMathFloatUtils.isFloat(this.step)) {
this.initFloatStepMap();
} else {
this.initStepMap();
}
this.initSliderPosition();
}
}
}
}, checkStepTime);
/* 最长检测时间是10s */
timer = setTimeout(() => {
clearInterval(interval);
}, maxTime);
},
/**
* 把数据添加到元素上
*/
initEleData() {
this.$ele.slider.setAttribute("data-min", this.min.toString());
this.$ele.slider.setAttribute("data-max", this.max.toString());
this.$ele.slider.setAttribute("data-value", this.value.toString());
this.$ele.slider.setAttribute("data-step", this.step.toString());
(this.$ele.slider as any)["data-min"] = this.min;
(this.$ele.slider as any)["data-max"] = this.max;
(this.$ele.slider as any)["data-value"] = this.value;
(this.$ele.slider as any)["data-step"] = this.step;
},
/**
* 初始化滑块的总长度的数据(px)
*/
initTotalWidth() {
this.$data.totalWidth = popsDOMUtils.width(this.$ele.runAway);
},
/**
* 初始化每一个块的具体数据信息
*/
initStepMap() {
let index = 0;
// 计算出份数
let blockNums = (this.max - this.min) / this.step;
// 计算出每一份占据的px
this.$data.stepPx = this.$data.totalWidth / blockNums;
let widthPx = 0;
for (
let stepValue = this.min;
stepValue <= this.max;
stepValue += this.step
) {
let value = this.formatValue(stepValue);
let info = {};
if (value === this.min) {
/* 起始 */
info = {
value: value,
px: 0,
pxLeft: 0,
pxRight: this.$data.stepPx / 2,
percent: 0,
};
} else {
info = {
value: value,
px: widthPx,
pxLeft: widthPx - this.$data.stepPx / 2,
pxRight: widthPx + this.$data.stepPx / 2,
percent: widthPx / this.$data.totalWidth,
};
//if (value === this.max) {
// info["pxLeft"] = this.$data.stepBlockMap.get(
// index - 1
// ).pxRight;
// info["pxRight"] = this.$data.totalWidth;
//}
}
this.$data.stepBlockMap.set(index, info as any);
index++;
widthPx += this.$data.stepPx;
}
},
/**
* 初始化每一个块的具体数据信息(浮点)
*/
initFloatStepMap() {
let index = 0;
// 计算出份数
let blockNums = (this.max - this.min) / this.step;
// 计算出每一份占据的px
this.$data.stepPx = this.$data.totalWidth / blockNums;
let widthPx = 0;
for (
let stepValue = this.min;
stepValue <= this.max;
stepValue = PopsMathFloatUtils.add(stepValue, this.step)
) {
let value = this.formatValue(stepValue);
let info = {};
if (value === this.min) {
/* 起始 */
info = {
value: value,
px: 0,
pxLeft: 0,
pxRight: this.$data.stepPx / 2,
percent: 0,
};
} else {
info = {
value: value,
px: widthPx,
pxLeft: widthPx - this.$data.stepPx / 2,
pxRight: widthPx + this.$data.stepPx / 2,
percent: widthPx / this.$data.totalWidth,
};
//if (value === this.max) {
// info["pxLeft"] = this.$data.stepBlockMap.get(
// index - 1
// ).pxRight;
// info["pxRight"] = this.$data.totalWidth;
//}
}
this.$data.stepBlockMap.set(index, info as any);
index++;
widthPx += this.$data.stepPx;
}
},
/**
* 初始化slider的默认起始left的百分比值
*/
initSliderPosition() {
/* 设置起始默认style的left值 */
let percent = 0;
for (const [, stepBlockInfo] of this.$data.stepBlockMap.entries()) {
/* 判断值是否和区域内的值相等 */
if (stepBlockInfo.value == this.value) {
percent = stepBlockInfo.percent;
this.$data.dragWidth = stepBlockInfo.px;
break;
}
}
percent = this.formatValue(percent * 100);
this.setSliderPosition(percent);
},
/**
* 判断数字是否是浮点数
* @param num
* @returns
*/
isFloat(num: number) {
return Number(num) === num && num % 1 !== 0;
},
/**
* 值改变的回调
* @param event
* @param value
*/
valueChangeCallBack(event: any, value: number) {
if (typeof formConfig.callback === "function") {
formConfig.callback(event, value);
}
},
/**
* 根据拖拽距离获取滑块应该在的区间和值
*/
getDragInfo(dragX: number) {
let result = this.$data.stepBlockMap.get(0);
for (const [, stepBlockInfo] of this.$data.stepBlockMap.entries()) {
if (
stepBlockInfo.pxLeft <= dragX &&
dragX < stepBlockInfo.pxRight
) {
result = stepBlockInfo;
break;
}
}
return result;
},
/**
* 获取滑块的当前脱拖拽占据的百分比
* @param {number} dragWidth
*/
getSliderPositonPercent(dragWidth: number) {
return dragWidth / this.$data.totalWidth;
},
/**
* 根据step格式化value
* @param num
*/
formatValue(num: number) {
if (PopsMathFloatUtils.isFloat(this.step)) {
num = parseFloat(num.toFixed(2));
} else {
num = parseInt(num.toString());
}
return num;
},
/**
* 设置滑块的位置偏移(left)
* @param percent 百分比
*/
setSliderPosition(percent: number) {
if (parseInt(percent.toString()) === 1) {
percent = 1;
}
if (percent > 1) {
percent = percent / 100;
}
/* 滑块按钮的偏移 */
this.$ele.buttonWrapper.style.left = `${percent * 100}%`;
/* 滑块进度的宽度 */
this.$ele.bar.style.width = `${percent * 100}%`;
},
/**
* 禁止拖拽
*/
disableDrag() {
this.$ele.runAway.classList.add("pops-slider-is-disabled");
},
/**
* 允许拖拽
*/
allowDrag() {
this.$ele.runAway.classList.remove("pops-slider-is-disabled");
},
/**
* 判断当前滑块是否被禁用
*/
isDisabledDrag() {
return this.$ele.runAway.classList.contains(
"pops-slider-is-disabled"
);
},
/**
* 设置进度条点击定位的事件
*/
setRunAwayClickEvent() {
popsDOMUtils.on(
this.$ele.runAway,
"click",
void 0,
(event) => {
if (
event.target !== this.$ele.runAway &&
event.target !== this.$ele.bar
) {
return;
}
let clickX = parseFloat((event as any).offsetX);
this.dragStartCallBack();
this.dragMoveCallBack(event, clickX, this.value);
this.dragEndCallBack(clickX);
},
{
capture: false,
}
);
},
/**
* 拖拽开始的回调,如果返回false,禁止拖拽
*/
dragStartCallBack() {
if (!this.$data.isMove) {
if (this.isDisabledDrag()) {
return false;
}
this.$data.isMove = true;
}
return true;
},
/**
* 拖拽中的回调
* @param event 事件
* @param dragX 当前拖拽的距离
* @param oldValue 旧的值
*/
dragMoveCallBack(
event: MouseEvent | TouchEvent,
dragX: number,
oldValue: number
) {
let dragPercent = 0;
if (dragX <= 0) {
dragPercent = 0;
this.value = this.min;
} else if (dragX >= this.$data.totalWidth) {
dragPercent = 1;
this.value = this.max;
} else {
const dragInfo = this.getDragInfo(dragX)!;
dragPercent = dragInfo.percent;
this.value = this.formatValue(dragInfo.value);
}
this.$data.dragPercent = dragPercent;
this.setSliderPosition(this.$data.dragPercent);
this.showToolTip();
if (oldValue !== this.value) {
this.valueChangeCallBack(event, this.value);
}
},
/**
* 拖拽结束的回调
*/
dragEndCallBack(dragX: number) {
this.$data.isMove = false;
if (dragX <= 0) {
this.$data.dragWidth = 0;
} else if (dragX >= this.$data.totalWidth) {
this.$data.dragWidth = this.$data.totalWidth;
} else {
this.$data.dragWidth = dragX;
}
this.closeToolTip();
},
/**
* 设置点击拖拽事件
*/
setPanEvent() {
const AnyTouch = popsUtils.AnyTouch();
this.$tooltip = new AnyTouch(this.$ele.button, {
preventDefault() {
return false;
},
});
/**
* 当前的拖拽的距离px
*/
let currentDragX = 0;
/* 监听拖拽 */
this.$tooltip.on("at:move", (event: any) => {
if (!this.dragStartCallBack()) {
return;
}
let oldValue = this.value;
const runAwayRect = this.$ele.runAway.getBoundingClientRect();
let displacementX =
event.x - (runAwayRect.left + globalThis.screenX);
if (displacementX <= 0) {
displacementX = 0;
} else if (displacementX >= runAwayRect.width) {
displacementX = runAwayRect.width;
}
currentDragX = displacementX;
/* 拖拽移动 */
this.dragMoveCallBack(event, currentDragX, oldValue);
});
/* 监听触点离开,处理某些情况下,拖拽松开,但是未触发pan事件,可以通过设置这个来关闭tooltip */
this.$tooltip.on("at:end", (event: any) => {
this.dragEndCallBack(currentDragX);
});
},
/**
* 显示悬浮的
*/
showToolTip() {
this.$data.tooltip.toolTip.show();
},
/**
* 关闭悬浮的
*/
closeToolTip() {
this.$data.tooltip.toolTip.close();
},
/**
* 检测在1000ms内,是否停止了拖拽
*/
checkStopDragMove() {
if (this.$data.isCheckingStopDragMove) {
return;
}
this.$data.isCheckingStopDragMove = true;
let interval = setInterval(() => {
if (!this.$data.isMove) {
this.$data.isCheckingStopDragMove = false;
this.closeToolTip();
clearInterval(interval);
}
}, 200);
setTimeout(() => {
this.$data.isCheckingStopDragMove = false;
clearInterval(interval);
}, 2000);
},
/**
* 设置拖拽按钮的悬浮事件
*/
setToolTipEvent() {
/**
* 获取提示的内容
*/
function getToolTipContent() {
if (typeof formConfig.getToolTipContent === "function") {
return formConfig.getToolTipContent(PopsPanelSlider.value);
} else {
return PopsPanelSlider.value as any as string;
}
}
let tooltip = pops.tooltip({
target: this.$ele.button,
content: getToolTipContent,
zIndex: () => {
return PopsInstanceUtils.getPopsMaxZIndex().zIndex;
},
isFixed: true,
className: "github-tooltip",
only: false,
eventOption: {
capture: true,
passive: true,
},
showBeforeCallBack: () => {
this.intervalInit();
},
showAfterCallBack: (toolTipNode) => {
tooltip.toolTip.changeContent(getToolTipContent());
},
closeBeforeCallBack: () => {
if (this.$data.isMove) {
this.checkStopDragMove();
return false;
} else {
}
},
alwaysShow: false,
position: "top",
arrowDistance: 10,
});
this.$data.tooltip = tooltip;
},
};
PopsPanelSlider.init();
(liElement as any)["data-slider"] = PopsPanelSlider;
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> input
* @param formConfig
*/
createSectionContainerItem_input(formConfig: PopsPanelInputDetails) {
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
let inputType = "text";
if (formConfig.isPassword) {
inputType = "password";
} else if (formConfig.isNumber) {
inputType = "number";
}
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-input pops-user-select-none">
<input type="${inputType}" placeholder="${formConfig.placeholder}">
</div>
`
);
const PopsPanelInput = {
[Symbol.toStringTag]: "PopsPanelInput",
$ele: {
panelInput:
liElement.querySelector<HTMLDivElement>(".pops-panel-input")!,
input: liElement.querySelector<HTMLInputElement>("input")!,
inputSpanIcon: document.createElement("span"),
inputSpanIconInner: null as any as HTMLSpanElement,
icon: null as any as HTMLElement,
},
$data: {
value: formConfig.getValue(),
isView: false,
},
init() {
this.initEle();
this.setInputValue(this.$data.value);
/* 如果是密码框,放进图标 */
if (formConfig.isPassword) {
this.setCircleIcon(pops.config.iconSVG.view);
this.setCircleIconClickEvent();
} else {
/* 先判断预设值是否为空,不为空添加清空图标按钮 */
if (this.$ele.input.value != "") {
this.setCircleIcon(pops.config.iconSVG.circleClose);
this.setCircleIconClickEvent();
}
}
this.setInputChangeEvent();
if (formConfig.disabled) {
this.disable();
}
if (typeof formConfig.handlerCallBack === "function") {
formConfig.handlerCallBack(liElement, this.$ele.input);
}
},
/**
* 初始化$ele的配置
*/
initEle() {
this.$ele.input.parentElement!.insertBefore(
this.$ele.inputSpanIcon,
this.$ele.input.nextSibling
);
this.$ele.inputSpanIcon.className = "pops-panel-input__suffix";
PopsSafeUtils.setSafeHTML(
this.$ele.inputSpanIcon,
/*html*/ `
<span class="pops-panel-input__suffix-inner">
<i class="pops-panel-icon"></i>
</span>
`
);
this.$ele.inputSpanIconInner =
this.$ele.inputSpanIcon.querySelector<HTMLElement>(
".pops-panel-input__suffix-inner"
)!;
this.$ele.icon =
this.$ele.inputSpanIcon.querySelector<HTMLElement>(
".pops-panel-icon"
)!;
},
/**
* 禁用
*/
disable() {
this.$ele.input.disabled = true;
this.$ele.panelInput.classList.add("pops-input-disabled");
},
/**
* 取消禁用
*/
notDisable() {
this.$ele.input.disabled = false;
this.$ele.panelInput.classList.remove("pops-input-disabled");
},
/**
* 判断是否已被禁用
*/
isDisabled() {
return this.$ele.input.disabled;
},
/**
* 设置输入框内容
* @param {string} [value=""] 值
*/
setInputValue(value = "") {
this.$ele.input.value = value;
},
/**
* 设置input元素的type
* @param [typeValue="text"] type值
*/
setInputType(typeValue = "text") {
this.$ele.input.setAttribute("type", typeValue);
},
/**
* 删除图标按钮
*/
removeCircleIcon() {
PopsSafeUtils.setSafeHTML(this.$ele.icon, "");
},
/**
* 添加清空图标按钮
* @param [svgHTML=pops.config.iconSVG.circleClose] svg图标,默认为清空的图标
*/
setCircleIcon(svgHTML = pops.config.iconSVG.circleClose) {
PopsSafeUtils.setSafeHTML(this.$ele.icon, svgHTML);
},
/**
* 添加图标按钮的点击事件
*/
setCircleIconClickEvent() {
popsDOMUtils.on(this.$ele.icon, "click", void 0, () => {
if (this.isDisabled()) {
return;
}
/* 删除图标 */
this.removeCircleIcon();
if (formConfig.isPassword) {
/* 密码输入框 */
if (this.$data.isView) {
/* 当前可见 => 点击改变为隐藏 */
this.$data.isView = false;
/* 显示输入框内容,且更换图标为隐藏图标 */
this.setInputType("text");
this.setCircleIcon(pops.config.iconSVG.hide);
} else {
/* 当前不可见 => 点击改变为显示 */
this.$data.isView = true;
/* 隐藏输入框内容,且更换图标为显示图标 */
this.setInputType("password");
this.setCircleIcon(pops.config.iconSVG.view);
}
} else {
/* 普通输入框 */
/* 清空内容 */
this.setInputValue("");
/* 获取焦点 */
this.$ele.input.focus();
/* 触发内容改变事件 */
this.$ele.input.dispatchEvent(new Event("input"));
}
});
},
/**
* 监听输入框内容改变
*/
setInputChangeEvent() {
popsDOMUtils.on(
this.$ele.input,
["input", "propertychange"],
void 0,
(event) => {
this.$data.value = this.$ele.input.value;
if (!formConfig.isPassword) {
/* 不是密码框 */
if (
this.$ele.input.value !== "" &&
this.$ele.icon.innerHTML === ""
) {
/* 不为空,显示清空图标 */
this.setCircleIcon(pops.config.iconSVG.circleClose);
this.setCircleIconClickEvent();
} else if (this.$ele.input.value === "") {
this.removeCircleIcon();
}
}
if (typeof formConfig.callback === "function") {
if (formConfig.isNumber) {
formConfig.callback(
event as any,
this.$ele.input.value,
this.$ele.input.valueAsNumber
);
} else {
formConfig.callback(event as any, this.$ele.input.value);
}
}
}
);
},
};
PopsPanelInput.init();
(liElement as any)["data-input"] = PopsPanelInput;
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> textarea
* @param formConfig
*/
createSectionContainerItem_textarea(formConfig: PopsPanelTextAreaDetails) {
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-textarea">
<textarea placeholder="${formConfig.placeholder ?? ""}">
</textarea>
</div>
`
);
const PopsPanelTextArea = {
[Symbol.toStringTag]: "PopsPanelTextArea",
$ele: {
panelTextarea: liElement.querySelector<HTMLDivElement>(
".pops-panel-textarea"
)!,
textarea: liElement.querySelector<HTMLTextAreaElement>(
".pops-panel-textarea textarea"
)!,
},
$data: {
value: formConfig.getValue(),
},
init() {
this.setValue(this.$data.value);
this.setChangeEvent();
if (formConfig.disabled) {
this.disable();
}
},
disable() {
this.$ele.textarea.setAttribute("disabled", "true");
this.$ele.panelTextarea.classList.add("pops-panel-textarea-disable");
},
notDisable() {
this.$ele.textarea.removeAttribute("disabled");
this.$ele.panelTextarea.classList.remove(
"pops-panel-textarea-disable"
);
},
isDisabled() {
return (
this.$ele.textarea.hasAttribute("disabled") ||
this.$ele.panelTextarea.classList.contains(
"pops-panel-textarea-disable"
)
);
},
setValue(value: string) {
this.$ele.textarea.value = value;
},
/**
* 监听选择内容改变
*/
setChangeEvent() {
popsDOMUtils.on(
this.$ele.textarea,
["input", "propertychange"],
void 0,
(event) => {
this.$data.value = (event as any).target.value;
if (typeof formConfig.callback === "function") {
formConfig.callback(event as any, (event as any).target.value);
}
}
);
},
};
PopsPanelTextArea.init();
(liElement as any)["data-textarea"] = PopsPanelTextArea;
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> select
* @param formConfig
*/
createSectionContainerItem_select(formConfig: PopsPanelSelectDetails<any>) {
const that = this;
let liElement = document.createElement("li");
(liElement as any)["__formConfig__"] = formConfig;
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = /*html*/ `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-select pops-user-select-none">
<select></select>
</div>
`
);
const PopsPanelSelect = {
[Symbol.toStringTag]: "PopsPanelSelect",
$ele: {
panelSelect:
liElement.querySelector<HTMLDivElement>(".pops-panel-select")!,
select: liElement.querySelector<HTMLSelectElement>(
".pops-panel-select select"
)!,
},
$eleKey: {
disable: "__disable__",
value: "__value__",
forms: "__forms__",
},
$data: {
defaultValue: formConfig.getValue(),
},
init() {
this.initOption();
this.setChangeEvent();
this.setClickEvent();
if (formConfig.disabled) {
this.disable();
}
},
/**
* 给option元素设置属性
* @param $ele
* @param key
* @param value
*/
setNodeValue($ele: HTMLElement, key: string, value: any) {
Reflect.set($ele, key, value);
},
/**
* 获取option元素上设置的属性
* @param $ele
* @param value
* @param key
*/
getNodeValue($ele: HTMLElement, key: string) {
return Reflect.get($ele, key);
},
/**
* 禁用选项
*/
disable() {
this.$ele.select.setAttribute("disabled", "true");
this.$ele.panelSelect.classList.add("pops-panel-select-disable");
},
/**
* 取消禁用
*/
notDisable() {
this.$ele.select.removeAttribute("disabled");
this.$ele.panelSelect.classList.remove("pops-panel-select-disable");
},
/**
* 判断是否禁用
*/
isDisabled() {
return (
this.$ele.select.hasAttribute("disabled") ||
this.$ele.panelSelect.classList.contains(
"pops-panel-select-disable"
)
);
},
/**
* 初始化选项
*/
initOption() {
formConfig.data.forEach((dataItem) => {
// 初始化默认选中
let optionElement = document.createElement("option");
this.setNodeValue(
optionElement,
this.$eleKey.value,
dataItem.value
);
this.setNodeValue(
optionElement,
this.$eleKey.disable,
dataItem.disable
);
this.setNodeValue(
optionElement,
this.$eleKey.forms,
dataItem.forms
);
if (dataItem.value === this.$data.defaultValue) {
this.setOptionSelected(optionElement);
}
optionElement.innerText = dataItem.text;
this.$ele.select.appendChild(optionElement);
});
},
/**
* 设置选项选中
*/
setOptionSelected($option: HTMLOptionElement) {
$option.setAttribute("selected", "true");
},
/** 检测所有option并设置禁用状态 */
setSelectOptionsDisableStatus() {
if (this.$ele.select.options && this.$ele.select.options.length) {
Array.from(this.$ele.select.options).forEach((optionItem) => {
this.setOptionDisableStatus(optionItem);
});
}
},
/** 设置禁用状态 */
setOptionDisableStatus(optionElement: HTMLOptionElement) {
let disable = false;
let optionDisableAttr = this.getNodeValue(
optionElement,
this.$eleKey.disable
);
if (optionDisableAttr === "function") {
let value = this.getNodeValue(optionElement, this.$eleKey.value);
disable = Boolean(optionDisableAttr(value));
}
if (disable) {
optionElement.setAttribute("disabled", "true");
} else {
optionElement.removeAttribute("disabled");
}
},
/** 获取option上的信息 */
getSelectOptionInfo($option: HTMLOptionElement) {
let optionValue = this.getNodeValue($option, this.$eleKey.value);
let optionText = $option.innerText || $option.textContent!;
let optionForms = this.getNodeValue(
$option,
this.$eleKey.forms
) as (typeof formConfig.data)[0]["forms"];
return {
value: optionValue,
text: optionText,
forms: optionForms,
$option: $option,
};
},
/**
* 监听选择内容改变
*/
setChangeEvent() {
popsDOMUtils.on(this.$ele.select, "change", void 0, (event) => {
let $isSelectedElement = (event as any).target[
(event as any).target.selectedIndex
] as HTMLOptionElement;
let selectInfo = this.getSelectOptionInfo($isSelectedElement);
this.setSelectOptionsDisableStatus();
if (typeof formConfig.callback === "function") {
formConfig.callback(
event as any,
selectInfo.value,
selectInfo.text
);
}
let forms =
typeof selectInfo.forms === "function"
? selectInfo.forms()
: selectInfo.forms;
if (Array.isArray(forms)) {
/* 如果成功创建,加入到中间容器中 */
let childUListClassName = "pops-panel-select-child-forms";
// 移除旧的元素
while (liElement.nextElementSibling) {
if (
liElement.nextElementSibling.classList.contains(
childUListClassName
)
) {
liElement.nextElementSibling.remove();
} else {
break;
}
}
let $childUList = document.createElement("ul");
$childUList.className = childUListClassName;
popsDOMUtils.after(liElement, $childUList);
that.uListContainerAddItem(formConfig as any, {
ulElement: $childUList,
});
}
});
},
/**
* 监听点击事件
*/
setClickEvent() {
popsDOMUtils.on(this.$ele.select, "click", void 0, (event) => {
this.setSelectOptionsDisableStatus();
if (typeof formConfig.clickCallBack === "function") {
formConfig.clickCallBack(event, this.$ele.select);
}
});
},
};
PopsPanelSelect.init();
Reflect.set(liElement, "data-select", PopsPanelSelect);
return liElement;
},
/**
* 获取中间容器的元素<li>
* type ==> select-multiple
* @param formConfig
*/
createSectionContainerItem_select_multiple_new(
formConfig: PopsPanelSelectMultipleDetails<any>
) {
let liElement = document.createElement("li");
Reflect.set(liElement, "__formConfig__", formConfig);
this.setElementClassName(liElement, formConfig.className);
this.setElementAttributes(liElement, formConfig.attributes);
this.setElementProps(liElement, formConfig.props);
/* 左边底部的描述的文字 */
let leftDescriptionText = "";
if (Boolean(formConfig.description)) {
leftDescriptionText = /*html*/ `<p class="pops-panel-item-left-desc-text">${formConfig.description}</p>`;
}
PopsSafeUtils.setSafeHTML(
liElement,
/*html*/ `
<div class="pops-panel-item-left-text">
<p class="pops-panel-item-left-main-text">${formConfig.text}</p>
${leftDescriptionText}
</div>
<div class="pops-panel-select-multiple">
<div class="el-select__wrapper">
<div class="el-select__selection">
<!-- 这个是用于手动输入的,这里暂不适配 -->
<div class="el-select__selected-item el-select__input-wrapper">
</div>
<!-- 这个是placeholder -->
<div class="el-select__selected-item el-select__placeholder">
</div>
</div>
<!-- 下拉箭头 -->
<div class="el-select__suffix">
<i class="el-icon el-select__caret el-select__icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path fill="currentColor" d="M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.712a29.12 29.12 0 0 0 0-41.728 30.592 30.592 0 0 0-42.752 0z"></path>
</svg>
</i>
</div>
</div>
</div>
`
);
const PopsPanelSelectMultiple = {
[Symbol.toStringTag]: "PopsPanelSelectMultiple",
$el: {
/** 容器 */
$container: void 0 as any as HTMLElement,
/** 包括的容器 */
$wrapper: void 0 as any as HTMLElement,
/** 内容区域 */
$section: void 0 as any as HTMLElement,
/** 手动输入 */
$selectedInputWrapper: void 0 as any as HTMLElement,
/** 灰色提示语 */
$selectedPlaceHolderWrapper: void 0 as any as HTMLElement,
/** 下拉箭头区域 */
$suffix: void 0 as any as HTMLElement,
/** 下拉箭头图标 */
$suffixIcon: void 0 as any as HTMLElement,
},
$data: {
/** 默认值 */
defaultValue: formConfig.getValue(),
selectInfo: [] as any as PopsPanelSelectMultipleDataOption<any>[],
},
/** 初始化 */
init() {
this.initDefault();
this.inintEl();
this.initPlaceHolder();
this.updateTagElement();
this.setSelectContainerClickEvent();
},
/** 初始化默认值 */
initDefault() {
formConfig.data.forEach((dataItem) => {
if (this.$data.defaultValue.includes(dataItem.value)) {
// 初始化选中的配置
this.$data.selectInfo.push({
text: dataItem.text,
value: dataItem.value,
isHTML: Boolean(dataItem.isHTML),
disable: dataItem.disable,
});
}
});
},
/** 初始化$el变量 */
inintEl() {
this.$el.$container = liElement.querySelector<HTMLElement>(
".pops-panel-select-multiple"
)!;
this.$el.$wrapper = liElement.querySelector<HTMLElement>(
".el-select__wrapper"
)!;
this.$el.$section = liElement.querySelector<HTMLElement>(
".el-select__selection"
)!;
this.$el.$selectedInputWrapper = liElement.querySelector<HTMLElement>(
".el-select__selected-item.el-select__input-wrapper"
)!;
this.$el.$selectedPlaceHolderWrapper =
liElement.querySelector<HTMLElement>(
".el-select__selected-item.el-select__placeholder"
)!;
this.$el.$suffix =
liElement.querySelector<HTMLElement>(".el-select__suffix")!;
this.$el.$suffixIcon = liElement.querySelector<HTMLElement>(
".el-select__suffix .el-icon"
)!;
// 先把手动输入框隐藏
this.hideInputWrapper();
},
/** 初始化提示文字 */
initPlaceHolder() {
let placeholder = "";
if (typeof formConfig.placeholder === "string") {
placeholder = formConfig.placeholder;
} else if (typeof formConfig.placeholder === "function") {
let placeholderResult = formConfig.placeholder();
if (typeof placeholderResult === "string") {
placeholder = placeholderResult;
}
}
let $placeholder = popsDOMUtils.createElement("span", {
innerText: placeholder,
});
this.$el.$selectedPlaceHolderWrapper.appendChild($placeholder);
},
/** 初始化tag */
updateTagElement() {
// 遍历数据,寻找对应的值
formConfig.data.forEach((dataItem) => {
let findValue = this.$data.selectInfo.find(
(item) => item.value === dataItem.value
);
if (findValue) {
// 选中的值和获取的所有的值相同
let selectedInfo = this.createSelectedItem({
text: dataItem.text,
isHTML: dataItem.isHTML,
});
this.addSelectedItem(selectedInfo.$tag);
this.setSelectedItemCloseIconClickEvent({
$tag: selectedInfo.$tag,
$closeIcon: selectedInfo.$closeIcon,
value: dataItem.value,
text: dataItem.text,
});
}
});
this.checkTagEmpty();
},
/**
* 生成一个tag项
* @param data 配置
*/
createSelectedItem(data: {
/** tag的文本 */
text: string;
isHTML?: boolean;
}) {
const $selectedItem = popsDOMUtils.createElement("div", {
className: "el-select__selected-item el-select__choose_tag",
innerHTML: /*html*/ `
<span class="el-tag is-closable el-tag--info el-tag--default el-tag--light">
<span class="el-tag__content">
<span class="el-select__tags-text"></span>
</span>
<!-- 关闭tag的图标 -->
<i class="el-