go-captcha-svelte
Version:
GoCaptcha for Svelte, which implements click mode, slider mode, drag-drop mode and rotation mode.
183 lines (182 loc) • 5.95 kB
JavaScript
/**
* @Author Awen
* @Date 2024/06/01
* @Email wengaolng@gmail.com
**/
import { checkTargetFather } from "../helper/helper";
import { writable, get } from 'svelte/store';
export function useHandler(data, event, config, clearCbs) {
const state = writable({ x: get(data).thumbX || 0, y: get(data).thumbY || 0 });
let isFreeze = false;
let rootRef;
let containerRef;
let tileRef;
const unsubscribe = data.subscribe(() => {
if (!isFreeze) {
state.set({ x: get(data).thumbX || 0, y: get(data).thumbY || 0 });
}
});
const dragEvent = (e) => {
if (!checkTargetFather(containerRef, e)) {
return;
}
const touch = e.touches && e.touches[0];
const offsetLeft = tileRef.offsetLeft;
const offsetTop = tileRef.offsetTop;
const width = containerRef.offsetWidth;
const height = containerRef.offsetHeight;
const tileWidth = tileRef.offsetWidth;
const tileHeight = tileRef.offsetHeight;
const maxWidth = width - tileWidth;
const maxHeight = height - tileHeight;
let isMoving = false;
let tmpLeaveDragEvent = null;
let startX = 0;
let startY = 0;
let tileLeft = 0;
let tileTop = 0;
if (touch) {
startX = touch.pageX - offsetLeft;
startY = touch.pageY - offsetTop;
}
else {
startX = e.clientX - offsetLeft;
startY = e.clientY - offsetTop;
}
const moveEvent = (e) => {
isMoving = true;
const mTouche = e.touches && e.touches[0];
let left = 0;
let top = 0;
if (mTouche) {
left = mTouche.pageX - startX;
top = mTouche.pageY - startY;
}
else {
left = e.clientX - startX;
top = e.clientY - startY;
}
if (left <= 0) {
left = 0;
}
if (top <= 0) {
top = 0;
}
if (left >= maxWidth) {
left = maxWidth;
}
if (top >= maxHeight) {
top = maxHeight;
}
state.set({ x: left, y: top });
tileLeft = left;
tileTop = top;
const ec = get(event);
ec.move && ec.move(left, top);
e.cancelBubble = true;
e.preventDefault();
};
const upEvent = (e) => {
if (!checkTargetFather(containerRef, e)) {
return;
}
clearEvent();
if (!isMoving) {
return;
}
isMoving = false;
if (tileLeft < 0 || tileTop < 0) {
return;
}
const ec = get(event);
ec.confirm && ec.confirm({ x: tileLeft, y: tileTop }, () => {
resetData();
});
e.cancelBubble = true;
e.preventDefault();
};
const leaveDragBlockEvent = (e) => {
tmpLeaveDragEvent = e;
};
const enterDragBlockEvent = () => {
tmpLeaveDragEvent = null;
};
const leaveUpEvent = (_) => {
if (!tmpLeaveDragEvent) {
return;
}
upEvent(tmpLeaveDragEvent);
clearEvent();
};
const scope = get(config).scope;
const dragDom = scope ? rootRef : containerRef;
const scopeDom = scope ? rootRef : document.body;
const clearEvent = () => {
scopeDom.removeEventListener("mousemove", moveEvent, false);
// @ts-ignore
scopeDom.removeEventListener("touchmove", moveEvent, { passive: false });
dragDom.removeEventListener("mouseup", upEvent, false);
dragDom.removeEventListener("mouseenter", enterDragBlockEvent, false);
dragDom.removeEventListener("mouseleave", leaveDragBlockEvent, false);
dragDom.removeEventListener("touchend", upEvent, false);
scopeDom.removeEventListener("mouseleave", upEvent, false);
scopeDom.removeEventListener("mouseup", leaveUpEvent, false);
isFreeze = false;
};
isFreeze = true;
scopeDom.addEventListener("mousemove", moveEvent, false);
scopeDom.addEventListener("touchmove", moveEvent, { passive: false });
dragDom.addEventListener("mouseup", upEvent, false);
dragDom.addEventListener("mouseenter", enterDragBlockEvent, false);
dragDom.addEventListener("mouseleave", leaveDragBlockEvent, false);
dragDom.addEventListener("touchend", upEvent, false);
scopeDom.addEventListener("mouseleave", upEvent, false);
scopeDom.addEventListener("mouseup", leaveUpEvent, false);
};
const closeEvent = (e) => {
close();
e.cancelBubble = true;
e.preventDefault();
return false;
};
const refreshEvent = (e) => {
refresh();
e.cancelBubble = true;
e.preventDefault();
return false;
};
const resetData = () => {
state.set({ x: get(data).thumbX || 0, y: get(data).thumbY || 0 });
};
const clearData = () => {
resetData();
clearCbs && clearCbs();
};
const close = () => {
const ec = get(event);
ec.close && ec.close();
resetData();
};
const refresh = () => {
const ec = get(event);
ec.refresh && ec.refresh();
resetData();
};
const initRefs = (root, container, tile) => {
rootRef = root;
containerRef = container;
tileRef = tile;
};
return {
state,
initRefs,
unsubscribe,
dragEvent,
closeEvent,
refreshEvent,
resetData,
clearData,
close,
refresh,
};
}