HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/TDijk1/erp-apps.eu/wwwroot/CMSScripts/CMSModules/CMS.WebAnalytics/ModalDialog.js
cmsdefine(["jQuery", "Underscore"], function ($, _) {
    "use strict";
    
    var defaults = {
        width: 500,
        height: 500,
        title: "Default title",
        draggable: true,
        closeButton: true,
        canBeMaximized: true,
        onClose: function() {},
        resourceStrings: {
            maximize: "Full screen",
            restore: "Restore",
            close: "Close",
        },
        buttons: []
    };


    /**
     * Wrapper around the jQuery UI dialog widget, respecting the CMS design guidelines. Should be used in case when
     * the content to be displayed is part of the DOM, not the whole page which should be displayed in iframe. For such
     * cases there is modalDialog method in global space available.
     *
     * @param   contentSelector         string      selector of the DOM object to be displayed within the dialog
     * @param   settings                object      settings object for configuring the dialog behavior and appearance
     *              width               int         specifies width of the dialog in pixels
     *              height              int         specifies height of the dialog in pixels
     *              title               string      specifies title of the dialog
     *              draggable           boolean     determines whether the dialog should be draggable or not. Dialog title bar is used for handle
     *              closeButton         boolean     determines whether the close button should be available within the dialog title bar
     *              canBeMaximized      boolean     determines whether the dialog can be maximized to fill the screen and then restored to its original size and position
     *              onClose             callback    method called when the dialog is closed
     *              resourceStrings     object      object containing localization strings used by the dialog
     *                  maximize        string      maximize button title
     *                  restore         string      restore button title
     *                  close           string      close button title
     *              buttons             array       collection of buttons to be displayed in the dialog footer. Every button is represented by the object with properties
     *                                              'title', specifying text inside the button and 'action', containing method called whenever the button is clicked
     * 
     * @example
     * Following example shows how to use the dialog with some common settings
     * 
     * caller.html
     * <div id="dialog-content" style="display:none">
     *   <h1>Some header</h1>
     *   ... other content
     * </div>
     *
     * <button id="btn">Show dialog</button>
     *
     * caller.js
     * var dialog = new ModalDialog("#dialog-content", { title: "My title", buttons: [{ title: "Enter", action: function () { alert("Enter clicked"); } }] });
     *
     * $("#btn").on("click", function() {
     *     dialog.open();
     * })
     */
    var ModalDialog = function (contentSelector, settings) {
        if (!contentSelector) {
            throw "Content selector has to be specified";
        }
        
        this._settings = _.defaults(settings || {}, defaults);

        var $dialog = this._buildDialog(),
            $topDialog = this._moveToTopFrameContext($dialog);

        this._$dialogContent = $(contentSelector);
        this._$dialogContentParent = this._$dialogContent.parent();
        
        this._isMaximized = false;
        
        if (!$topDialog.dialog) {
            console.error("jQuery UI dialog widget is not available.");
            return;
        }

        this._dialog = $topDialog.dialog({
            autoOpen: false,
            width: this._settings.width,
            height: this._settings.height,
            title: this._settings.title,
            modal: true,
            draggable: this._settings.draggable,
            close: this._settings.onClose
        });

        this._setupWidget();
        this._cleanUp();
        this._handleWindowResize();
    };


    /**
     * Opens the dialog.
     */
    ModalDialog.prototype.open = function () {
        this._$content.append(this._$dialogContent.show());
        this._dialog.dialog("open");
    };


    /**
     * Closes the dialog. 
     */
    ModalDialog.prototype.close = function () {
        this._dialog.dialog("close");
        this._$dialogContentParent.append(this._$dialogContent.hide());
    };


    /**
     * Fires on the window resize. In case the dialog is in maximized state, adjusts its size and ensures the dialog position in the center of the window.
     */
    ModalDialog.prototype._handleWindowResize = function() {
        $(window.top).resize(function () {
            if (this._isMaximized) {
                this._resizeToMaximalSize();
                this._center();
            }
        }.bind(this));
    };


    /**
     * Sets up the dialog underlying jQuery UI widget. Adds custom CSS class and ensure the dialog header will be the drag handle.
     */
    ModalDialog.prototype._setupWidget = function() {
        this._widget = this._dialog.dialog("widget");
        this._widget.addClass("modal-dialog");

        if (this._settings.draggable) {
            this._setupWidgetDraggable();
        }
    };    


    /**
     * Sets up the dialog underlying jQuery UI widget draggable environment. Ensures the dialog header bar will be the drag handle.
     */
    ModalDialog.prototype._setupWidgetDraggable = function() {
            this._widget.draggable({
                cancel: '.ui-dialog-titlebar-close',
                handle: '.dialog-header',
            });
    };


    /**
     * Depending on the current state, either maximize or restore the dialog.
     */
    ModalDialog.prototype._toggleSize = function() {
        if (this._isMaximized) {
            this._restore();
        } else {
            this._maximize();
        }
    };


    /**
     * Moves the dialog to the top most frame. Uses jQuery context of the top most frame
     * to make sure all interactions will be working.
     *
     * @param  dialog  DOM object       dialog object to be injected to the top most frame.
     *
     * @returns        jQuery object    jQuery object representing the dialog existing in the top most frame context
     */
    ModalDialog.prototype._moveToTopFrameContext = function(dialog) {
        $(window.top.document).append(dialog);
        return window.top.$cmsj.noConflict()(dialog);
    };


    /**
     * Build DOM object representing the dialog with all its parts, including header, content placeholder and the footer.
     * Hooks event handlers to the header buttons.
     */
    ModalDialog.prototype._buildDialog = function() {
        var dialogRoot = $("<div></div>"),
            dialogHeader = $("<div />")
                .addClass("dialog-header non-selectable"),
            actionButtons = $("<div />")
                .addClass("dialog-header-action-buttons"),
            title = $("<h2 />")
                .addClass("dialog-header-title")
                .text(this._settings.title),
            content = $("<div />")
                .addClass("dialog-content"),
            footer = $("<div />").addClass("dialog-footer control-group-inline");

        dialogHeader.on('dblclick', this._toggleSize.bind(this));

        if (this._settings.canBeMaximized) {
            this._toggleButton = this._buildActionButton("action-button", "icon-modal-maximize cms-icon-80", this._settings.resourceStrings.maximize, "toggle");
            this._toggleButton.find("i").on("click", this._toggleSize.bind(this));
            actionButtons.append(this._toggleButton);
        }

        if (this._settings.closeButton) {
            var closeButton = this._buildActionButton("action-button close-button", "icon-modal-close cms-icon-150", this._settings.resourceStrings.close, "close");
            closeButton.find("i").on("click", this.close.bind(this));
            actionButtons.append(closeButton);
        }

        if (this._settings.draggable) {
            dialogHeader.addClass("handle");
        }

        dialogHeader.append(actionButtons).append(title);
        dialogRoot.append(dialogHeader).append(content).append(footer);

        this._$dialogHeader = dialogHeader;
        this._addButtons(footer);
        this._$content = content;

        return dialogRoot;
    };


    /**
     * Adds all buttons provided with the input settings object to the dialog footer. Registers their click events to the callbacks 
     * provided in the configuration object.
     *
     * @param    dialogFooter    jQuery object    represents the dialog footer
     */
    ModalDialog.prototype._addButtons = function(dialogFooter) {
        this._settings.buttons.forEach(function (button) {
            dialogFooter.append($("<button />").addClass("btn btn-primary").text(button.title).on("click", button.action));
        });
    };


    /**
     * Builds DOM object representing action button in the dialog header.
     * 
     * @param   buttonClass     string      CSS class to be added to the outer most div element of the button. Usually contains 'action-button'
     * @param   iconClass       string      CSS class defining font icon of the button. Should contain both icon type and size
     * @param   title           string      used as tooltip of the button
     *
     * @returns                             DOM object containing the built button
     */
    ModalDialog.prototype._buildActionButton = function (buttonClass, iconClass, title) {
        return $("<div />")
            .addClass(buttonClass)
            .append("<a/>")
            .find("a")
            .append(
                $("<span />")
                    .addClass("sr-only")
                    .text(title)
            )
            .append(
                $("<i />")
                    .addClass(iconClass)
                    .attr("aria-hidden", "true")
                    .css("cursor", "pointer")
                    .attr("title", title)
            )
            .end();
    };


    /**
     * Performs maximization of the dialog. Stores original size and position for restoring the dialog in future. 
     * After dialog maximization moves it to the center of the window.
     */
    ModalDialog.prototype._maximize = function () {
        this._originalSize = {
            width: this._dialog.dialog("option", "width"),
            height: this._dialog.dialog("option", "height"),
        };
        this._originalPosition = this._dialog.dialog("option", "position");

        this._dialog.dialog("option", "draggable", false);
        this._dialog.dialog("option", "resizable", false);
        this._$dialogHeader.removeClass("handle");

        this._changeToggleButtonToRestore();

        this._resizeToMaximalSize();
        this._center();
        this._isMaximized = true;
    };


    /**
     * Changes maximize button to the restore one. Alters both icon and the tooltip text.
     */
    ModalDialog.prototype._changeToggleButtonToRestore = function() {
        this._toggleButton.find("i").removeClass("icon-modal-maximize").addClass("icon-modal-minimize").attr("title", this._settings.resourceStrings.restore);
        this._toggleButton.find("a span").text(this._settings.resourceStrings.restore);
    };
    

    /**
    * Changes restore button to the maximize one. Alters both icon and the tooltip text.
    */
    ModalDialog.prototype._changeToggleButtonToMaximize = function() {
        this._toggleButton.find("i").removeClass("icon-modal-minimize").addClass("icon-modal-maximize").attr("title", this._settings.resourceStrings.maximize);
        this._toggleButton.find("a span").text(this._settings.resourceStrings.maximize);
    };


    /**
     * Performs restore (minimize) action of the dialog. Resize the dialog to the previously saved dimensions and move the dialog to the saved position.
     */
    ModalDialog.prototype._restore = function() {
        this._dialog.dialog("option", "width", this._originalSize.width);
        this._dialog.dialog("option", "height", this._originalSize.height);
        this._dialog.dialog("option", "position", this._originalPosition);

        this._dialog.dialog("option", "draggable", this._settings.draggable);
        this._dialog.dialog("option", "resizable", true);

        this._changeToggleButtonToMaximize();
        this._setupWidgetDraggable();
        this._$dialogHeader.addClass("handle");

        this._isMaximized = false;
    };


    /**
     * Maximize the dialog to its maximal size, respecting the margin.
     */
    ModalDialog.prototype._resizeToMaximalSize = function() {
        var windowWidth = $(window.top).width(),
            windowHeight = $(window.top).height(),
            verticalPadding = 24,
            horizontalPadding = 48;

        this._dialog.dialog("option", "width", windowWidth - 2 * horizontalPadding);
        this._dialog.dialog("option", "height", windowHeight - 2 * verticalPadding);
    };


    /**
     * Move dialog to the center of the window.
     */
    ModalDialog.prototype._center = function() {
        this._dialog.dialog( "option", "position", { my: "center", at: "center", of: window.top } );
    };


    /**
     * Removes unnecessary DOM object generated by the jQuery UI dialog.
     */
    ModalDialog.prototype._cleanUp = function () {
        // This ID is used in aria-labelledby attribute of the dialog. Since the original title is removed, 
        // the ID has to be moved to the new dialog header to satisfy accessibility of the dialog
        var widgetTitleBar = this._widget.find(".ui-dialog-titlebar"),
            ariaLabelledById = widgetTitleBar.find("*[id]").attr("id");
        this._$dialogHeader.attr("id", ariaLabelledById);
        
        widgetTitleBar.remove();
    };

    return ModalDialog;
});