312 lines
10 KiB
JavaScript
312 lines
10 KiB
JavaScript
const traps = {
|
|
mousemoveoutside: /* @__PURE__ */ new WeakMap(),
|
|
clickoutside: /* @__PURE__ */ new WeakMap()
|
|
};
|
|
function createTrapHandler(name, el, originalHandler) {
|
|
if (name === "mousemoveoutside") {
|
|
const moveHandler = (e) => {
|
|
if (el.contains(e.target))
|
|
return;
|
|
originalHandler(e);
|
|
};
|
|
return {
|
|
mousemove: moveHandler,
|
|
touchstart: moveHandler
|
|
};
|
|
} else if (name === "clickoutside") {
|
|
let mouseDownOutside = false;
|
|
const downHandler = (e) => {
|
|
mouseDownOutside = !el.contains(e.target);
|
|
};
|
|
const upHanlder = (e) => {
|
|
if (!mouseDownOutside)
|
|
return;
|
|
if (el.contains(e.target))
|
|
return;
|
|
originalHandler(e);
|
|
};
|
|
return {
|
|
mousedown: downHandler,
|
|
mouseup: upHanlder,
|
|
touchstart: downHandler,
|
|
touchend: upHanlder
|
|
};
|
|
}
|
|
console.error(`[evtd/create-trap-handler]: name \`${name}\` is invalid. This could be a bug of evtd.`);
|
|
return {};
|
|
}
|
|
function ensureTrapHandlers(name, el, handler) {
|
|
const handlers = traps[name];
|
|
let elHandlers = handlers.get(el);
|
|
if (elHandlers === void 0) {
|
|
handlers.set(el, elHandlers = /* @__PURE__ */ new WeakMap());
|
|
}
|
|
let trapHandler = elHandlers.get(handler);
|
|
if (trapHandler === void 0) {
|
|
elHandlers.set(handler, trapHandler = createTrapHandler(name, el, handler));
|
|
}
|
|
return trapHandler;
|
|
}
|
|
function trapOn(name, el, handler, options) {
|
|
if (name === "mousemoveoutside" || name === "clickoutside") {
|
|
const trapHandlers = ensureTrapHandlers(name, el, handler);
|
|
Object.keys(trapHandlers).forEach((key) => {
|
|
on(key, document, trapHandlers[key], options);
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function trapOff(name, el, handler, options) {
|
|
if (name === "mousemoveoutside" || name === "clickoutside") {
|
|
const trapHandlers = ensureTrapHandlers(name, el, handler);
|
|
Object.keys(trapHandlers).forEach((key) => {
|
|
off(key, document, trapHandlers[key], options);
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function createDelegate() {
|
|
if (typeof window === "undefined") {
|
|
return {
|
|
on: () => {
|
|
},
|
|
off: () => {
|
|
}
|
|
};
|
|
}
|
|
const propagationStopped = /* @__PURE__ */ new WeakMap();
|
|
const immediatePropagationStopped = /* @__PURE__ */ new WeakMap();
|
|
function trackPropagation() {
|
|
propagationStopped.set(this, true);
|
|
}
|
|
function trackImmediate() {
|
|
propagationStopped.set(this, true);
|
|
immediatePropagationStopped.set(this, true);
|
|
}
|
|
function spy(event, propName, fn) {
|
|
const source = event[propName];
|
|
event[propName] = function() {
|
|
fn.apply(event, arguments);
|
|
return source.apply(event, arguments);
|
|
};
|
|
return event;
|
|
}
|
|
function unspy(event, propName) {
|
|
event[propName] = Event.prototype[propName];
|
|
}
|
|
const currentTargets = /* @__PURE__ */ new WeakMap();
|
|
const currentTargetDescriptor = Object.getOwnPropertyDescriptor(Event.prototype, "currentTarget");
|
|
function getCurrentTarget() {
|
|
var _a;
|
|
return (_a = currentTargets.get(this)) !== null && _a !== void 0 ? _a : null;
|
|
}
|
|
function defineCurrentTarget(event, getter) {
|
|
if (currentTargetDescriptor === void 0)
|
|
return;
|
|
Object.defineProperty(event, "currentTarget", {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: getter !== null && getter !== void 0 ? getter : currentTargetDescriptor.get
|
|
});
|
|
}
|
|
const phaseToTypeToElToHandlers = {
|
|
bubble: {},
|
|
capture: {}
|
|
};
|
|
const typeToWindowEventHandlers = {};
|
|
function createUnifiedHandler() {
|
|
const delegeteHandler = function(e) {
|
|
const { type, eventPhase, target, bubbles } = e;
|
|
if (eventPhase === 2)
|
|
return;
|
|
const phase = eventPhase === 1 ? "capture" : "bubble";
|
|
let cursor = target;
|
|
const path = [];
|
|
while (true) {
|
|
if (cursor === null)
|
|
cursor = window;
|
|
path.push(cursor);
|
|
if (cursor === window) {
|
|
break;
|
|
}
|
|
cursor = cursor.parentNode || null;
|
|
}
|
|
const captureElToHandlers = phaseToTypeToElToHandlers.capture[type];
|
|
const bubbleElToHandlers = phaseToTypeToElToHandlers.bubble[type];
|
|
spy(e, "stopPropagation", trackPropagation);
|
|
spy(e, "stopImmediatePropagation", trackImmediate);
|
|
defineCurrentTarget(e, getCurrentTarget);
|
|
if (phase === "capture") {
|
|
if (captureElToHandlers === void 0)
|
|
return;
|
|
for (let i = path.length - 1; i >= 0; --i) {
|
|
if (propagationStopped.has(e))
|
|
break;
|
|
const target2 = path[i];
|
|
const handlers = captureElToHandlers.get(target2);
|
|
if (handlers !== void 0) {
|
|
currentTargets.set(e, target2);
|
|
for (const handler of handlers) {
|
|
if (immediatePropagationStopped.has(e))
|
|
break;
|
|
handler(e);
|
|
}
|
|
}
|
|
if (i === 0 && !bubbles && bubbleElToHandlers !== void 0) {
|
|
const bubbleHandlers = bubbleElToHandlers.get(target2);
|
|
if (bubbleHandlers !== void 0) {
|
|
for (const handler of bubbleHandlers) {
|
|
if (immediatePropagationStopped.has(e))
|
|
break;
|
|
handler(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (phase === "bubble") {
|
|
if (bubbleElToHandlers === void 0)
|
|
return;
|
|
for (let i = 0; i < path.length; ++i) {
|
|
if (propagationStopped.has(e))
|
|
break;
|
|
const target2 = path[i];
|
|
const handlers = bubbleElToHandlers.get(target2);
|
|
if (handlers !== void 0) {
|
|
currentTargets.set(e, target2);
|
|
for (const handler of handlers) {
|
|
if (immediatePropagationStopped.has(e))
|
|
break;
|
|
handler(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unspy(e, "stopPropagation");
|
|
unspy(e, "stopImmediatePropagation");
|
|
defineCurrentTarget(e);
|
|
};
|
|
delegeteHandler.displayName = "evtdUnifiedHandler";
|
|
return delegeteHandler;
|
|
}
|
|
function createUnifiedWindowEventHandler() {
|
|
const delegateHandler = function(e) {
|
|
const { type, eventPhase } = e;
|
|
if (eventPhase !== 2)
|
|
return;
|
|
const handlers = typeToWindowEventHandlers[type];
|
|
if (handlers === void 0)
|
|
return;
|
|
handlers.forEach((handler) => handler(e));
|
|
};
|
|
delegateHandler.displayName = "evtdUnifiedWindowEventHandler";
|
|
return delegateHandler;
|
|
}
|
|
const unifiedHandler = createUnifiedHandler();
|
|
const unfiendWindowEventHandler = createUnifiedWindowEventHandler();
|
|
function ensureElToHandlers(phase, type) {
|
|
const phaseHandlers = phaseToTypeToElToHandlers[phase];
|
|
if (phaseHandlers[type] === void 0) {
|
|
phaseHandlers[type] = /* @__PURE__ */ new Map();
|
|
window.addEventListener(type, unifiedHandler, phase === "capture");
|
|
}
|
|
return phaseHandlers[type];
|
|
}
|
|
function ensureWindowEventHandlers(type) {
|
|
const windowEventHandlers = typeToWindowEventHandlers[type];
|
|
if (windowEventHandlers === void 0) {
|
|
typeToWindowEventHandlers[type] = /* @__PURE__ */ new Set();
|
|
window.addEventListener(type, unfiendWindowEventHandler);
|
|
}
|
|
return typeToWindowEventHandlers[type];
|
|
}
|
|
function ensureHandlers(elToHandlers, el) {
|
|
let elHandlers = elToHandlers.get(el);
|
|
if (elHandlers === void 0) {
|
|
elToHandlers.set(el, elHandlers = /* @__PURE__ */ new Set());
|
|
}
|
|
return elHandlers;
|
|
}
|
|
function handlerExist(el, phase, type, handler) {
|
|
const elToHandlers = phaseToTypeToElToHandlers[phase][type];
|
|
if (elToHandlers !== void 0) {
|
|
const handlers = elToHandlers.get(el);
|
|
if (handlers !== void 0) {
|
|
if (handlers.has(handler))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function windowEventHandlerExist(type, handler) {
|
|
const handlers = typeToWindowEventHandlers[type];
|
|
if (handlers !== void 0) {
|
|
if (handlers.has(handler)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function on2(type, el, handler, options) {
|
|
let mergedHandler;
|
|
if (typeof options === "object" && options.once === true) {
|
|
mergedHandler = (e) => {
|
|
off2(type, el, mergedHandler, options);
|
|
handler(e);
|
|
};
|
|
} else {
|
|
mergedHandler = handler;
|
|
}
|
|
const trapped = trapOn(type, el, mergedHandler, options);
|
|
if (trapped)
|
|
return;
|
|
const phase = options === true || typeof options === "object" && options.capture === true ? "capture" : "bubble";
|
|
const elToHandlers = ensureElToHandlers(phase, type);
|
|
const handlers = ensureHandlers(elToHandlers, el);
|
|
if (!handlers.has(mergedHandler))
|
|
handlers.add(mergedHandler);
|
|
if (el === window) {
|
|
const windowEventHandlers = ensureWindowEventHandlers(type);
|
|
if (!windowEventHandlers.has(mergedHandler)) {
|
|
windowEventHandlers.add(mergedHandler);
|
|
}
|
|
}
|
|
}
|
|
function off2(type, el, handler, options) {
|
|
const trapped = trapOff(type, el, handler, options);
|
|
if (trapped)
|
|
return;
|
|
const capture = options === true || typeof options === "object" && options.capture === true;
|
|
const phase = capture ? "capture" : "bubble";
|
|
const elToHandlers = ensureElToHandlers(phase, type);
|
|
const handlers = ensureHandlers(elToHandlers, el);
|
|
if (el === window) {
|
|
const mirrorPhase = capture ? "bubble" : "capture";
|
|
if (!handlerExist(el, mirrorPhase, type, handler) && windowEventHandlerExist(type, handler)) {
|
|
const windowEventHandlers = typeToWindowEventHandlers[type];
|
|
windowEventHandlers.delete(handler);
|
|
if (windowEventHandlers.size === 0) {
|
|
window.removeEventListener(type, unfiendWindowEventHandler);
|
|
typeToWindowEventHandlers[type] = void 0;
|
|
}
|
|
}
|
|
}
|
|
if (handlers.has(handler))
|
|
handlers.delete(handler);
|
|
if (handlers.size === 0) {
|
|
elToHandlers.delete(el);
|
|
}
|
|
if (elToHandlers.size === 0) {
|
|
window.removeEventListener(type, unifiedHandler, phase === "capture");
|
|
phaseToTypeToElToHandlers[phase][type] = void 0;
|
|
}
|
|
}
|
|
return {
|
|
on: on2,
|
|
off: off2
|
|
};
|
|
}
|
|
const { on, off } = createDelegate();
|
|
export { off as a, on as o };
|