Source: events-waiter.js

(function() {
module.exports = EventsWaiter

/** Create an object that can call the callback function when all registered events are completed.
 * @constructor EventsWaiter
 */
 /*
 * @method {undefined} #addEvent(string: event) - Register an event.
 * @method {undefined} #removeEvent(string: event) - Unregister an event.
 * @method {undefined} #completeEvent(string: event) - Mark an event as completed.
 * @method {undefined} #wait(function: callback) - Start waiting. Call the callback function when all events are completed.
 * @method {undefined} #dontWait() - Stop waiting.
 * @method {undefined} #reset() - Rallback this object to the inital state.

 * @method {undefined} #_tryToComplete() - Check conditions of the waiting stop. Stop waiting and call the callback function if conditions are truly.
 * @method {boolean} #_areEventsCompleted() - Return true if all events are completed, else rerurn false.

 * @member {array} ~_events - The events list.
 * @member {function|null} ~_callback - The callback that will be called when all events are completed.
 * @member {boolean} ~_waitingStarted - The flag that specified the waiting state.
 */
function EventsWaiter() {
    /** The events list.
     * @member {array} EventsWaiter~_events
     * @private
     */
    this._events = []

    /** The callback that will be called when all events are completed.
     * @member {function} EventsWaiter~_callback
     * @private
     */
    this._callback = null

    /** The flag that specified the waiting state.
     * @member {boolean} EventsWaiter~_waitingStarted
     * @private
     */
    this._waitingStarted = false
};

/** Register an event.
 * @method EventsWaiter#addEvent
 * @param {string} event - Event name.
 * @returns {undefined}
 */
EventsWaiter.prototype.addEvent = function(event) {
    if (typeof(event) !== 'string') throw new Error("The option 'event' should be a string.")

    this._events.push(event)
}

/** Unregister an event.
 * @method EventsWaiter#removeEvent
 * @param {string} event - Event name.
 * @returns {undefined}
 */
EventsWaiter.prototype.removeEvent = function(event) {
    if (typeof(event) !== 'string') throw new Error("The option 'event' should be a string.")

    for (var i = 0; i < this._events.length; i++) {
        if (this._events[i] === event) {
            this._events.splice(i, 1)
        };
    };
}

/** Mark an event as completed.
 * @method EventsWaiter#completeEvent
 * @param {string} event - Event name.
 * @returns {undefined}
 */
EventsWaiter.prototype.completeEvent = function(event) {
    if (typeof(event) !== 'string') throw new Error("The option 'event' should be a string.")

    this.removeEvent(event)
    this._tryToComplete()
}

/** Start waiting. Call the callback function when all events are completed.
 * @method EventsWaiter#wait
 * @param {function} callback
 * @returns {undefined}
 */
EventsWaiter.prototype.wait = function(callback) {
    if (!(callback instanceof Function)) throw new Error("The option 'callback' should be a function.")

    this._callback = callback
    this._waitingStarted = true
    this._tryToComplete()
}

/** Stop waiting.
 * @method EventsWaiter#dontWait
 * @returns {undefined}
 */
EventsWaiter.prototype.dontWait = function() {
    this._waitingStarted = false
    this._callback = null
}

/** Rallback this object to the inital state.
 * @method EventsWaiter#reset
 * @returns {undefined}
 */
EventsWaiter.prototype.reset = function() {
    this._events = []
    this._callback = null
    this._waitingStarted = false
}

/** Check conditions of the waiting stop. Stop waiting and call the callback function if conditions are truly.
 * @method EventsWaiter#_tryToComplete
 * @returns {undefined}
 * @private
 */
EventsWaiter.prototype._tryToComplete = function() {
  if (this._waitingStarted) {
    if (this._areEventsCompleted()) {
      var callback = this._callback
      this.dontWait()
      callback()
    }
  }
}

/** Return true if all events are completed, else rerurn false.
 * @method EventsWaiter#_areEventsCompleted
 * @returns {boolean}
 * @private
 */
EventsWaiter.prototype._areEventsCompleted = function() {
    if (this._events.length === 0) return true
    return false
}
})()