Source: modules/popup.js

/*******************************************************************************
 * Handling of PopUps
 ******************************************************************************/
var POPUPS = [];

/**
 * Close all popups that have been opened with the popupHandler
 */
var closeAllPopUps = function () {
    Object.keys(POPUPS).forEach(function (value, index) {
        POPUPS[value].hide();
    });
};

/**
 * Opens a URL in a popup / popover
 * This is inteded for login forms and the prompt dialog.
 * 
 * @param   {string}   popupURL       The URL to open
 * @param   {function} finishFunction Function to execute when page has been opened
 * @param   {string}   popUpId        unique popupID if you know it already
 * @param   {boolean}  singular       if true, same popUpId can be reused, meaning addtional dialogs in same container
 * @returns {object}   The popup
 */
var popupHandler = function (popupURL, finishFunction, popUpId, singular) {

    if (popUpId && POPUPS[popUpId] != null && !singular) {
        return POPUPS[popUpId];
    }

    this.internalID = '_POPUPS' + Math.floor(Math.random() * 1000);
    this.popUpId = popUpId || this.internalID;
    this.popupURL = popupURL;
    this.finishFunction = finishFunction;
    this.formAction = null;
    this.popupContent = null;
    this.popupClose = null;

    // Singular is just for creating unique array entries
    POPUPS[this.internalID] = this;

    var self = this;
    
    /**
     * Retrieve the element that will hold the popup div.
     * @returns {element} the element that will hold the popup
     */
    this.documentFrameHolder = function() {
        var node = window.jQuery ? jQuery('div.webguicontainer')[0] : getId('__contentwrapper').parentNode;
        return node;
    };

    /**
     * Show the popup
     */
    this.show = function () {

        var iframe = getId(this.popUpId);
        var dialog = this.showDialog( iframe );
        if ( dialog !== false ) { return dialog; } // Already existing or a simple dialog

        if (!iframe) {
            var iframe = document.createElement("iframe");
            iframe.id = this.popUpId;
            iframe.name = iframe.id;
            iframe.addClassName("popup");

            // Firefox is soooooo blazing fast that the iframe is loaded before the
            // onload function is registered
            this.documentFrameHolder().appendChild(iframe);

            var retries = 10;
            var loadFunction = function () {

                var form = null;
                var thisDocument = this.document || this.contentDocument;
                var windowDocument = self.windowDocument.call(this);

                try {
                    var formList = Array.from( thisDocument.getElementsByTagName("form") ).concat( Array.from( windowDocument.getElementsByTagName("form") ) );
                    for(var i=0; i<formList.length; i++ ) {
                        var elem = formList[i];
                        if ( elem.className.indexOf('htmlpromptform') != -1 ) {
                            form = elem;
                            break;
                        }
                    }
                } catch (e) {
                    console.log("Error while getting form on thisDocument or WindowDocument " + e);
                } finally {
                    if (!form && windowDocument && retries > 0) {
                        window.setTimeout(loadFunction, 500);
                        retries--;
                        return;
                    }

                    var coverFrame = getId(self.popUpId + 'CoverFrame');
                    if (coverFrame) {
                        coverFrame.parentNode.removeChild(coverFrame);
                        coverFrame = null;
                    }
                }

                try {
                    self.formAction = form.action;
                    form.action = "javascript:try { var handler = (window.parent.htmlviewer || window.parent); console.log(handler); (new handler.popupHandler(\"" + self.popupURL.replace("\"", "\\\"") + "\", null, \"" + self.internalID + "\")).submitFormFunction(this); } catch(e) { console.log(e); alert(e) }";
                } catch (e) {
                    console.log("Error while registering JavaScript " + e);
                }

                removeEvent(iframe, "load", loadEvent);
                debug("Prompt Registration done.");
            };

            var loadEvent = function () {
                (new loadingView()).hide();
                window.setTimeout(loadFunction, 500);
            };

            addEvent(iframe, "load", loadEvent);
        }

        // The cover frame goes over the iframe to make the iframes content in-accessible until it is loaded.
        var coverFrame = document.createElement("div");
        coverFrame.id = self.popUpId + "CoverFrame";
        coverFrame.addClassName("popUpCoverFrame");
        this.documentFrameHolder().appendChild(coverFrame);

        iframe.src = this.popupURL;
        return this;
    };
    
    this.showDialog = function( contentWrapper ) {

        if ( this.popupURL ) {
            // There is a popup url, return nothing to do here.
            return false;
        }
        
        if ( !contentWrapper ) {
        
            var contentWrapper = document.createElement('div');
            contentWrapper.addClassName('popupWrapper');
            contentWrapper.id = this.popUpId;
            this.documentFrameHolder().appendChild(contentWrapper);

            var contentWrapperBackground = document.createElement('div');
            contentWrapperBackground.addClassName('popupWrapperBackground');
            contentWrapper.appendChild(contentWrapperBackground);
        }

        // save for external access
        this.popupContent = document.createElement('div');
        this.popupContent.addClassName('popup');
        contentWrapper.appendChild(this.popupContent);

        // Save for external access
        this.popupClose = document.createElement("div");
        this.popupClose.appendChild(document.createTextNode("x"));
        this.popupClose.className = "close";
        this.popupContent.appendChild(this.popupClose);
        addEvent(this.popupClose, 'click', this.hide);

        addEvent(window, 'keydown', this.__hideByKey);
        
        return this;
    };
    
    /**
     * add a header element to the content panel
     * @param {string} header the header string
     */
    this.addHeader = function( header, level ) {
        var h1 = document.createElement('h' + ( level || '1'));
        h1.appendChild(document.createTextNode( header ));
        this.popupContent.appendChild(h1);
    };

    /**
     * Add a body element to the popup content panel
     * @param {Element} body a body element
     */
    this.addBody = function( body ) {
        this.popupContent.appendChild( body );
    };

    /**
     * Add an entry to the detail section. Will open the section if it does not yet exist.
     * @param {string}  label       the label of the detail entry
     * @param {string}  value       a value that will be printed preformatted
     * @param {boolean} showDefault display this value by default
     */
    this.addDetail = function( label, value, showDefault ) {

        if ( !this.popupDetailSection ) {
            this.popupDetailSection = document.createElement("div");
            this.popupDetailSection.addClassName('details');
            this.popupContent.appendChild( this.popupDetailSection );

            var expanderButton = document.createElement("div");
            expanderButton.appendChild(document.createTextNode(showDefault?"/\\":"\/"));
            expanderButton.className = "expander";
            this.popupContent.appendChild(expanderButton);

            self.popupContent.addRemoveClass('showDetails', showDefault);
            addEvent(expanderButton, 'click', function () {
                expanderButton.innerHTML = '';
                if (!self.popupContent.hasClassName('showDetails')) {
                    expanderButton.appendChild(document.createTextNode("/\\"));
                    self.popupContent.addClassName('showDetails');
                } else {
                    expanderButton.appendChild(document.createTextNode("\/"));
                    self.popupContent.removeClassName('showDetails');
                }
            });
        }
        
        var labelElement = document.createElement("label");
        labelElement.appendChild(document.createTextNode(label + ':'));

        var labelDetails = document.createElement("pre");
        labelDetails.appendChild(document.createTextNode(value));
        labelElement.appendChild(labelDetails);

        var labelBreak = document.createElement("br");
        labelElement.appendChild(labelBreak);
        
        this.popupDetailSection.appendChild(labelElement);
    };
    
    // Creates the new prompt array - which should be triggered by the iframe
    this.submitFormFunction = function (event) {

        var documentElement = self.windowDocument.call(window);
        var form = documentElement.getElementsByTagName('form')[0];
        if (!form) {
            throw getTranslation("prompts.promptFormNotFound");
        }

        var input = Array.prototype.slice.call(form.getElementsByTagName('input'), 0);
        var select = Array.prototype.slice.call(form.getElementsByTagName('select'), 0);

        form.onsubmit = null;
        var returnVar = typeof this.finishFunction == 'function' ? this.finishFunction(event, form, input.concat(select)) : null;
        this.hide();
        return returnVar;
    };
    
    this.windowDocument = function() {
        var windowParent = this[self.popUpId] || window.top[self.popUpId] || {};
        return windowParent.document || windowParent.contentDocument || document;
    };

    /**
     * Hide the popup after an amount of time
     * @param {number} timed timout to close the popup
     */
    this.hide = function (timed) {

        var popup = getId(self.popUpId);
        if (!popup) {
            return;
        }

        // If there are no more errors, remove the errorview entirely
        if (popup.childNodes.length > 2) {
            self.popupContent.parentNode.removeChild(self.popupContent);
        } else {

            // Anzeige der Seite, nachdem der Fehler weg ist
            // getId('__contentwrapper').className = '';
            popup.style.display = 'none';
            window.setTimeout(function () {
                window.setTimeout(function () {
                    if (popup.parentNode) {
                        popup.parentNode.removeChild(popup);
                    }
                }, 1000);
                popup.id += '_expose';
            }, timed || 0);
        }

        removeEvent(window, 'keydown', self.hide);
        delete POPUPS[self.internalID];
    };
    
    /**
     * Hide the popup by pressing the excape key
     */
    this.__hideByKey = function( event )  {
        if (event.which) {
            var keycode = event.which;
        } else {
            var keycode = event.keyCode;
        }
        
        if ( keycode == 27 ) {
            self.hide();
        }
    };
};