API Docs for: 0.0.1
Show:

File: src/dialog/dialog.js

"use strict";
/**
 * Defines a dialog-panel to display messages.
 * Every message that fulfills will get the dialog-content as well as the pressed button as return.
 *
 *
 * <i>Copyright (c) 2014 ITSA - https://github.com/itsa</i>
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 *
 * @module dialog
 * @class Dialog
 * @since 0.0.1
*/

require('js-ext');
require('polyfill');
require('./css/dialog.css');

var NAME = '[dialog]: ',
    MESSAGE_LEVELS = {
        'message': 1,
        'warn': 2,
        'error': 3
    },
    MESSAGE_HASHES = {
        'message': 'messages',
        'warn': 'warnings',
        'error': 'errors'
    },
    MESSAGE_HASHES_NR = {
        1: 'messages',
        2: 'warnings',
        3: 'errors'
    },
    FOLLOWUP_DELAY = 150,
    createHashMap = require('js-ext/extra/hashmap.js').createMap;

module.exports = function (window) {

    var DOCUMENT = window.document,
        Classes = require('js-ext/extra/classes.js'),
        UTILS = require('utils'),
        later = UTILS.later,
        async = UTILS.async,
        dialog, Dialog, Event;

    window._ITSAmodules || Object.protectedProp(window, '_ITSAmodules', createHashMap());

/*jshint boss:true */
    if (Dialog=window._ITSAmodules.Dialog) {
/*jshint boss:false */
        return Dialog; // Dialog was already created
    }

    require('panel')(window);
    Event = require('itsa-event');

    /**
     * Model that is passed through to the Panel.
     *
     * @property model
     * @default {
            draggable: true
       }
     * @type Object
     * @since 0.0.1
     */

    /**
     * Internal property that tells what message-level is currently active.
     *
     * @property _currentMessageLevel
     * @default 0
     * @type Number
     * @private
     * @since 0.0.1
     */

    /**
     * Internal hash all queued message with level=1 (*:message)
     *
     * @property messages
     * @default []
     * @type Array
     * @since 0.0.1
     */

    /**
     * Internal hash all queued message with level=2 (*:warn)
     *
     * @property warnings
     * @default []
     * @type Array
     * @since 0.0.1
     */

    /**
     * Internal hash all queued message with level=3 (*:error)
     *
     * @property errors
     * @default []
     * @type Array
     * @since 0.0.1
     */
    Dialog = Classes.createClass(function() {
        var instance = this;
        instance.model = {
            draggable: true
        };
        instance._currentMessageLevel = 0;
        instance.messages = [];
        instance.warnings = [];
        instance.errors = [];
        instance.createContainer();
        instance.setupListeners();
    }, {

       /**
         * Creates a Panel-instance that will be used to display the messages.
         * Sets instance.model as panel's model and defines model.callback
         * which fulfills the message when a button on the dialog is pressed,
         *
         * @method createContainer
         * @since 0.0.1
         */
        createContainer: function() {
            var instance = this,
                model = instance.model;
            model.callback = function(buttonNode) {
                var containerNode = DOCUMENT.createElement('div'),
                    contentNode = instance.panel.getElement('>div[is="content"]'),
                    messagePromise = model.messagePromise;
                containerNode = contentNode.cloneNode(true);
                // now append a copy of the buttonNode:
                containerNode.append(buttonNode.getOuterHTML());
                messagePromise.fulfill(containerNode);
                // we can safely remove the newly created container-node: the vdom holds it for 1 minute
                containerNode.remove();
            };
            instance.panel = DOCUMENT.createPanel(model);
        },

       /**
         * Processes messages that are emitted by `messages`-module and add them in the queue.
         *
         * @method queueMessage
         * @param e {Object} the eventobject
         * @since 0.0.1
         */
        queueMessage: function(e) {
            var instance = this,
                messagePromise = e.messagePromise,
                type = e.type,
                level = MESSAGE_LEVELS[type],
                list = instance[MESSAGE_HASHES[type]];
            list[list.length] = messagePromise;
            messagePromise.finally(
                function() {
                    list.remove(messagePromise);
                    // handle the next message (if there)
                    instance.handleMessage(true);
                }
            );
            (level>instance._currentMessageLevel) && instance.handleMessage(!instance.isWaiting(), level);
        },

       /**
         * Defines subscribers to the events: *:message, *:warn and *:error.
         *
         * @method setupListeners
         * @since 0.0.1
         */
        setupListeners: function() {
            var instance = this;
            Event.after(['*:message', '*:warn', '*:error'], instance.queueMessage.bind(instance));
        },

       /**
         * Tells whether `dialog` is waitin g for new messages and is currently iddle.
         *
         * @method isWaiting
         * @return {Boolean} whether `dialog` is waitin g for new messages
         * @since 0.0.1
         */
        isWaiting: function() {
            return (this._currentMessageLevel===0);
        },

       /**
         * Retrieves the next message from the queue and calls showMessage() if it finds one.
         *
         * @method handleMessage
         * @param [delay] {Boolean} if there should be a delay between the previous dialog and the new one
         * @param [level] {Number} to force handling a specific level
         * @since 0.0.1
         */
        handleMessage: function(delay, level) {
            var instance = this,
                model = instance.model,
                messagePromise;
            if (!level) {
                // search level
                if (instance.errors.length>0) {
                    level = 3;
                }
                else if (instance.warnings.length>0) {
                    level = 2;
                }
                else if (instance.messages.length>0) {
                    level = 1;
                }
            }
            if (!level || (instance[MESSAGE_HASHES_NR[level]].length===0)) {
                // DO NOT make messagePromise null: it sould be there as return value
                // of the last message
                instance._currentMessageLevel = 0;
                model.header = null;
                model.content = '';
                model.footer = null;
                model.validate = null;
                model.visible = false;
                return;
            }
            instance._currentMessageLevel = level;
            // now process the highest message
            messagePromise = instance[MESSAGE_HASHES_NR[level]][0];
            if (delay) {
                model.visible = false;
                later(instance.showMessage.bind(instance, messagePromise), FOLLOWUP_DELAY);
            }
            else {
                async(instance.showMessage.bind(instance, messagePromise));
            }
        },

       /**
         * Shows the specified message-promise.
         *
         * @method showMessage
         * @param messagePromise {Promise} the message to be shown.
         * @since 0.0.1
         */
        showMessage: function(messagePromise) {
            var model = this.model;
            window.scrollTo(0, 0);
            model.messagePromise = messagePromise;
            model.header = messagePromise.header;
            model.content = messagePromise.content;
            model.footer = messagePromise.footer;
            model.validate = messagePromise.validate;
            model.visible = true;
        }
    });

    // instantiate Dialog and make it operational:
    dialog = new Dialog();

    window._ITSAmodules.Dialog = Dialog;

    return Dialog;
};