uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
142 lines (112 loc) • 3.67 kB
JavaScript
import {isIE} from './env';
import {findAll} from './selector';
import {closest, within} from './filter';
import {isArray, isBoolean, isFunction, isString, toNode, toNodes} from './lang';
export function on(...args) {
let [targets, type, selector, listener, useCapture] = getArgs(args);
targets = toEventTargets(targets);
if (listener.length > 1) {
listener = detail(listener);
}
if (useCapture && useCapture.self) {
listener = selfFilter(listener);
}
if (selector) {
listener = delegate(selector, listener);
}
useCapture = useCaptureFilter(useCapture);
type.split(' ').forEach(type =>
targets.forEach(target =>
target.addEventListener(type, listener, useCapture)
)
);
return () => off(targets, type, listener, useCapture);
}
export function off(targets, type, listener, useCapture = false) {
useCapture = useCaptureFilter(useCapture);
targets = toEventTargets(targets);
type.split(' ').forEach(type =>
targets.forEach(target =>
target.removeEventListener(type, listener, useCapture)
)
);
}
export function once(...args) {
const [element, type, selector, listener, useCapture, condition] = getArgs(args);
const off = on(element, type, selector, e => {
const result = !condition || condition(e);
if (result) {
off();
listener(e, result);
}
}, useCapture);
return off;
}
export function trigger(targets, event, detail) {
return toEventTargets(targets).reduce((notCanceled, target) =>
notCanceled && target.dispatchEvent(createEvent(event, true, true, detail))
, true);
}
export function createEvent(e, bubbles = true, cancelable = false, detail) {
if (isString(e)) {
const event = document.createEvent('CustomEvent'); // IE 11
event.initCustomEvent(e, bubbles, cancelable, detail);
e = event;
}
return e;
}
function getArgs(args) {
if (isFunction(args[2])) {
args.splice(2, 0, false);
}
return args;
}
function delegate(selector, listener) {
return e => {
const current = selector[0] === '>'
? findAll(selector, e.currentTarget).reverse().filter(element => within(e.target, element))[0]
: closest(e.target, selector);
if (current) {
e.current = current;
listener.call(this, e);
}
};
}
function detail(listener) {
return e => isArray(e.detail) ? listener(e, ...e.detail) : listener(e);
}
function selfFilter(listener) {
return function (e) {
if (e.target === e.currentTarget || e.target === e.current) {
return listener.call(null, e);
}
};
}
function useCaptureFilter(options) {
return options && isIE && !isBoolean(options)
? !!options.capture
: options;
}
function isEventTarget(target) {
return target && 'addEventListener' in target;
}
function toEventTarget(target) {
return isEventTarget(target) ? target : toNode(target);
}
export function toEventTargets(target) {
return isArray(target)
? target.map(toEventTarget).filter(Boolean)
: isString(target)
? findAll(target)
: isEventTarget(target)
? [target]
: toNodes(target);
}
export function isTouch(e) {
return e.pointerType === 'touch' || !!e.touches;
}
export function getEventPos(e) {
const {touches, changedTouches} = e;
const {clientX: x, clientY: y} = touches && touches[0] || changedTouches && changedTouches[0] || e;
return {x, y};
}