document.addEventListener( "DOMContentLoaded", function( event ) {

    // Замена текста на всех страницах
    const utils_sec = document.querySelector( "#pages-utils" )
    if ( utils_sec ) {
        utils_sec.querySelector( ".button.replace" ).addEventListener( "click", function( event ) {
            const data = {
                fn: "replace_in_pages",
                table: utils_sec.querySelector( `input[name="table"]` ).value,
                id_col: utils_sec.querySelector( `input[name="id_col"]` ).value,
                column: utils_sec.querySelector( `input[name="column"]` ).value,
                search_regex: utils_sec.querySelector( `input[name="search_regex"]` ).value,
                replace: utils_sec.querySelector( `input[name="replace"]` ).value,
            };
            if ( data.search_regex && confirm( __( "replace_in_pages_confirm" ) ) ) {
                api( data, function( answer ) {
                    notify_answer( answer );
                } );
            }
        } );
    }

    const pages_sec = document.querySelector( "#pages" );
    if ( ! pages_sec ) return;

    // Делает перевод на выбранный в настройках язык.
    // Сами переводы добавляются в шаблон админки во время ее формирования.
    function __( str ) {
        return _( str, "pages.mod.php" );
    }

    const tabs_el = document.body.querySelector( ":scope > header .tabs" );

    const main_el = pages_sec.querySelector( ":scope > .main" );
    const pages_el = main_el.querySelector( ":scope > .pages" );

    const add_page_btn = pages_sec.querySelector( ".header .add.button" );
    const trash_page_btn = pages_sec.querySelector( ".header .trash.button" );
    
    const search_options = {
        widget: pages_sec.querySelector( ":scope > .header .search.widget" ),
        api_fn: "get_pages_list",
        answer_fn: set_pages_list,
    }

    const search = search_widget_controls( search_options ); //: { widget, search_run_fn }

    const pager_options = {
        footer: pages_sec.querySelector( ":scope > .footer" ),
        cookie: "pages_pager",
        api_fn: "get_pages_list",
        answer_fn: set_pages_list,
        search: search,
    }

    api( { fn: "get_pages_list" }, set_pages_list, function( answer ) {
        console.log( "mod pages: get_pages_list error" );
    } );

    function set_pages_list( answer ) {
        if ( answer.error ) {
            console.error( answer.error );
        }

        if ( ! answer.result ) {
            return;
        }

        const result = answer.result;

        if ( result.overload ) {
            notify_answer( answer );
        }

        pages_el.innerHTML = "";

        // Вставка плашек страниц
        let loaded = 0;
        const start = Date.now();
        for ( let i = 0; i < result.pages.length; i++ ) {
            pages_el.insertAdjacentHTML( "beforeend", result.pages[i].html );
            loaded = loaded + 1;
            const new_page = pages_el.lastElementChild;
            
            page_controls( new_page ); // Кнопки "Свойства", "Сохранить".
            page_plashka_controls( new_page ); // Кнопки "Pin", "Publish", "Редактировать", Чекбоксы

            // Ctrl+S чтобы сохранять свойства из плашек
            new_page.addEventListener( "keydown", function( event ) {
                // ы and і - fix for librewolf
                if ( event.ctrlKey === true && ( event.code === "KeyS" || e.key == "ы" || e.key == "і" ) ) {
                    event.preventDefault();
                    const save_button = new_page.querySelector( `.buttons .save.button` );
                    save_button.click();
                }
            } );
            
            const widget = new_page.querySelector( `.select.widget` );
            select_controls( widget, { "mode": "init" } );

            if ( Date.now() - start > 1000 ) {
                let message = __( "browser_overloaded_xxx" );
                message = message.replace( "xxx", i + 1 );
                message = message.replace( "nnn", result.pages.length );
                notify_answer( { "result": { "notify_html": message } } );
                break;
            }
        }

        pager_options.loaded = loaded;
        pager_options.count = result.count;
        create_pager( pager_options );
    }

    // Только для плашек в списке страниц (pin, publish, edit, dblclick)
    function page_plashka_controls( page_el ) {
        // Pin Page
        const page_pin = page_el.querySelector( ".pin" );
        if ( page_pin ) page_pin.addEventListener( "click", function( event ) {
            const box  = page_pin.closest( "[data-id]" );
            const id   = box.getAttribute( "data-id" );
            let pin    = box.getAttribute( "data-pin" );
            if ( pin === "1" ) {
                pin = "0";
            } else {
                pin = "1";
            }
            const data = {
                fn:  "page_pin",
                id:  id,
                pin: pin
            }
            api( data, function( answer ) {
                if ( answer.result ) {
                    box.setAttribute( "data-pin", pin );
                }
            } );
        } );
        
        // Publish Page
        const page_eye = page_el.querySelector( ".eye" );
        if ( page_eye ) page_eye.addEventListener( "click", function( event ) {
            const box     = page_eye.closest( "[data-id]" );
            const id      = box.getAttribute( "data-id" );
            let published = box.getAttribute( "data-published" );
            if ( published === "1" ) {
                published = "0";
            } else {
                published = "1";
            }
            const data = {
                fn:  "page_publish",
                id:  id,
                published: published
            }
            api( data, function( answer ) {
                if ( answer.result ) {
                    box.setAttribute( "data-published", published );
                    if ( published == "1" ) {
                        page_eye.setAttribute( "title", __( "published" ) );
                    } else {
                        page_eye.setAttribute( "title", __( "unpublished" ) );
                    }
                }
            } );
        } );

        // Выбор всех страниц двойным кликом
        const page_check = page_el.querySelector( `:scope > input[type=checkbox]` );
        if ( page_check ) page_check.addEventListener( "dblclick", function( e ) {
            const stat = ! page_check.checked;
            pages_el.querySelectorAll( ":scope > div > input[type=checkbox]" ).forEach( function( chbox ) {
                chbox.checked = stat;
            } );
        } );

        // Редактировать страницу
        const page_edit = page_el.querySelector( ".edit" );
        if ( page_edit ) page_edit.addEventListener( "click", function( event ) {
            const page_id = page_edit.closest( "[data-id]" ).getAttribute( "data-id" );

            // Может быть нужный div уже создан
            const ed = pages_sec.querySelector( `.editor[data-id="${page_id}"]` );
            if ( ed ) {
                // Если он уже есть, значит просто отобразить его
                ed.classList.remove( "hidden" );
                tabs_el.querySelector( `.page[data-id="${page_id}"]` ).classList.add( "active" );
            } else {
                // Видимо еще не загрузился
                if ( typeof CodeMirror !== "function" ) {
                    return false;
                }
                // Получить страницу с сервера
                api( { fn: "get_page", id: page_id }, function ( answer ) {
                    edit_page( answer );
                } );
            }
        } );
    }

    // Свойства страниц встречаются в двух местах - в списке и в редакторе
    function update_page_properties( page_el, data, opt = {} ) {
        const pprop_el = page_el.querySelector( `.pprop` );

        page_el.setAttribute( "data-modified" , data.modified );

        const title_el = page_el.querySelector( `a.title` );
        title_el.innerHTML = data.title;
        title_el.setAttribute( "href", data.base_path + data.url );

        pprop_el.querySelector( `input[name="title"]` ).value = data.title;
        pprop_el.querySelector( `input[name="seo_title"]` ).value = data.seo_title;
        pprop_el.querySelector( `textarea[name="description"]` ).value = data.description;
        pprop_el.querySelector( `textarea[name="tags"]` ).value = data.tags;
        pprop_el.querySelector( `input[name="date"]` ).value = data.date;
        pprop_el.querySelector( `input[name="time"]` ).value = data.time;

        // Обновить в кнопке
        const btn_span = tabs_el.querySelector( `[data-id="${data.id}"] span` );
        if ( btn_span ) btn_span.innerText = short_title( data.title );

        const url_el = pprop_el.querySelector( `[name="url"]` );
        if ( opt.mode !== "init" && ! opt.second && url_el.value != data.url ) {
            notify_answer( { "warning": { "notify_html": __( "url_changed" ) + data.title } } );
        }
        url_el.value = data.url;

        const widget = pprop_el.querySelector( `.template.select` );
        const options = widget.querySelector( `.options` );
        options.innerHTML = data.options;
        select_controls( widget, {
            "mode": opt.mode,
            "value": data.t_tr,
            "option": data.t,
            "old_option": data.t,
        } );

        const textarea = page_el.querySelector( `.textarea > textarea` );
        if ( textarea && data.text !== undefined ) {
            textarea.value = data.text;
        }

        // Только для списка страниц
        const date = page_el.querySelector( `.date` );
        if ( date ) {
            date.innerHTML = data.created;
            if ( data.planned ) {
                date.classList.add( "future" );
            } else {
                date.classList.remove( "future" );
            }
        }
    }

    function get_properties( page_el ) {
        const pprop_el = page_el.querySelector( `.pprop` );
        const t_select = pprop_el.querySelector( `.template.select .selected` );
        const data = {
            id: page_el.getAttribute( "data-id" ),
            modified: page_el.getAttribute( "data-modified" ),
            title: pprop_el.querySelector( `input[name="title"]` ).value,
            url: pprop_el.querySelector( `input[name="url"]` ).value,
            seo_title: pprop_el.querySelector( `input[name="seo_title"]` ).value,
            description: pprop_el.querySelector( `textarea[name="description"]` ).value,
            tags: pprop_el.querySelector( `textarea[name="tags"]` ).value,
            date: pprop_el.querySelector( `input[name="date"]` ).value,
            time: pprop_el.querySelector( `input[name="time"]` ).value,
            template: t_select.getAttribute( "data-value" ),
            old_template: t_select.getAttribute( "data-old-value" ),
        }
        const text_el = page_el.querySelector( `.textarea > textarea` );
        if ( text_el ) {
            data.text = text_el.value;
        }
        return data;
    }

    // Создание страницы
    add_page_btn.addEventListener( "click", function ( event ) {
        // Сбросить поиск и пагинацию
        api( { fn: "get_pages_list" }, function( answer ) {
            set_pages_list( answer );
            api( { fn: "create_page" }, function( answer ) {
                notify_answer( answer );
                if ( answer.result ) {
                    pages_el.insertAdjacentHTML( "afterbegin", answer.result.pages[0].html );
                    
                    // Подкрутить список страниц в начало
                    main_el.scrollTop = 0;

                    const new_page = pages_el.firstElementChild;
                    page_controls( new_page );
                    page_plashka_controls( new_page );
                    const widget = new_page.querySelector( `.select.widget` );
                    select_controls( widget, { "mode": "init" } );

                    // Удалить последний элемент если был предел
                    if ( pager_options.loaded == get_cookie( pager_options.cookie ) ) {
                        pages_el.lastElementChild.remove();
                    } else {
                        pager_options.loaded = pager_options.loaded + 1;
                    }
                    
                    // Пересоздание кнопок пагинации
                    pager_options.count = pager_options.count + 1;
                    create_pager( pager_options );
                }
            } );
        } );
    } );

    // Создает элементы ссылки для копирования
    function img_to_tag( image ) {
        const data_src = image.getAttribute( "data-src" );

        const width = image.getAttribute( "width" );
        const height = image.getAttribute( "height" );

        const ext = data_src.replace( /.*\./, "" ).toLowerCase();

        const img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ];
        const audio = [ "mp3", "ogg", "m4a", "flac" ];
        const video = [ "mp4", "mkv", "webm" ];

        let html;
        if ( img.indexOf( ext ) >= 0 ) {
            html = `<img alt="" src="{a}"`;
            if ( width ) { html += ` width="${width}"`; }
            if ( height ) { html += ` height="${height}"`; }
            html += ` loading="lazy">`;
        } else if ( audio.indexOf( ext ) >= 0 ) {
            html = `<audio src="{a}" controls></audio>`;
        } else if ( video.indexOf( ext ) >= 0 ) {
            html = `<video src="{a}" poster="" controls preload="none"></video>`;
        } else {
            const file_name = data_src.replace( /.*\//, "" );
            html = `<a href="{a}">${file_name}</a>`;
        }

        return {
            data_src: data_src,
            html: html,
            a_html: `<a href="${data_src}" target=_blank>${data_src}</a>`,
        };
    }

    // generate link to clicked file
    function img_click( file_el, cm ) {
        const files_el = file_el.closest( `.files` );
        files_el.querySelectorAll( `.file` ).forEach( function( block ) {
            block.classList.remove( "active" );
        } );
        file_el.classList.add( "active" );
        const image = file_el.querySelector( `img` );
        
        const tag = img_to_tag( image );
        const link = tag.html.replace( /</g, "&lt;").replace( />/g, "&gt;").replace( "{a}", tag.a_html );

        const tag_el = file_el.closest( `.panel` ).querySelector( `.link .tag` );
        tag_el.innerHTML = link;

        const inner_link = tag_el.querySelector( `a` );
        inner_link.addEventListener( "click", function ( event ) {
            file_link_click( event, cm );
        } );
        cm.focus();
    }

    function file_link_click( event, cm ) {
        event.preventDefault();
        const text = event.target.getAttribute( "href" );
        if ( copy_to_clipboard( text ) ) {
            notify_answer( { "notify": { "notify_html": __( "copyed" ) } } );
        } else {
            notify_answer( { "notify": { "notify_html": __( "copy_error" ) } } );
        }
        cm.focus();
    }

    // enable or disable delete files button
    function img_rechecked( mediateka ) {
        const checked = mediateka.querySelectorAll( ".files input[type=checkbox]:checked" );
        if ( checked.length ) {
            mediateka.querySelector( ".del" ).classList.remove( "disabled" );
        } else {
            mediateka.querySelector( ".del" ).classList.add( "disabled" );
        }
    }

    function mediateka_controls( mediateka, cm ) {
        const files_el = mediateka.querySelector( `.files` );
        // Клики по галочкам на картинках
        files_el.querySelectorAll( `input[type=checkbox]` ).forEach( function( checkbox ) {
            // Выбор всех картинок двойным кликом
            checkbox.addEventListener( "dblclick", function( event ) {
                const stat = ! checkbox.checked;
                files_el.querySelectorAll( `input[type=checkbox]` ).forEach( function( chbox ) {
                    chbox.checked = stat;
                } );
                img_rechecked( mediateka );
            } );
            checkbox.addEventListener( "change", function( event ) {
                img_rechecked( mediateka );
            } );
            checkbox.addEventListener( "click", function( event ) {
                event.stopPropagation();
            } );
        } );
        
        // Двойным кликом по картинке открывается предпросмотр
        files_el.querySelectorAll( "img" ).forEach( function( img ) {
            img.addEventListener( "dblclick", img_lbox );
        } );
        
        // Клики по файлам готовят код для вставки в редактор
        files_el.querySelectorAll( ".file" ).forEach( function( file_el ) {
            file_el.addEventListener( "click", function ( e ) {
                img_click( file_el, cm );
            } );

            // Поддержка Drag-and-Drop
            file_el.setAttribute( "draggable", "true" );
            file_el.addEventListener( "dragstart", function( e ) {
                const image = file_el.querySelector( `img` );
                const tag = img_to_tag( image );
                const link = tag.html.replace( "{a}", tag.data_src );
                // Передаем ссылку как plain text
                e.dataTransfer.setData( "text/plain", link );
            } );
        } );
    }

    // Общие для плашек и для редакторов обработчики
    // - Свойства открыть/закрыть
    // - Сохранить
    // - Транслитерация URL
    function page_controls( page_el, cm = false ) {
        // Свойства открыть/закрыть
        const page_prop = page_el.querySelector( `.button.prop` );
        page_prop.addEventListener( "click", function( event ) {
            page_el.classList.toggle( "properties" );
            // Если в редакторе
            if ( cm ) {
                const cursor = cm.getCursor();
                cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
                // Скрыть медиатеку
                if ( page_el.classList.contains( "properties" ) ) {
                    page_el.classList.remove( "mediateka" );
                }
            }
        } );

        // Сохранить свойства
        const page_save = page_el.querySelector( `.save.button` );
        if ( cm ) page_save.addEventListener( "mousedown", function( event ) {
            cm.has_focus = cm.hasFocus();
        } );
        page_save.addEventListener( "click", function( event ) {
            if ( cm ) {
                cm.save();
            }
            const data = get_properties( page_el );
            data.fn = "save_page";
            api( data, function( answer ) {
                notify_answer( answer );
                if ( answer.result ) {
                    // Новый текст может прийти если изменен шаблон,
                    // но предыдущая заготовка не изменена.
                    // При создании страницы она заполняется из шаблона.
                    if ( cm && answer.result.new_text ) {
                        cm.setValue( answer.result.new_text );
                    }
                    
                    update_page_properties( page_el, answer.result, { "mode": "options" } );
                    // Определяем селектор для второго набора свойств
                    let second_page_el;
                    if ( cm ) {
                        second_page_el = pages_el.querySelector( `.page[data-id="${data.id}"]` );
                        if ( cm.has_focus ) {
                            cm.focus();
                        }
                    } else {
                        second_page_el = pages_sec.querySelector( `.editor[data-id="${data.id}"]` );
                    }
                    if ( second_page_el ) {
                        update_page_properties( second_page_el, answer.result, { "mode": "options", "second": true } );
                    }

                    update_home();

                    // Маркер последнего редактирования
                    pages_el.querySelectorAll( `:scope > div` ).forEach( function( el ) {
                        el.classList.remove( "last" );
                    } );
                    pages_el.querySelector( `:scope > [data-id="${data.id}"]` ).classList.add( "last" );

                    // Убрать маркеры изменения
                    if ( cm ) {
                        page_el.setAttribute( "data-changed", "false" );
                        const page_id = page_el.getAttribute( "data-id" );
                        const tab_button = tabs_el.querySelector( `.page[data-id="${page_id}"]` );
                        tab_button.setAttribute( "data-changed", "false" );
                    }

                    // В любом случае нужно сообщить модулю меню, чтобы перечитал список страниц для выпадающих списков
                    document.body.dispatchEvent( new Event( "page_updated" ) );

                    // TODO: Обновить Меню целиком - а приходит ли такое событие? 
                    if ( answer.result.update_menu == true ) {
                        const event = new Event( "update_menu" );
                        document.body.dispatchEvent( event );
                    }
                }
            } );
        } );

        // Транслитерация URL
        const pprop_el = page_el.querySelector( `.pprop` );
        pprop_el.querySelectorAll( `.button.translit` ).forEach( function( btn ) {
            btn.addEventListener( "click", function( e ) {
                const url = pprop_el.querySelector( `input[name="title"]` ).value;
                const tr_url = url_translit( url );
                btn.previousElementSibling.value = tr_url;
            } );
        } );
    }

    function edit_page( answer ) {
        notify_answer( answer );
        if ( answer.result ) {
            const r = answer.result;

            // Добавить кнопку на панель
            const tab_button = document.createElement( "div" );
            const span = document.createElement( "span" );
            span.innerText = short_title( r.title );
            tab_button.appendChild( span );
            tab_button.classList.add( "button", "page", "active" );
            tab_button.setAttribute( "data-id", r.id );
            tabs_el.querySelectorAll( `.page.active` ).forEach( function( btn ) {
                btn.classList.remove( "active" );
            } );
            tabs_el.appendChild( tab_button );

            // Щелчок по кнопке в tabs скрывает/показывает редактор
            // Нужное индивидуальное поведение:
            // - не отжимать кнопку если не на #pages
            tab_button.addEventListener( "click", function( event ) {
                // Определить, есть ли переход на #pages
                const to_pages = window.location.hash !== "#pages";
                // Активна ли кнопка в момент нажатия
                const active = tab_button.classList.contains( "active" );

                // Всегда переходить на #pages
                window.location.hash = "#pages";

                // Деактивировать все кнопки
                tabs_el.querySelectorAll( `.page` ).forEach( function( btn ) {
                    btn.classList.remove( "active" );
                } );

                // Скрыть все редакторы
                pages_sec.querySelectorAll( `:scope > .editor` ).forEach( function( ed ) {
                    ed.classList.add( "hidden" );
                } );

                // Нажать только если была отжата
                if ( to_pages || ! active ) {
                    tab_button.classList.add( "active" );
                    ed.classList.remove( "hidden" );
                    cm.focus(); // Чуть ниже определяется
                }
            } );

            // Добавление редактора
            // Внутри <template> элементы спрятаны из дерева
            // и querySelector на них не наткнется
            // Не забывать про .content
            const ed = pages_sec.querySelector( `template` ).content.firstElementChild.cloneNode( true );
            ed.setAttribute( "data-id", r.id );
            pages_sec.appendChild( ed );

            update_page_properties( ed, r, { "mode": "init" } );

            // Подключить Codemirror
            const cm = codemirror_connect(
                ed.querySelector( `.textarea > textarea` ),
                { cursor_save_to: "cursor_page_" + r.id }
            );

            page_controls( ed, cm );
            
            const mediateka = ed.querySelector( `.mediateka` );
            const del_files_btn = mediateka.querySelector( `.del.button` );
            const files_el = mediateka.querySelector( `.files` );
            const link_tag = mediateka.querySelector( `.link .tag` );

            // Images
            link_tag.innerHTML = "";
            del_files_btn.classList.add( "disabled" );
            files_el.innerHTML = r.flist;

            mediateka_controls( mediateka, cm );

            // Показать панель тегов на широких экранах
            if ( document.documentElement.offsetWidth >= 1024 ) {
                ed.classList.add( "tags" );
            }

            // Отобразить до присоединения редактора чтобы корректно отрисовалось
            ed.classList.remove( "hidden" );

            cm.restore_cursor();
            cm.focus();

            // Следить за изменениями в редакторе
            ed.setAttribute( "data-changed", "false" );
            cm.on( "change", function( cm, change ) {
                ed.setAttribute( "data-changed", "true" );
                tab_button.setAttribute( "data-changed", "true" );
            } );

            const tags = ed.querySelector( ".panel > .tags" );

            bind_key( ed, "CtrlKeyS", ed.querySelector( `.save.button` ), "click" );
            bind_key( ed, "CtrlKeyH", tags.querySelector( `[data-otag="<h2>"]` ), "click" );
            bind_key( ed, "CtrlKeyP", tags.querySelector( `[data-otag="<p>"]` ), "click" );
            bind_key( ed, "CtrlKeyB", tags.querySelector( `[data-otag="<b>"]` ), "click" );
            bind_key( ed, "CtrlKeyD", tags.querySelector( `[data-otag="<div>"]` ), "click" );
            bind_key( ed, "CtrlKeyL", tags.querySelector( `[data-otag="<li>"]` ), "click" );
            bind_key( ed, "CtrlShiftKeyS", tags.querySelector( `[data-otag="<span>"]` ), "click" );
            bind_key( ed, "CtrlKeyK", tags.querySelector( `[data-otag="<kbd>"]` ), "click" );
            bind_key( ed, "CtrlKeyM", tags.querySelector( `[data-otag^="<figure>"]` ), "click" );
            bind_key( ed, "CtrlComma", tags.querySelector( `[data-otag="<code>"]` ), "click" );
            bind_key( ed, "CtrlShiftComma", tags.querySelector( `[data-otag="<pre><code>"]` ), "click" );
            bind_key( ed, "CtrlPeriod", tags.querySelector( `[data-otag="<blockquote>"]` ), "click" );
            bind_key( ed, "CtrlShiftPeriod", tags.querySelector( `[data-otag="<mark>"]` ), "click" );
            bind_key( ed, "CtrlKeyU", tags.querySelector( `[data-tag="ul"]` ), "click" );
            bind_key( ed, "CtrlKeyO", tags.querySelector( `[data-tag="ol"]` ), "click" );
            bind_key( ed, "CtrlShiftKeyA", tags.querySelector( `[data-type="wrap-a"]` ), "click" );
            bind_key( ed, "CtrlShiftKeyC", tags.querySelector( `[data-otag="<!-- "]` ), "click" );

            ed.classList.remove( "hidden", "template" );

            // Закрытие редактора
            ed.querySelector( `.close.button` ).addEventListener( "click", function( e ) {
                ed.remove();
                // Удалить вкладку-кнопку
                const btn = tabs_el.querySelector( `.page[data-id="${r.id}"]` );
                if ( btn ) btn.remove();
                // Удалить событие
                document.querySelector( `aside a[href="#pages"]` ).removeEventListener( "click", cm_focus );
            } );

            // Сворачивание редактора
            ed.querySelector( `.minimize.button` ).addEventListener( "click", function( e ) {
                ed.classList.add( "hidden" );
                const btn = tabs_el.querySelector( `.page[data-id="${r.id}"]` );
                btn.classList.remove( "active" );
            } );

            // Кнопка "Медиатека"
            ed.querySelector( `.button.media` ).addEventListener( "click", function( e ) {
                ed.classList.toggle( "mediateka" );
                // Скрыть свойства
                if ( ed.classList.contains( "mediateka" ) ) {
                    ed.classList.remove( "properties" );
                }
                // Чтобы место редактирования не уходило за экран
                const cursor = cm.getCursor();
                cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
                cm.focus();
            } );

            // Кнопка копирования тега картинки
            const copy_img_btn = mediateka.querySelector( ".button.copy" );
            copy_img_btn.addEventListener( "click", function( event ) {
                const text = copy_img_btn.previousElementSibling.innerText;
                if ( ! text ) {
                    notify_answer( { "notify": { "notify_html": __( "select_file" ) } } );
                } else if ( copy_to_clipboard( text ) ) {
                    notify_answer( { "notify": { "notify_html": __( "copyed" ) } } );
                } else {
                    notify_answer( { "notify": { "notify_html": __( "copy_error" ) } } );
                }
                cm.focus();
            } );

            // Загрузка файлов страницы
            const upload_input = mediateka.querySelector( "input[type=file]" );
            upload_input.addEventListener( "change", async function( event ) {
                const data = {
                    "fn": "upload_files",
                    "id": ed.getAttribute( "data-id" ),
                    "files": upload_input.files,
                }
                const bar = mediateka.querySelector( ".progress" );
                api( data, 
                    function result_fn( answer ) {
                        bar.style = "";
                        upload_input.value = "";
                        notify_answer( answer );
                        if ( answer.result ) {
                            files_el.innerHTML = answer.result.flist;
                            mediateka_controls( mediateka, cm );
                            // Выбрать загруженный файл
                            files_el.firstElementChild.click();
                        }
                    },
                    function error_fn( event ) {
                        if ( event.target.status == 413 ) {
                            notify_answer( { "error": { "notify_html": __( "too_large" ) } } );
                        } else {
                            notify_answer( { "error": { "notify_html": __( "json_parse_error" ) } } );
                        }
                        bar.style = "";
                    },
                    function ajax_progress( event ) {
                        const percent = Math.round( ( event.loaded / event.total ) * 100 );
                        bar.style.width = percent + "%";
                    },
                    function ajax_error( event ) {
                        notify_answer( { "error": { "notify_html": __( "error_upload_file" ) } } );
                        bar.style = "";
                    },
                    function ajax_abort( event ) {
                        notify_answer( { "error": { "notify_html": __( "error_upload_file" ) } } );
                        bar.style = "";
                    },
                );
            } );

            // Удаление файлов из медиатеки
            del_files_btn.addEventListener( "click", function( e ) {
                if ( ! del_files_btn.classList.contains( "disabled" ) ) {
                    const file_list = [];
                    const src_list = [];
                    files_el.querySelectorAll( `input[type=checkbox]:checked` ).forEach( function( checkbox ) {
                        if ( checkbox.checked ) {
                            const file = checkbox.closest( `.file` );
                            file_list.push( file );
                            const src = file.querySelector( `img` ).getAttribute( "data-src" );
                            src_list.push( src );
                        }
                    } );
                    const data = {
                        fn: "del_files",
                        flist: src_list
                    };
                    api( data, function( answer ) {
                        notify_answer( answer );
                        link_tag.innerHTML = "";
                        if ( answer.result ) {
                            for ( const file of file_list ) {
                                file.remove();
                            }
                            del_files_btn.classList.add( "disabled" );
                        }
                    } );
                }
            } );

            // Кнопка "Заменить"
            ed.querySelector( ".replace.button" ).addEventListener( "click", function( event ) {
                const dialog = ed.querySelector( ".CodeMirror-dialog" );
                if ( dialog ) {
                    dialog.remove();
                } else {
                    const mediateka_hidden = ! mediateka.classList.contains( "hidden" );
                    if ( mediateka_hidden && window.innerWidth < 1024 ) {
                        ed.querySelector( ".button.media" ).click();
                    }
                    cm.execCommand( "replace" );
                }
            } );

            // show/hide tags
            ed.querySelector( ".buttons .button.tags" ).addEventListener( "click", function( e ) {
                ed.classList.toggle( "tags" );
                cm.focus();
                cm.refresh(); // иначе курсор прыгает в строку ниже
            } );

            // for tags
            tags.querySelectorAll( "[data-type='wrap']" ) .forEach( function( btn ) {
                btn.addEventListener( "click", function( event ) {
                    const otag = btn.getAttribute( "data-otag" );
                    const ctag = btn.getAttribute( "data-ctag" ).replaceAll( "\\n", "\n" );
                    const len  = btn.getAttribute( "data-len" );
                    const ch   = btn.getAttribute( "data-ch" );
                    const line = btn.getAttribute( "data-line" );
                    
                    const cursor = cm.getCursor();
                    const selections = cm.getSelections();
                    const replacements = [];
                    for ( let i = 0; i < selections.length; i++ ) {
                        replacements[i] = otag + selections[i] + ctag;
                    }
                    cm.replaceSelections( replacements );
                    // Прятять панельку на мобильнике
                    if ( window.innerWidth < 1024 ) {
                        ed.classList.remove( "tags" );
                    }
                    if ( selections.length < 2 ) {
                        if ( line ) {
                            cursor.line += +line;
                            cursor.ch = +ch;
                        } else if ( len ) {
                            cursor.ch += +len;
                        }
                        cm.setCursor( cursor );
                    }
                    cm.focus();
                } );
            } );

            // for <a> tag
            tags.querySelectorAll( `[data-type="wrap-a"]` ) .forEach( function( btn ) {
                btn.addEventListener( "click", function( e ) {
                    const cursor = cm.getCursor();
                    const selections = cm.getSelections();
                    const replacements = [];
                    
                    for ( let i = 0; i < selections.length; i++ ) {
                        if ( selections[i].match( /https?:\/\// ) ) {
                            replacements[i] = `<a href="${selections[i]}" target=_blank>${selections[i]}</a>`;
                        } else {
                            replacements[i] = `<a href="" target=_blank>${selections[i]}</a>`;
                        }
                    }
                    
                    cm.replaceSelections( replacements );

                    if ( selections.length == 1 && selections[0] === "" ) {
                        cursor.ch += 9;
                        cm.setCursor( cursor );
                    }
                    
                    if ( window.innerWidth < 1024 ) {
                        ed.classList.remove( "tags" );
                    }

                    cm.focus();
                } );
            } );

            // for tags <ul> and <ol>
            tags.querySelectorAll( "[data-type='wrap-list']" ) .forEach( function( btn ) {
                btn.addEventListener( "click", function( e ) {
                    const cursor = cm.getCursor();
                    const tag = btn.getAttribute( "data-tag" );
                    const selections = cm.getSelections();
                    const replacements = [];

                    if ( selections.length == 1 && selections[0] === "" ) {
                        replacements[0] = `<${tag}>\n    <li></li>\n</${tag}>`;
                    } else if ( selections.length == 1 ) {
                        const lines = selections[0].split( "\n" );
                        replacements[0] = `<${tag}>\n    <li>` + lines.join( "</li>\n    <li>" ) + `</li>\n</${tag}>`;
                    } else {
                        const n = selections.length - 1;
                        for ( let i = 0; i <= n; i++ ) {
                            replacements[i] = `    <li>${selections[i]}</li>`;
                        }
                        replacements[0] = `<${tag}>\n` + replacements[0];
                        replacements[n] = replacements[n] + `\n</${tag}>`;
                    }

                    cm.replaceSelections( replacements );

                    // Поставить курсор в li
                    cursor.line += 1;
                    cursor.ch = 8;
                    cm.setCursor( cursor );
                    
                    if ( window.innerWidth < 1024 ) {
                        ed.classList.remove( "tags" );
                    }

                    cm.focus();
                } );
            } );

            // prevent hide cursor when window resize
            window.addEventListener( "resize", function() {
                const cursor = cm.getCursor();
                cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
            } );
            
            // Возврат фокуса редактору при кликах на "Страницы"
            if ( cm ) {
                document.querySelector( "aside a[href='#pages']" ).addEventListener( "click", cm_focus );
            }
            
            // Функция описано отдельно чтобы отцеплять ее
            // Тут возможно множество срабатываний если открыто много редакторов, но ничего страшного
            function cm_focus( event ) {
                setTimeout( function( event ) {
                    cm.focus();
                }, 50 );
            }
        }
    }

    // Удаление страниц
    trash_page_btn.addEventListener( "click", function( event ) {
        const ids = [];
        pages_el.querySelectorAll( ".page > input[type=checkbox]:checked" ).forEach( function( checkbox ) {
            const id = checkbox.closest( "[data-id]" ).getAttribute( "data-id" );
            ids.push( id );
        } );
        if ( ids.length === 0 ) {
            notify_answer( { "notify": { "notify_html": __( "no_selected_pages" ) } } );
            return;
        }
        const data = {
            fn: "del_pages",
            ids: ids
        };
        api( data, function( answer ) {
            notify_answer( answer );

            data.ids.forEach( function( id ) {
                const button = tabs_el.querySelector( `.page[data-id="${id}"]` );
                const ed = pages_sec.querySelector( `.editor[data-id="${id}"]` );
                if ( button ) { button.remove(); }
                if ( ed ) { ed.remove(); }
            } );

            if ( answer.result ) {
                pager_options.search.search_run_fn();
            }
            // update event for menu
            if ( answer.result.update_menu === true ) {
                const event = new Event( "update_menu" );
                document.body.dispatchEvent( event );
            }
        } );
    } );

    // view in lightbox
    function img_lbox() {
        const src = this.getAttribute( "data-src" );
        const ext = src.replace( /.*\./, "" );
        const img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ];
        const mus = [ "mp3", "ogg", "m4a", "flac", "opus" ];
        const vid = [ "mp4", "mkv", "webm" ];
        if ( document.querySelector( "#lbox" ) == null ) {
            let el;
            if ( img.indexOf( ext ) >= 0 ) {
                el = document.createElement( "img" );
            } else if ( mus.indexOf( ext ) >= 0 ) {
                el = document.createElement( "audio" );
                el.setAttribute( "controls", true );
            } else if ( vid.indexOf( ext ) >= 0 ) {
                el = document.createElement( "video" );
                el.setAttribute( "controls", true );
            }
            if ( el !== undefined ) {
                el.src = src;
                const div = document.createElement( "div" );
                div.id = "lbox";
                div.appendChild( el );
                document.body.appendChild( div );
                div.addEventListener( "click", function( event ) {
                    this.remove();
                } );
            }
        }
    }

    // Мягкая транслитерация URL.
    // Если есть что заменять - заменяем, а так же пробелы меняем на -.
    // Если нет пары для замены - оставляем оригинальный символ.
    // Перечень находится в .cms/lang/translit.php
    function url_translit( url ) {
        url = url.toLowerCase();
        for ( let i in cms.tr ) {
            url = url.replaceAll( i, cms.tr[i] );
        }
        url = url.replace( / +/g, "-" );
        url = url.replace( /--+/g, "-" );
        url = url.replace( /^[-_]+|[-_]+$/g, "" );
        return url;
    }
    
    // Подсвечивать главную
    function update_home() {
        pages_el.querySelectorAll( `:scope > [data-id]` ).forEach( function( page ) {
            if ( page.querySelector( `a.title[href="${cms.base_path}"]` ) ) {
                page.classList.add( "home" );
            } else {
                page.classList.remove( "home" );
            }
        } );
    }

} );
