@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
185 lines (156 loc) • 4.85 kB
text/typescript
import { get } from './store'
import type { EventTarget, HandlerObject } from './store'
import { EventObject } from './object'
export const returnTrue = () => true
export const returnFalse = () => false
export function stopPropagationCallback(e: Event) {
e.stopPropagation()
}
export function addEventListener<TElement extends Element>(
elem: TElement,
type: string,
handler: EventListener,
) {
if (elem.addEventListener != null) {
elem.addEventListener(type, handler as any)
}
}
export function removeEventListener<TElement extends Element>(
elem: TElement,
type: string,
handler: EventListener,
) {
if (elem.removeEventListener != null) {
elem.removeEventListener(type, handler as any)
}
}
const rNotHTMLWhite = /[^\x20\t\r\n\f]+/g
const rNamespace = /^([^.]*)(?:\.(.+)|)/
export function splitType(types: string) {
return (types || '').match(rNotHTMLWhite) || ['']
}
export function normalizeType(type: string) {
const parts = rNamespace.exec(type) || []
return {
originType: parts[1] ? parts[1].trim() : parts[1],
namespaces: parts[2]
? parts[2]
.split('.')
.map((ns) => ns.trim())
.sort()
: [],
}
}
export function isValidTarget(target: Element | Record<string, any>) {
// Accepts only:
// - Node
// - Node.ELEMENT_NODE
// - Node.DOCUMENT_NODE
// - Object
// - Any
return target.nodeType === 1 || target.nodeType === 9 || !+target.nodeType
}
export function isValidSelector(elem: EventTarget, selector?: string) {
if (selector) {
const node = elem as Element
return node.querySelector != null && node.querySelector(selector) != null
}
return true
}
type Handler = (...args: any[]) => void
let seed = 0
const cache: WeakMap<Handler, number> = new WeakMap()
export function ensureHandlerId(handler: Handler) {
if (!cache.has(handler)) {
cache.set(handler, seed)
seed += 1
}
return cache.get(handler)!
}
export function getHandlerId(handler: Handler) {
return cache.get(handler)
}
export function removeHandlerId(handler: Handler) {
return cache.delete(handler)
}
export function setHandlerId(handler: Handler, id: number) {
return cache.set(handler, id)
}
export function getHandlerQueue(elem: EventTarget, event: EventObject) {
const queue = []
const store = get(elem)
const bag = store && store.events && store.events[event.type]
const handlers = (bag && bag.handlers) || []
const delegateCount = bag ? bag.delegateCount : 0
if (
delegateCount > 0 &&
// Support: Firefox <=42 - 66+
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
// Support: IE 11+
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
!(
event.type === 'click' &&
typeof event.button === 'number' &&
event.button >= 1
)
) {
for (
let curr = event.target as Node;
curr !== elem;
curr = curr.parentNode || (elem as Node)
) {
// Don't check non-elements
// Don't process clicks on disabled elements
if (
curr.nodeType === 1 &&
!(event.type === 'click' && (curr as any).disabled === true)
) {
const matchedHandlers: HandlerObject[] = []
const matchedSelectors: { [selector: string]: boolean } = {}
for (let i = 0; i < delegateCount; i += 1) {
const handleObj = handlers[i]
const selector = handleObj.selector!
if (selector != null && matchedSelectors[selector] == null) {
const node = elem as Element
const nodes: Element[] = []
node.querySelectorAll(selector).forEach((child) => {
nodes.push(child)
})
matchedSelectors[selector] = nodes.includes(curr as Element)
}
if (matchedSelectors[selector]) {
matchedHandlers.push(handleObj)
}
}
if (matchedHandlers.length) {
queue.push({ elem: curr, handlers: matchedHandlers })
}
}
}
}
// Add the remaining (directly-bound) handlers
if (delegateCount < handlers.length) {
queue.push({ elem, handlers: handlers.slice(delegateCount) })
}
return queue
}
export function isWindow(obj: any): obj is Window {
return obj != null && obj === obj.window
}
export function contains(a: any, b: any) {
const adown = a.nodeType === 9 ? a.documentElement : a
const bup = b && b.parentNode
return (
a === bup ||
!!(
bup &&
bup.nodeType === 1 &&
// Support: IE 9 - 11+
// IE doesn't have `contains` on SVG.
(adown.contains
? adown.contains(bup)
: a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16)
)
)
}