Mercurial
view .cms/js/pages.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
line wrap: on
line source
document.addEventListener( "DOMContentLoaded", function( event ) { function _( str ) { return __( str, "pages.mod.php" ); } // Полностью этот скрипт отключить нельзя если включены Инструменты, // поэтому нужна проверка if ( document.querySelector( "#pages" ) ) { api( { fn: "get_pages_list" }, set_pages_list ); } function set_pages_list( r ) { if ( ! document.querySelector( "#pages" ) ) return; if ( r.no_database ) { document.querySelector( "#pages .pages-grid" ).innerHTML = r.no_database; return; } if ( r.overloaded ) { let m = _( "server_overloaded_xxx" ); m = m.replace( "xxx", r.pages.length ); notify( m, "info-error", 5000 ); } // Запоминаем результаты какого поиска мы получили // Это нужно чтобы не загружать снова все страницы при создании новой // не производить сброс поиска. let pages_search = document.querySelector( "#pages .page-search" ); pages_search.setAttribute( "data-result-of", r.search ); let grid = document.querySelector( "#pages .pages-grid" ); let count = document.querySelector( "#pages .main-footer .count" ); let loaded = document.querySelector( "#pages .main-footer .loaded" ); if ( cms.clear_pages_list ) { cms.clear_pages_list = false; grid.innerHTML = ""; loaded.value = "0"; } // Всего страниц в БД count.innerText = r.count; // При удалении страниц подгружаются последние и не нужно менять смещение у пейджера if ( cms.dont_change_offset ) { cms.dont_change_offset = false; } else { loaded.setAttribute( "data-offset", r.offset ); } // insert pages let start = Date.now(); for ( let i = 0; i < r.pages.length; i++ ) { grid.insertAdjacentHTML( "beforeend", r.pages[i].html ); loaded.value = +loaded.value + 1; let page = grid.querySelector( `[data-id="${r.pages[i].id}"]` ); set_controls( page ); if ( Date.now() - start > 1000 ) { let m = _( "browser_overloaded_xxx" ); m = m.replace( "xxx", i + 1 ); m = m.replace( "nnn", r.pages.length ); notify( m, "info-error", 5000 ); break; } } create_pager(); // При создании страницы было обнаружено что поиск не сброшен, // поэтому была вызвана функция загрузки страниц с пустым поиском // и пришло время создать новую страницу if ( cms.create_page_fn ) { cms.create_page_fn(); cms.create_page_fn = null; } } function create_pager() { let loaded = document.querySelector( "#pages .main-footer .loaded" ); let offset = parseInt( loaded.getAttribute( "data-offset" ) ); let count = parseInt( document.querySelector( "#pages .main-footer .count" ).innerText ); if ( count === 0 ) { count++; } let cookie_pp = get_cookie( "pages_pager" ); let pages = Math.ceil( count / cookie_pp ); let pager = document.querySelector( "#pages .main-footer .pager" ); pager.innerHTML = ""; if ( pages > 1 ) { for ( let i = 1; i <= pages; i++ ) { let p = document.createElement( "div" ); p.innerText = i; p.setAttribute( "data-offset", ( i - 1 ) * cookie_pp ); pager.appendChild( p ); } pager.querySelector( `[data-offset="${offset}"]` ).classList.add( "active" ); pager.childNodes.forEach( function( el ) { el.addEventListener( "click", function( e ) { let offset = this.getAttribute( "data-offset" ); let search = document.querySelector( "#pages .page-search" ).value; let data = { fn: "get_pages_list", offset: offset, search: search } document.querySelector( "#pages .main-main" ).scrollTop = 0; cms.clear_pages_list = true; api( data, set_pages_list ); } ); } ); // scroll pager.onmousedown = function( e ) { let pageX = 0; let pageY0 = 0; document.onmousemove = function( e ) { if ( pageX !== 0 ) { pager.scrollLeft = pager.scrollLeft + ( pageX - e.pageX ); } pageX = e.pageX; // fix for google chrome if ( pageY0 === 0 ) { pageY0 = e.pageY; } if ( Math.abs( pageY0 - e.pageY ) > 64 ) { const event = new Event( "mouseup" ); pager.dispatchEvent( event ); } } // end drag pager.onmouseup = function() { document.onmousemove = null; pager.onmouseup = null; } // disable browser drag pager.ondragstart = function() { return false; } } } } // pager counter let pager_counter = document.querySelector( "#pages .main-footer input" ); if ( pager_counter ) pager_counter.addEventListener( "keydown", function( e ) { if ( e.keyCode === 13 ) { // keyCode work on mobile let p = document.querySelector( "#pages .main-footer input" ).value; set_cookie_expires( "pages_pager", p ); cms.clear_pages_list = true; api( { fn: "get_pages_list", search: document.querySelector( "#pages .page-search" ).value }, set_pages_list ); } } ); function set_controls( selector ) { // Open properties selector.querySelectorAll( ".page-prop-btn" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { let id = this.closest( "[data-id]" ).getAttribute( "data-id" ); document.querySelector( `#pages .pages-grid [data-id="${id}"]` ).classList.toggle( "open" ); } ); } ); // Save properties selector.querySelectorAll( ".page-prop-save-btn" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { let id = this.closest( "[data-id]" ).getAttribute( "data-id" ); let item = document.querySelector( `#pages .pages-grid [data-id="${id}"] ` ); let data = { fn: "save_prop", id: id, title: item.querySelector( '[name="title"]' ).value, seo_title: item.querySelector( '[name="seo_title"]' ).value, url: item.querySelector( '[name="url"]' ).value, date: item.querySelector( '[name="date"]' ).value, time: item.querySelector( '[name="time"]' ).value, template: item.querySelector( '.template-select-grid .field-select' ).getAttribute( "data-template" ), old_template: item.querySelector( '.template-select-grid .field-select' ).getAttribute( "data-old-template" ), description: item.querySelector( '[name="description"]' ).value, tags: item.querySelector( '[name="tags"]' ).value, } api( data, function( r ) { if ( r.ok == "false" ) { // FIXME: never fire notify( r.info_text, r.info_class, 5000 ); } if ( r.ok == "true" ) { // Update Title, URL and Date item.querySelector( ".page-name" ).innerHTML = r.title; item.querySelector( ".page-name" ).setAttribute( "href", r.base_path + r.url ); update_home(); let url_el = item.querySelector( "[name=url]" ); if ( url_el.value != r.url ) { notify( _( "url_changed" ), "info-error", 5000 ); } url_el.value = r.url; let date = item.querySelector( ".page-date" ); date.innerHTML = r.created; if ( r.planned ) { date.classList.add( "future" ); } else { date.classList.remove( "future" ); } // update old template item.querySelector( '.template-select-grid .field-select' ).setAttribute( "data-old-template", data.template ); // edit marker document.querySelectorAll( "#pages .pages-grid > div" ).forEach( function( el ) { el.classList.remove( "last-edited" ); } ); setTimeout( function() { item.classList.add( "last-edited" ); }, 200 ); // highlight save button button.classList.add( "saved" ); setTimeout( function() { button.classList.remove( "saved" ); }, 200 ); notify( r.info_text, r.info_class, 5000 ); // update event for menu if ( r.update_menu == "true" ) { let event = new Event( "update_menu" ); document.body.dispatchEvent( event ); } } } ); } ); } ); // Pin Page selector.querySelectorAll( ".pin" ).forEach( function( pin ) { pin.addEventListener( "click", function( e ) { let box = this.closest( "[data-id]" ); let id = box.getAttribute( "data-id" ); let pin = box.getAttribute( "data-pin" ); if ( pin === "1" ) { pin = "0"; } else { pin = "1"; } let data = { fn: "page_pin", id: id, pin: pin } api( data, function( r ) { if ( r.ok == "true" ) { box.setAttribute( "data-pin", pin ); } } ); } ); } ); // Publish Page selector.querySelectorAll( ".published" ).forEach( function( pub ) { pub.addEventListener( "click", function( e ) { let box = this.closest( "[data-id]" ); let id = box.getAttribute( "data-id" ); let published = box.getAttribute( "data-published" ); if ( published === "1" ) { published = "0"; } else { published = "1"; } let data = { fn: "page_publish", id: id, published: published } api( data, function( r ) { if ( r.ok == "true" ) { box.setAttribute( "data-published", published ); if ( published == "1" ) { pub.setAttribute( "title", _( "published" ) ); } else { pub.setAttribute( "title", _( "unpublished" ) ); } } } ); } ); } ); // Edit page selector.querySelectorAll( ".page-edit-btn" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { button.classList.add( "loading" ); let id = this.closest( "[data-id]" ).getAttribute( "data-id" ); // get page from server api( { fn: "get_page", id: id }, function( r ) { button.classList.remove( "loading" ); if ( r.result == "ok" ) { let title = document.querySelector( "#pages .page-editor-title" ); title.innerHTML = r.page.title; title.setAttribute( "href", r.base_path + r.page.url ); let props = document.querySelector( "#pages .page-properties" ); props.querySelector( "input[name='title']" ).value = r.page.title; props.querySelector( "input[name='url']" ).value = r.page.url; props.querySelector( "input[name='seo_title']" ).value = r.page.seo_title; props.querySelector( "textarea[name='description']" ).value = r.page.description; props.querySelector( "textarea[name='tags']" ).value = r.page.tags; props.querySelector( "input[name='date']" ).value = r.date; props.querySelector( "input[name='time']" ).value = r.time; let select = props.querySelector( ".template-select-grid" ); let options = select.querySelector( ".field-options" ); options.innerHTML = r.options; let tpl = select.querySelector( ".field-select" ); tpl.setAttribute( "data-template", r.option ); tpl.setAttribute( "data-old-template", r.option ); tpl.querySelector( ".value" ).innerText = r.option_tr; document.querySelector( "#pages .page-editor > textarea" ).value = r.page.text; if ( r.page.modified != null ) { // prevent delete attribute document.querySelector( "#pages .page-editor > textarea" ).setAttribute( "data-modified", r.page.modified ); } document.querySelector( "#pages .save-page-button" ).setAttribute( "data-id", r.page.id ); options.querySelectorAll( ".option" ).forEach( function( option ) { option.addEventListener( "click", click_select_option ); } ); // Images document.querySelector( "#pages .link-file-tag" ).innerHTML = ""; document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" ); document.querySelector( "#pages .mediateka-files-grid" ).innerHTML = r.flist; document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]" ).forEach( function( checkbox ) { checkbox.addEventListener( "dblclick", img_check_dblclick ); checkbox.addEventListener( "change", img_rechecked ); } ); document.querySelectorAll( "#pages .file-block" ).forEach( function( block ) { block.addEventListener( "click", img_click ); } ); document.querySelectorAll( "#pages .mediateka-files-grid img" ).forEach( function( img ) { img.addEventListener( "dblclick", img_lbox ); } ); // Show Editor document.querySelector( "#pages .page-editor-bg" ).classList.remove( "hidden" ); document.body.classList.add( "editor" ); // for notifications // Connect Editor codemirror_connect( "#pages .page-editor > textarea", "cm" ); // restore scroll and cursor position let cursor = localStorage.getItem( "cursor_page_" + id ); if ( cursor ) { cursor = JSON.parse( cursor ); window.cm.scrollTo( cursor.left, cursor.top ); window.cm.setCursor( { line:cursor.line, ch:cursor.ch } ); window.cm.refresh(); //window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } ); // fix glitch } // track changes document.querySelector( "#pages .close-page-button" ).setAttribute( "data-changed", "false" ); document.querySelector( "#pages .page-editor-grid" ).setAttribute( "data-changed", "false" ); cm.on( "change", function( cm, change ) { document.querySelector( "#pages .close-page-button" ).setAttribute( "data-changed", "true" ); document.querySelector( "#pages .page-editor-grid" ).setAttribute( "data-changed", "true" ); } ); // save scroll and cursor position [ "cursorActivity", "scroll" ].forEach( function( event ) { cm.on( event, function() { let cursor = window.cm.getCursor(); let scroll = window.cm.getScrollInfo(); localStorage.setItem( "cursor_page_" + id, JSON.stringify( { line:cursor.line, ch:cursor.ch, left: scroll.left, top: scroll.top } ) ); } ); } ); // set focus to editor cm.focus(); // Save Page Ctrl+S document.documentElement.addEventListener( "keydown", CtrlS ); // open tags panel if ( document.documentElement.offsetWidth >= 1024 ) { document.querySelector( "#pages .page-editor-grid" ).classList.add( "tags-opened" ); } } } ); } ); } ); // Select selector.querySelectorAll( ".field-select" ).forEach( function( select ) { select.addEventListener( "click", function( e ) { e.stopPropagation(); this.parentElement.classList.toggle( "open" ); // это можно убрать если переставить стили на родителя select.nextElementSibling.classList.toggle( "open" ); } ); } ); // Option шаблона // вынесено в функцию потому что динамическое изменение selector.querySelectorAll( ".field-options .option" ).forEach( function( option ) { option.addEventListener( "click", click_select_option ); } ); // Транслитерация URL selector.querySelectorAll( ".url-translit" ).forEach( function( btn ) { btn.addEventListener( "click", function( e ) { let url = selector.querySelector( "input[name='title']" ).value; let tr_url = url_translit( url ); this.previousElementSibling.value = tr_url; } ); } ); // Выбор всех страниц двойным кликом let check = selector.querySelector( `:scope > input[type=checkbox]` ); if ( check ) check.addEventListener( "dblclick", function( e ) { let stat = ! this.checked; document.querySelectorAll( "#pages .pages-grid > div > input[type=checkbox]" ).forEach( function( chbox ) { chbox.checked = stat; } ); } ); } // Клик по опции выбора шаблона function click_select_option( e ) { let select = this.closest( ".template-select-grid" ); let value = this.getAttribute( "value" ); select_switch_to( select, value ); } // function select_switch_to( select, value ) { let field_select = select.querySelector( ".field-select" ); let old_value = field_select.getAttribute( "data-template" ); if ( old_value != value ) { let old_name = field_select.innerText; let field_options = select.querySelector( ".field-options" ); let option = field_options.querySelector( `[value="${value}"]` ); field_select.querySelector( ".value" ).innerText = option.innerText; field_select.setAttribute( "data-template", value ); option.remove(); let option_html = `<div class=option value="${old_value}">${old_name}</div>`; field_options.insertAdjacentHTML( "afterbegin", option_html ); field_options.firstChild.addEventListener( "click", click_select_option ); } } // Select for editor document.querySelectorAll( ".page-properties .field-select" ).forEach( function( select ) { select.addEventListener( "click", function( e ) { e.stopPropagation(); this.parentElement.classList.toggle( "open" ); // это можно убрать если переставить стили на родителя select.nextElementSibling.classList.toggle( "open" ); } ); } ); // Select // Закрытие выпадающих списков при кликах вне их, а так же по ним document.body.addEventListener( "click", function( e ) { document.querySelectorAll( "#pages .template-select-grid" ).forEach( function( list ) { list.classList.remove( "open" ); } ); // это можно убрать если переставить стили на родителя document.querySelectorAll( "#pages .field-options" ).forEach( function( list ) { list.classList.remove( "open" ); } ); } ); // Search page let pages_search = document.querySelector( "#pages .page-search" ); if ( pages_search ) pages_search.addEventListener( "keydown", function( e ) { if ( e.keyCode === 13 ) { // сохраняем событие целиком чтобы ниже считать Shift, Ctrl, Alt cms.search_event = e; search_pages(); } } ); let search_btn = document.querySelector( "#pages .page-search-button" ); if ( search_btn ) search_btn.addEventListener( "click", function( e ) { // клик по кнопке не дает Ctrl, Shift, Alt, запишем это cms.search_event = { "ctrlKey": false, "shiftKey": false, "altKey": false }; search_pages(); document.querySelector( "#pages .page-search" ).focus(); } ); function search_pages() { let search_string = document.querySelector( "#pages .page-search" ).value; let data = { fn: "get_pages_list", search: search_string, Ctrl: cms.search_event.ctrlKey, Shift: cms.search_event.shiftKey, Alt: cms.search_event.altKey, }; cms.clear_pages_list = true; api( data, set_pages_list ); } // Reset Search let reset_btn = document.querySelector( "#pages .reset" ); if ( reset_btn ) reset_btn.addEventListener( "click", function() { document.querySelector( "#pages .page-search" ).value = ""; document.querySelector( "#pages .page-search-button" ).click(); } ); // Delete pages document.querySelectorAll( "#pages .del-pages-btn" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { let ids = []; document.querySelectorAll( "#pages .pages-grid input[type=checkbox]:checked" ).forEach( function( ch ) { let id = ch.closest( "[data-id]" ).getAttribute( "data-id" ); ids.push( id ); } ); if ( ids.length === 0 ) { notify( _( "no_selected_pages" ), "info-error", 5000 ); return; } if ( ! confirm( _( "confirm_delete_pages" ) ) ) { return; } let data = { fn: "del_pages", ids: ids }; api( data, function( r ) { if ( r.info_text ) { notify( r.info_text, r.info_class, 5000 ); if ( r.info_class == "info-success" ) { data.ids.forEach( function( id ) { document.querySelector( `#pages .pages-grid [data-id="${id}"]` ).remove(); localStorage.removeItem( "cursor_page_" + id ); } ); let count = document.querySelector( "#pages .main-footer .count" ); let loaded = document.querySelector( "#pages .main-footer .loaded" ); loaded.value = parseInt( loaded.value ) - data.ids.length; count.innerText = parseInt( count.innerText ) - data.ids.length; // load pages let offset = +loaded.getAttribute( "data-offset" ) + document.querySelectorAll( "#pages .pages-grid > *" ).length; let search = document.querySelector( "#pages .page-search" ).value; let data2 = { fn: "get_pages_list", count: data.ids.length, offset: offset, search: search }; // Не менять атрибут смещения у пейджера cms.dont_change_offset = true; api( data2, set_pages_list ); } } // update event for menu if ( r.update_menu == "true" ) { let event = new Event( "update_menu" ); document.body.dispatchEvent( event ); } } ); } ); } ); // copy file link button document.querySelector( "#pages .link-file-copy-btn" ).addEventListener( "click", function( e ) { let img = this.previousElementSibling.innerText; let tmp = document.createElement( "textarea" ); document.body.appendChild( tmp ); tmp.value = img; tmp.select(); let r = document.execCommand( "copy" ); tmp.remove(); if ( r ) { if ( img ) { notify( _( "copyed" ), "info-success", 5000 ); } else { notify( _( "select_file" ), "info-error", 5000 ); } } else { notify( _( "copy_error" ), "info-error", 5000 ); } cm.focus(); } ); function CtrlS( e ) { // ы and і - fix for librewolf if ( ( e.code == "KeyS" || e.key == "ы" || e.key == "і" ) && e.ctrlKey == true ) { e.preventDefault(); // don't save page if ( window.location.hash == "#pages" ) { document.querySelector( "#pages .save-page-button" ).click(); } } /*/ Ловим кнопки codemirror if ( e.code == "F1" ) { let dialog = document.querySelector( ".CodeMirror-dialog-top" ); let html = dialog.outerHTML; cms.dialog = html; //notify( html, "info-success", 5000000 ); } if ( e.code == "F2" ) { document.querySelector( ".CodeMirror" ).insertAdjacentHTML( "beforeend", cms.dialog ); } */ } // Save Page document.querySelectorAll( "#pages .save-page-button" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { window.cm.save(); // drop changes to textarea let main_div = document.querySelector( "#pages" ); let prop_div = main_div.querySelector( ".page-properties" ); let data = { fn: "save_page", id: main_div.querySelector( ".save-page-button" ).getAttribute( "data-id" ), modified: main_div.querySelector( ".page-editor > textarea" ).getAttribute( "data-modified" ), text: main_div.querySelector( ".page-editor > textarea" ).value, title: prop_div.querySelector( "input[name='title']" ).value, url: prop_div.querySelector( "input[name='url']" ).value, seo_title: prop_div.querySelector( "input[name='seo_title']" ).value, description: prop_div.querySelector( "textarea[name='description']" ).value, tags: prop_div.querySelector( "textarea[name='tags']" ).value, date: prop_div.querySelector( "input[name='date']" ).value, time: prop_div.querySelector( "input[name='time']" ).value, template: prop_div.querySelector( ".template-select-grid .field-select" ).getAttribute( "data-template" ), old_template: prop_div.querySelector( ".template-select-grid .field-select" ).getAttribute( "data-old-template" ), } api( data, function( r ) { if ( r.ok == "true" ) { // set text if ( r.new_text ) { window.cm.setValue( r.new_text ); } // Update Title and URL main_div.querySelector( ".page-editor-title" ).innerHTML = r.title; main_div.querySelector( ".page-editor-title" ).setAttribute( "href", r.base_path + r.url ); prop_div.querySelector( "input[name='url']" ).value = r.url; // update old template prop_div.querySelector( ".template-select-grid .field-select" ).setAttribute( "data-old-template", data.template ); // Update item in page list let item = main_div.querySelector( `.pages-grid [data-id='${data.id}']` ); item.querySelector( `.page-name` ).innerHTML = r.title; item.querySelector( `.page-name` ).setAttribute( "href", r.base_path + r.url ); update_home(); item.querySelector( `input[name='title']` ).value = r.title; item.querySelector( `input[name='url']` ).value = r.url; item.querySelector( `input[name='seo_title']` ).value = data.seo_title; item.querySelector( `textarea[name='description']` ).value = data.description; item.querySelector( `textarea[name='tags']` ).value = data.tags; // Выставить шаблон в плашке в списке страниц let select = item.querySelector( `.template-select-grid` ); select_switch_to( select, data.template ); item.querySelector( `.template-select-grid .field-select` ).setAttribute( "data-old-template", data.template ); item.querySelector( `input[name='date']` ).value = data.date; item.querySelector( `input[name='time']` ).value = data.time; if ( r.planned ) { item.querySelector( `.page-date` ).classList.add( "future" ); } else { item.querySelector( `.page-date` ).classList.remove( "future" ); } main_div.querySelector( ".page-editor > textarea" ).setAttribute( "data-modified", r.modified ); main_div.querySelector( ".close-page-button" ).setAttribute( "data-changed", "false" ); main_div.querySelector( ".page-editor-grid" ).setAttribute( "data-changed", "false" ); // edit marker main_div.querySelectorAll( ".pages-grid > div" ).forEach( function( item ) { item.classList.remove( "last-edited" ); } ); item.classList.add( "last-edited" ); // close editor after save if ( main_div.querySelector( ".save-page-button" ).getAttribute( "data-close" ) === "true" ) { main_div.querySelector( ".save-page-button" ).setAttribute( "data-close", "false" ); main_div.querySelector( ".close-page-button" ).click(); } // highlight save button main_div.querySelector( ".save-page-button" ).classList.add( "saved" ); setTimeout( function() { main_div.querySelector( ".save-page-button" ).classList.remove( "saved" ); }, 1000 ); notify( r.info_text, r.info_class, r.info_time ); // update event for menu if ( r.update_menu == "true" ) { let event = new Event( "update_menu" ); document.body.dispatchEvent( event ); } } if ( r.ok == "false" ) { // highlight save button main_div.querySelector( ".save-page-button" ).classList.add( "error" ); setTimeout( function() { main_div.querySelector( ".save-page-button" ).classList.remove( "error" ); }, 1000 ); notify( r.info_text, r.info_class, r.info_time ); } } ); } ); } ); // transliterate file name function __tr_file( str ) { let ext = str.match( /\.[^\.]+$/, "" ); str = str.replace( /\.[^\.]+$/, "" ); let sp = cms.tr[" "]; cms.tr[" "] = "_"; for ( let i in cms.tr ) { let re = new RegExp( i, "g" ); str = str.replace( re, cms.tr[i] ); } if ( sp === undefined ) { delete cms.tr[" "]; } else { cms.tr[" "] = sp; } str = str.replace( /[^-A-Za-z0-9_]+/g, "" ); if ( ext[0] ) { str = str + ext[0]; } str = str.toLowerCase(); return str; } // Upload files let upload_btn = document.querySelector( "#pages .upload-files input[type=file]" ); if ( upload_btn ) upload_btn.addEventListener( "change", async function( event ) { const formData = new FormData(); let id = document.querySelector( "#pages .save-page-button" ).getAttribute( "data-id" ); formData.append( "id", id ); formData.append( "fn", "upload_files" ); let n = 0; for ( let i = 0; i < this.files.length; i++ ) { formData.append( "myfile[]", this.files[i] ); let f = `${cms.base_path}uploads/${id}/` + __tr_file( this.files[i].name ); let f_exists = document.querySelector( `#pages .file-block [data-src="${f}"]` ); if ( f_exists ) { n++; } } let google_chrome_fix = this; if ( n ) { let c = confirm( _( "same_files" ) + ` - ${n} ` + _( "pc" ) + "\n" + _( "confirm_replace" ) ); if ( ! c ) { google_chrome_fix.value = ""; return c; } } let bar = document.querySelector( "#pages .upload-progress" ); let ajax = new XMLHttpRequest(); ajax.upload.addEventListener( "progress", function( event ) { let percent = Math.round( (event.loaded / event.total) * 100 ); bar.style.width = percent + "%"; }, false ); ajax.addEventListener( "error", function( event ) { notify( _( "error_upload_file" ), "info-error", 3600000 ); bar.style = ""; }, false ); ajax.addEventListener( "abort", function( event ) { notify( _( "error_upload_file" ), "info-error", 3600000 ); bar.style = ""; }, false ); ajax.addEventListener( "load", function( event ) { bar.style = ""; google_chrome_fix.value = ""; if ( event.target.status == 413 ) { notify( _( "too_large" ), "info-error", 5000 ); } else { let r = JSON.parse( event.target.responseText ); if ( r.info_text ) { notify( r.info_text, r.info_class, r.info_time ); if ( r.info_class == "info-success" ) { // удалить файлы которые были обновлены let tmp = document.createElement( "div" ); tmp.innerHTML = r.flist; let imgs = tmp.querySelectorAll( "img" ); imgs.forEach( function( img ) { let file = img.getAttribute( "data-src" ); let exists_file = document.querySelector( `#pages .file-block [data-src="${file}"]` ); if ( exists_file ) { exists_file.parentElement.remove(); } } ); let container = document.querySelector( "#pages .mediateka-files-grid" ); container.innerHTML = r.flist + container.innerHTML; // images checkboxes container.querySelectorAll( "input[type=checkbox]" ).forEach( function( checkbox ) { checkbox.addEventListener( "dblclick", img_check_dblclick ); checkbox.addEventListener( "change", img_rechecked ); } ); // open lightbox container.querySelectorAll( "img" ).forEach( function( img ) { img.addEventListener( "dblclick", img_lbox ); } ); // generate link container.querySelectorAll( ".file-block" ).forEach( function( file_block ) { file_block.addEventListener( "click", img_click ); } ); // select last uploaded container.querySelector( ".file-block" ).click(); } } } }, false ); ajax.open( "POST", cms.api ); ajax.send( formData ); } ); // Close Editor document.querySelectorAll( "#pages .close-page-button" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { // hide mediateka if ( ! document.querySelector( "#pages .page-editor-panel" ).classList.contains( "hidden" ) ) { document.querySelector( "#pages .open-mediateka" ).click(); } // hide editor document.querySelector( "#pages .page-editor-bg" ).classList.add( "hidden" ); document.body.classList.remove( "editor" ); document.documentElement.removeEventListener( "keydown", CtrlS ); // detach if ( window.cm !== undefined ) { if ( this.getAttribute( "data-changed" ) === "true" ) { if ( confirm( _( "confirm_save" ) ) ) { document.querySelector( "#pages .save-page-button" ).setAttribute( "data-close", "true" ); document.querySelector( "#pages .save-page-button" ).click(); return; } } window.cm.toTextArea(); window.cm = null; } } ); } ); // Create Page document.querySelectorAll( "#pages .add-page-btn" ).forEach( function( btn ) { btn.addEventListener( "click", function ( e ) { // Отложенный вызов на случай если нужно очистить поиск cms.create_page_fn = function() { api( { fn: "create_page" }, function( r ) { if ( r.info_text ) { notify( r.info_text, r.info_class, r.info_time ); } if ( r.pages ) { let grid = document.querySelector( "#pages .pages-grid" ); grid.insertAdjacentHTML( "afterbegin", r.pages[0].html ); // Подкрутить список страниц в начало document.querySelector( "#pages .main-main" ).scrollTop = 0; let page_box = grid.querySelector( `[data-id="${r.pages[0].id}"]` ); set_controls( page_box ); let counter = document.querySelector( "#pages .main-footer .count" ); counter.innerText = +counter.innerText + 1; let showed_pages_el = document.querySelector( "#pages .main-footer .counters input" ); if ( showed_pages_el.value === get_cookie( "pages_pager" ) ) { document.querySelector( "#pages .pages-grid > div:last-child" ).remove(); } else { showed_pages_el.value = +showed_pages_el.value + 1; } } } ); } // Если сейчас не результаты поиска отображены, // и если мы видим первый пейджер // то сразу выполнить создание страницы let empty_search = document.querySelector( "#pages .page-search" ).getAttribute( "data-result-of" ) === ""; let offset_zero = +document.querySelector( "#pages .main-footer .counters input" ).getAttribute( "data-offset" ) === 0; if ( empty_search && offset_zero ) { cms.create_page_fn(); cms.create_page_fn = null; } else { document.querySelector( "#pages .reset" ).click(); // Создание страницы произведет функция set_pages_list() } } ); } ); // Open Properties document.querySelector( "#pages .open-properties" ).addEventListener( "click", function( e ) { document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "properties" ); document.querySelector( "#pages .page-properties" ).classList.toggle( "hidden" ); if ( window.cm ) { let cursor = window.cm.getCursor(); window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } ); } if ( document.querySelector( "#pages .page-editor-grid" ).classList.contains( "properties" ) ) { document.querySelector( "#pages .page-editor-grid" ).classList.remove( "mediateka" ); document.querySelector( "#pages .page-editor-panel" ).classList.add( "hidden" ); } } ); // Open Mediateka document.querySelector( "#pages .open-mediateka" ).addEventListener( "click", function( e ) { document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "mediateka" ); document.querySelector( "#pages .page-editor-panel" ).classList.toggle( "hidden" ); if ( window.cm ) { let cursor = window.cm.getCursor(); window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } ); } if ( document.querySelector( "#pages .page-editor-grid" ).classList.contains( "mediateka" ) ) { document.querySelector( "#pages .page-editor-grid" ).classList.remove( "properties" ); document.querySelector( "#pages .page-properties" ).classList.add( "hidden" ); } cm.focus(); } ); // Replace Dialog Toggle document.querySelector( "#pages .codemirror-replace" ).addEventListener( "click", function( e ) { let dialog = document.querySelector( "#pages .CodeMirror-dialog" ); if ( dialog ) { dialog.remove(); } else { let mediateka = ! document.querySelector( "#pages .page-editor-panel" ).classList.contains( "hidden" ); if ( mediateka && window.innerWidth < 1024 ) { document.querySelector( "#pages .open-mediateka" ).click(); } window.cm.execCommand( "replace" ); } } ); // generate link to clicked file function img_click() { this.parentElement.querySelectorAll( ".file-block" ).forEach( function( block ) { block.classList.remove( "active-file" ); } ); this.classList.add( "active-file" ); let i = this.querySelector( "img" ); let t = i.getAttribute( "data-type" ); let link = i.getAttribute( "data-src" ); let w = i.getAttribute( "width" ); let h = i.getAttribute( "height" ); let e = link.replace( /.*\./, "" ); let img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ]; let mus = [ "mp3", "ogg", "m4a", "flac" ]; let vid = [ "mp4", "mkv", "webm" ]; let a = `<a href="${link}" target=_blank>${link}</a>`; let tag = this.closest( ".mediateka-grid" ).querySelector( ".link-file-tag" ); if ( img.indexOf( e ) >= 0 ) { link = `<img alt="" src="${a}"`; if ( w ) { link += ` width="${w}"`; } if ( h ) { link += ` height="${h}"`; } link += ` loading="lazy"`; link += ">"; tag.innerHTML = link; } else if ( mus.indexOf( e ) >= 0 ) { link = `<audio src="${a}" controls></audio>`; tag.innerHTML = link; } else if ( vid.indexOf( e ) >= 0 ) { link = `<video src="${a}" poster="" controls preload="none"></video>`; tag.innerHTML = link; } else { link = `<a href="${a}">TEXT</a>`; tag.innerHTML = link; } let inner_link = tag.querySelector( "a" ); inner_link.addEventListener( "click", file_link_click ); cm.focus(); } function file_link_click( e ) { e.preventDefault(); let tmp = document.createElement( "textarea" ); document.body.appendChild( tmp ); tmp.value = e.target.getAttribute( "href" ); tmp.select(); let r = document.execCommand( "copy" ); tmp.remove(); if ( r ) { notify( _( "copyed" ), "info-success", 5000 ); } else { notify( _( "copy_error" ), "info-error", 5000 ); } cm.focus(); } // enable or disable delete files button function img_rechecked() { let checked = document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]:checked" ); if ( checked.length ) { document.querySelector( "#pages .del-uploaded-files" ).classList.remove( "disabled" ); } else { document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" ); } } // Выбор всех картинок двойным кликом function img_check_dblclick( e ) { let stat = ! this.checked; document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]" ).forEach( function( chbox ) { chbox.checked = stat; } ); img_rechecked(); } // view in lightbox function img_lbox() { let src = this.getAttribute( "data-src" ); let e = src.replace( /.*\./, "" ); let img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ]; let mus = [ "mp3", "ogg", "m4a", "flac" ]; let vid = [ "mp4", "mkv", "webm" ]; let t; if ( document.querySelector( "#lbox-window" ) == null ) { if ( img.indexOf( e ) >= 0 ) { t = document.createElement( "img" ); } else if ( mus.indexOf( e ) >= 0 ) { t = document.createElement( "audio" ); t.setAttribute( "controls", true ); } else if ( vid.indexOf( e ) >= 0 ) { t = document.createElement( "video" ); t.setAttribute( "controls", true ); } if ( t !== undefined ) { t.src = src; let d = document.createElement( "div" ); d.id = "lbox-window"; d.appendChild( t ); document.body.appendChild( d ); d.addEventListener( "click", function( e ) { this.remove(); } ); } } } // Delete files document.querySelector( "#pages .del-uploaded-files" ).addEventListener( "click", function( e ) { if ( ! this.classList.contains( "disabled" ) ) { let flist = []; document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]:checked" ).forEach( function( e ) { let f = e.closest( ".file-block" ).querySelector( "img" ).getAttribute( "data-src" ); flist.push( f ); } ); let data = { fn: "del_files", flist: flist }; api( data, function( r ) { if ( r.info_text ) { document.querySelector( "#pages .link-file-tag" ).innerHTML = ""; notify( r.info_text, r.info_class, r.info_time ); if ( r.info_class == "info-success" ) { for ( let f in flist ) { document.querySelector( `#pages .mediateka-files-grid img[data-src="${flist[f]}"]` ).parentElement.remove(); } document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" ); } } } ); } } ); // prevent hide cursor when window resize window.addEventListener( "resize", function() { if ( window.cm ) { let cursor = window.cm.getCursor(); window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } ); } } ); // show/hide tags let tags_btn = document.querySelector( "#pages .tags-helper" ); if ( tags_btn ) tags_btn.addEventListener( "click", function( e ) { document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "tags-opened" ); cm.focus(); cm.refresh(); } ); // for tags document.querySelectorAll( "#pages .tags-grid [data-type='wrap']" ) .forEach( function( btn ) { btn.addEventListener( "click", function( e ) { let otag = this.getAttribute( "data-otag" ); let ctag = this.getAttribute( "data-ctag" ); let len = this.getAttribute( "data-len" ); let ch = this.getAttribute( "data-ch" ); let line = this.getAttribute( "data-line" ); //wrap_selections( otag, ctag, len, line, ch ); let cursor = cm.getCursor(); let selections = cm.getSelections(); let replacements = []; for ( let i = 0; i < selections.length; i++ ) { replacements[i] = otag + selections[i] + ctag; } cm.replaceSelections( replacements ); // Прятять панельку на мобильнике if ( window.innerWidth < 1024 ) { //document.querySelector( "#pages .tags-helper" ).click(); let grid = this.closest( ".editor-grid" ); grid.classList.remove( "tags-opened" ); } if ( selections.length < 2 ) { if ( line ) { cursor.line += +line; cursor.ch = +ch; } else if ( len ) { cursor.ch += +len; } cm.setCursor( cursor ); } cm.focus(); cm.refresh(); } ); } ); // for <a> tag document.querySelectorAll( "#pages .tags-grid [data-type='wrap-a']" ) .forEach( function( btn ) { btn.addEventListener( "click", function( e ) { let cursor = cm.getCursor(); let selections = cm.getSelections(); let 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 ) { //document.querySelector( "#pages .tags-helper" ).click(); let grid = this.closest( ".editor-grid" ); grid.classList.remove( "tags-opened" ); } cm.focus(); cm.refresh(); } ); } ); // for tags <ul> and <ol> document.querySelectorAll( "#pages .tags-grid [data-type='wrap-list']" ) .forEach( function( btn ) { btn.addEventListener( "click", function( e ) { let tag = this.getAttribute( "data-tag" ); let selections = cm.getSelections(); let replacements = []; if ( selections.length == 1 && selections[0] === "" ) { replacements[0] = `<${tag}>\n <li></li>\n</${tag}>`; } else if ( selections.length == 1 ) { let lines = selections[0].split( "\n" ); replacements[0] = `<${tag}>\n <li>` + lines.join( "</li>\n <li>" ) + `</li>\n</${tag}>`; } else { let 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 ); if ( window.innerWidth < 1024 ) { //document.querySelector( "#pages .tags-helper" ).click(); let grid = this.closest( ".editor-grid" ); grid.classList.remove( "tags-opened" ); } cm.focus(); cm.refresh(); } ); } ); // fix glitches codemirror let fix = document.querySelector( "aside a[href='#pages']" ); if ( fix ) fix.addEventListener( "click", function( e ) { setTimeout( function( e ) { if ( window.cm ) { cm.refresh(); cm.focus(); } }, 50 ); } ); // Транслитерация URL let tr_url = document.querySelector( "#pages .page-editor-grid .url-translit" ); if ( tr_url ) tr_url.addEventListener( "click", function( e ) { let url = document.querySelector( "#pages .page-editor-grid .page-properties input[name='title']" ).value; let tr_url = url_translit( url ); this.previousElementSibling.value = tr_url; } ); function url_translit( url ) { url = url.toLowerCase(); for ( let i in cms.tr ) { let re = new RegExp( i, "g" ); url = url.replace( re, cms.tr[i] ); } url = url.replace( / +/g, "-" ); url = url.replace( /[^-a-z0-9_]+/g, "" ); url = url.replace( /^[-_]+|[-_]+$/g, "" ); return url; } function update_home() { document.querySelectorAll( `#pages .pages-grid [data-id]` ).forEach( function( page ) { if ( page.querySelector( `.page-name[href="${cms.base_path}"]` ) ) { page.classList.add( "home" ); } else { page.classList.remove( "home" ); } } ); } // Замена текста на всех страницах document.querySelectorAll( "#pages-utils .replace-btn" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { let data = { fn: "replace_in_pages", table: document.querySelector( "#pages-utils input[name='table']" ).value, id_col: document.querySelector( "#pages-utils input[name='id_col']" ).value, column: document.querySelector( "#pages-utils input[name='column']" ).value, search_regex: document.querySelector( "#pages-utils input[name='search_regex']" ).value, replace: document.querySelector( "#pages-utils input[name='replace']" ).value, }; if ( data.search_regex && confirm( _( "replace_in_pages_confirm" ) ) ) { api( data, function( r ) { if ( r.info_text ) { notify( r.info_text, r.info_class, r.info_time ); } } ); } } ); } ); } );