/**
 * Edit window for a single info popup entry.
 *
 * Uses the standard QUIQQER settings-form look (data-table / field-container),
 * a QUISwitch for the active state, a ColorPicker for the media colour and an
 * inline multilingual content editor. The design (display mode) is chosen
 * through small preview cards instead of a plain select. The entry is created
 * on save, so closing a fresh window without saving creates nothing.
 *
 * @module package/quiqqer/info-popup/bin/controls/EntryWindow
 * @author www.pcsg.de
 */
define('package/quiqqer/info-popup/bin/controls/EntryWindow', [

    'qui/QUI',
    'qui/controls/windows/Confirm',
    'qui/controls/buttons/Switch',
    'qui/controls/elements/ColorPicker',
    'controls/lang/InputMultiLang',
    'controls/lang/ContentMultiLang',
    'controls/groups/Select',
    'controls/projects/project/media/Input',
    'package/quiqqer/info-popup/bin/controls/DesignSelect',
    'Ajax',
    'Locale',

    'css!package/quiqqer/info-popup/bin/controls/EntryWindow.css'

], function (QUI, QUIConfirm, QUISwitch, ColorPicker, InputMultiLang, ContentMultiLang,
             GroupSelect, MediaInput, DesignSelect, QUIAjax, QUILocale) {
    "use strict";

    const lg = 'quiqqer/info-popup';

    // display modes that render a media region (image / colour surface)
    const MEDIA_DESIGNS = ['sidebar', 'sidebarRight', 'top'];

    return new Class({

        Extends: QUIConfirm,
        Type: 'package/quiqqer/info-popup/bin/controls/EntryWindow',

        Binds: [
            '$onOpen',
            '$onSubmit',
            '$buildForm',
            '$openContentEditor',
            '$updateContentPreview',
            '$onContentKeyDown',
            '$refreshVisibilityRow',
            '$refreshDesignRows',
            '$refreshLanguagesRow',
            '$onLanguageFlagClick'
        ],

        options: {
            entryId: false,
            projectName: false,
            maxWidth: 820,
            maxHeight: 800,
            autoclose: false,
            backgroundClosable: false,
            icon: 'fa fa-bullhorn'
        },

        initialize: function (options) {
            this.parent(options);

            this.$Form = null;
            this.$ActiveSwitch = null;
            this.$TitleInput = null;
            this.$contentValue = '';
            this.$GroupSelect = null;
            this.$MediaInput = null;
            this.$ColorPicker = null;
            this.$MediaAutoHeightSwitch = null;
            this.$CenterContentSwitch = null;
            this.$DesignSelect = null;
            this.$designValue = '';
            this.$AllLanguagesSwitch = null;
            this.$projectLanguages = [];
            this.$defaultLanguage = '';
            // active target languages, used only when "all languages" is off
            this.$languageSelection = [];

            this.setAttribute('title', QUILocale.get(
                lg,
                this.getAttribute('entryId') ? 'window.edit.title' : 'window.create.title'
            ));

            this.setAttribute('ok_button', {
                text: QUILocale.get(lg, 'window.save'),
                textimage: 'fa fa-save'
            });

            this.setAttribute('cancel_button', {
                text: QUILocale.get(lg, 'window.cancel'),
                textimage: 'fa fa-remove'
            });

            this.addEvents({
                onOpen: this.$onOpen,
                onSubmit: this.$onSubmit
            });
        },

        /**
         * event : on open - load data (edit) and build the form
         */
        $onOpen: function (Win) {
            const self = this;

            this.Loader.show();

            const Content = Win.getContent();
            Content.set('html', '');

            let load = Promise.resolve({});

            if (this.getAttribute('entryId')) {
                load = new Promise(function (resolve) {
                    QUIAjax.get('package_quiqqer_info-popup_ajax_get', resolve, {
                        'package': 'quiqqer/info-popup',
                        id: self.getAttribute('entryId')
                    });
                });
            }

            Promise.all([load, this.$loadProjectLanguages()]).then(function (results) {
                self.$buildForm(Content, results[0] || {});
                self.Loader.hide();
            });
        },

        /**
         * Load the project languages and default language into the control,
         * used for the language targeting picker.
         *
         * @return {Promise}
         */
        $loadProjectLanguages: function () {
            const self = this;

            return new Promise(function (resolve) {
                require(['Projects'], function (Projects) {
                    Projects.get(self.getAttribute('projectName')).getConfig().then(function (config) {
                        const langs = (config && config.langs) ? String(config.langs).split(',') : [];

                        self.$projectLanguages = langs.map((lang) => lang.trim()).filter((lang) => lang !== '');
                        self.$defaultLanguage = (config && config.default_lang) || self.$projectLanguages[0] || '';

                        resolve();
                    }).catch(function () {
                        self.$projectLanguages = [];
                        self.$defaultLanguage = '';
                        resolve();
                    });
                });
            });
        },

        /**
         * Build the form and initialize the sub controls.
         *
         * @param {HTMLElement} Content
         * @param {Object} entry
         */
        $buildForm: function (Content, entry) {
            const isCreate = !this.getAttribute('entryId');

            const row = (label, fieldHtml) => {
                return '<tr><td><label class="field-container">' +
                    '<span class="field-container-item">' + label + '</span>' +
                    fieldHtml +
                    '</label></td></tr>';
            };

            const desc = (text) => {
                return '<tr><td><span class="quiqqer-info-popup-entry-desc">' + text + '</span></td></tr>';
            };

            this.$Form = new Element('form', {
                'class': 'quiqqer-info-popup-entry',
                events: {
                    submit: function (event) {
                        event.stop();
                    }
                }
            }).inject(Content);

            this.$Form.set('html',
                '<table class="data-table data-table-flexbox"><tbody>' +

                row(QUILocale.get(lg, 'entry.active'),
                    '<span class="field-container-field" data-name="active-wrapper"></span>') +

                row(QUILocale.get(lg, 'entry.allLanguages'),
                    '<span class="field-container-field" data-name="allLanguages-wrapper"></span>') +

                '<tr data-name="languages-row"><td><div class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.languages') + '</span>' +
                '    <div class="field-container-field quiqqer-info-popup-entry-languages" ' +
                '         data-name="languages-picker" role="group" aria-label="' +
                QUILocale.get(lg, 'entry.languages') + '"></div>' +
                '</div></td></tr>' +
                '<tr data-name="languages-desc"><td>' +
                '    <span class="quiqqer-info-popup-entry-desc">' +
                QUILocale.get(lg, 'entry.languages.description') + '</span>' +
                '</td></tr>' +
                '<tr data-name="languages-error-row"><td>' +
                '    <span class="quiqqer-info-popup-entry-error" data-name="languages-error" ' +
                '          role="alert" hidden>' + QUILocale.get(lg, 'entry.languages.error') + '</span>' +
                '</td></tr>' +

                row(QUILocale.get(lg, 'entry.priority'),
                    '<input type="number" class="field-container-field" data-name="priority" value="0" />') +
                desc(QUILocale.get(lg, 'entry.priority.description')) +

                row(QUILocale.get(lg, 'entry.title'),
                    '<span class="field-container-field" data-name="title-wrapper"></span>') +

                '<tr><td><div class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.content') + '</span>' +
                '    <div class="field-container-field quiqqer-info-popup-entry-content-preview" ' +
                '         data-name="content-preview" role="button" tabindex="0"></div>' +
                '</div></td></tr>' +

                row(QUILocale.get(lg, 'entry.validFrom'),
                    '<input type="datetime-local" class="field-container-field" data-name="validFrom" />') +

                row(QUILocale.get(lg, 'entry.validTo'),
                    '<input type="datetime-local" class="field-container-field" data-name="validTo" />') +
                desc(QUILocale.get(lg, 'entry.validTo.description')) +

                row(QUILocale.get(lg, 'entry.visibility'),
                    '<select class="field-container-field" data-name="visibility">' +
                    '<option value="always">' + QUILocale.get(lg, 'visibility.always') + '</option>' +
                    '<option value="guest">' + QUILocale.get(lg, 'visibility.guest') + '</option>' +
                    '<option value="authenticated">' + QUILocale.get(lg, 'visibility.authenticated') + '</option>' +
                    '<option value="groups">' + QUILocale.get(lg, 'visibility.groups') + '</option>' +
                    '</select>') +

                '<tr data-name="groups-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.visibilityGroups') + '</span>' +
                '    <span class="field-container-field" data-name="groups-wrapper"></span>' +
                '</label></td></tr>' +

                '<tr><td><div class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.displayMode') + '</span>' +
                '    <div class="field-container-field" data-name="design-wrapper"></div>' +
                '</div></td></tr>' +
                desc(QUILocale.get(lg, 'entry.displayMode.description')) +

                row(QUILocale.get(lg, 'entry.verticalAlign'),
                    '<select class="field-container-field" data-name="verticalAlign">' +
                    '<option value="top">' + QUILocale.get(lg, 'valign.top') + '</option>' +
                    '<option value="center">' + QUILocale.get(lg, 'valign.center') + '</option>' +
                    '<option value="bottom">' + QUILocale.get(lg, 'valign.bottom') + '</option>' +
                    '</select>') +

                row(QUILocale.get(lg, 'entry.centerContent'),
                    '<span class="field-container-field" data-name="centerContent-wrapper"></span>') +
                desc(QUILocale.get(lg, 'entry.centerContent.description')) +

                '<tr data-name="mediaImage-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaImage') + '</span>' +
                '    <span class="field-container-field" data-name="mediaImage-wrapper"></span>' +
                '</label></td></tr>' +

                '<tr data-name="mediaAutoHeight-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaAutoHeight') + '</span>' +
                '    <span class="field-container-field" data-name="mediaAutoHeight-wrapper"></span>' +
                '</label></td></tr>' +
                '<tr data-name="mediaAutoHeight-desc"><td><span class="quiqqer-info-popup-entry-desc">' +
                QUILocale.get(lg, 'entry.mediaAutoHeight.description') + '</span></td></tr>' +

                '<tr data-name="mediaColor-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaColor') + '</span>' +
                '    <span class="field-container-field" data-name="mediaColor-wrapper"></span>' +
                '</label></td></tr>' +
                '<tr data-name="mediaColor-desc"><td><span class="quiqqer-info-popup-entry-desc">' +
                QUILocale.get(lg, 'entry.mediaColor.description') + '</span></td></tr>' +

                row(QUILocale.get(lg, 'entry.maxWidth'),
                    '<input type="number" min="0" class="field-container-field" data-name="maxWidth" />') +

                row(QUILocale.get(lg, 'entry.maxHeight'),
                    '<input type="number" min="0" class="field-container-field" data-name="maxHeight" />') +
                desc(QUILocale.get(lg, 'entry.size.description')) +

                '</tbody></table>'
            );

            // active switch
            this.$ActiveSwitch = new QUISwitch({
                status: isCreate ? true : parseInt(entry.active) === 1
            }).inject(this.$Form.querySelector('[data-name="active-wrapper"]'));

            // plain fields
            this.$Form.querySelector('[data-name="priority"]').value = parseInt(entry.priority) || 0;
            this.$Form.querySelector('[data-name="validFrom"]').value = this.$toInputDate(entry.validFrom);
            this.$Form.querySelector('[data-name="validTo"]').value = this.$toInputDate(entry.validTo);
            this.$Form.querySelector('[data-name="visibility"]').value = entry.visibility || 'always';
            this.$Form.querySelector('[data-name="verticalAlign"]').value = entry.verticalAlign || 'top';

            this.$CenterContentSwitch = new QUISwitch({
                status: parseInt(entry.centerContent) === 1
            }).inject(this.$Form.querySelector('[data-name="centerContent-wrapper"]'));

            if (entry.maxWidth) {
                this.$Form.querySelector('[data-name="maxWidth"]').value = parseInt(entry.maxWidth);
            }

            if (entry.maxHeight) {
                this.$Form.querySelector('[data-name="maxHeight"]').value = parseInt(entry.maxHeight);
            }

            // multilang title (lightweight, inline)
            this.$TitleInput = new InputMultiLang({
                name: 'title',
                value: entry.title || ''
            }).inject(this.$Form.querySelector('[data-name="title-wrapper"]'));

            // content: rich preview box that opens the multilingual editor in
            // its own window on click (lazy: the editor loads only on demand).
            this.$contentValue = entry.content || '';

            const ContentPreview = this.$Form.querySelector('[data-name="content-preview"]');
            ContentPreview.addEventListener('click', this.$openContentEditor);
            ContentPreview.addEventListener('keydown', this.$onContentKeyDown);
            this.$updateContentPreview();

            // design preview cards (own control, reused in the project settings).
            // An empty value means "use the project default".
            this.$designValue = entry.displayMode || '';
            this.$DesignSelect = new DesignSelect({
                value: this.$designValue,
                allowEmpty: true,
                events: {
                    onChange: (value) => {
                        this.$designValue = value;
                        this.$refreshDesignRows();
                    }
                }
            }).inject(this.$Form.querySelector('[data-name="design-wrapper"]'));

            // groups select
            this.$GroupSelect = new GroupSelect().inject(
                this.$Form.querySelector('[data-name="groups-wrapper"]')
            );

            if (entry.visibilityGroups) {
                String(entry.visibilityGroups).split(',').forEach((groupId) => {
                    groupId = groupId.trim();

                    if (groupId !== '') {
                        this.$GroupSelect.addItem(groupId);
                    }
                });
            }

            // language targeting: an empty stored value means "all languages"
            const targetLanguages = this.$parseLanguages(entry.languages);
            const isRestricted = targetLanguages.length > 0;

            this.$languageSelection = isRestricted
                ? targetLanguages
                : (this.$defaultLanguage ? [this.$defaultLanguage] : []);

            this.$AllLanguagesSwitch = new QUISwitch({
                status: !isRestricted,
                events: {
                    onChange: this.$refreshLanguagesRow
                }
            }).inject(this.$Form.querySelector('[data-name="allLanguages-wrapper"]'));

            this.$buildLanguageFlags();

            // media image
            this.$MediaInput = new MediaInput({
                name: 'mediaImage',
                project: this.getAttribute('projectName')
            }).inject(this.$Form.querySelector('[data-name="mediaImage-wrapper"]'));

            if (entry.mediaImage) {
                this.$MediaInput.setValue(entry.mediaImage);
            }

            this.$MediaAutoHeightSwitch = new QUISwitch({
                status: parseInt(entry.mediaAutoHeight) === 1
            }).inject(this.$Form.querySelector('[data-name="mediaAutoHeight-wrapper"]'));

            // media colour (parsed picker with clear button)
            this.$ColorPicker = new ColorPicker().inject(
                this.$Form.querySelector('[data-name="mediaColor-wrapper"]')
            );

            if (entry.mediaColor) {
                this.$ColorPicker.setValue(entry.mediaColor);
            }

            // toggles
            this.$Form.querySelector('[data-name="visibility"]')
                .addEventListener('change', this.$refreshVisibilityRow);

            this.$refreshVisibilityRow();
            this.$refreshDesignRows();
            this.$refreshLanguagesRow();
        },

        /**
         * Parse a stored language value (JSON array string, array or null) into
         * a clean list of language codes limited to the project languages.
         *
         * @param {String|Array|null} value
         * @return {Array}
         */
        $parseLanguages: function (value) {
            let data = value;

            if (typeof value === 'string') {
                if (value === '') {
                    return [];
                }

                try {
                    data = JSON.parse(value);
                } catch (e) {
                    return [];
                }
            }

            if (!Array.isArray(data)) {
                return [];
            }

            const known = this.$projectLanguages;

            return data
                .map((code) => String(code).trim())
                .filter((code) => code !== '' && (known.length === 0 || known.includes(code)));
        },

        /**
         * Build the clickable flag picker from the project languages. Each flag
         * is a toggle button whose pressed state mirrors $languageSelection.
         */
        $buildLanguageFlags: function () {
            const Picker = this.$Form.querySelector('[data-name="languages-picker"]');
            Picker.set('html', '');

            this.$projectLanguages.forEach((code) => {
                const Button = new Element('button', {
                    'class': 'quiqqer-info-popup-entry-language',
                    type: 'button',
                    'data-name': 'language-flag',
                    'data-lang': code,
                    'aria-pressed': this.$languageSelection.includes(code) ? 'true' : 'false',
                    'aria-label': code,
                    title: code,
                    html: '<img src="' + URL_BIN_DIR + '16x16/flags/' + code + '.png" alt="" aria-hidden="true" />' +
                        '<span class="quiqqer-info-popup-entry-language-code">' + code + '</span>'
                });

                Button.addEventListener('click', this.$onLanguageFlagClick);
                Button.inject(Picker);
            });
        },

        /**
         * Toggle a language in the selection and reflect it in aria-pressed.
         *
         * @param {Event} event
         */
        $onLanguageFlagClick: function (event) {
            event.preventDefault();

            const Button = event.currentTarget;
            const code = Button.getAttribute('data-lang');
            const index = this.$languageSelection.indexOf(code);

            if (index === -1) {
                this.$languageSelection.push(code);
                Button.setAttribute('aria-pressed', 'true');
            } else {
                this.$languageSelection.splice(index, 1);
                Button.setAttribute('aria-pressed', 'false');
            }

            this.$hideLanguagesError();
        },

        /**
         * Show the flag picker only when "all languages" is off. Turning the
         * toggle off with an empty selection seeds the project default language.
         */
        $refreshLanguagesRow: function () {
            const all = this.$AllLanguagesSwitch.getStatus();

            if (!all && this.$languageSelection.length === 0 && this.$defaultLanguage) {
                this.$languageSelection = [this.$defaultLanguage];
                this.$buildLanguageFlags();
            }

            const display = all ? 'none' : '';

            this.$Form.querySelector('[data-name="languages-row"]').style.display = display;
            this.$Form.querySelector('[data-name="languages-desc"]').style.display = display;
            this.$Form.querySelector('[data-name="languages-error-row"]').style.display = display;

            if (all) {
                this.$hideLanguagesError();
            }
        },

        $hideLanguagesError: function () {
            this.$Form.querySelector('[data-name="languages-error"]').hidden = true;
        },

        /**
         * Open the multilingual content editor in its own window (lazy, so the
         * editor is only loaded when the user actually edits the content).
         */
        $openContentEditor: function () {
            const self = this;
            let ContentInput = null;

            new QUIConfirm({
                title: QUILocale.get(lg, 'window.content.title'),
                icon: 'fa fa-edit',
                maxWidth: 900,
                maxHeight: 700,
                autoclose: false,
                backgroundClosable: false,
                ok_button: {
                    text: QUILocale.get(lg, 'window.save'),
                    textimage: 'fa fa-check'
                },
                cancel_button: {
                    text: QUILocale.get(lg, 'window.cancel'),
                    textimage: 'fa fa-remove'
                },
                events: {
                    onOpen: function (Win) {
                        Win.getContent().set('html', '');

                        ContentInput = new ContentMultiLang({
                            name: 'content',
                            value: self.$contentValue || ''
                        }).inject(Win.getContent());
                    },
                    onSubmit: function (Win) {
                        // flush the currently edited language into the input
                        // before reading (periodical save only runs every 1s)
                        if (ContentInput.$Editor) {
                            ContentInput.$saveContent();
                        }

                        self.$contentValue = ContentInput.getValue();
                        self.$updateContentPreview();
                        Win.close();
                    }
                }
            }).open();
        },

        /**
         * Keyboard support for the content preview (Enter / Space).
         *
         * @param {KeyboardEvent} event
         */
        $onContentKeyDown: function (event) {
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                this.$openContentEditor();
            }
        },

        /**
         * Render the content preview from the stored multilingual value. Shows
         * the formatted content of the current language (fallback: first
         * non-empty language) or a placeholder when empty.
         */
        $updateContentPreview: function () {
            const Preview = this.$Form.querySelector('[data-name="content-preview"]');
            const html = this.$contentPreviewHtml(this.$contentValue);

            if (html) {
                Preview.set('html', html);
                Preview.classList.remove('quiqqer-info-popup-entry-content-preview--empty');
                return;
            }

            Preview.set('text', QUILocale.get(lg, 'entry.content.empty'));
            Preview.classList.add('quiqqer-info-popup-entry-content-preview--empty');
        },

        /**
         * Extract the formatted content HTML for the current language from the
         * multilingual JSON value.
         *
         * @param {String} json
         * @return {String}
         */
        $contentPreviewHtml: function (json) {
            if (!json) {
                return '';
            }

            let data = null;

            try {
                data = JSON.parse(json);
            } catch (e) {
                return String(json);
            }

            if (!data || typeof data !== 'object') {
                return String(json);
            }

            if (data[QUILocale.getCurrent()]) {
                return data[QUILocale.getCurrent()];
            }

            for (const key in data) {
                if (data[key]) {
                    return data[key];
                }
            }

            return '';
        },

        /**
         * Show the groups row only for the "groups" visibility mode.
         */
        $refreshVisibilityRow: function () {
            const isGroups = this.$Form.querySelector('[data-name="visibility"]').value === 'groups';
            this.$Form.querySelector('[data-name="groups-row"]').style.display = isGroups ? '' : 'none';
        },

        /**
         * Show the media rows (image + colour) only for designs with a media
         * region, so image and colour appear only when they actually apply.
         */
        $refreshDesignRows: function () {
            const hasMedia = MEDIA_DESIGNS.includes(this.$designValue);
            const display = hasMedia ? '' : 'none';

            this.$Form.querySelector('[data-name="mediaImage-row"]').style.display = display;
            this.$Form.querySelector('[data-name="mediaColor-row"]').style.display = display;
            this.$Form.querySelector('[data-name="mediaColor-desc"]').style.display = display;

            const autoHeightDisplay = this.$designValue === 'top' ? '' : 'none';
            this.$Form.querySelector('[data-name="mediaAutoHeight-row"]').style.display = autoHeightDisplay;
            this.$Form.querySelector('[data-name="mediaAutoHeight-desc"]').style.display = autoHeightDisplay;
        },

        /**
         * event : on submit - collect the values, create (if new) and save
         */
        $onSubmit: function () {
            const self = this;

            // block saving a language-restricted popup without any target
            if (!this.$AllLanguagesSwitch.getStatus() && this.$languageSelection.length === 0) {
                this.$Form.querySelector('[data-name="languages-error"]').hidden = false;
                return;
            }

            const data = {
                active: this.$ActiveSwitch.getStatus() ? 1 : 0,
                priority: parseInt(this.$Form.querySelector('[data-name="priority"]').value) || 0,
                title: this.$TitleInput.getValue(),
                content: this.$contentValue,
                languages: this.$AllLanguagesSwitch.getStatus() ? null : this.$languageSelection,
                validFrom: this.$Form.querySelector('[data-name="validFrom"]').value,
                validTo: this.$Form.querySelector('[data-name="validTo"]').value,
                visibility: this.$Form.querySelector('[data-name="visibility"]').value,
                visibilityGroups: this.$GroupSelect.getValue(),
                displayMode: this.$designValue,
                verticalAlign: this.$Form.querySelector('[data-name="verticalAlign"]').value,
                centerContent: this.$CenterContentSwitch.getStatus() ? 1 : 0,
                mediaImage: this.$MediaInput.getValue(),
                mediaColor: this.$ColorPicker.getValue(),
                mediaAutoHeight: this.$MediaAutoHeightSwitch.getStatus() ? 1 : 0,
                maxWidth: this.$Form.querySelector('[data-name="maxWidth"]').value,
                maxHeight: this.$Form.querySelector('[data-name="maxHeight"]').value
            };

            this.Loader.show();

            const save = function (entryId) {
                QUIAjax.post('package_quiqqer_info-popup_ajax_save', function () {
                    self.fireEvent('saved', [self]);
                    self.close();
                }, {
                    'package': 'quiqqer/info-popup',
                    id: entryId,
                    data: JSON.encode(data),
                    onError: function () {
                        self.Loader.hide();
                    }
                });
            };

            if (this.getAttribute('entryId')) {
                save(this.getAttribute('entryId'));
                return;
            }

            // create mode: persist the entry only now, then save the data
            QUIAjax.post('package_quiqqer_info-popup_ajax_create', function (newId) {
                self.setAttribute('entryId', newId);
                save(newId);
            }, {
                'package': 'quiqqer/info-popup',
                project: self.getAttribute('projectName'),
                onError: function () {
                    self.Loader.hide();
                }
            });
        },

        /**
         * Convert a database datetime ("Y-m-d H:i:s") to the value expected
         * by an <input type="datetime-local">.
         *
         * @param {String} value
         * @return {String}
         */
        $toInputDate: function (value) {
            if (!value) {
                return '';
            }

            return String(value).replace(' ', 'T').substr(0, 16);
        }
    });
});
