Mercurial
view .cms/js/menu.js @ 1:1d486627aa1e draft default tip
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Sat, 12 Oct 2024 02:51:39 +0000 |
parents | 78edf6b517a0 |
children |
line wrap: on
line source
document.addEventListener( "DOMContentLoaded", function( event ) { function _( str ) { return __( str, "menu.mod.php" ); } function select3( selects ) { selects.forEach( function( select ) { // именно keyup чтобы не пересекалось с input select.querySelector( "input" ).addEventListener( "keyup", function( e ) { api( { fn: "get_search_pages_list", search: this.value }, function( r ) { if ( r.html ) { select.querySelector( ".list-search" ).innerHTML = r.html; select.querySelectorAll( ".list-search li" ).forEach( function( li ) { li.addEventListener( "click", select3_li ); } ); } } ); } ); // prevent close dropdown when click on input select.querySelector( "input" ).addEventListener( "click", function( e ) { e.stopPropagation(); } ); // show/hide dropdown list select.querySelector( ".field-select" ).addEventListener( "click", function ( event ) { event.stopPropagation(); this.parentElement.classList.toggle( "open" ); let list = event.currentTarget.nextElementSibling; // это можно убрать если переставить стили на родителя list.classList.toggle( "open" ); if ( list.classList.contains( "open" ) ) { let input = select.querySelector( "input" ); input.focus(); input.dispatchEvent( new Event( "keyup" ) ); } } ); } ); } // click selected item function select3_li( e ) { let id = this.getAttribute( "data-id" ); let url = this.getAttribute( "data-url" ); let title = this.innerText; let input_title = this.closest( ".select-grid" ).querySelector( ".field-select" ); let old_id = input_title.getAttribute( "data-old-id" ); input_title.querySelector( ".value" ).innerText = title; input_title.setAttribute( "data-id", id ); // поменять url в поле ввода let input_url = this.closest( ".menu-prop" ).querySelector( "input[name='url']" ); input_url.value = url; // поменять заголовок и ссылку вверху let a = this.closest( ".item" ).querySelector( ":scope > a" ); a.setAttribute( "href", cms.base_path + url ); let replaced_title = this.closest( ".menu-prop" ).querySelector( `input[name="title"]` ).value; if ( replaced_title ) title = replaced_title; a.innerText = title; if ( id === "0" ) { input_url.removeAttribute( "disabled" ); } else { input_url.setAttribute( "disabled", true ); } // remove li except data-id=0 Array.from( this.parentElement.children ).forEach( function( li ) { if ( li.getAttribute( "data-id" ) !== "0" ) { li.remove(); } } ); // close dropdown list input_title.click(); // изменение if ( old_id != id ) { input_title.dispatchEvent( new Event( "input" ) ); } } api( { fn: "get_menu_items" }, set_menu_items ); function set_menu_items( r ) { document.querySelector( "#menu .menu-grid" ).innerHTML = r.list; // set parents for each menu item document.querySelectorAll( "#menu [data-parent]" ).forEach( function( el ) { el.nextElementSibling.insertAdjacentHTML( "beforeend", r.parents ); let pid = el.getAttribute( "data-parent" ); let parent = el.nextElementSibling.querySelector( `[value="${pid}"]` ).innerText.trim(); el.querySelector( ".value" ).innerText = parent; // remove self let self = el.closest( "[data-item]" ).getAttribute( "data-item" ); self = el.nextElementSibling.querySelector( `[value="${self}"]` ); if ( self ) { self.remove(); } } ); // selects let selects = document.querySelectorAll( "#menu .select-grid" ); select3( selects ); // Select document.querySelectorAll( "#menu .area-select-grid .field-select-menu, #menu .parent-select-grid .field-select" ).forEach( function( select ) { select.addEventListener( "click", function( e ) { e.stopPropagation(); this.parentElement.classList.toggle( "open" ); // это можно убрать если переставить стили на родителя select.nextElementSibling.classList.toggle( "open" ); } ); } ); // Option for menu document.querySelectorAll( "#menu .area-select-grid .field-options .option" ).forEach( function( option ) { option.addEventListener( "click", function( e ) { let input = this.closest( ".area-select-grid" ).querySelector( ".field-select-menu" ); let old_val = input.getAttribute( "data-menu-area" ); let new_val = this.getAttribute( "value" ); if ( old_val != new_val ) { input.querySelector( ".value" ).innerText = this.innerText; input.setAttribute( "data-menu-area", new_val ); // Событие изменения let event = new Event( "input" ); input.dispatchEvent( event ); } //e.stopPropagation(); убираем чтобы закрылось автоматически } ); } ); // Option for item document.querySelectorAll( "#menu .parent-select-grid .field-options .option" ).forEach( function( option ) { option.addEventListener( "click", parent_li_click ); } ); function parent_li_click( e ) { let input = this.closest( ".parent-select-grid" ).querySelector( ".field-select" ); let old_val = input.getAttribute( "data-parent" ); let new_val = this.getAttribute( "value" ); if ( old_val != new_val ) { input.querySelector( ".value" ).innerText = this.innerText.trim(); input.setAttribute( "data-parent", new_val ); // Событие изменения let event = new Event( "input" ); input.dispatchEvent( event ); } //e.stopPropagation(); убираем чтобы закрылось автоматически } // Toggle Menu Properties let prop_buttons = document.querySelectorAll( "#menu .menu-buttons .prop" ); prop_buttons.forEach( function( button ) { button.addEventListener( "click", function( e ) { e.stopPropagation(); this.closest( "[data-item]" ).classList.toggle( "open" ); } ); } ); // Отлавливать изменения полей в меню чтобы показать Сохранить document.querySelectorAll( "#menu .menu" ).forEach( function( menu ) { menu.querySelectorAll( "input, .field-select-menu" ).forEach( function( input ) { input.addEventListener( "input", function( event ) { let menu = this.closest( ".menu" ); menu.classList.add( "changed" ); } ); } ); } ); // Отлавливать изменения полей в пунктах чтобы показать Сохранить document.querySelectorAll( "#menu .item" ).forEach( function( item ) { item.querySelectorAll( "input, .field-select" ).forEach( function( input ) { input.addEventListener( "input", function( event ) { let item = this.closest( ".item" ); item.classList.add( "changed" ); } ); } ); } ); // Save Properties document.querySelectorAll( "#menu .menu-buttons .save" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { e.stopPropagation(); let item = this.closest( "[data-item]" ); let mid = item.getAttribute( "data-item" ); let area = item.querySelector( "[data-menu-area]" ); if ( area ) { area = area.getAttribute( "data-menu-area" ); } let tag_title = item.querySelector( "[name='tag_title']" ); if ( tag_title ) { tag_title = tag_title.value; } let url = item.querySelector( "[name='url']" ); if ( url ) { url = url.value; } let id = item.querySelector( "[name='id']" ); if ( id ) { id = id.getAttribute( "data-id" ); } let pid_el = item.querySelector( "[data-parent]" ); let pid,old_pid; if ( pid_el ) { pid = pid_el.getAttribute( "data-parent" ); old_pid = pid_el.getAttribute( "data-old-parent" ); } let target = item.querySelector( "[name='targetblank']" ); if ( target ) { target = target.checked; } let old_sort_el = item.querySelector( "[name='sort']" ); let old_sort = old_sort_el.getAttribute( "data-sort" ); let data = { fn: "save_menu_item", mid: mid, title: item.querySelector( "[name='title']" ).value, tag_title: tag_title, url: url, id: id, pid: pid, old_pid: old_pid, classes: item.querySelector( "[name='classes']" ).value, sort: item.querySelector( "[name='sort']" ).value, area: area, target: target } document.querySelectorAll( `#menu [data-item]` ).forEach( function( el ) { el.classList.remove( "last-edited" ); } ); api( data, function( r ) { if ( r.ok == "false" ) { notify( r.info_text, r.info_class, r.info_time ); } if ( r.ok == "true" ) { item.classList.remove( "changed" ); let item_with_childs = item.parentElement; if ( r.list ) { set_menu_items( r ); } else if ( old_sort != data.sort ) { // пересортировка имеет смысл если не было замены всего списка // обновить сортировку для сравнения old_sort_el.setAttribute( "data-sort", data.sort ); let grid; if ( data.area === null ) { grid = item.closest( ".items-grid" ); } else { grid = item.closest( ".menu-grid" ); } let before = null; for ( let n = 0; n < grid.children.length; n++ ) { let node = grid.children[n]; if ( node != item_with_childs ) { let sort = node.querySelector( '[data-item] [name="sort"]' ).value; if ( +data.sort < +sort ) { before = node; break; } } }; grid.insertBefore( item_with_childs, before ); } // Замена title let title; if ( data.title != "" ) title = data.title; else title = item.querySelector( ".select-grid .value" ).innerText; item.querySelector( ":scope > a" ).innerText = title; // обновить родителей у подпунктов // поскольку мог измениться title // и только у строго дочерних, которых может и не быть let childs_grid = item.nextElementSibling; if ( childs_grid ) { let childs_selector = childs_grid.querySelectorAll( ":scope > div > .item .parent-select-grid" ); if ( childs_selector ) childs_selector.forEach( function( grid ) { let input = grid.querySelector( "[data-parent]" ); let pid = input.getAttribute( "data-parent" ); let options = grid.querySelector( ":scope > .field-options" ); options.innerHTML = r.parents; options.querySelectorAll( ".option" ).forEach( function( option ) { option.addEventListener( "click", parent_li_click ); } ); // тайтл вычисляется выше input.querySelector( ".value" ).innerText = title; } ); } // Last Edited Marker setTimeout( function() { document.querySelector( `#menu [data-item="${data.mid}"]` ).classList.add( "last-edited" ); }, 200 ); } } ); } ); } ); // Delete Menu or Item document.querySelectorAll( "#menu .menu-buttons .del" ).forEach( function( button ) { button.addEventListener( "click", function( e ) { e.stopPropagation(); clear_highlite(); let item = button.closest( ".item,.menu" ).parentNode; item.classList.add( "will-be-deleted" ); setTimeout( function() { if ( ! confirm( __( "confirm_delete", "menu.mod.php" ) ) ) { item.classList.remove( "will-be-deleted" ); return; } let data = { fn: "del_menu_item", mid: button.closest( "[data-item]" ).getAttribute( "data-item" ) }; api( data, function( r ) { if ( r.info_text ) { notify( r.info_text, r.info_class, r.info_time ); if ( r.info_class == "info-success" ) { set_menu_items( r ); } } } ); }, 20 ); } ); } ); // Create Item document.querySelectorAll( "#menu .main-main .append" ).forEach( function( button ) { button.addEventListener( "click", modMenuCreate ); } ); // Линия к родителю let items = document.querySelectorAll( "#menu .item" ); items.forEach( function( el ) { el.addEventListener( "click", function( e ) { // Если опускание мыши было не на нас, то игнорим if ( mouse_down_el != this ) return; mouse_down_el = null; let highlited = this.classList.contains( "highlite-children" ); clear_highlite(); // Назначить классы if ( ! highlited ) { this.classList.add( "highlite-children" ); this.closest( ".items-grid" ).classList.add( "highlite-parent" );; } } ); } ); // Опускание мыши // Возможна ситуация когда нажатие мыши было на кнопке Свойства, // а отпускание на плашке. В этом случае может появиться линия к родителю. // Поэтому нужно записывать что опускание было на плашке или панельке кнопок. let mouse_down_el; // элемент на котором было опускание мыши items.forEach( function( el ) { el.addEventListener( "mousedown", function( e ) { // чтобы проигнорировать клики по дочерним if ( e.target == this ) mouse_down_el = this; } ); // див с кнопками можно тыкать let mb = el.querySelector( ".menu-buttons" ); if ( mb ) mb.addEventListener( "mousedown", function( e ) { // чтобы проигнорировать клики по дочерним if ( e.target == this ) mouse_down_el = this.parentElement; } ); } ); // Сбросить классы function clear_highlite() { document.querySelectorAll( "#menu .items-grid.highlite-parent" ).forEach( function( el ) { el.classList.remove( "highlite-parent" ); } ); document.querySelectorAll( "#menu .item.highlite-children" ).forEach( function( el ) { el.classList.remove( "highlite-children" ); } ); } } // Select // Закрытие выпадающих списков при кликах вне их, а так же по ним document.body.addEventListener( "click", function( e ) { // это можно убрать если переставить стили на родителя document.querySelectorAll( "#menu .field-options" ).forEach( function( list ) { list.classList.remove( "open" ); } ); document.querySelectorAll( "#menu .area-select-grid, #menu .select-grid, #menu .parent-select-grid" ).forEach( function( list ) { list.classList.remove( "open" ); } ); } ); // Создание меню или пункта меню function modMenuCreate( e ) { e.stopPropagation(); let pid = this.closest( "[data-item]" ).getAttribute( "data-item" ); api( { fn : "create_menu_item", pid : pid }, function( r ) { if ( r.info_text ) { notify( r.info_text, r.info_class, r.info_time ); if ( r.info_class == "info-success" ) { set_menu_items( r ); let item = document.querySelector( `#menu [data-item="${r.mid}"]` ); item.classList.add( "open" ); item.classList.add( "last-edited" ); // Докрутить к новому элементу item.scrollIntoView( { behavior: "smooth", block: "center" } ); } } } ); } // Create Menu document.querySelector( "#menu .main-footer .create" ).addEventListener( "click", modMenuCreate ); // update page used in menu document.body.addEventListener( "update_menu", function( e ) { api( { fn: "get_menu_items" }, set_menu_items ); } ); } );