/**
* BasicEventHandler's event. This itself extends the standard Event API for html element. So, you can use the default element's event such as click, focus, blur, etc.
* Methods that uses Event are: `on()`, `off()`, `one()`, `trigger()`
* @typedef BasicEventHandler#Event
* @type {Event}
* @see https://developer.mozilla.org/en-US/docs/Web/API/Event/Event
*/
/**
* Javascript's Promise type event handler.
* The state will switch from **off** to **on** once. And after that, it will stay in that state forever, so any further `until()` call will be resolved immidiately.
* Methods that uses Event are: `until()`, `resolveState()`, `rejectState()`
* @typedef BasicEventHandler#State
* @type {Promise}
* @since 4.12.1
*/
/**
* @class
* @classdesc
* The basic event handler for classes
* This class will generates JQuery on, off, one, trigger events
* And will add onReady hook
*/
class BasicEventHandler {
constructor ($elm) {
this.__switches = [];
var waitForStates = {}
/**
* State monitor. Wait until a state is resolved.
* Will wait until resolveState is called.
* Will immidiately executed if resolveState is already called
* @async
* @param {String} state - State name
* @returns {Promise<*>} - Returns any variables passed on resolveState
* @since 4.12.4
* @example <caption>Basic usage</caption>
* await basicEventHandler.until("ready");
*
* @example <caption>Asynchronous chaining</caption>
* basicEventHandler.until("ready")
* .then((result) = >{
* console.log(result);
* })
*
* basicEventHandler.resolveState("ready", "Hello world");
* // prints: Hello world
*
* @example <caption>Immidiately executed if `resolveState` with the same state has already been called</caption>
* basicEventHandler.resolveState("ready", "App is ready");
*
* var msg = await basicEventHandler.until("ready");
* console.log(msg);
* //immidately prints "App is ready"
*/
this.until = async function(state) {
if (waitForStates[state]) return waitForStates[state].promise;
var prom = new Promise((resolve, reject) => {
waitForStates[state] = {
resolve:resolve,
reject:reject,
state:"waiting"
}
})
waitForStates[state].promise = prom;
return prom;
}
/**
* Resolve a state
* @param {String} state - State name
* @param {*} [arg] - Arguments to be passed to `until`
*/
this.resolveState = function(state, arg) {
if (!waitForStates[state]) {
var prom = new Promise((resolve, reject) => {
waitForStates[state] = {
resolve:resolve,
reject:reject,
state:"resolved"
}
})
waitForStates[state].promise = prom;
}
waitForStates[state].resolve(arg)
}
this.unresolveState = function(state) {
delete waitForStates[state]
}
/**
* Reject a state
* @param {String} state - State name
* @param {String} [error] - Error message
*/
this.rejectState = function(state, error="") {
if (!waitForStates[state]) {
var prom = new Promise((resolve, reject) => {
waitForStates[state] = {
resolve:resolve,
reject:reject,
state:"rejected"
}
})
waitForStates[state].promise = prom;
}
if (error) {
waitForStates[state].reject();
} else {
waitForStates[state].reject(new Error(error));
}
}
var processors = {}
/**
* Add a custom process to a value.
* @param {String} processName - Name of the process
* @param {*} value - Value to be processed
* @returns {*} - By default will return value as is
*/
this.processWith = function(processName, value, ...args) {
if (typeof processors[processName] !== "function") return value;
return processors[processName].apply(this, [].concat(value, args))
}
this.defineProcess = function(processName, process) {
if (typeof process !== "function") return console.warn("Invalid process")
if (typeof processName !== "string") return console.warn("Invalid processName")
processors[processName] = process;
}
this.removeProcess = function(processName) {
if (processors[processName]) delete processors[processName];
}
if ($elm && typeof window !== "undefined") {
this.$elm = $elm || $("<div></div>");
// jquery event
/**
* Create a new event with JQuery eventing convenience
* Equal to `$(document).on()`
* @param {String} evt - Event name
* @param {Function} fn - Function to trigger
* @since 4.3.20
* trans.on('transLoaded', (e, opt)=> {
* // do something
* })
*/
this.on = function(evt, fn) {
this.$elm.on(evt, fn)
}
/**
* Removes an event
* Equal to `$(document).off()`
* @param {String} evt - Event name
* @param {Function} fn - Function to trigger
* @since 4.3.20
* @example
* trans.off('transLoaded', (e, opt)=> {
* // do something
* })
*/
this.off = function(evt) {
this.$elm.off(evt)
}
/**
* Run the event once
* Trigger an event and immediately removes it
* Equal to `$(document).one()`
* @param {String} evt - Event name
* @param {Function} fn - Function to trigger
* @since 4.3.20
*/
this.one = function(evt, fn) {
this.$elm.one(evt, fn)
}
/**
* Trigger an event
* Equal to `$(document).trigger()`
* @param {String} evt - Event name
* @param {Function} fn - Function to trigger
* @since 4.3.20
*/
this.trigger = function(evt, param) {
this.$elm.trigger(evt, param)
}
} else {
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
this.on = (evt, fn) => {
eventEmitter.on(evt, fn.bind(this))
}
this.off = (evt) => {
eventEmitter.off(evt)
}
this.one = (evt, fn) => {
eventEmitter.one(evt, fn.bind(this))
}
this.trigger = (evt, ...param) => {
param.unshift(eventEmitter)
eventEmitter.emit(evt, param)
}
}
BasicEventHandler.prototype.onReady = function (onReadyEvent) {
if (typeof onReadyEvent !== 'function') return console.error("Error triggering onReady : parameter must be a function");
this.__onReadyPool = this.__onReadyPool||[];
if (Boolean(this.isInitialized) == false) {
this.__onReadyPool.push(onReadyEvent)
} else {
for (var i=0; i<this.__onReadyPool.length; i++) {
this.__onReadyPool[i].apply(this, arguments);
}
this.__onReadyPool = [];
onReadyEvent.apply(this, arguments);
}
}
}
}
module.exports = BasicEventHandler;