UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering

310 lines 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.on = on; exports.off = off; exports.dispatch = dispatch; exports.trigger = trigger; const tslib_1 = require("tslib"); const util_1 = require("./util"); const store_1 = require("./store"); const hook_1 = require("./hook"); const store_2 = require("./store"); const object_1 = require("./object"); require("./special"); let triggered; function on(elem, types, handler, data, selector) { if (!(0, util_1.isValidTarget)(elem)) { return; } // Caller can pass in an object of custom data in lieu of the handler let handlerData; if (typeof handler !== 'function') { const { handler: h, selector: s } = handler, others = tslib_1.__rest(handler, ["handler", "selector"]); handler = h; // eslint-disable-line selector = s; // eslint-disable-line handlerData = others; } // Ensure that invalid selectors throw exceptions at attach time // if (!isValidSelector(elem, selector)) { // throw new Error('Delegate event with invalid selector.') // } const store = (0, store_1.ensure)(elem); // Ensure the main handle let mainHandler = store.handler; if (mainHandler == null) { mainHandler = store.handler = function (e, ...args) { return triggered !== e.type ? dispatch(elem, e, ...args) : undefined; }; } // Make sure that the handler has a unique ID, used to find/remove it later const guid = (0, util_1.ensureHandlerId)(handler); // Handle multiple events separated by a space (0, util_1.splitType)(types).forEach((item) => { const { originType, namespaces } = (0, util_1.normalizeType)(item); // There *must* be a type, no attaching namespace-only handlers if (!originType) { return; } let type = originType; let hook = (0, hook_1.get)(type); // If selector defined, determine special event type, otherwise given type type = (selector ? hook.delegateType : hook.bindType) || type; // Update hook based on newly reset type hook = (0, hook_1.get)(type); // handleObj is passed to all event handlers const handleObj = Object.assign({ type, originType, data, selector, guid, handler: handler, namespace: namespaces.join('.') }, handlerData); // Init the event handler queue if we're the first const events = store.events; let bag = events[type]; if (!bag) { bag = events[type] = { handlers: [], delegateCount: 0 }; // Only use addEventListener if the `hook.steup` returns false if (!hook.setup || hook.setup(elem, data, namespaces, mainHandler) === false) { (0, util_1.addEventListener)(elem, type, mainHandler); } } if (hook.add) { (0, util_1.removeHandlerId)(handleObj.handler); hook.add(elem, handleObj); (0, util_1.setHandlerId)(handleObj.handler, guid); } // Add to the element's handler list, delegates in front if (selector) { bag.handlers.splice(bag.delegateCount, 0, handleObj); bag.delegateCount += 1; } else { bag.handlers.push(handleObj); } }); } function off(elem, types, handler, selector, mappedTypes) { const store = (0, store_2.get)(elem); if (!store) { return; } const events = store.events; if (!events) { return; } // Once for each type.namespace in types; type may be omitted (0, util_1.splitType)(types).forEach((item) => { const { originType, namespaces } = (0, util_1.normalizeType)(item); // Unbind all events (on this namespace, if provided) for the element if (!originType) { Object.keys(events).forEach((key) => { off(elem, key + item, handler, selector, true); }); return; } let type = originType; const hook = (0, hook_1.get)(type); type = (selector ? hook.delegateType : hook.bindType) || type; const bag = events[type]; if (!bag) { return; } const rns = namespaces.length > 0 ? new RegExp(`(^|\\.)${namespaces.join('\\.(?:.*\\.|)')}(\\.|$)`) : null; // Remove matching events const originHandlerCount = bag.handlers.length; for (let i = bag.handlers.length - 1; i >= 0; i -= 1) { const handleObj = bag.handlers[i]; if ((mappedTypes || originType === handleObj.originType) && (!handler || (0, util_1.getHandlerId)(handler) === handleObj.guid) && (rns == null || (handleObj.namespace && rns.test(handleObj.namespace))) && (selector == null || selector === handleObj.selector || (selector === '**' && handleObj.selector))) { bag.handlers.splice(i, 1); if (handleObj.selector) { bag.delegateCount -= 1; } if (hook.remove) { hook.remove(elem, handleObj); } } } if (originHandlerCount && bag.handlers.length === 0) { if (!hook.teardown || hook.teardown(elem, namespaces, store.handler) === false) { (0, util_1.removeEventListener)(elem, type, store.handler); } delete events[type]; } }); // Remove data and the expando if it's no longer used if (Object.keys(events).length === 0) { (0, store_1.remove)(elem); } } function dispatch(elem, evt, ...args) { const event = object_1.EventObject.create(evt); event.delegateTarget = elem; const hook = (0, hook_1.get)(event.type); if (hook.preDispatch && hook.preDispatch(elem, event) === false) { return; } const handlerQueue = (0, util_1.getHandlerQueue)(elem, event); // Run delegates first; they may want to stop propagation beneath us for (let i = 0, l = handlerQueue.length; i < l && !event.isPropagationStopped(); i += 1) { const matched = handlerQueue[i]; event.currentTarget = matched.elem; for (let j = 0, k = matched.handlers.length; j < k && !event.isImmediatePropagationStopped(); j += 1) { const handleObj = matched.handlers[j]; // If event is namespaced, then each handler is only invoked if it is // specially universal or its namespaces are a superset of the event's. if (event.rnamespace == null || (handleObj.namespace && event.rnamespace.test(handleObj.namespace))) { event.handleObj = handleObj; event.data = handleObj.data; const hookHandle = (0, hook_1.get)(handleObj.originType).handle; const result = hookHandle ? hookHandle(matched.elem, event, ...args) : handleObj.handler.call(matched.elem, event, ...args); if (result !== undefined) { event.result = result; if (result === false) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if (hook.postDispatch) { hook.postDispatch(elem, event); } return event.result; } function trigger(event, eventArgs, elem, onlyHandlers) { let eventObj = event; let type = typeof event === 'string' ? event : event.type; let namespaces = typeof event === 'string' || eventObj.namespace == null ? [] : eventObj.namespace.split('.'); const node = elem; // Don't do events on text and comment nodes if (node.nodeType === 3 || node.nodeType === 8) { return; } if (type.indexOf('.') > -1) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split('.'); type = namespaces.shift(); namespaces.sort(); } const ontype = type.indexOf(':') < 0 && `on${type}`; // Caller can pass in a EventObject, Object, or just an event type string eventObj = event instanceof object_1.EventObject ? event : new object_1.EventObject(type, typeof event === 'object' ? event : null); eventObj.namespace = namespaces.join('.'); eventObj.rnamespace = eventObj.namespace ? new RegExp(`(^|\\.)${namespaces.join('\\.(?:.*\\.|)')}(\\.|$)`) : null; // Clean up the event in case it is being reused eventObj.result = undefined; if (!eventObj.target) { eventObj.target = node; } const args = [eventObj]; if (Array.isArray(eventArgs)) { args.push(...eventArgs); } else { args.push(eventArgs); } const hook = (0, hook_1.get)(type); if (!onlyHandlers && hook.trigger && hook.trigger(node, eventObj, eventArgs) === false) { return; } let bubbleType; // Determine event propagation path in advance, per W3C events spec. // Bubble up to document, then to window; watch for a global ownerDocument const eventPath = [node]; if (!onlyHandlers && !hook.noBubble && !(0, util_1.isWindow)(node)) { bubbleType = hook.delegateType || type; let last = node; let curr = node.parentNode; while (curr != null) { eventPath.push(curr); last = curr; curr = curr.parentNode; } // Only add window if we got to document const doc = node.ownerDocument || document; if (last === doc) { const win = last.defaultView || last.parentWindow || window; eventPath.push(win); } } let lastElement = node; // Fire handlers on the event path for (let i = 0, l = eventPath.length; i < l && !eventObj.isPropagationStopped(); i += 1) { const currElement = eventPath[i]; lastElement = currElement; eventObj.type = i > 1 ? bubbleType : hook.bindType || type; // Custom handler const store = (0, store_2.get)(currElement); if (store) { if (store.events[eventObj.type] && store.handler) { store.handler.call(currElement, ...args); } } // Native handler const handle = (ontype && currElement[ontype]) || null; if (handle && (0, util_1.isValidTarget)(currElement)) { eventObj.result = handle.call(currElement, ...args); if (eventObj.result === false) { eventObj.preventDefault(); } } } eventObj.type = type; // If nobody prevented the default action, do it now if (!onlyHandlers && !eventObj.isDefaultPrevented()) { const preventDefault = hook.preventDefault; if ((preventDefault == null || preventDefault(eventPath.pop(), eventObj, eventArgs) === false) && (0, util_1.isValidTarget)(node)) { // Call a native DOM method on the target with the same name as the // event. Don't do default actions on window. if (ontype && typeof node[type] === 'function' && !(0, util_1.isWindow)(node)) { // Don't re-trigger an onFOO event when we call its FOO() method const tmp = node[ontype]; if (tmp) { node[ontype] = null; } // Prevent re-triggering of the same event, since we already bubbled it above triggered = type; if (eventObj.isPropagationStopped()) { lastElement.addEventListener(type, util_1.stopPropagationCallback); } node[type](); if (eventObj.isPropagationStopped()) { lastElement.removeEventListener(type, util_1.stopPropagationCallback); } triggered = undefined; if (tmp) { node[ontype] = tmp; } } } } return eventObj.result; } //# sourceMappingURL=core.js.map