js-web-tools
Version:
Tools for Javascript develpers
197 lines (169 loc) • 5.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var handlers = {};
var specialEvents = {};
specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'; // every element and callback function will have an unique dtId
var _dtId = 1;
function hasProp(obj, propName) {
return Object.prototype.hasOwnProperty.call(obj, propName);
}
/**
* Get dtId of Element or callback function
* @param {Object|Function} obj Element or callback function
* @return {Number} unique dtId
*/
function getDtId(obj) {
return obj._dtId || (obj._dtId = _dtId++);
}
/**
* Get event object of event string, the first `.` is used to split event and namespace
*
* @param {String} event Event type string with namespace or not
* @return {Object} An Object with `e` and `ns` key
*/
function parse(event) {
var dotIndex = event.indexOf('.');
if (dotIndex > 0) {
return {
e: event.substring(0, event.indexOf('.')),
ns: event.substring(dotIndex + 1, event.length)
};
}
return {
e: event
};
}
/**
* Find matched event handlers
* @param {Element} el the element to find
* @param {String} selector Used by event delegation, null if not
* @param {String} event Event string may with namespace
* @param {Function} callback the callback to find, optional
* @return {Array} Array of handlers bind to el
*/
function findHandlers(el, selector, event, callback) {
event = parse(event);
var elEventHandlers = handlers[getDtId(el)];
return elEventHandlers.filter(function (handler) {
return handler && (!event.e || handler.e === event.e) && (!event.ns || handler.ns === event.ns) && (!callback || handler.callback === callback) && (!selector || handler.selector === selector);
});
}
function removeEvent(el, selector, event, callback) {
var eventName = parse(event).e;
/* istanbul ignore else */
if (el._dtId) {
var elHandlers = handlers[getDtId(el)];
var matchedHandlers = findHandlers(el, selector, event, callback);
matchedHandlers.forEach(function (handler) {
/* istanbul ignore else */
if (el.removeEventListener) {
el.removeEventListener(eventName, handler.delegator || handler.callback);
} else if (el.detachEvent) {
el.detachEvent('on' + eventName, handler.delegator || handler.callback);
}
elHandlers.splice(elHandlers.indexOf(handler), 1);
});
}
}
function bindEvent(el, selector, event, callback, delegator) {
var eventName = parse(event).e;
var ns = parse(event).ns;
/* istanbul ignore else */
if (el.addEventListener) {
el.addEventListener(eventName, delegator || callback, false);
} else if (el.attachEvent) {
el.attachEvent('on' + eventName, delegator || callback);
} // push events to handlers
var id = getDtId(el);
handlers[id] = handlers[id] || [];
handlers[id].push({
delegator: delegator,
callback: callback,
e: eventName,
ns: ns,
selector: selector
});
}
var Events = {
/**
* Register a callback
*
* @param {Element} el the element to bind event to
* @param {String} eventType event type, can with namesapce
* @param {Function} callback callback to invoke
* @return {Null} return null
*/
on: function on(el, eventType, callback) {
bindEvent(el, null, eventType, callback);
},
/**
* Unregister a callback
*
* @param {Element} el the element to bind event to
* @param {String} eventType event type, can with namesapce
* @param {Function} callback optional, callback to invoke
* @return {Null} return null
*/
off: function off(el, eventType, callback) {
// find callbacks
removeEvent(el, null, eventType, callback);
},
/**
* Register a callback that will execute exactly once
*
* @param {Element} el the element to bind event to
* @param {String} eventType event type, can with namesapce
* @param {Function} callback callback to invoke
* @return {Null} return null
*/
once: function once(el, eventType, callback) {
var recursiveFunction = function recursiveFunction(e) {
Events.off(e.currentTarget, e.type, recursiveFunction);
return callback(e);
};
this.on(el, eventType, recursiveFunction);
},
// Delegate a callback to selector under el
delegate: function delegate(el, selector, eventType, callback) {
// bind event to el. and check if selector match
var delegator = function delegator(e) {
var els = el.querySelectorAll(selector);
var matched = false;
for (var i = 0; i < els.length; i++) {
var _el = els[i];
if (_el === e.target || _el.contains(e.target)) {
matched = _el;
break;
}
}
if (matched) {
callback.apply(matched, [].slice.call(arguments));
}
};
bindEvent(el, selector, eventType, callback, delegator);
},
// Undelegate a callback to selector under el
undelegate: function undelegate(el, selector, eventType, callback) {
removeEvent(el, selector, eventType, callback);
},
// Dispatch an event with props to el
trigger: function trigger(el, eventType, props) {
var event = document.createEvent(specialEvents[eventType] || 'Events');
var bubbles = true;
if (props) {
for (var name in props) {
/* istanbul ignore else */
if (hasProp(props, name)) {
name === 'bubbles' ? bubbles = !!props[name] : event[name] = props[name];
}
}
}
event.initEvent(eventType, bubbles, true);
el.dispatchEvent(event);
}
};
var _default = Events;
exports["default"] = _default;