0
|
1 document.addEventListener( "DOMContentLoaded", function( event ) {
|
|
2
|
|
3 function _( str ) {
|
|
4 return __( str, "menu.mod.php" );
|
|
5 }
|
|
6
|
|
7 function select3( selects ) {
|
|
8 selects.forEach( function( select ) {
|
|
9 // именно keyup чтобы не пересекалось с input
|
|
10 select.querySelector( "input" ).addEventListener( "keyup", function( e ) {
|
|
11 api( { fn: "get_search_pages_list", search: this.value }, function( r ) {
|
|
12 if ( r.html ) {
|
|
13 select.querySelector( ".list-search" ).innerHTML = r.html;
|
|
14 select.querySelectorAll( ".list-search li" ).forEach( function( li ) {
|
|
15 li.addEventListener( "click", select3_li );
|
|
16 } );
|
|
17 }
|
|
18 } );
|
|
19 } );
|
|
20 // prevent close dropdown when click on input
|
|
21 select.querySelector( "input" ).addEventListener( "click", function( e ) {
|
|
22 e.stopPropagation();
|
|
23 } );
|
|
24 // show/hide dropdown list
|
|
25 select.querySelector( ".field-select" ).addEventListener( "click", function ( event ) {
|
|
26 event.stopPropagation();
|
|
27 this.parentElement.classList.toggle( "open" );
|
|
28 let list = event.currentTarget.nextElementSibling;
|
|
29
|
|
30 // это можно убрать если переставить стили на родителя
|
|
31 list.classList.toggle( "open" );
|
|
32
|
|
33 if ( list.classList.contains( "open" ) ) {
|
|
34 let input = select.querySelector( "input" );
|
|
35 input.focus();
|
|
36 input.dispatchEvent( new Event( "keyup" ) );
|
|
37 }
|
|
38 } );
|
|
39 } );
|
|
40 }
|
|
41
|
|
42 // click selected item
|
|
43 function select3_li( e ) {
|
|
44 let id = this.getAttribute( "data-id" );
|
|
45 let url = this.getAttribute( "data-url" );
|
|
46 let title = this.innerText;
|
|
47 let input_title = this.closest( ".select-grid" ).querySelector( ".field-select" );
|
|
48 let old_id = input_title.getAttribute( "data-old-id" );
|
|
49 input_title.querySelector( ".value" ).innerText = title;
|
|
50 input_title.setAttribute( "data-id", id );
|
|
51 // поменять url в поле ввода
|
|
52 let input_url = this.closest( ".menu-prop" ).querySelector( "input[name='url']" );
|
|
53 input_url.value = url;
|
|
54 // поменять заголовок и ссылку вверху
|
|
55 let a = this.closest( ".item" ).querySelector( ":scope > a" );
|
|
56 a.setAttribute( "href", cms.base_path + url );
|
|
57 let replaced_title = this.closest( ".menu-prop" ).querySelector( `input[name="title"]` ).value;
|
|
58 if ( replaced_title ) title = replaced_title;
|
|
59 a.innerText = title;
|
|
60 if ( id === "0" ) {
|
|
61 input_url.removeAttribute( "disabled" );
|
|
62 } else {
|
|
63 input_url.setAttribute( "disabled", true );
|
|
64 }
|
|
65 // remove li except data-id=0
|
|
66 Array.from( this.parentElement.children ).forEach( function( li ) {
|
|
67 if ( li.getAttribute( "data-id" ) !== "0" ) {
|
|
68 li.remove();
|
|
69 }
|
|
70 } );
|
|
71 // close dropdown list
|
|
72 input_title.click();
|
|
73 // изменение
|
|
74 if ( old_id != id ) {
|
|
75 input_title.dispatchEvent( new Event( "input" ) );
|
|
76 }
|
|
77 }
|
|
78
|
|
79 api( { fn: "get_menu_items" }, set_menu_items );
|
|
80
|
|
81 function set_menu_items( r ) {
|
|
82
|
|
83 document.querySelector( "#menu .menu-grid" ).innerHTML = r.list;
|
|
84
|
|
85 // set parents for each menu item
|
|
86 document.querySelectorAll( "#menu [data-parent]" ).forEach( function( el ) {
|
|
87 el.nextElementSibling.insertAdjacentHTML( "beforeend", r.parents );
|
|
88 let pid = el.getAttribute( "data-parent" );
|
|
89 let parent = el.nextElementSibling.querySelector( `[value="${pid}"]` ).innerText.trim();
|
|
90 el.querySelector( ".value" ).innerText = parent;
|
|
91 // remove self
|
|
92 let self = el.closest( "[data-item]" ).getAttribute( "data-item" );
|
|
93 self = el.nextElementSibling.querySelector( `[value="${self}"]` );
|
|
94 if ( self ) {
|
|
95 self.remove();
|
|
96 }
|
|
97 } );
|
|
98
|
|
99 // selects
|
|
100 let selects = document.querySelectorAll( "#menu .select-grid" );
|
|
101 select3( selects );
|
|
102
|
|
103 // Select
|
|
104 document.querySelectorAll( "#menu .area-select-grid .field-select-menu, #menu .parent-select-grid .field-select" ).forEach( function( select ) {
|
|
105 select.addEventListener( "click", function( e ) {
|
|
106 e.stopPropagation();
|
|
107 this.parentElement.classList.toggle( "open" );
|
|
108
|
|
109 // это можно убрать если переставить стили на родителя
|
|
110 select.nextElementSibling.classList.toggle( "open" );
|
|
111 } );
|
|
112 } );
|
|
113 // Option for menu
|
|
114 document.querySelectorAll( "#menu .area-select-grid .field-options .option" ).forEach( function( option ) {
|
|
115 option.addEventListener( "click", function( e ) {
|
|
116 let input = this.closest( ".area-select-grid" ).querySelector( ".field-select-menu" );
|
|
117 let old_val = input.getAttribute( "data-menu-area" );
|
|
118 let new_val = this.getAttribute( "value" );
|
|
119 if ( old_val != new_val ) {
|
|
120 input.querySelector( ".value" ).innerText = this.innerText;
|
|
121 input.setAttribute( "data-menu-area", new_val );
|
|
122 // Событие изменения
|
|
123 let event = new Event( "input" );
|
|
124 input.dispatchEvent( event );
|
|
125 }
|
|
126 //e.stopPropagation(); убираем чтобы закрылось автоматически
|
|
127 } );
|
|
128 } );
|
|
129 // Option for item
|
|
130 document.querySelectorAll( "#menu .parent-select-grid .field-options .option" ).forEach( function( option ) {
|
|
131 option.addEventListener( "click", parent_li_click );
|
|
132 } );
|
|
133 function parent_li_click( e ) {
|
|
134 let input = this.closest( ".parent-select-grid" ).querySelector( ".field-select" );
|
|
135 let old_val = input.getAttribute( "data-parent" );
|
|
136 let new_val = this.getAttribute( "value" );
|
|
137 if ( old_val != new_val ) {
|
|
138 input.querySelector( ".value" ).innerText = this.innerText.trim();
|
|
139 input.setAttribute( "data-parent", new_val );
|
|
140 // Событие изменения
|
|
141 let event = new Event( "input" );
|
|
142 input.dispatchEvent( event );
|
|
143 }
|
|
144 //e.stopPropagation(); убираем чтобы закрылось автоматически
|
|
145 }
|
|
146
|
|
147 // Toggle Menu Properties
|
|
148 let prop_buttons = document.querySelectorAll( "#menu .menu-buttons .prop" );
|
|
149 prop_buttons.forEach( function( button ) {
|
|
150 button.addEventListener( "click", function( e ) {
|
|
151 e.stopPropagation();
|
|
152 this.closest( "[data-item]" ).classList.toggle( "open" );
|
|
153 } );
|
|
154 } );
|
|
155
|
|
156 // Отлавливать изменения полей в меню чтобы показать Сохранить
|
|
157 document.querySelectorAll( "#menu .menu" ).forEach( function( menu ) {
|
|
158 menu.querySelectorAll( "input, .field-select-menu" ).forEach( function( input ) {
|
|
159 input.addEventListener( "input", function( event ) {
|
|
160 let menu = this.closest( ".menu" );
|
|
161 menu.classList.add( "changed" );
|
|
162 } );
|
|
163 } );
|
|
164 } );
|
|
165
|
|
166 // Отлавливать изменения полей в пунктах чтобы показать Сохранить
|
|
167 document.querySelectorAll( "#menu .item" ).forEach( function( item ) {
|
|
168 item.querySelectorAll( "input, .field-select" ).forEach( function( input ) {
|
|
169 input.addEventListener( "input", function( event ) {
|
|
170 let item = this.closest( ".item" );
|
|
171 item.classList.add( "changed" );
|
|
172 } );
|
|
173 } );
|
|
174 } );
|
|
175
|
|
176 // Save Properties
|
|
177 document.querySelectorAll( "#menu .menu-buttons .save" ).forEach( function( button ) {
|
|
178 button.addEventListener( "click", function( e ) {
|
|
179 e.stopPropagation();
|
|
180
|
|
181 let item = this.closest( "[data-item]" );
|
|
182 let mid = item.getAttribute( "data-item" );
|
|
183
|
|
184 let area = item.querySelector( "[data-menu-area]" );
|
|
185 if ( area ) {
|
|
186 area = area.getAttribute( "data-menu-area" );
|
|
187 }
|
|
188
|
|
189 let tag_title = item.querySelector( "[name='tag_title']" );
|
|
190 if ( tag_title ) {
|
|
191 tag_title = tag_title.value;
|
|
192 }
|
|
193
|
|
194 let url = item.querySelector( "[name='url']" );
|
|
195 if ( url ) {
|
|
196 url = url.value;
|
|
197 }
|
|
198
|
|
199 let id = item.querySelector( "[name='id']" );
|
|
200 if ( id ) {
|
|
201 id = id.getAttribute( "data-id" );
|
|
202 }
|
|
203
|
|
204 let pid_el = item.querySelector( "[data-parent]" );
|
|
205 let pid,old_pid;
|
|
206 if ( pid_el ) {
|
|
207 pid = pid_el.getAttribute( "data-parent" );
|
|
208 old_pid = pid_el.getAttribute( "data-old-parent" );
|
|
209 }
|
|
210
|
|
211 let target = item.querySelector( "[name='targetblank']" );
|
|
212 if ( target ) {
|
|
213 target = target.checked;
|
|
214 }
|
|
215
|
|
216 let old_sort_el = item.querySelector( "[name='sort']" );
|
|
217 let old_sort = old_sort_el.getAttribute( "data-sort" );
|
|
218
|
|
219 let data = {
|
|
220 fn: "save_menu_item",
|
|
221 mid: mid,
|
|
222 title: item.querySelector( "[name='title']" ).value,
|
|
223 tag_title: tag_title,
|
|
224 url: url,
|
|
225 id: id,
|
|
226 pid: pid,
|
|
227 old_pid: old_pid,
|
|
228 classes: item.querySelector( "[name='classes']" ).value,
|
|
229 sort: item.querySelector( "[name='sort']" ).value,
|
|
230 area: area,
|
|
231 target: target
|
|
232 }
|
|
233 document.querySelectorAll( `#menu [data-item]` ).forEach( function( el ) {
|
|
234 el.classList.remove( "last-edited" );
|
|
235 } );
|
|
236 api( data, function( r ) {
|
|
237 if ( r.ok == "false" ) {
|
|
238 notify( r.info_text, r.info_class, r.info_time );
|
|
239 }
|
|
240 if ( r.ok == "true" ) {
|
|
241 item.classList.remove( "changed" );
|
|
242 let item_with_childs = item.parentElement;
|
|
243 if ( r.list ) {
|
|
244 set_menu_items( r );
|
|
245 } else if ( old_sort != data.sort ) {
|
|
246 // пересортировка имеет смысл если не было замены всего списка
|
|
247 // обновить сортировку для сравнения
|
|
248 old_sort_el.setAttribute( "data-sort", data.sort );
|
|
249 let grid;
|
|
250 if ( data.area === null ) {
|
|
251 grid = item.closest( ".items-grid" );
|
|
252 } else {
|
|
253 grid = item.closest( ".menu-grid" );
|
|
254 }
|
|
255 let before = null;
|
|
256 for ( let n = 0; n < grid.children.length; n++ ) {
|
|
257 let node = grid.children[n];
|
|
258 if ( node != item_with_childs ) {
|
|
259 let sort = node.querySelector( '[data-item] [name="sort"]' ).value;
|
|
260 if ( +data.sort < +sort ) {
|
|
261 before = node;
|
|
262 break;
|
|
263 }
|
|
264 }
|
|
265 };
|
|
266 grid.insertBefore( item_with_childs, before );
|
|
267 }
|
|
268
|
|
269 // Замена title
|
|
270 let title;
|
|
271 if ( data.title != "" )
|
|
272 title = data.title;
|
|
273 else
|
|
274 title = item.querySelector( ".select-grid .value" ).innerText;
|
|
275 item.querySelector( ":scope > a" ).innerText = title;
|
|
276
|
|
277 // обновить родителей у подпунктов
|
|
278 // поскольку мог измениться title
|
|
279 // и только у строго дочерних, которых может и не быть
|
|
280 let childs_grid = item.nextElementSibling;
|
|
281 if ( childs_grid ) {
|
|
282 let childs_selector = childs_grid.querySelectorAll( ":scope > div > .item .parent-select-grid" );
|
|
283
|
|
284 if ( childs_selector ) childs_selector.forEach( function( grid ) {
|
|
285 let input = grid.querySelector( "[data-parent]" );
|
|
286 let pid = input.getAttribute( "data-parent" );
|
|
287 let options = grid.querySelector( ":scope > .field-options" );
|
|
288 options.innerHTML = r.parents;
|
|
289 options.querySelectorAll( ".option" ).forEach( function( option ) {
|
|
290 option.addEventListener( "click", parent_li_click );
|
|
291 } );
|
|
292 // тайтл вычисляется выше
|
|
293 input.querySelector( ".value" ).innerText = title;
|
|
294 } );
|
|
295 }
|
|
296
|
|
297 // Last Edited Marker
|
|
298 setTimeout( function() {
|
|
299 document.querySelector( `#menu [data-item="${data.mid}"]` ).classList.add( "last-edited" );
|
|
300 }, 200 );
|
|
301 }
|
|
302 } );
|
|
303 } );
|
|
304 } );
|
|
305
|
|
306 // Delete Menu or Item
|
|
307 document.querySelectorAll( "#menu .menu-buttons .del" ).forEach( function( button ) {
|
|
308 button.addEventListener( "click", function( e ) {
|
|
309 e.stopPropagation();
|
|
310 clear_highlite();
|
|
311 let item = button.closest( ".item,.menu" ).parentNode;
|
|
312 item.classList.add( "will-be-deleted" );
|
|
313 setTimeout( function() {
|
|
314 if ( ! confirm( __( "confirm_delete", "menu.mod.php" ) ) ) {
|
|
315 item.classList.remove( "will-be-deleted" );
|
|
316 return;
|
|
317 }
|
|
318 let data = {
|
|
319 fn: "del_menu_item",
|
|
320 mid: button.closest( "[data-item]" ).getAttribute( "data-item" )
|
|
321 };
|
|
322 api( data, function( r ) {
|
|
323 if ( r.info_text ) {
|
|
324 notify( r.info_text, r.info_class, r.info_time );
|
|
325 if ( r.info_class == "info-success" ) {
|
|
326 set_menu_items( r );
|
|
327 }
|
|
328 }
|
|
329 } );
|
|
330 }, 20 );
|
|
331 } );
|
|
332 } );
|
|
333
|
|
334 // Create Item
|
|
335 document.querySelectorAll( "#menu .main-main .append" ).forEach( function( button ) {
|
|
336 button.addEventListener( "click", modMenuCreate );
|
|
337 } );
|
|
338
|
|
339 // Линия к родителю
|
|
340 let items = document.querySelectorAll( "#menu .item" );
|
|
341 items.forEach( function( el ) {
|
|
342 el.addEventListener( "click", function( e ) {
|
|
343 // Если опускание мыши было не на нас, то игнорим
|
|
344 if ( mouse_down_el != this ) return;
|
|
345 mouse_down_el = null;
|
|
346 let highlited = this.classList.contains( "highlite-children" );
|
|
347 clear_highlite();
|
|
348 // Назначить классы
|
|
349 if ( ! highlited ) {
|
|
350 this.classList.add( "highlite-children" );
|
|
351 this.closest( ".items-grid" ).classList.add( "highlite-parent" );;
|
|
352 }
|
|
353 } );
|
|
354 } );
|
|
355 // Опускание мыши
|
|
356 // Возможна ситуация когда нажатие мыши было на кнопке Свойства,
|
|
357 // а отпускание на плашке. В этом случае может появиться линия к родителю.
|
|
358 // Поэтому нужно записывать что опускание было на плашке или панельке кнопок.
|
|
359 let mouse_down_el; // элемент на котором было опускание мыши
|
|
360 items.forEach( function( el ) {
|
|
361 el.addEventListener( "mousedown", function( e ) {
|
|
362 // чтобы проигнорировать клики по дочерним
|
|
363 if ( e.target == this )
|
|
364 mouse_down_el = this;
|
|
365 } );
|
|
366 // див с кнопками можно тыкать
|
|
367 let mb = el.querySelector( ".menu-buttons" );
|
|
368 if ( mb ) mb.addEventListener( "mousedown", function( e ) {
|
|
369 // чтобы проигнорировать клики по дочерним
|
|
370 if ( e.target == this )
|
|
371 mouse_down_el = this.parentElement;
|
|
372 } );
|
|
373 } );
|
|
374 // Сбросить классы
|
|
375 function clear_highlite() {
|
|
376 document.querySelectorAll( "#menu .items-grid.highlite-parent" ).forEach( function( el ) {
|
|
377 el.classList.remove( "highlite-parent" );
|
|
378 } );
|
|
379 document.querySelectorAll( "#menu .item.highlite-children" ).forEach( function( el ) {
|
|
380 el.classList.remove( "highlite-children" );
|
|
381 } );
|
|
382 }
|
|
383
|
|
384 }
|
|
385
|
|
386 // Select
|
|
387 // Закрытие выпадающих списков при кликах вне их, а так же по ним
|
|
388 document.body.addEventListener( "click", function( e ) {
|
|
389 // это можно убрать если переставить стили на родителя
|
|
390 document.querySelectorAll( "#menu .field-options" ).forEach( function( list ) {
|
|
391 list.classList.remove( "open" );
|
|
392 } );
|
|
393
|
|
394 document.querySelectorAll( "#menu .area-select-grid, #menu .select-grid, #menu .parent-select-grid" ).forEach( function( list ) {
|
|
395 list.classList.remove( "open" );
|
|
396 } );
|
|
397 } );
|
|
398
|
|
399 // Создание меню или пункта меню
|
|
400 function modMenuCreate( e ) {
|
|
401 e.stopPropagation();
|
|
402 let pid = this.closest( "[data-item]" ).getAttribute( "data-item" );
|
|
403 api( { fn : "create_menu_item", pid : pid }, function( r ) {
|
|
404 if ( r.info_text ) {
|
|
405 notify( r.info_text, r.info_class, r.info_time );
|
|
406 if ( r.info_class == "info-success" ) {
|
|
407 set_menu_items( r );
|
|
408 let item = document.querySelector( `#menu [data-item="${r.mid}"]` );
|
|
409 item.classList.add( "open" );
|
|
410 item.classList.add( "last-edited" );
|
|
411 // Докрутить к новому элементу
|
|
412 item.scrollIntoView( { behavior: "smooth", block: "center" } );
|
|
413 }
|
|
414 }
|
|
415 } );
|
|
416 }
|
|
417
|
|
418 // Create Menu
|
|
419 document.querySelector( "#menu .main-footer .create" ).addEventListener( "click", modMenuCreate );
|
|
420
|
|
421 // update page used in menu
|
|
422 document.body.addEventListener( "update_menu", function( e ) {
|
|
423 api( { fn: "get_menu_items" }, set_menu_items );
|
|
424 } );
|
|
425
|
|
426 } );
|