$(document).ready(async () => {

    /**
     * @constant
     * Plugin qui contient la localisation des textes
     */
    const plugin_text = 'mel_news';

    /**
     * @constant
     * URL du site web
     */
    const news_contact_url = window.location.origin + window.location.pathname;

    /**
     * @constant
     * Enumération de tous les modes disponibles
     */
    const modes = {
        /**
         * Mode "Toutes les informations" : Toutes les informations d'un même site est affiché sur la page. 
         * Une modification entraîne la modification de toutes les informations lié au site modifié.
         */
        all:"tout",
        /**
         * Mode "Vignette", chaque informations d'un site est encapsulé dans une vignette où l'on peut naviguer du plus récent au plus ancien.
         */
        vignette:"un"
    };

    /**
     * @constant
     * Enumération de tous les modes tris dsiponibles.
     */
    const sort_modes = {
        /**
         * Tri par date - du plus ancien au plus récent
         */
        date_asc:"date_asc",
        /**
         * Tri par date - du plus récent au plus ancien
         */
        date_desc:"date_desc",
        /**
         * Tri par site
         */
        site:"site",
        /**
         * Tri par source (intra/inter/twitter)
         */
        source:"source"
    };

    /**
     * @constant
     * Enumération des id de filtres disponibles.
     */
    const filters = {
        types:{
            intranet:"#mel-new-filter-1",
            twitter:"#mel-new-filter-2",
            //rss:"#mel-new-filter-3"
        },
        categories:{
            headlines:"#mel-new-filter-4",
            //defaults:"#mel-new-filter-5",
            customs:"#mel-new-filter-6"
        }
    }

    /**
     * @constant
     * Mode de la page (Tout/Vignette)
     * @type {number}
     */
    const mode = rcmail.env.news_mode;
    /**
     * @constant
     * Tri de la page (Date/Site/Source)
     * @type {string}
     */
    const sort_mode = rcmail.env.news_sort_mode;
    /**
     * @constant
     * Nombres de lignes visibles pour commencer
     * @type {string}
     */
    const nbRows = rcmail.env.news_starting_nb_rows;

    /**
     * Ajoute les script twitter à la page avec gestion d'erreur.
     * @returns Script créé
     */
    function setTwitterSrc() {
        let script = document.createElement('script');
        // any script can be loading from any domain
        script.src = "https://platform.twitter.com/widgets.js";
        script.setAttribute("async", "async");

        document.head.append(script);
        script.onload = function () {

        };

        script.onerror = function(e, a, b) {
            if (setTwitterSrc.first === undefined)
            {
                rcmail.display_message(rcmail.gettext('twitter_navigator_error', plugin_text), "error");
                setTwitterSrc.first = false;
            }

            for (let index = 0; index < MelCustomNews.allCustomNews.length; index++) {
                const element = MelCustomNews.allCustomNews[index];
                
                if (element.type === "twitter")
                {
                    element.$news.find(".square-contents .headlines-title").css("display", "block").html(`Twitter de ${element.id}`);
                    element.$news.find(".square-contents .headlines-contents").css("display", "block").html(
                        `<a href="https://twitter.com/${element.id}" target="_blank">${rcmail.gettext('open_in_new_tab', plugin_text)} <span class="icon-mel-external"></span></a>`
                    );
                    element.$news.find(".square-contents").css("padding", "30px");
                }
            }
        };

        return script;
    };

    /**
     * Met la première lettre de la chaîne de caractère en majuscule.
     * @param {string} a 
     * @returns String capitalisé
     */
    function strUcFirst(a){return (a+'').charAt(0).toUpperCase()+a.substr(1)};
    window.strUcFirst = strUcFirst;

    /**
     * @class
     * @classdesc gère les différentes popup de la pages des informations
     */
    class NewsPopup
    {
        constructor()
        {
            if (window.create_popUp !== undefined)
                delete window.create_popUp

            const _GlobalModalConfig = this.isSettings() ? parent.GlobalModalConfig : GlobalModalConfig;
            const _GlobalModal = this.isSettings() ? parent.GlobalModal : GlobalModal;

            let config = new _GlobalModalConfig();
            config.title = rcmail.gettext('loading');
            config.content = `<center><span class="spinner-grow"><span class="sr-only">${rcmail.gettext('loading')}</span></span></center>`;
            config.footer = "";
            this.modal = new _GlobalModal("globalModal", config);
            this.symbols = {
                allIsSelected:Symbol("allIsSelected")
            };

            const modal_show = this.modal.show;
            this.modal.show = function()
            {
                if(!!window.create_popUp) window.create_popUp = undefined;

                if ($('#created-modal-title-div-auto').length > 0) this.removeBeforeTitle();

                this.on_click_exit = () => this.close();

                this.notHaveReduced();
                modal_show.call(this);
            }
        }

        /**
         * Permet de récupérer une instance statique de la classe.
         * @returns {NewsPopup}
         */
        static fabric()
        {
            if (NewsPopup.cache === undefined)
                NewsPopup.cache = new NewsPopup();

            return NewsPopup.cache;
        }

        /**
         * 
         * @param {string} title Titre de la modale
         * @param  {...{classes:string, icon:string, title:string, action:Function}} choices Liste des choix disponibles
         * @returns Permet le chaînage
         */
        drawChoice(title, ...choices)
        {
            this.modal.footer.querry.html("");
            this.modal.editTitle(title);

            let $html = $('<div style="display:flex"></div>');
            for (const key in choices) {
                if (Object.hasOwnProperty.call(choices, key)) {
                    const element = choices[key];
                    $html.append($(`<button style="margin-top:0px;margin-right:15px" class="btn btn-block ${element.classes === undefined ? "btn-secondary" : element.classes} btn-mel">
                    <span class="block ${element.icon}"></span> ${element.title}
                </button>`).click(element.action));
                }
            }

            this.modal.editBody("");
            this.modal.contents.append($html);

            return this;
        }

        /**
         * Ouvre la modale de publication de flux.
         * @param {string} id Id du flux
         * @param {boolean} isFlux Si vrai, il s'agit d'un flux rss, sinon, d'une publication
         * @returns Chaînage
         */
        createOrEditPublish(id = null, isFlux = false)
        {
            let obFields = '';
            const classes = "form-control input-mel required"
            let news = new MelPublishNew(id);

            //Gère les données des flux
            if (rcmail.env.news_current_news_datas !== undefined)
            {
                news.server_uid = rcmail.env.news_current_news_datas.uid;
                news.setService(rcmail.env.news_current_news_datas.service);
                news.title = news.id;

                if (rcmail.env.news_service_for_publish[rcmail.env.news_current_news_datas.service] === undefined)
                    rcmail.env.news_service_for_publish[rcmail.env.news_current_news_datas.service] = rcmail.env.news_current_news_datas.service.split(',', 2)[0].split("=")[1];

                rcmail.env.news_current_news_datas = undefined;
            }//Gère les données de l'édition/des flux enfants
            else if (!isFlux && id !== null)
            {
                //console.log("else", rcmail.env.news_service_for_publish, news);
                if (rcmail.env.news_service_for_publish[news.type] === undefined && news.type !== null && news.type !== undefined && news.type !== "")
                    rcmail.env.news_service_for_publish[news.type] = news.type.split(',', 2)[0].split("=")[1];
            }

            //Titre de la modale
            if (id === null) this.modal.editTitle(rcmail.gettext('create_publish', plugin_text));
            else this.modal.editTitle(`${rcmail.gettext('edit', plugin_text)} "${news.title}"`);

            //Si on modifie une vrai news
            if (id !== null && id !== "generated-tmp-id")
                obFields = `<div style="text-align:right;"><button id="publish-delete-button" class="mel-button btn btn-danger" style="">${rcmail.gettext('delete')} <span class="plus icon-mel-trash"></span></button></div>`;

            //Affichage du texte
            let html = obFields + '<div><div class="row"><div class="service-left col-12">' + this.createSelect(rcmail.gettext('choose_service', plugin_text), "mel-publish-service", rcmail.gettext('select_service', plugin_text), Enumerable.from(rcmail.env.news_service_for_publish).select(x => {return {value:x.key,text:x.value}}).toArray(), id === null ? "none" : news.getService()) + '</div><div class="service-right hidden"><button id="np-select-child" class="mel-button btn btn-secondary" style="margin-top: 53px;">Choisir un sous-service</button></div></div></div>';
            
            //Si on publie une publication
            if (!isFlux)
            {
                html += '<div>' + this.createInput(rcmail.gettext('choose_title', plugin_text), "mel-publish-title", "text", rcmail.gettext('admin_news_title', plugin_text), news.title, "mel-publish-title", classes) + '</div>';
                html += '<div>' + this.createTextarea(rcmail.gettext('write_admin_news', plugin_text), "mel-publish-body", rcmail.gettext('admin_news_placeholder', plugin_text), news.body) + '</div>';
            }//Si on publie un flux
            else {
                html += this.createSelect(rcmail.gettext('choose_intranet', plugin_text), "news-intranet-select", rcmail.gettext('select_website', plugin_text), Enumerable.from(rcmail.env.news_intranet_list).select(x => {return {value:x.key, text:x.value.name}}).toArray(), (id === null ? "none" : news.id));
            }

            //Modification de l'affichage de la modale (Voir la classe modal de mel_metapage)
            this.modal.editBody('<div class="np-content mel-r">'+html+'</div><div class="np-other mel-r"></div>');

            //Affichage de pied de modal
            this.modal.footer.querry.html("");

            //Suppression de la publicartion
            this.modal.modal.find("#publish-delete-button").click(() => {
                if (confirm(rcmail.gettext('delete_confirm', plugin_text)))
                {
                    this.modal.close();
                    rcmail.set_busy(true);
                    rcmail.display_message(rcmail.gettext('deleting', plugin_text), "loading");
                    this.post((isFlux ? "delete_rss" : "delete"), {
                        _uid:(isFlux ? news.server_uid : id)
                    },
                    (datas) => {
                        rcmail.clear_messages();
                        rcmail.set_busy(false);
                        if (datas === "denied")
                        {
                            rcmail.display_message(rcmail.gettext('action_denied', plugin_text), "error");
                        }
                        else {
                            rcmail.display_message(rcmail.gettext('succefuly_published', plugin_text), "confirmation");
                            rcmail.set_busy(true, "loading");
                            window.location.reload();
                        }
                    });
                }
            });

            //Affichage des sous-services ou non
            this.modal.modal.find("#mel-publish-service").on("change", () => {
                const col_right = 3;
                const col_left = 12 - col_right;
                const col_class_right = `col-${col_right}`;

                let service_right = this.modal.modal.find(".service-right");

                if (!service_right.hasClass(col_class_right) && this.modal.modal.find("#mel-publish-service").val() !== "none")
                {
                    service_right.addClass(col_class_right).removeClass("hidden");
                    this.modal.modal.find(".service-left").removeClass("col-12").addClass(`col-${col_left}`);
                    this.modal.modal.find("#np-select-child").click(() => {
                        this.modal.modal.find(".np-content").css("display", "none");
                        this.modal.footer.querry.css("display", "none");
                        new AnnuaireTree(this.modal.modal.find(".np-other"))
                        .setAction(AnnuaireTree.actionsList.onGetAddress, (arbre, service) => {
                            return `${news_contact_url}?_task=addressbook&_is_from=iframe&_action=plugin.annuaire&_source=amande&_base=${btoa(service)}&_remote=1`;
                        })
                        .setAction(AnnuaireTree.actionsList.htmlButton, (arbre, html, service,datas) => {
                            const end = ',dc=equipement,dc=gouv,dc=fr';
                            service = datas.dn;

                            if (!service.includes(end))
                                service += end;

                            html = $(html);
                            let $querry = html.find(".button-text");
                            let text = $querry.html();
                            $querry.remove();
                            $querry = html.append(`<button data-service="${service}" class="mel-button no-button-margin true bckg nbtn-action">${datas.dn.replace(',dc=equipement,dc=gouv,dc=fr', '') === this.modal.modal.find("#mel-publish-service").val() ? '<span class="icon-mel-check icon"></span>' : '<span class="icon"></span>'}${text}</button>`);
                            return html[0].outerHTML;
                        })
                        .setAction(AnnuaireTree.actionsList.afterShowChildren, (arbre, datas, service, $button, $span) => {            
                            if (!Enumerable.from(datas.elements).any(x => x.classes.length > 0 && x.classes[0] === "folder"))
                            {
                                $span.removeClass(arbre.icons.opened).addClass(arbre.icons.empty).parent().parent().addClass("disabled").attr("disabled", "disabled");
                            }
                        })
                        .setAction(AnnuaireTree.actionsList.onNotFolderClick, (arbre, service, $button) => {
                            arbre.panel.find("button.nbtn-action .icon").removeClass("icon-mel-check");
                            $button.find(".icon").addClass("icon-mel-check");
                        })
                        .setAction(AnnuaireTree.actionsList.afterSetup, (arbre) => {
                            arbre.panel.append($(`<button class="added-undo-button mel-button btn btn-primary">${rcmail.gettext('back')} <span class="plus icon-mel-undo"></span></button>`).click(() => {
                                this.modal.modal.find(".np-other").html("");
                                this.modal.modal.find(".np-content").css("display", "");
                                this.modal.footer.querry.css("display", "");
                            }));

                            if (arbre.panel.find("li").length === 0)
                            {
                                arbre.panel.find("button.added-undo-button").click();
                                rcmail.display_message(rcmail.gettext('no_sub_services', plugin_text));
                            }
                            else {
                                arbre.panel.append($(`<button style="float:right" class="mel-button btn btn-primary">${rcmail.gettext('validate', plugin_text)} <span class="plus icon-mel-check"></span></button>`).click(() => {
                                    const selected = arbre.panel.find("button.nbtn-action .icon-mel-check");
                                    if (selected.length > 0)
                                    {
                                        const btn = selected.parent();
                                        if (this.modal.modal.find("#mel-publish-service").find(`option[value="${btn.data("service")}"]`).length > 0) this.modal.modal.find("#mel-publish-service").val(btn.data("service"));
                                        else {
                                            this.modal.modal.find("#mel-publish-service").append(`<option value=${btn.data("service")}>${btn.find(".name").html()} - ${btn.find(".description").html()}</option>`).val(btn.data("service"));
                                            
                                            if (rcmail.env.news_service_for_publish === undefined)
                                                rcmail.env.news_service_for_publish = {};
                                            
                                            rcmail.env.news_service_for_publish[btn.data("service")] = btn.find(".name").html() + "-" + btn.find(".description").html();
                                        }
                                    }

                                    arbre.panel.find("button.added-undo-button").click();

                                }));

                                arbre.panel.prepend(`<h4>${rcmail.gettext('choose_sub_service', plugin_text)}</h4>`);
                            }


                            
                        })
                        .setupTree(this.modal.modal.find("#mel-publish-service").val());
                    });
                }
            });

            if (!isFlux)//Si publication
            {
                //Bouton de sauvegarde
                $(`<button class="mel-button" style="margin-right:15px">${rcmail.gettext('visualize', plugin_text)} <span class="plus icon-mel-${(news.id === "" ? "plus" : "pencil")}"></span></button>`).click(() => {
                    if (this.check([$("#mel-publish-service"), $("#mel-publish-title"), $("#mel-publish-body")], {2:() => tinyMCE.activeEditor.getContent() === ""})) 
                        this.confirm("createOrEditPublish", {id:"news-generated-tmp-id", trueId:news.id});
                }).appendTo(this.modal.footer.querry);

                $('label[for="mel-publish-body"]').css("display", "inline-block").css("width", 'auto')
                .parent().append(`<div id=div-publish-notify style="display:none;/*inline-block*/;float:right;margin-top:15px;"><input id=publish-notify type=checkbox /> <label for="publish-notify">${rcmail.gettext('ask_notify', plugin_text)}</label></div>`);

                $('label[for="mel-publish-body"]').after($('#div-publish-notify'));

                //Gestion de l'editeur html
                setTimeout(async  () => {

                    if (rcmail.editor !== undefined && rcmail.editor.editor !== null)
                    {
                        rcmail.editor.editor.remove();
                        rcmail.editor.editor = null;
                        delete rcmail.editor;
                    }

                    let config = rcmail.env.editor_config;
                    config.disabled_buttons = ["image", "media"];

                    rcmail.editor_init(config, "mel-publish-body");
                    this.modal.show();

                    if (NewsPopup.corrected !== true)
                    {
                        $(document).on('focusin', function(e) {
                            if ($(e.target).closest(".tox-dialog").length) {
                                e.stopImmediatePropagation();
                            }
                        });

                        NewsPopup.corrected = true;
                    }

                    let it = 0;
                    await wait(() => {
                        if (it++ > 5)
                            return false;
                
                        return rcmail.editor === undefined || rcmail.editor === null || rcmail.editor.editor === null;
                    });

                    rcmail.command("updateEditor");

                }, 10);
            }
            else{//Si on publie un flux

                if (this.modal.modal.find("#mel-publish-service").val() !== "none")
                {
                    this.modal.modal.find("#mel-publish-service").change();
                }

                //Gestion de la sauvegarde
                $(`<button class="mel-button" style="margin-right:15px">${(news.id === "" ? rcmail.gettext('publish', plugin_text) : rcmail.gettext('edit', plugin_text))} <span class="plus icon-mel-${(news.id === "" ? "plus" : "pencil")}"></span></button>`).click(() => {
                    if (this.check([this.modal.modal.find("#mel-publish-service")])) 
                    {
                        this.modal.close();
                        rcmail.set_busy(true);
                        rcmail.display_message(rcmail.gettext('adding', plugin_text), "loading");
                        mel_metapage.Functions.post(
                            mel_metapage.Functions.url("news", 'publish_rss'),
                            {
                                _uid:(news.server_uid === undefined ? id : news.server_uid),
                                _service:this.modal.modal.find("#mel-publish-service").val(),
                                _source:this.modal.modal.find('#news-intranet-select').val()
                            },
                            (datas) => {
                                rcmail.clear_messages();
                                rcmail.set_busy(false);
                                if (datas === "denied")
                                {
                                    rcmail.display_message(rcmail.gettext('action_denied', plugin_text), "error");
                                }
                                else {
                                    rcmail.display_message(rcmail.gettext('succefuly_published', plugin_text), "confirmation");
                                    rcmail.set_busy(true, "loading");
                                    window.location.reload();
                                }
                            }
                        );
                    }
                }).appendTo(this.modal.footer.querry);

                //Affichage de la modale
                this.modal.show();
            }

            return this;
        }

        /**
         * Vérifie si plusieurs champs sont valides
         * @param {array<JqueryElement>} itemToTest Champs à tester
         * @param {JSON} specCond - Fonctions pour valider un champs spécifique
         * @returns 
         */
        check(itemToTest = [], specCond = {})
        {
            $(".fieldNotOkay").remove();

            for (let index = 0; index < itemToTest.length; index++) {
                const element = itemToTest[index];
                const val = element.val();

                const valid = specCond[index] === undefined ? (val === "none" || val === "") : specCond[index]();

                if (valid)
                {
                    element.parent().append(`<span class="fieldNotOkay" style="color:red;">*${rcmail.gettext('error_field_required', plugin_text)}</span>`);
                    return false;
                }
            }

            return true;
        }

        /**
         * Page de confirmation d'une autre page. 
         * @param {string} caller Page qui a appelé cette fonciton
         * @param {*} args Divers arguments
         * @returns Chaînage
         */
        confirm(caller, args)
        {
            switch (caller) {
                case "createOrEditPublish":
                    const service_datas = {
                        name:$("#mel-publish-service").find(`option[value="${$("#mel-publish-service").val()}"]`).html(),
                        value:$("#mel-publish-service").val()
                    };

                    let news = new MelPublishNew(null)
                    .create($("#mel-publish-title").val(), tinyMCE.activeEditor.getContent())
                    .setService($("#mel-publish-service").val())
                    .setId(args.id);

                    //Modification du titre de la modale
                    this.modal.editTitle(rcmail.gettext('visualize_admin_news', plugin_text));

                    const today = moment();
                    const today_formated = `${rcmail.gettext(today.format('dddd'), plugin_text)} ${today.format('DD')} ${rcmail.gettext(today.format('MMMM'), plugin_text)}, ${today.format('YYYY')}`;

                    //Modification du corps de la modale
                    this.modal.editBody(`
                    <div class="square_div">
                        <div class="contents " id="${args.id}" data-service="${$("#mel-publish-service").val()}" style=overflow:auto>
                            <div class="square-contents">
                                <p class="headlines-by">${rcmail.gettext('information', plugin_text)} ${news.getService().split(",")[0].split("=")[1]}</p>
                                <h3 class="headlines-title bold title">${news.title}</h3>
                                <p class="headlines-publish">${rcmail.gettext('published_at', plugin_text)} ${today_formated}</p>
                                <div class="headlines-contents body">${tinyMCE.activeEditor.getContent()}</div>
                            </div>
                        </div>
                    </div>`)

                    //Modification du pied de la modale
                    this.modal.footer.querry.html("");
                    $(`<button class="mel-button white news-bottom-button-modal-l">${rcmail.gettext('back')} <span class="plus icon-mel-undo"></span></button>`).click(() => {
                        this.createOrEditPublish(args.id.replace("news-", ''));
                        let select = this.modal.modal.find("#mel-publish-service");
                        if (select.find(`option[value="${service_datas.value}"]`).length === 0)
                        {
                            select.append(`<option value="${service_datas.value}">${service_datas.name}</option>`).val(service_datas.value);
                        }
                    }).appendTo(this.modal.footer.querry);
                    $(`<button class="mel-button news-bottom-button-modal-r">${rcmail.gettext('confirmation', plugin_text)} <span class="plus icon-mel-plus"></span></button>`).click(() => {
                    
                        if (args.trueId !== "" && args.trueId !== null && args.trueId !== undefined)
                            news.id = args.trueId;

                        this.modal.close();
                        rcmail.set_busy(true);
                        rcmail.display_message(rcmail.gettext('publishing', plugin_text), "loading");

                        let _post = news.toPostDatas("news-generated-tmp-id");

                        //if ($("#publish-notify")[0].checked === true) _post["_notify"] = true;
                            
                        mel_metapage.Functions.post(
                            mel_metapage.Functions.url("news", 'publish'),
                            _post
                            ,
                            (datas) => {
                                rcmail.clear_messages();
                                rcmail.set_busy(false);
                                if (datas === "denied")
                                {
                                    rcmail.display_message(rcmail.gettext('action_denied', plugin_text), "error");
                                }
                                else {
                                    rcmail.display_message(rcmail.gettext('succefuly_published', plugin_text), "confirmation");
                                    rcmail.set_busy(true, "loading");
                                    window.location.reload();
                                }
                            }
                        );

                    }).appendTo(this.modal.footer.querry);
                    break;
            
                default:
                    console.error('###[confirm]Impossible de créer une fenêtre de confirmation pour cette action, elle n\'éxiste pas !', caller);
                    break;
            }

            return this;
        }

        /**
         * Affiche la modale pour créer ou modifier un flux custom
         * @param {string} id Id du flux 
         * @param {boolean|string} isAdmin Si on est en mode administrateur
         * @returns Chaînage
         */
        createOrEdit(id = null, isAdmin = false)
        {
            if (id === null || id === "")
            {
              //Api de twitter ne marche plus
              this.showStep2(new MelNews(null).setType(MelNews.type.intranet));
              
                // this.modal.editTitle(rcmail.gettext('personal_create_title', plugin_text));

                // let $flex = $('<div style="display:flex"></div>')
                // // Intranet
                // .append($(`<button style="margin-top:0px;margin-right:15px" class="btn btn-block btn-secondary btn-mel"><span class="block icon-mel-intranet"></span>${rcmail.gettext('intranet_website', plugin_text)}</button>`).click(() => {
                //         this.showStep2(new MelNews(null).setType(MelNews.type.intranet));
                //     })
                // )               
                // // Twitter
                // .append($(`<button style="margin-top:0px;margin-right:15px" class="btn btn-block btn-secondary btn-mel"><span class="block icon-mel-twitter"></span>${rcmail.gettext('twitter_account', plugin_text)}</button>`).click(() => {
                //         this.showStep2(new MelNews(null).setType(MelNews.type.twitter));
                //     })
                // )
                // // Internet
                // // .append($(`<button style="margin-top:0px;margin-right:15px" class="btn btn-block btn-secondary btn-mel"><span class="block icon-mel-rss"></span>Flux RSS externe</button>`).click(() => {
                // //         this.showStep2(new MelNews(null).setType(MelNews.type.internet));
                // //     })
                // // );

                // this.modal.editBody($flex);
                // this.modal.footer.querry.html("");
                this.modal.show();
            }
            else{
                const news = id.$news !== undefined ? id : new MelCustomNews(id);
                this.showStep2(news, true, isAdmin);
                this.modal.show();
            }

            return this;
        }

        /**
         * Si on est appelé dans la modale des paramètres de rc.
         * @returns 
         */
        isSettings()
        {
            return window !== parent && parent.rcmail.env.task === "settings";
        }

        /**
         * Affiche la suite de @see createOrEdit.
         * @param {MelNews} datas Données de la news
         * @param {Boolean} isEdit Si on modifie une news existante
         * @param {boolean} isAdmin Si on est en mode administrateur
         * @returns Chaînage
         */
        showStep2(datas, isEdit = false, isAdmin = false)
        {

            const obFields = `<p class="red-star-removed"><star class="red-star mel-before-remover">*</star>${rcmail.gettext('required_fields', plugin_text)}</p>`;
            const formats = [
                {
                    id:"mel-news-format-check-1",
                    value:"small",
                    text:rcmail.gettext('small_format', plugin_text)
                },
                {
                    id:"mel-news-format-check-2",
                    value:"large",
                    text:rcmail.gettext('large_format', plugin_text)
                }
            ];
            let html = obFields;

            if (mode === modes.all && (isEdit && datas.type !== MelNews.type.twitter))
            {
                html = `
                <div class="alert alert-warning" role="alert">
                    <span class="icon-mel-warning"></span> ${rcmail.gettext('intra_edit_alert', plugin_text)}
                </div>` + html;
            }

            this.modal.editBody("");

            switch (datas.type) {
                case MelNews.type.intranet:

                    if (!isEdit)
                        this.modal.editTitle(rcmail.gettext('personal_add_intranet_title', plugin_text));
                    else
                        this.modal.editTitle(rcmail.gettext('personal_edit_intranet_title', plugin_text));

                    html += this.createSelect(rcmail.gettext('choose_intranet', plugin_text), "news-intranet-select", rcmail.gettext('select_website', plugin_text), Enumerable.from(rcmail.env.news_intranet_list).select(x => {return {value:x.key, text:x.value.name}}).toArray(), datas.id);
                    
                    break;

                case MelNews.type.twitter:
                    if (!isEdit)
                        this.modal.editTitle(rcmail.gettext('personal_add_twitter_title', plugin_text));
                    else
                        this.modal.editTitle(rcmail.gettext('personal_edit_twitter_title', plugin_text));

                    html += this.createInput(rcmail.gettext('enter_twitter_account', plugin_text), "news-twitter-input", "text", `@${rcmail.gettext('enter_twitter_account_placeholder', plugin_text)}`, datas.id, "mel-twitter", "form-control input-mel required");
                    break;

                case MelNews.type.internet:
                    if (!isEdit)
                        this.modal.editTitle("Ajouter un flux RSS externe (étape 2/2)");
                    else
                        this.modal.editTitle("Modifier un flux RSS externe");

                    html += this.createSelect("Choisir le flux RSS à afficher", "news-internet-select", "Sélectionner un site", [], "none");
                
                    break;
            
                default:
                    break;
            }

            html += this.createCheckBoxChoices(rcmail.gettext('choose_block_format', plugin_text), "newsMelFormat", formats, datas.format, true);

            this.modal.editBody(html);

            //Actions faites après la mise en place du html

            if (datas.type === MelNews.type.intranet && isAdmin !== false && atob(isAdmin) == "true")
            {
                html = $(`<div style="text-align:right;"><button id="publishmode" class="mel-button" style="margin-top:0;margin-bottom:15px;float:">${rcmail.gettext('go_to_publisher_mode', plugin_text)}</button></div>`);
                html.find("button").click(() => {
                    this.createOrEditPublish(datas.$news.data('uid'), true);
                });

                this.modal.contents.prepend(html);
            }

            this.modal.footer.querry.html("");

            $(`<button class="mel-button white .news-bottom-button-modal-l">${(isEdit ? rcmail.gettext('cancel') : rcmail.gettext('back') )} <span class="plus icon-mel-undo"></span></button>`).click(() => {
                if (!isEdit)
                    this.createOrEdit(datas.id);
                else
                    this.modal.close();
            }).appendTo(this.modal.footer.querry);

            $(`<button class="mel-button news-bottom-button-modal-r">${(!isEdit ? rcmail.gettext('add', plugin_text) : rcmail.gettext('edit', plugin_text))} <span class="plus icon-mel-${(datas.id === "" ? "plus" : "pencil")}"></span></button>`).click(() => {

                let url;//= (datas.type === intranet ? $("#news-intranet-select") : $("#news-twitter-input")).val();
                
                if (datas.type === "intranet") url = this.modal.modal.find("#news-intranet-select").val();
                else if (datas.type === "twitter")
                {
                    url = this.modal.modal.find("#news-twitter-input").val();

                    if (url[0] === "@")
                        url = url.replace("@", "");
                }

                if (url === "" || url === "none")
                {
                    rcmail.display_message(rcmail.gettext('error_invalid_value', plugin_text), "error");
                    return;
                }

                this.modal.close();

                (this.isSettings() ? parent.rcmail : rcmail).set_busy(true, "loading");

                if (isEdit)
                {
                    this.post("update_custom", 
                    {
                        _url:url,
                        _format:(this.modal.modal.find("#mel-news-format-check-1")[0].checked ? "small" : "large"),
                        _last_url:datas.id
                    }, 
                    (response) => {
                        const isSettings = this.isSettings();
                        (isSettings ? parent.rcmail : rcmail).set_busy(false);
                        (isSettings ? parent.rcmail : rcmail).clear_messages();
                        if (response === "denied")
                        {
                            if (datas.type === "twitter")
                            {
                                this.modal.show();
                                (isSettings ? parent.rcmail : rcmail).display_message(rcmail.gettext('error_invalid_account', plugin_text), "error");
                            }
                        }
                        else if (response === "nok")
                        {
                            this.modal.show();
                            (isSettings ? parent.rcmail : rcmail).display_message(rcmail.gettext('error_maj', plugin_text), "error");  
                        }
                        else {
                            if (mode === modes.all)
                            {
                                (isSettings ? parent.rcmail : rcmail).set_busy(true, "loading");

                                if (isSettings)
                                {
                                    const navigator = parent != parent.parent ? parent.parent : parent;
                                    let $frame = navigator.$("iframe.news-frame");//[0].contentWindow.location.reload();
                                    
                                    if ($frame.length > 0)
                                        $frame[0].contentWindow.location.reload();
                                    else if (navigator.$(".news-frame").length > 0)
                                        navigator.rcmail.refresh();                       
                                }

                            }

                            window.location.reload();
                        }
                    },
                    (a,b,c) => {
                        console.error("###[showStep2]",a,b,c);
                        (isSettings ? parent.rcmail : rcmail).set_busy(false);
                        (isSettings ? parent.rcmail : rcmail).clear_messages();
                    });
                }
                else {
                    this.post("add_custom", 
                    {
                        _url:url,
                        _format:(this.modal.modal.find("#mel-news-format-check-1")[0].checked ? "small" : "large"),
                        _source:datas.type
                    }, 
                    (response) => {
                        rcmail.set_busy(false);
                        rcmail.clear_messages();
                        if (response === "denied")
                        {
                            if (datas.type === "twitter")
                            {
                                this.modal.show();
                                rcmail.display_message(rcmail.gettext('error_invalid_account', plugin_text), "error");
                            }
                        }
                        else {
                            this.modal.close();
                            rcmail.set_busy(true, "loading");

                            if (parent.$("iframe.settings-frame").length > 0)
                                parent.$("iframe.settings-frame")[0].contentWindow.location.reload();
                            else if (parent.$(".settings-frame").length > 0)
                                parent.$("#preferences-frame")[0].contentWindow.location.reload();

                            window.location.reload();
                        }
                    },
                    (a,b,c) => {
                        console.error("###[showStep2]",a,b,c);
                        rcmail.set_busy(false);
                        rcmail.clear_messages();
                    });
                }
            }).appendTo(this.modal.footer.querry);
            
            return this;
            
        }

        /**
         * Affiche la modale de filtrage
         * @returns Chaînage
         */
        filter()
        {
            this.modal.editTitle(rcmail.gettext('filter_modal_title', plugin_text));

            const filters = {
                type:{
                    name:rcmail.gettext('by_type', plugin_text),
                    array:[{value:"intranet", text:rcmail.gettext('intranet_websites', plugin_text), id:"mel-new-filter-1"}/*, {value:"rss", text:"Flux RSS", id:"mel-new-filter-3"}*/]
                },
                category:{
                    name:rcmail.gettext('by_category', plugin_text),
                    array:[{value:"news", text:rcmail.gettext('headlines', plugin_text), id:"mel-new-filter-4"}, /*{value:"defaults", text:"Sites par défauts", id:"mel-new-filter-5"},*/ {value:"custom", text:rcmail.gettext('your_personal', plugin_text), id:"mel-new-filter-6"}]
                }
            }

            let html = "";

            if (this.filters === undefined)
                this.filters = {};

            for (const key in filters) {
                if (Object.hasOwnProperty.call(filters, key)) {
                    const element = filters[key];
                    html += `<h4>${element.name}</h4>`;
                    html += this.createCheckBoxChoices(null, "mel-news-filters", element.array, this.filters, false, false);

                    if (this.filters[element.id] === undefined)
                        this.filters[element.id] = true;
                }
            }

            this.modal.editBody(html);

            this.modal.footer.querry.html("");
            $(`<button class="mel-button news-bottom-button-modal-r">${rcmail.gettext('Filtrer', plugin_text)} <span class="plus icofont-filter"></span></button>`).click(async () => {
               (await this.updateFilter()).modal.close();
            }).appendTo(this.modal.footer.querry);

            this.modal.show();

            return this;
        }

        /**
         * @async Met à jours l'affichage lié au filtre.
         * @returns Chaînage
         */
        async updateFilter()
        {
            $('input[name="mel-news-filters"]').each((i,e) => {
                this.filters[e.id] = e.checked;
                $(e).addClass("disabled").attr("disabled", "disabled");
            });

            if (this.filters[undefined] !== undefined)
                delete this.filters[undefined];

            if (this.filters["undefined"] !== undefined)
                delete this.filters["undefined"];

            // // rcmail.set_busy(true, "loading");
            // // await this.post("setFilter", {_filter:JSON.stringify(this.filters)}).always(() => {
            // //     rcmail.set_busy(false);
            // //     rcmail.clear_messages();
            // //     rcmail.display_message("Filtre sauvegarder avec succès !");
            // // });
            rcmail.command("news.filter", () => {
                this.modal.close();
            });

            return this;
        }

        sort()
        {
            return this;
        }

        /**
         * Retourne un input en html en string
         * @param {string} title Label de l'input
         * @param {string} id Id de l'input
         * @param {string} type Type de l'input
         * @param {string} placeholder Placeholder de l'input
         * @param {string | number} value Valeur de l'input
         * @param {string} name Nom de l'input
         * @param {string} classes Classes de l'input
         * @param {string} attrs Autres attributs de l'input
         * @returns Input
         */
        createInput(title, id, type, placeholder, value, name = "", classes = "",attrs="")
        {
            let html = title !== null ? `<label for="${id}" class="span-mel t1 first">${title}<span style="color:red">*</span> </label>` : "";
            html += `<input class="${classes}" id="${id}" ${attrs} ${name === null || name === undefined || name === "" ? "" : `name="${name}"`} type="${type}" placeholder="${placeholder}" value="${value}" />`;
            return html;
        }

        /**
         * Retourne un select en html en string
         * @param {string} title Label du select 
         * @param {string} id Id du select 
         * @param {string} placeholder Première valeur, non séléctionnable, du select
         * @param {array<{value:*, text:string}>} values Valeurs disponibles du select
         * @param {*} value Valeur par défaut
         * @returns Select
         */
        createSelect(title, id, placeholder, values, value)
        {
            let html = `<label for="${id}" class="span-mel t1 first">${title}<span style="color:red">*</span> </label>`;
            html += `<select class="form-control input-mel custom-select pretty-select" id="${id}">`;

            if (placeholder !== "" && placeholder !== null && placeholder !== undefined)
                html += `<option style="display:none;" value="none">${placeholder}</option>`;

            for (const key in values) {
                if (Object.hasOwnProperty.call(values, key)) {
                    const element = values[key];
                    html += `<option value="${element.value}" ${element.value === value ? "selected" : ""}>${element.text}</option>`;
                }
            }

            html += "</select>";

            return html;    
        }

        /**
         * Créer une liste de checkboxes en html en string
         * @param {string} title Légende
         * @param {string} name Nom de toutes les checkboxes
         * @param {array<{id:string, text:string, value:boolean}>} values 
         * @param {boolean} value Valeur par défaut
         * @param {boolean} format Si vrai, elles sont affichés horizontalement
         * @param {boolean} isRadio Type de la checkboxes
         * @returns Checkboxes
         */
        createCheckBoxChoices(title, name, values, value, format = false, isRadio = true)
        {
            let html = `<fieldset>
            <legend class="red-star-after span-mel t1 mel-after-remover" ${title === null ? 'style=display:none;' : ''}>${title}</legend>`;

            if (format)
                html += '<div class="row">';

            for (const key in values) {
                if (Object.hasOwnProperty.call(values, key)) {
                    const element = values[key];

                    if (format)
                        html += `<div class="col-md-${12/values.length}">`;

                    html += `<div class="custom-control custom-${isRadio ? 'radio' : 'switch'}" ${!format && !isRadio ? 'style=display:block' : ''}>`;
                    html += this.createInput(null, element.id, (isRadio ? "radio" : "checkbox"), "", element.value, name, (" custom-control-input required " + (isRadio ? "" : "form-check-input")),(  typeof value === "string" ? (value === element.value ? "checked" : "") : (value[element.id] === false ? "" : "checked")));    
                    html += `<label class="custom-control-label" for="${element.id}">${element.text}</label></div>`;               
                
                    if (format)
                        html += "</div>";
                }
            }
            if (format)
                html += "</div>";

            html += "</fieldset>";

            return html;
        }

        /**
         * Créer un textarea en html en string
         * @param {string} title Label du textarea
         * @param {string} id Id du textarea
         * @param {string} placeholder Placeholder du textarea
         * @param {string} value Valeur par défaut
         * @returns Textarea
         */
        createTextarea(title, id, placeholder, value)
        {
            let html = `<label for="${id}" class="span-mel t1 first">${title}<span style="color:red">*</span> </label>`;
            html += `<textarea class="form-control input-mel mce_editor" placeholder="${placeholder}" id="${id}">${value}</textarea>`;
            return html;
        }

        /**
         * @async Retourne une requête ajax post
         * @param {string} action Action roundcube
         * @param {JSON} datas Données de la requête à envoyer au serveur
         * @param {Function} onSuccess Fonction réalisé avec succès
         * @param {Function} onError Fonction réalisé avec echec
         * @returns {Promise<any>} Ajax
         */
        post(action, datas, onSuccess, onError = (a,b,c) => {})
        {
            return mel_metapage.Functions.post(
                mel_metapage.Functions.url("news", action),
                datas,
                onSuccess,
                onError
            );
        }

    }

    /**
     * @class MelNews
     * @classdesc Représente une information
     */
    class MelNews{
        /**
         * Construit la classe
         * @param {string} id Id de l'information
         */
        constructor(id)
        {
            this.init();

            if (id !== null)
                this.setup(id);
        }

        /**
         * Initialise les variables de la classe
         * @returns Chaînage
         */
        init()
        {
            this.$news = null;
            this.id = "";
            this.link = "";
            this.format = MelNews.format.small;
            this.type = MelNews.type.intranet;
            return this;
        }

        /**
         * Ajoutes des valeurs aux variables de la classe
         * @param {string} id Id de l'information
         * @returns Chaînage
         */
        setup(id)
        {
            if (this.$news  === undefined || this.$news === null)
            {
                try {
                    this.$news = $(`#news-${id}`);

                    if (this.$news.length === 0)
                        this.$news = $(`[data-uid="${id}"]`);

                } catch (error) {
                    try {
                        if (this.$news === null)
                            this.$news = $(`[data-uid="${id}"]`);
                    } catch (error) {
                        
                    }
                }
            }
            
            this.id = id;
            this.link = this.$news.data("link");
            this.format = this.$news.data("format");
            this.type = this.$news.data("type");
            this.date = moment(this.$news.data("date"));
            return this;
        }

        /**
         * En mode vignette, ajoute la gestion des informations au html de la vignette
         * @returns Chaînage
         */
        setup_vignette(){

            //Ne marche pas sur les flux twitter
            if (this.type === MelNews.type.twitter)
                return this;

            //Gestion de l'original
            if (this.current === undefined)
            {
                this.original = this.$news[0].outerHTML
                this.current = -1;
            }

            //Si il n'y a pas les flèches
            if (this.$news.find(".vignette-arrows").length === 0 && (rcmail.env.news_vignette_all_news_datas[this.type] !== undefined || rcmail.env.news_vignette_all_news_datas[this.id] !== undefined))
            {
                //Div qui contient les flèches
                let $html = $(`<div class="vignette-arrows" style="text-align:right;">
                <button style="margin-top:0;margin-bottom:15px" class="btn-mel-invisible btn-arrow btn btn-secondary"><span class="icon-mel-arrow-left"></span></button>
                <button style="margin-top:0;margin-bottom:15px" class="btn-mel-invisible btn-arrow btn btn-secondary"><span class="icon-mel-arrow-right"></span></button>
                </div>
                `);

                //Action de la flèche gauche
                let $left = $html.find(".icon-mel-arrow-left").parent().addClass("disabled").attr("disabled", "disabled");
                $left.click((e) => {

                    let reclick = false;
                    let news_datas;

                    if (rcmail.env.news_vignette_all_news_datas[this.id] === undefined)
                        news_datas = rcmail.env.news_vignette_all_news_datas[this.type];
                    else
                        news_datas = rcmail.env.news_vignette_all_news_datas[this.id];

                    let tmp;

                    try {
                        if (this.current - 1 === -1)
                        {
                            tmp = this.original;
                            this.current = -1;
                        }
                        else
                            tmp = news_datas[--this.current];
                    } catch (error) {
                        tmp = undefined;
                    }

                    if (tmp === undefined)
                    {
                        return;
                    
                    }

                    if (this.type === MelNews.type.intranet && this.$news.data("copy") === ($(tmp).children().data("copy") === undefined ? $(tmp).data("copy") : $(tmp).children().data("copy")))
                    {
                        reclick = true;
                    }

                    this.$right.removeClass("disabled").removeAttr("disabled");


                    this.$news.find(".square-contents").children().each((i,e) => {
                        e = $(e);

                        if(!e.hasClass("vignette-arrows"))
                        {
                            e.remove();
                        }
                    });

                    this.$news.data("copy", $(tmp).children().data("copy")).find(".square-contents").append($(tmp).find(".square-contents").html());

                    if (this.current === -1)
                        $(e.currentTarget).addClass("disabled").attr("disabled", "disabled");
                    else if (reclick)
                        this.$left.click();
                });

                //Action de la flèche droite
                let $right = $html.find(".icon-mel-arrow-right").parent();
                $right.click((e) => {

                    let reclick = false;
                    let news_datas;

                    if (rcmail.env.news_vignette_all_news_datas[this.id] === undefined)
                        news_datas = rcmail.env.news_vignette_all_news_datas[this.type];
                    else
                        news_datas = rcmail.env.news_vignette_all_news_datas[this.id];

                    let tmp;

                    try {
                        tmp = news_datas[++this.current];
                    } catch (error) {
                        tmp = undefined;
                    }

                    if (tmp === undefined)
                    {
                        return;
                    }

                    if (this.type === MelNews.type.intranet && this.$news.data("copy") === ($(tmp).children().data("copy") === undefined ? $(tmp).data("copy") : $(tmp).children().data("copy")))
                    {
                        reclick = true;
                    }

                    this.$left.removeClass("disabled").removeAttr("disabled");

                    this.$news.find(".square-contents").children().each((i,e) => {
                        e = $(e);

                        if(!e.hasClass("vignette-arrows"))
                        {
                            e.remove();
                        }
                    });

                    this.$news.data("copy", $(tmp).children().data("copy")).find(".square-contents").append($(tmp).find(".square-contents").html());

                    if (news_datas[this.current + 1] === undefined)
                        $(e.currentTarget).addClass("disabled").attr("disabled", "disabled");
                    else if (reclick)
                        this.$right.click();
                });

                this.$news.find(".square-contents").prepend($html);

                this.$right = this.$news.find(".square-contents").find(".icon-mel-arrow-right").parent();
                this.$left = this.$news.find(".square-contents").find(".icon-mel-arrow-left").parent();
            }

            return this;
        }

        /**
         * Met à jour la querry html de la classe
         * @param {JqueryElement} $querry Nouvelle querry
         * @returns Chaînage
         */
        setNews($querry)
        {
            this.$news = $querry;
            return this;
        }

        /**
         * Met à jours le type de la classe.  
         * @see MelNews.type
         * @param {string} type Type de la classe
         * @returns Chaînage
         */
        setType(type)
        {
            this.type = type;
            return this;
        }
    }

    /**
     * Enumération des formats de la news
     */
    MelNews.format = {
        /**
         * Petit format (col-md-3)
         */
        small:"small",
        /**
         * Grand format (col-md-6)
         */
        large:"large"
    };

    /**
     * Enumération des types de news
     */
    MelNews.type = {
        internet:"internet",
        intranet:"intranet",
    };

    class MelCustomNews extends MelNews
    {
        constructor(id)
        {
            super(id);
        }

        static fromServer(serverDatas, original = null)
        {
            let created = new MelCustomNews(serverDatas.id);
            created.id = serverDatas.id;
            created.date = moment(serverDatas.datas.date);
            created.format = original !== null && serverDatas.size === "same" ? original.format : serverDatas.size;
            created.link = serverDatas.datas.link;
            created.site = serverDatas.service;
            created.type = original !== null && serverDatas.source === "same" ? original.type : serverDatas.source;
            created.$news = $(created.loadHtml(rcmail.env.news_skeleton, serverDatas.datas));

            return created;
        }

        init(){
            super.init();
            return this;
        }

        setup(id) {

            this.$news = $(`.rss[data-uid="${id}"]`);

            if (id.includes("@"))
                id = id.split("@")[0];

            super.setup(id);
            this.date = moment(this.$news.data("date"));

            if (!this.date.isValid())
                this.date = moment();

            this.site = this.$news.data("site");
            return this;
        };

        loadHtml(skeleton, content, optional_style = 'style="margin-bottom:15px"')
        {
            return skeleton.
            replaceAll("<type/>", "rss").
            replaceAll("<optional_style/>", optional_style).
            replaceAll("<site/>", this.site).
            replaceAll("<raw_date/>", this.date.format()).
            replaceAll("<uid/>", this.id).
            replaceAll("<datalink/>", this.link).
            replaceAll("<dataformat/>", this.format).
            replaceAll("<datatype/>", this.type).
            replaceAll("<datacopy/>", this.link).
            replaceAll("<div_title/>", "").
            replaceAll("<headlines_other_classes/>", "headlines-rss-type").
            replaceAll("<service/>", this.site).
            replaceAll("<title/>", content.title).
            replaceAll("<text/>", content.content).
            replaceAll("<additionnal_contents/>", `<div style="position: absolute;bottom: 30px;" class="headlines-source"><p>Source : ${strUcFirst(this.type)}</p><p class='p-buttons'>
            <button style="margin-top:0;margin-right:5px;" title="Copier" onclick="rcmail.command('news.copy', $(this))" class="mel-button btn btn-secondary roundbadge large r-news"><span class=" icon-mel-copy"><span class="sr-only">Copier le lien</span></span></button>
            <button style="margin:0" title="Editer" onclick="rcmail.command(\'news.edit\', this)" class="mel-button btn btn-secondary roundbadge large r-news"><span class=" icon-mel-pencil"><span class="sr-only">Modifier</span></span></button>
            </p></div>`).
            replaceAll("<date/>", `Publié le ${this.tradDate(this.date.format('dddd DD MMMM YYYY'))}`)
            ;
        }

        tradDate(date)
        {
            let array = date.split(" ");
            date = "";

            for (const key in array) {
                if (Object.hasOwnProperty.call(array, key)) {
                    const element = array[key];
                    date += rcmail.gettext(element, "mel_news") + " ";
                }
            }

            return date;
        }

        async refresh() 
        {
            let temp_url = window.location.origin + window.location.pathname;

            if (temp_url[temp_url.length - 1] === '/')
                temp_url = temp_url.slice(0, temp_url.length - 1);

            const url = temp_url + this.link;

            await mel_metapage.Functions.get(url, 
            {
                _url:this.id
            }, 
            (datas) => {//headlines-contents
                if (mode === modes.all)
                    this._refresh_mode_all(JSON.parse(datas));
                else
                {
                    datas = JSON.parse(datas);
                    const uid = $(datas[0]).data("uid");
                    this.$news.parent().html(datas[0]);
                    this.$news =  $(`[data-uid="${uid}"]`);
                    rcmail.env.news_vignette_all_news_datas[this.id] = datas;
                    delete this.original;
                    delete this.current;
                    this.setup_vignette();



                }

            });
        }

        _refresh_mode_all(datas)
        {
            let oldNews = Enumerable.from(MelCustomNews.allCustomNews).where(x => x.id !== this.id);
            let newNews = [];

            for (const key in datas) {
                if (Object.hasOwnProperty.call(datas, key)) {
                    const element = datas[key];
                    newNews.push(MelCustomNews.fromServer(element, this));
                }
            }

            oldNews.forEach((x, i) => 
                {
                    i = x.$news.clone();
                    x.$news.remove();
                    x.$news = i;

                    if (x.$news.length > 1)
                        x.$news = $(x.$news[0]);
                });
            
            oldNews = oldNews.concat(newNews);//.orderByDescending(x => x.date).toArray();

            switch (sort_mode) {
                case sort_modes.date_desc:
                    oldNews = oldNews.orderByDescending(x => x.date.unix());
                    break;

                case sort_modes.date_asc:
                    oldNews = oldNews.orderBy(x => x.date.unix());
                    break;

                case sort_modes.site:
                    oldNews = oldNews.orderBy(x => x.site);
                    break;
            
                case sort_modes.source:
                    oldNews = oldNews.orderBy(x => x.type);
                    break;
                default:
                    throw {
                        message:"Ce type de tri n'existe pas !",
                        element:this
                    };
            }

            MelCustomNews.allCustomNews = oldNews.toArray();
            let $col;
            let col = 0;
            let $parent = $("#i-custom-news");
            $parent.html("");
            $parent = $parent.append('<div class="row"></div>').find(".row");

            let started = false;
            for (const key in MelCustomNews.allCustomNews) {
                if (Object.hasOwnProperty.call(MelCustomNews.allCustomNews, key)) {
                    if (col >= 12*nbRows && rcmail.env.news_more_showed !== "loading" && rcmail.env.news_more_showed !== true)
                        break;

                    if (MelCustomNews.allCustomNews[key].format === "small")
                    {
                        $col = $('<div class="col-3"></div>');
                        col += 3;
                    }
                    else
                    {
                        $col = $('<div class="col-6"></div>');
                        col += 6;
                    }

                    MelCustomNews.allCustomNews[key].$news = MelCustomNews.allCustomNews[key].$news.appendTo($col);

                    if (MelCustomNews.allCustomNews[key].type === MelNews.type.twitter)
                    {
                        MelCustomNews.allCustomNews[key].$news.find(".headlines-contents").html(`<a class="twitter-timeline" href="https://twitter.com/${MelCustomNews.allCustomNews[key].id}?ref_src=twsrc%5Etfw"></a>`);
                        
                        if (!started)
                            started = true;
                    }
                    else if (MelCustomNews.allCustomNews[key].type !== MelNews.type.twitter && MelCustomNews.allCustomNews[key].$news.data("copy") !== "") {
                        MelCustomNews.allCustomNews[key].$news.find(".square-contents").children().each((i, e) => {
                            if ($(e).hasClass("vignette-arrows"))
                                return;
    
                            $(e).css("cursor", "pointer").attr("title", "Ouvrir dans un nouvel onglet");
                        });
                    }

                    $col.appendTo($parent);
                }
            }

            if (started)
            {
                $('script[src="https://platform.twitter.com/widgets.js"]').remove();
                setTwitterSrc();//$("body").append('<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> ');
            }

        }

        static CreateAndSetup(initialRefresh = false){
            let array = [];
            $("#i-custom-news .mel-news").each((i,e) => {
                const uid = $(e).data("uid");

                if ($(e).hasClass("rss"))
                    array.push(new MelCustomNews(uid));
                else
                {
                    array.push(new MelNews(uid).setNews($(e)).setup(uid));
                }
                
                if (array[array.length-1].type !== MelNews.type.twitter && array[array.length-1].$news.data("copy") !== "")
                {
                    array[array.length-1].$news.find(".square-contents").children().each((i, e) => {
                        if ($(e).hasClass("vignette-arrows"))
                            return;

                        $(e).css("cursor", "pointer").attr("title", rcmail.gettext('open_in_new_tab', plugin_text));
                    });
                }
            });
            MelCustomNews.allCustomNews = array;
            return MelCustomNews.Refresh(initialRefresh);
        }

        static async Refresh(initialRefresh = false)
        {
            if (MelCustomNews.Refresh.started !== true)
                MelCustomNews.Refresh.started = true;
            else
                return;

            let $button = $("#seemoreorless .plus");
            const button_initial_class = $button.hasClass("icon-mel-chevron-down") ? "icon-mel-chevron-down" : "icon-mel-chevron-up";
            $button.removeClass("icon-mel-chevron-down").addClass("spinner-grow spinner-grow-sm").addClass("disabled").attr("disabled", "disabled");

            let arrayOfRefresh = [];

            if (mode === modes.all)
            {
                let array_id = [];
                for (const key in MelCustomNews.allCustomNews) {
                    if (Object.hasOwnProperty.call(MelCustomNews.allCustomNews, key)) {
                        const element = MelCustomNews.allCustomNews[key];
                        if (!array_id.includes(element.id))
                        {
                            if (initialRefresh === true && element.site !== "")
                                continue;

                            if (element.type === MelNews.type.twitter)
                                continue;

                            array_id.push(element.id);
                            try {
                                arrayOfRefresh.push(element.refresh());
                            } catch (error) {
                                
                            }

                        }
                    }
                }
            }
            else {
                for (const key in MelCustomNews.allCustomNews) {
                    if (Object.hasOwnProperty.call(MelCustomNews.allCustomNews, key)) {
                        const element = MelCustomNews.allCustomNews[key];

                        if (initialRefresh === true && element.site !== "")
                        {
                            try {
                                MelCustomNews.allCustomNews[key].setup_vignette();
                            } catch (error) {
                                console.error("Rv", error);
                            }
                            continue;
                        }

                        if (element.type === MelNews.type.twitter)
                            continue;

                        try {
                            arrayOfRefresh.push(element.refresh());
                        } catch (error) {
                            
                        }
                    }
                }
            }


            await Promise.all(arrayOfRefresh);

            $("#seemoreorless .plus").addClass(button_initial_class).removeClass("spinner-grow").removeClass("spinner-grow-sm").removeClass("disabled").removeAttr("disabled");
            
            MelCustomNews.Refresh.started = false;
        }

        static async Reorder()
        {
            rcmail.set_busy(true, "loading");
            let $parent = $("#i-custom-news .row").css("display", "none");
            $("#i-custom-news-temp").html('<center><div class="spinner-grow"><span class="sr-only">Loading....</span></div></center>');

            let initialclass = $("#seemoreorless .plus").hasClass("icon-mel-chevron-down") ? "icon-mel-chevron-down" : "icon-mel-chevron-up";
            $("#seemoreorless .plus").removeClass("icon-mel-chevron-down").addClass("spinner-grow spinner-grow-sm").addClass("disabled").attr("disabled", "disabled");
            let news = Enumerable.from(MelCustomNews.allCustomNews);

            const sorting = rcmail.env.news_sort_mode

            switch (sorting) {
                case sort_modes.date_desc:
                    news = news.orderByDescending(x => x.date);
                    break;

                case sort_modes.date_asc:
                    news = news.orderBy(x => x.date);
                    break;

                case sort_modes.site:
                    news = news.orderBy(x => x.site === undefined ? x.$news.find(".headlines-by").html() : x.site);
                    break;
            
                case sort_modes.source:
                    news = news.orderBy(x => x.type);
                    break;
                default:
                    throw {
                        message:"Ce type de tri n'existe pas !",
                        element:this
                    };
            }

            news = news.toArray();
            let $col;

            let started = false;
            for (const key in news) {
                if (Object.hasOwnProperty.call(news, key)) {
                    $col = null;
                    const element = news[key];

                    if (element.format === "small")
                    {
                        $col = $(`<div class="col-3" style="display:${element.$news.parent().css("display")}"></div>`);
                    }
                    else
                    {
                        $col = $(`<div class="col-6" style="display:${element.$news.parent().css("display")}"></div>`);
                    }

                    element.$news.clone().appendTo($col);
                    element.$news.parent().remove();
                    $col.appendTo($parent);
                    element.$news = $col.find(".mel-news");

                    if (element.type === MelNews.type.twitter)
                    {
                        element.$news.find(".headlines-contents").html(`<a class="twitter-timeline" href="https://twitter.com/${element.id}?ref_src=twsrc%5Etfw"></a>`);
                        
                        if (!started)
                            started = true;
                    }
                }
            }

             if (started)
             {
                 $('script[src="https://platform.twitter.com/widgets.js"]').remove();
                 setTwitterSrc();//$("body").append('<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> ');
             }

            $("#seemoreorless .plus").addClass(initialclass).removeClass("spinner-grow").removeClass("spinner-grow-sm").removeClass("disabled").removeAttr("disabled");
            $("#i-custom-news-temp").html("");
            $parent.css("display", "");
            rcmail.set_busy(false);
            rcmail.clear_messages();
        }

        static async Filter(doAfter = null)
        {
            let enum_news = Enumerable.from(MelCustomNews.allCustomNews);
            enum_news.forEach((x, i) => {
                x.$news.parent().css("display", "");
            });

            if (NewsPopup.fabric().filters === undefined)
                return

            let promises = [];
            for (const key in filters) {
                if (Object.hasOwnProperty.call(filters, key)) {
                    const filter = filters[key];
                    
                    for (const name in filter) {
                        if (Object.hasOwnProperty.call(filter, name)) {
                            const _element = $(filter[name]);
                            const $element = _element.length === 0 ? [{checked:NewsPopup.fabric().filters[filter[name]]}] : _element;

                            if ($element[0].checked === false)
                            {
                                if (key === "types")
                                {
                                    promises.push(new Promise((a, b) => {
                                        enum_news.where(x => x.type === name).forEach(x => {
                                            x.$news.parent().css("display", "none")
                                        });
                                        a();
                                    }));
                                    enum_news = enum_news.where(x => x.type !== name);
                                }
                                else {
                                    switch (name) {
                                        case "headlines": //defaults/customs
                                            promises.push(new Promise((a, b) => {
                                                enum_news.where(x => x.type.includes('ou=')).forEach(x => {
                                                    x.$news.parent().css("display", "none")
                                                });
                                                a();
                                            }));
                                            enum_news = enum_news.where(x => !x.type.includes('ou='));
                                            break;

                                        case "customs": 
                                            promises.push(new Promise((a, b) => {
                                                enum_news.where(x => x.type === "twitter" || x.type === 'intranet').forEach(x => {
                                                    x.$news.parent().css("display", "none")
                                                });
                                                a();
                                            }));
                                            enum_news = enum_news.where(x => x.type !== "twitter" && x.type !== 'intranet');
                                            break;
                                    
                                        default:
                                            break;
                                    }
                                }
                            }

                        }
                    }

                }
            }

            await Promise.all(promises);

            if (doAfter !== null)
                doAfter();
        }

        
    }

    class MelPublishNew extends MelNews
    {
        constructor(id)
        {
            super(id);
            this.ini().startup(id);
        }

        ini()
        {
            this.body = "";
            this.title = "";
            return this;
        }

        startup(id)
        {
            if (id !== null)
            {
                this.body = this.$news.find(".body").html();

                if (this.body === undefined)
                    this.body = this.$news.find(".headlines-contents").html();

                this.title = this.$news.find(".title").html();

                if (this.title === undefined)
                    this.title = this.$news.find(".headlines-title").html();

                if (this.$news.data("service") !== undefined)
                    this.setService(this.$news.data("service"));

                if (this.$news.data("type") !== undefined)
                    this.setService(this.$news.data("type"));

                if (id.includes("@"))
                    this.id = id.split("@")[0];
            }

            return this;
        }

        create(title, body)
        {
            this.title = title;
            this.body = body;
            return this;
        }

        setId(id)
        {
            this.id = id;
            return this;
        }

        setService(service)
        {
            return this.setType(service);
        }

        getService()
        {
            return this.type;
        }

        toPostDatas(ignoreId = null)
        {
            let item = {
                _title:this.title,
                _description:this.body,
                _service:this.getService()
            };

            if (ignoreId !== this.id)
                item._uid = this.id;

            return item;
        }
    }

if (rcmail.env.news_dont_load === undefined)
{
    init_news();
}
else {
    rcmail.register_command("news.settings.edit", (args) => {
        const id = args[0];
        const format = args[1];
        const source = args[2];
        let news = new MelCustomNews("");
        news.id = id;
        news.format = format;
        news.type = source;
        NewsPopup.fabric().createOrEdit(news);

    }, true);

    rcmail.register_command("news.settings.delete", (id) => {
        if (confirm(rcmail.gettext('delete_confirmation', plugin_text)))
        {
            parent.rcmail.set_busy(true, "loading");
            mel_metapage.Functions.post(
                mel_metapage.Functions.url("news", "delete_custom"),
                {
                    _url:id
                },
                (datas) => {
                    
                    const navigator = parent !== parent.parent ? parent.parent : parent;

                    let $frame = navigator.$("iframe.news-frame");//[0].contentWindow.location.reload();

                    if ($frame.length > 0)
                        $frame[0].contentWindow.location.reload();
                    else if (navigator.$(".news-frame").length > 0)
                        navigator.rcmail.refresh();   

                    window.location.reload();
                }
            )
        }

    }, true);

    $(document).ready(() => {
        (window !== parent ? parent.rcmail : rcmail).set_busy(false);
        (window !== parent ? parent.rcmail : rcmail).clear_messages();
    });
}

    function init_news()
    {

        rcmail.register_command("news.filter", (x = null) => {
            MelCustomNews.Filter(x);
        }, true);

        rcmail.register_command('news.copy', (x) => {
            if (typeof x === "string") mel_metapage.Functions.copy(x);
            else mel_metapage.Functions.copy(x.parent().parent().parent().data("copy"));
        }, true);

        rcmail.register_command('news.edit.action', (x) => {
            let $data = $(x).parent().parent().parent();

            try {
                let news_datas = JSON.parse(atob($(x).data("news")));
                rcmail.env.news_current_news_datas = news_datas;
                NewsPopup.fabric().createOrEdit($data.data("uid"), btoa(news_datas.isPublisher));
            } catch (error) {
                NewsPopup.fabric().createOrEdit($data.data("uid"));
            }

        }, true);

        rcmail.register_command('news.edit', (x) => {
            if ($(x).data("news") !== undefined && $(x).data("news") !== null && $(x).data("news") !== "")
            {
                rcmail.command('news.edit.action', x);
                return;
            }

            NewsPopup.fabric().drawChoice(rcmail.gettext('draw_choice_title', plugin_text), 
            {
                icon:"icon-mel-pencil",
                title:rcmail.gettext('edit_flux', plugin_text),
                action:() => {
                    rcmail.command('news.edit.action', x)
                }
            },
            {
                icon:"icon-mel-trash",
                title:rcmail.gettext('delete_flux', plugin_text),
                action:() => {
                    let text;

                    if (mode === modes.all && $(x).parent().parent().parent().data("type") === MelNews.type.intranet)
                    {
                        text = rcmail.gettext('delete_flux_warning_all_intra', plugin_text);
                    }
                    else text = rcmail.gettext('delete_flux_warning', plugin_text);

                    if (confirm(text))
                    {
                        parent.rcmail.set_busy(true, "loading");
                        NewsPopup.fabric().modal.close();
                        mel_metapage.Functions.post(
                            mel_metapage.Functions.url("news", "delete_custom"),
                            {
                                _url:(new MelCustomNews($(x).parent().parent().parent().data("uid"))).id
                            },
                            (datas) => {          
                                window.location.reload();
                            }
                        );
                    }
                }
            }
            ).modal.show();

        }, true);

        rcmail.register_command('news.published.edit', (x) => {
            let $data = $(x).parent().parent().parent();
            NewsPopup.fabric().createOrEditPublish($data.data('uid'));
        }, true);

        rcmail.register_command('news.click', (x) => {
            if (x._event !== undefined)
            {
                let $parent = $(x._event.originalTarget === undefined ? x._event.target : x._event.originalTarget);
                let it = 0;
                while (it < 3) {
                    if ($parent.hasClass("vignette-arrows"))
                        return;
                    else {
                        $parent = $parent.parent();
                        ++it;
                    }
                }
            }

            element = x.element.parent();

            if (element.data("site") !== MelNews.type.twitter && element.data("copy") !== "")
            {
                window.open(element.data("copy"), '_blank').focus();
            }
        }, true);

        rcmail.register_command('news.keydown', (x) => {
            if (x._event.keyCode === 13) rcmail.command("news.click", {_event:undefined, element:x.element});
        }, true);

        let initial = true;
        let storage = mel_metapage.Storage.get("news_last_day_refresh");

        if (storage === null || moment(storage).startOf("day").format("DD/MM/YYYY") !== moment().startOf("day").format("DD/MM/YYYY"))
        {
            initial = false;
            mel_metapage.Storage.set("news_last_day_refresh", moment());
            rcmail.set_busy(true);
            rcmail.display_message(rcmail.gettext('update_news', plugin_text), "loading");
        }

        MelCustomNews.CreateAndSetup(initial).then(() => {
            if (initial === false)
            {
                rcmail.set_busy(false);
                rcmail.clear_messages();
                rcmail.display_message(rcmail.gettext('new_successfuly_updated', plugin_text), "confirmation");
            }

            if (Enumerable.from(MelCustomNews.allCustomNews).any(x => x.type === MelNews.type.twitter))
            {
                $('script[src="https://platform.twitter.com/widgets.js"]').remove();
                setTwitterSrc();
            }

            if (Enumerable.from(MelCustomNews.allCustomNews).select(x => x.format === 'small' ? 3 : 6).sum() < 12 * nbRows)
                $("#seemoreorless").remove();
        });

        if (Enumerable.from(rcmail.env.news_service_for_publish).any())
        {

            $("#news-button-publish").removeClass("disabled").removeAttr("disabled").click(() => {
                NewsPopup.fabric().createOrEditPublish();
            });

            $("#news-button-publish-flux").removeClass("disabled").removeAttr("disabled").click(() => {
                NewsPopup.fabric().createOrEditPublish(null, true);
            });

        }
        else {
            $("#news-button-publish").hide();
            $("#news-button-publish-flux").hide();
        }

        let it = 0;
        wait(() => {
            if (++it >= 5)
                return false;
            
            return window.news_ui === undefined;
        }).then(() => {
            if (window.news_ui !== undefined)
            {
                try {
                    news_ui.buttons.$filter.click(() => {
                        NewsPopup.fabric().filter();
                    });
    
                    news_ui.buttons.$sort.click(() => {
                        NewsPopup.fabric().sort();
                    });
    
                    news_ui.buttons.$add.click(() => {
                        NewsPopup.fabric().createOrEdit();
                    });
                } catch (error) {
                    console.error('###[init_news]', error);
                }
            }
        });

        $("#seemoreorless").click(() => {
            if (rcmail.env.news_more_showed === "loading")
                return;

            if (rcmail.env.news_more_showed !== true)
            {
                let $querry = $("#seemoreorless .plus").removeClass("icon-mel-chevron-down").addClass("spinner-grow spinner-grow-sm");
                
                rcmail.set_busy(true, "loading");
                rcmail.env.news_more_showed = "loading";
                mel_metapage.Functions.get(mel_metapage.Functions.url("news", "show_all_custom_news"), {},
                (datas) => {
                    let $parent = $("#i-custom-news");
                    let $temp = $("#i-custom-news-temp");
                    $temp.css("display", "none").html($parent.html());
                    $parent.css("display", "none").html(datas);
                    $temp.css("display", "");
                    MelCustomNews.CreateAndSetup().then(() => {
                        MelCustomNews.Filter().then(() => {
                            rcmail.set_busy(false);
                            rcmail.clear_messages();
                            $querry.removeClass("spinner-grow").removeClass("spinner-grow-sm").addClass("icon-mel-chevron-up").parent().find("rotomeca").html("Voir moins");
                            $parent.css("display", "");
                            $temp.html("");
                            rcmail.env.news_more_showed = true;

                            if (mode === modes.vignette)
                            {
                                let started = false;
                                for (const key in MelCustomNews.allCustomNews) {
                                    if (Object.hasOwnProperty.call(MelCustomNews.allCustomNews, key)) {
                                        try {
                                            MelCustomNews.allCustomNews[key].setup_vignette();
                                        } catch (error) {
                                            console.error("###",error)
                                        }

                                        if (MelCustomNews.allCustomNews[key].type === "twitter" && !started)
                                            started = true;
                                        
                                    }
                                }

                                if (started)
                                {
                                    $('script[src="https://platform.twitter.com/widgets.js"]').remove();
                                    setTwitterSrc();
                                    //$("body").append('<script async onerror="rcmail.command(`news.twitter.error`)" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> ');
                                }
                            }
                        })

                    })

                });
            } 
            else {
                rcmail.env.news_more_showed = false;
                $("#seemoreorless .plus").removeClass("icon-mel-chevron-up").addClass("icon-mel-chevron-down").parent().find("rotomeca").html("Voir plus");

                let col = 0;
                let arrayOk = [];
                for (const key in MelCustomNews.allCustomNews) {
                    if (Object.hasOwnProperty.call(MelCustomNews.allCustomNews, key)) {
                        const element = MelCustomNews.allCustomNews[key];
                        if (col >= nbRows*12)
                        {
                            element.$news.remove();
                        }
                        else {
                            if (element.format === "small") col += 3;
                            else col += 6;

                            arrayOk.push(element);
                        }
                    }
                }

                MelCustomNews.allCustomNews = arrayOk;
            }
        });

        $("#news-select-order").val(sort_mode);
        $("#news-select-order").on("change", () => {
            let ok = false;
            rcmail.env.news_sort_mode = $("#news-select-order").val();
            Promise.all([
            mel_metapage.Functions.post(mel_metapage.Functions.url("news", "update_sort"), {
                _mode:rcmail.env.news_sort_mode
            },
            (datas) => {
                ok = true;
            }),
            MelCustomNews.Reorder()]).then(() => {
                if (!ok)
                    rcmail.display_message(rcmail.gettext('error_reorder', plugin_text), "error");
            })
        });

        rcmail.addEventListener("mel_metapage_refresh", async () => {
            //start
            rcmail.triggerEvent("news.refresh.before");
            mel_metapage.Functions.get(
                mel_metapage.Functions.url("news", "get_rights"), 
                {},
                (success) => {
                    rcmail.env.news_service_for_publish = JSON.parse(success);

                    if (rcmail.env.news_service_for_publish !== null && rcmail.env.news_service_for_publish !== undefined && Enumerable.from(rcmail.env.news_service_for_publish).any())
                    {
                        $("#news-button-publish").show();
                        $("#news-button-publish-flux").show();
                    }
                    else {
                        $("#news-button-publish").hide();
                        $("#news-button-publish-flux").hide();
                    }
                }
            );

            //middle
            rcmail.triggerEvent("news.refresh");
            await MelCustomNews.Refresh();

            if (mode === modes.all) await MelCustomNews.Reorder();

            await MelCustomNews.Filter();

            //end
            for (let index = 0; index < MelCustomNews.allCustomNews.length; index++) {
                if (MelCustomNews.allCustomNews[index].type !== MelNews.type.twitter && MelCustomNews.allCustomNews[index].$news.data("copy") !== "")
                {
                    MelCustomNews.allCustomNews[index].$news.find(".square-contents").children().each((i, e) => {
                        if ($(e).hasClass("vignette-arrows"))
                            return;

                        $(e).css("cursor", "pointer").attr("title", rcmail.gettext('open_in_new_tab', plugin_text));
                    });
                }
            }
            rcmail.triggerEvent("news.refresh.after");
        });

        // window.MelCustomNews = MelCustomNews;

    }

    // rcmail.env.news_actions = {
    //     reorder:MelCustomNews.Reorder
    // };

});