comparison .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
comparison
equal deleted inserted replaced
-1:000000000000 0:78edf6b517a0
1 document.addEventListener( "DOMContentLoaded", function( event ) {
2
3 function _( str ) {
4 return __( str, "pages.mod.php" );
5 }
6
7 // Полностью этот скрипт отключить нельзя если включены Инструменты,
8 // поэтому нужна проверка
9 if ( document.querySelector( "#pages" ) ) {
10 api( { fn: "get_pages_list" }, set_pages_list );
11 }
12
13 function set_pages_list( r ) {
14
15 if ( ! document.querySelector( "#pages" ) ) return;
16
17 if ( r.no_database ) {
18 document.querySelector( "#pages .pages-grid" ).innerHTML = r.no_database;
19 return;
20 }
21
22 if ( r.overloaded ) {
23 let m = _( "server_overloaded_xxx" );
24 m = m.replace( "xxx", r.pages.length );
25 notify( m, "info-error", 5000 );
26 }
27
28 // Запоминаем результаты какого поиска мы получили
29 // Это нужно чтобы не загружать снова все страницы при создании новой
30 // не производить сброс поиска.
31 let pages_search = document.querySelector( "#pages .page-search" );
32 pages_search.setAttribute( "data-result-of", r.search );
33
34 let grid = document.querySelector( "#pages .pages-grid" );
35 let count = document.querySelector( "#pages .main-footer .count" );
36 let loaded = document.querySelector( "#pages .main-footer .loaded" );
37 if ( cms.clear_pages_list ) {
38 cms.clear_pages_list = false;
39 grid.innerHTML = "";
40 loaded.value = "0";
41 }
42
43 // Всего страниц в БД
44 count.innerText = r.count;
45
46 // При удалении страниц подгружаются последние и не нужно менять смещение у пейджера
47 if ( cms.dont_change_offset ) {
48 cms.dont_change_offset = false;
49 } else {
50 loaded.setAttribute( "data-offset", r.offset );
51 }
52
53 // insert pages
54 let start = Date.now();
55 for ( let i = 0; i < r.pages.length; i++ ) {
56 grid.insertAdjacentHTML( "beforeend", r.pages[i].html );
57 loaded.value = +loaded.value + 1;
58 let page = grid.querySelector( `[data-id="${r.pages[i].id}"]` );
59 set_controls( page );
60 if ( Date.now() - start > 1000 ) {
61 let m = _( "browser_overloaded_xxx" );
62 m = m.replace( "xxx", i + 1 );
63 m = m.replace( "nnn", r.pages.length );
64 notify( m, "info-error", 5000 );
65 break;
66 }
67 }
68
69 create_pager();
70
71 // При создании страницы было обнаружено что поиск не сброшен,
72 // поэтому была вызвана функция загрузки страниц с пустым поиском
73 // и пришло время создать новую страницу
74 if ( cms.create_page_fn ) {
75 cms.create_page_fn();
76 cms.create_page_fn = null;
77 }
78
79 }
80
81 function create_pager() {
82 let loaded = document.querySelector( "#pages .main-footer .loaded" );
83 let offset = parseInt( loaded.getAttribute( "data-offset" ) );
84 let count = parseInt( document.querySelector( "#pages .main-footer .count" ).innerText );
85 if ( count === 0 ) { count++; }
86 let cookie_pp = get_cookie( "pages_pager" );
87 let pages = Math.ceil( count / cookie_pp );
88 let pager = document.querySelector( "#pages .main-footer .pager" );
89 pager.innerHTML = "";
90 if ( pages > 1 ) {
91 for ( let i = 1; i <= pages; i++ ) {
92 let p = document.createElement( "div" );
93 p.innerText = i;
94 p.setAttribute( "data-offset", ( i - 1 ) * cookie_pp );
95 pager.appendChild( p );
96 }
97 pager.querySelector( `[data-offset="${offset}"]` ).classList.add( "active" );
98 pager.childNodes.forEach( function( el ) {
99 el.addEventListener( "click", function( e ) {
100 let offset = this.getAttribute( "data-offset" );
101 let search = document.querySelector( "#pages .page-search" ).value;
102 let data = {
103 fn: "get_pages_list",
104 offset: offset,
105 search: search
106 }
107 document.querySelector( "#pages .main-main" ).scrollTop = 0;
108 cms.clear_pages_list = true;
109 api( data, set_pages_list );
110 } );
111 } );
112 // scroll
113 pager.onmousedown = function( e ) {
114 let pageX = 0;
115 let pageY0 = 0;
116
117 document.onmousemove = function( e ) {
118 if ( pageX !== 0 ) {
119 pager.scrollLeft = pager.scrollLeft + ( pageX - e.pageX );
120 }
121 pageX = e.pageX;
122 // fix for google chrome
123 if ( pageY0 === 0 ) {
124 pageY0 = e.pageY;
125 }
126 if ( Math.abs( pageY0 - e.pageY ) > 64 ) {
127 const event = new Event( "mouseup" );
128 pager.dispatchEvent( event );
129 }
130 }
131
132 // end drag
133 pager.onmouseup = function() {
134 document.onmousemove = null;
135 pager.onmouseup = null;
136 }
137
138 // disable browser drag
139 pager.ondragstart = function() {
140 return false;
141 }
142 }
143 }
144 }
145
146 // pager counter
147 let pager_counter = document.querySelector( "#pages .main-footer input" );
148 if ( pager_counter ) pager_counter.addEventListener( "keydown", function( e ) {
149 if ( e.keyCode === 13 ) { // keyCode work on mobile
150 let p = document.querySelector( "#pages .main-footer input" ).value;
151 set_cookie_expires( "pages_pager", p );
152 cms.clear_pages_list = true;
153 api( { fn: "get_pages_list", search: document.querySelector( "#pages .page-search" ).value }, set_pages_list );
154 }
155 } );
156
157 function set_controls( selector ) {
158
159 // Open properties
160 selector.querySelectorAll( ".page-prop-btn" ).forEach( function( button ) {
161 button.addEventListener( "click", function( e ) {
162 let id = this.closest( "[data-id]" ).getAttribute( "data-id" );
163 document.querySelector( `#pages .pages-grid [data-id="${id}"]` ).classList.toggle( "open" );
164 } );
165 } );
166
167 // Save properties
168 selector.querySelectorAll( ".page-prop-save-btn" ).forEach( function( button ) {
169 button.addEventListener( "click", function( e ) {
170 let id = this.closest( "[data-id]" ).getAttribute( "data-id" );
171 let item = document.querySelector( `#pages .pages-grid [data-id="${id}"] ` );
172 let data = {
173 fn: "save_prop",
174 id: id,
175 title: item.querySelector( '[name="title"]' ).value,
176 seo_title: item.querySelector( '[name="seo_title"]' ).value,
177 url: item.querySelector( '[name="url"]' ).value,
178 date: item.querySelector( '[name="date"]' ).value,
179 time: item.querySelector( '[name="time"]' ).value,
180 template: item.querySelector( '.template-select-grid .field-select' ).getAttribute( "data-template" ),
181 old_template: item.querySelector( '.template-select-grid .field-select' ).getAttribute( "data-old-template" ),
182 description: item.querySelector( '[name="description"]' ).value,
183 tags: item.querySelector( '[name="tags"]' ).value,
184 }
185 api( data, function( r ) {
186 if ( r.ok == "false" ) { // FIXME: never fire
187 notify( r.info_text, r.info_class, 5000 );
188 }
189 if ( r.ok == "true" ) {
190
191 // Update Title, URL and Date
192 item.querySelector( ".page-name" ).innerHTML = r.title;
193 item.querySelector( ".page-name" ).setAttribute( "href", r.base_path + r.url );
194 update_home();
195 let url_el = item.querySelector( "[name=url]" );
196 if ( url_el.value != r.url ) {
197 notify( _( "url_changed" ), "info-error", 5000 );
198 }
199 url_el.value = r.url;
200 let date = item.querySelector( ".page-date" );
201 date.innerHTML = r.created;
202 if ( r.planned ) {
203 date.classList.add( "future" );
204 } else {
205 date.classList.remove( "future" );
206 }
207
208 // update old template
209 item.querySelector( '.template-select-grid .field-select' ).setAttribute( "data-old-template", data.template );
210
211 // edit marker
212 document.querySelectorAll( "#pages .pages-grid > div" ).forEach( function( el ) {
213 el.classList.remove( "last-edited" );
214 } );
215 setTimeout( function() {
216 item.classList.add( "last-edited" );
217 }, 200 );
218
219 // highlight save button
220 button.classList.add( "saved" );
221 setTimeout( function() {
222 button.classList.remove( "saved" );
223 }, 200 );
224
225 notify( r.info_text, r.info_class, 5000 );
226
227 // update event for menu
228 if ( r.update_menu == "true" ) {
229 let event = new Event( "update_menu" );
230 document.body.dispatchEvent( event );
231 }
232 }
233
234 } );
235 } );
236 } );
237
238 // Pin Page
239 selector.querySelectorAll( ".pin" ).forEach( function( pin ) {
240 pin.addEventListener( "click", function( e ) {
241 let box = this.closest( "[data-id]" );
242 let id = box.getAttribute( "data-id" );
243 let pin = box.getAttribute( "data-pin" );
244 if ( pin === "1" ) {
245 pin = "0";
246 } else {
247 pin = "1";
248 }
249 let data = {
250 fn: "page_pin",
251 id: id,
252 pin: pin
253 }
254 api( data, function( r ) {
255 if ( r.ok == "true" ) {
256 box.setAttribute( "data-pin", pin );
257 }
258 } );
259 } );
260 } );
261
262 // Publish Page
263 selector.querySelectorAll( ".published" ).forEach( function( pub ) {
264 pub.addEventListener( "click", function( e ) {
265 let box = this.closest( "[data-id]" );
266 let id = box.getAttribute( "data-id" );
267 let published = box.getAttribute( "data-published" );
268 if ( published === "1" ) {
269 published = "0";
270 } else {
271 published = "1";
272 }
273 let data = {
274 fn: "page_publish",
275 id: id,
276 published: published
277 }
278 api( data, function( r ) {
279 if ( r.ok == "true" ) {
280 box.setAttribute( "data-published", published );
281 if ( published == "1" ) {
282 pub.setAttribute( "title", _( "published" ) );
283 } else {
284 pub.setAttribute( "title", _( "unpublished" ) );
285 }
286 }
287 } );
288 } );
289 } );
290
291 // Edit page
292 selector.querySelectorAll( ".page-edit-btn" ).forEach( function( button ) {
293 button.addEventListener( "click", function( e ) {
294 button.classList.add( "loading" );
295 let id = this.closest( "[data-id]" ).getAttribute( "data-id" );
296 // get page from server
297 api( { fn: "get_page", id: id }, function( r ) {
298 button.classList.remove( "loading" );
299 if ( r.result == "ok" ) {
300 let title = document.querySelector( "#pages .page-editor-title" );
301 title.innerHTML = r.page.title;
302 title.setAttribute( "href", r.base_path + r.page.url );
303 let props = document.querySelector( "#pages .page-properties" );
304 props.querySelector( "input[name='title']" ).value = r.page.title;
305 props.querySelector( "input[name='url']" ).value = r.page.url;
306 props.querySelector( "input[name='seo_title']" ).value = r.page.seo_title;
307 props.querySelector( "textarea[name='description']" ).value = r.page.description;
308 props.querySelector( "textarea[name='tags']" ).value = r.page.tags;
309 props.querySelector( "input[name='date']" ).value = r.date;
310 props.querySelector( "input[name='time']" ).value = r.time;
311 let select = props.querySelector( ".template-select-grid" );
312 let options = select.querySelector( ".field-options" );
313 options.innerHTML = r.options;
314 let tpl = select.querySelector( ".field-select" );
315 tpl.setAttribute( "data-template", r.option );
316 tpl.setAttribute( "data-old-template", r.option );
317 tpl.querySelector( ".value" ).innerText = r.option_tr;
318 document.querySelector( "#pages .page-editor > textarea" ).value = r.page.text;
319 if ( r.page.modified != null ) { // prevent delete attribute
320 document.querySelector( "#pages .page-editor > textarea" ).setAttribute( "data-modified", r.page.modified );
321 }
322 document.querySelector( "#pages .save-page-button" ).setAttribute( "data-id", r.page.id );
323
324 options.querySelectorAll( ".option" ).forEach( function( option ) {
325 option.addEventListener( "click", click_select_option );
326 } );
327
328
329 // Images
330 document.querySelector( "#pages .link-file-tag" ).innerHTML = "";
331 document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" );
332 document.querySelector( "#pages .mediateka-files-grid" ).innerHTML = r.flist;
333 document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]" ).forEach( function( checkbox ) {
334 checkbox.addEventListener( "dblclick", img_check_dblclick );
335 checkbox.addEventListener( "change", img_rechecked );
336 } );
337 document.querySelectorAll( "#pages .file-block" ).forEach( function( block ) {
338 block.addEventListener( "click", img_click );
339 } );
340 document.querySelectorAll( "#pages .mediateka-files-grid img" ).forEach( function( img ) {
341 img.addEventListener( "dblclick", img_lbox );
342 } );
343
344 // Show Editor
345 document.querySelector( "#pages .page-editor-bg" ).classList.remove( "hidden" );
346 document.body.classList.add( "editor" ); // for notifications
347
348 // Connect Editor
349 codemirror_connect( "#pages .page-editor > textarea", "cm" );
350
351 // restore scroll and cursor position
352 let cursor = localStorage.getItem( "cursor_page_" + id );
353 if ( cursor ) {
354 cursor = JSON.parse( cursor );
355 window.cm.scrollTo( cursor.left, cursor.top );
356 window.cm.setCursor( { line:cursor.line, ch:cursor.ch } );
357 window.cm.refresh();
358 //window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } ); // fix glitch
359 }
360
361 // track changes
362 document.querySelector( "#pages .close-page-button" ).setAttribute( "data-changed", "false" );
363 document.querySelector( "#pages .page-editor-grid" ).setAttribute( "data-changed", "false" );
364 cm.on( "change", function( cm, change ) {
365 document.querySelector( "#pages .close-page-button" ).setAttribute( "data-changed", "true" );
366 document.querySelector( "#pages .page-editor-grid" ).setAttribute( "data-changed", "true" );
367 } );
368 // save scroll and cursor position
369 [ "cursorActivity", "scroll" ].forEach( function( event ) {
370 cm.on( event, function() {
371 let cursor = window.cm.getCursor();
372 let scroll = window.cm.getScrollInfo();
373 localStorage.setItem( "cursor_page_" + id, JSON.stringify( { line:cursor.line, ch:cursor.ch, left: scroll.left, top: scroll.top } ) );
374 } );
375 } );
376
377 // set focus to editor
378 cm.focus();
379
380 // Save Page Ctrl+S
381 document.documentElement.addEventListener( "keydown", CtrlS );
382
383 // open tags panel
384 if ( document.documentElement.offsetWidth >= 1024 ) {
385 document.querySelector( "#pages .page-editor-grid" ).classList.add( "tags-opened" );
386 }
387 }
388 } );
389 } );
390 } );
391
392 // Select
393 selector.querySelectorAll( ".field-select" ).forEach( function( select ) {
394 select.addEventListener( "click", function( e ) {
395 e.stopPropagation();
396 this.parentElement.classList.toggle( "open" );
397
398 // это можно убрать если переставить стили на родителя
399 select.nextElementSibling.classList.toggle( "open" );
400 } );
401 } );
402 // Option шаблона
403 // вынесено в функцию потому что динамическое изменение
404 selector.querySelectorAll( ".field-options .option" ).forEach( function( option ) {
405 option.addEventListener( "click", click_select_option );
406 } );
407
408 // Транслитерация URL
409 selector.querySelectorAll( ".url-translit" ).forEach( function( btn ) {
410 btn.addEventListener( "click", function( e ) {
411 let url = selector.querySelector( "input[name='title']" ).value;
412 let tr_url = url_translit( url );
413 this.previousElementSibling.value = tr_url;
414 } );
415 } );
416
417 // Выбор всех страниц двойным кликом
418 let check = selector.querySelector( `:scope > input[type=checkbox]` );
419 if ( check ) check.addEventListener( "dblclick", function( e ) {
420 let stat = ! this.checked;
421 document.querySelectorAll( "#pages .pages-grid > div > input[type=checkbox]" ).forEach( function( chbox ) {
422 chbox.checked = stat;
423 } );
424 } );
425
426 }
427
428 // Клик по опции выбора шаблона
429 function click_select_option( e ) {
430 let select = this.closest( ".template-select-grid" );
431 let value = this.getAttribute( "value" );
432 select_switch_to( select, value );
433 }
434
435 //
436 function select_switch_to( select, value ) {
437 let field_select = select.querySelector( ".field-select" );
438 let old_value = field_select.getAttribute( "data-template" );
439 if ( old_value != value ) {
440 let old_name = field_select.innerText;
441 let field_options = select.querySelector( ".field-options" );
442 let option = field_options.querySelector( `[value="${value}"]` );
443 field_select.querySelector( ".value" ).innerText = option.innerText;
444 field_select.setAttribute( "data-template", value );
445 option.remove();
446 let option_html = `<div class=option value="${old_value}">${old_name}</div>`;
447 field_options.insertAdjacentHTML( "afterbegin", option_html );
448 field_options.firstChild.addEventListener( "click", click_select_option );
449 }
450 }
451
452 // Select for editor
453 document.querySelectorAll( ".page-properties .field-select" ).forEach( function( select ) {
454 select.addEventListener( "click", function( e ) {
455 e.stopPropagation();
456 this.parentElement.classList.toggle( "open" );
457 // это можно убрать если переставить стили на родителя
458 select.nextElementSibling.classList.toggle( "open" );
459 } );
460 } );
461
462 // Select
463 // Закрытие выпадающих списков при кликах вне их, а так же по ним
464 document.body.addEventListener( "click", function( e ) {
465 document.querySelectorAll( "#pages .template-select-grid" ).forEach( function( list ) {
466 list.classList.remove( "open" );
467 } );
468
469 // это можно убрать если переставить стили на родителя
470 document.querySelectorAll( "#pages .field-options" ).forEach( function( list ) {
471 list.classList.remove( "open" );
472 } );
473 } );
474
475 // Search page
476 let pages_search = document.querySelector( "#pages .page-search" );
477 if ( pages_search ) pages_search.addEventListener( "keydown", function( e ) {
478 if ( e.keyCode === 13 ) {
479 // сохраняем событие целиком чтобы ниже считать Shift, Ctrl, Alt
480 cms.search_event = e;
481 search_pages();
482 }
483 } );
484
485 let search_btn = document.querySelector( "#pages .page-search-button" );
486 if ( search_btn ) search_btn.addEventListener( "click", function( e ) {
487 // клик по кнопке не дает Ctrl, Shift, Alt, запишем это
488 cms.search_event = { "ctrlKey": false, "shiftKey": false, "altKey": false };
489 search_pages();
490 document.querySelector( "#pages .page-search" ).focus();
491 } );
492
493 function search_pages() {
494 let search_string = document.querySelector( "#pages .page-search" ).value;
495 let data = {
496 fn: "get_pages_list",
497 search: search_string,
498 Ctrl: cms.search_event.ctrlKey,
499 Shift: cms.search_event.shiftKey,
500 Alt: cms.search_event.altKey,
501 };
502 cms.clear_pages_list = true;
503 api( data, set_pages_list );
504 }
505
506 // Reset Search
507 let reset_btn = document.querySelector( "#pages .reset" );
508 if ( reset_btn ) reset_btn.addEventListener( "click", function() {
509 document.querySelector( "#pages .page-search" ).value = "";
510 document.querySelector( "#pages .page-search-button" ).click();
511 } );
512
513 // Delete pages
514 document.querySelectorAll( "#pages .del-pages-btn" ).forEach( function( button ) {
515 button.addEventListener( "click", function( e ) {
516 let ids = [];
517 document.querySelectorAll( "#pages .pages-grid input[type=checkbox]:checked" ).forEach( function( ch ) {
518 let id = ch.closest( "[data-id]" ).getAttribute( "data-id" );
519 ids.push( id );
520 } );
521 if ( ids.length === 0 ) {
522 notify( _( "no_selected_pages" ), "info-error", 5000 );
523 return;
524 }
525 if ( ! confirm( _( "confirm_delete_pages" ) ) ) {
526 return;
527 }
528 let data = {
529 fn: "del_pages",
530 ids: ids
531 };
532 api( data, function( r ) {
533 if ( r.info_text ) {
534 notify( r.info_text, r.info_class, 5000 );
535 if ( r.info_class == "info-success" ) {
536 data.ids.forEach( function( id ) {
537 document.querySelector( `#pages .pages-grid [data-id="${id}"]` ).remove();
538 localStorage.removeItem( "cursor_page_" + id );
539 } );
540 let count = document.querySelector( "#pages .main-footer .count" );
541 let loaded = document.querySelector( "#pages .main-footer .loaded" );
542 loaded.value = parseInt( loaded.value ) - data.ids.length;
543 count.innerText = parseInt( count.innerText ) - data.ids.length;
544 // load pages
545 let offset = +loaded.getAttribute( "data-offset" ) + document.querySelectorAll( "#pages .pages-grid > *" ).length;
546 let search = document.querySelector( "#pages .page-search" ).value;
547 let data2 = {
548 fn: "get_pages_list",
549 count: data.ids.length,
550 offset: offset,
551 search: search
552 };
553 // Не менять атрибут смещения у пейджера
554 cms.dont_change_offset = true;
555 api( data2, set_pages_list );
556 }
557 }
558 // update event for menu
559 if ( r.update_menu == "true" ) {
560 let event = new Event( "update_menu" );
561 document.body.dispatchEvent( event );
562 }
563 } );
564 } );
565 } );
566
567 // copy file link button
568 document.querySelector( "#pages .link-file-copy-btn" ).addEventListener( "click", function( e ) {
569 let img = this.previousElementSibling.innerText;
570 let tmp = document.createElement( "textarea" );
571 document.body.appendChild( tmp );
572 tmp.value = img;
573 tmp.select();
574 let r = document.execCommand( "copy" );
575 tmp.remove();
576 if ( r ) {
577 if ( img ) {
578 notify( _( "copyed" ), "info-success", 5000 );
579 } else {
580 notify( _( "select_file" ), "info-error", 5000 );
581 }
582 } else {
583 notify( _( "copy_error" ), "info-error", 5000 );
584 }
585 cm.focus();
586 } );
587
588 function CtrlS( e ) {
589 // ы and і - fix for librewolf
590 if ( ( e.code == "KeyS" || e.key == "ы" || e.key == "і" ) && e.ctrlKey == true ) {
591 e.preventDefault(); // don't save page
592 if ( window.location.hash == "#pages" ) {
593 document.querySelector( "#pages .save-page-button" ).click();
594 }
595 }
596 /*/ Ловим кнопки codemirror
597 if ( e.code == "F1" ) {
598 let dialog = document.querySelector( ".CodeMirror-dialog-top" );
599 let html = dialog.outerHTML;
600 cms.dialog = html;
601 //notify( html, "info-success", 5000000 );
602 }
603 if ( e.code == "F2" ) {
604 document.querySelector( ".CodeMirror" ).insertAdjacentHTML( "beforeend", cms.dialog );
605 }
606 */
607 }
608
609 // Save Page
610 document.querySelectorAll( "#pages .save-page-button" ).forEach( function( button ) {
611 button.addEventListener( "click", function( e ) {
612 window.cm.save(); // drop changes to textarea
613 let main_div = document.querySelector( "#pages" );
614 let prop_div = main_div.querySelector( ".page-properties" );
615 let data = {
616 fn: "save_page",
617 id: main_div.querySelector( ".save-page-button" ).getAttribute( "data-id" ),
618 modified: main_div.querySelector( ".page-editor > textarea" ).getAttribute( "data-modified" ),
619 text: main_div.querySelector( ".page-editor > textarea" ).value,
620 title: prop_div.querySelector( "input[name='title']" ).value,
621 url: prop_div.querySelector( "input[name='url']" ).value,
622 seo_title: prop_div.querySelector( "input[name='seo_title']" ).value,
623 description: prop_div.querySelector( "textarea[name='description']" ).value,
624 tags: prop_div.querySelector( "textarea[name='tags']" ).value,
625 date: prop_div.querySelector( "input[name='date']" ).value,
626 time: prop_div.querySelector( "input[name='time']" ).value,
627 template: prop_div.querySelector( ".template-select-grid .field-select" ).getAttribute( "data-template" ),
628 old_template: prop_div.querySelector( ".template-select-grid .field-select" ).getAttribute( "data-old-template" ),
629 }
630 api( data, function( r ) {
631 if ( r.ok == "true" ) {
632 // set text
633 if ( r.new_text ) {
634 window.cm.setValue( r.new_text );
635 }
636
637 // Update Title and URL
638 main_div.querySelector( ".page-editor-title" ).innerHTML = r.title;
639 main_div.querySelector( ".page-editor-title" ).setAttribute( "href", r.base_path + r.url );
640 prop_div.querySelector( "input[name='url']" ).value = r.url;
641
642 // update old template
643 prop_div.querySelector( ".template-select-grid .field-select" ).setAttribute( "data-old-template", data.template );
644
645 // Update item in page list
646 let item = main_div.querySelector( `.pages-grid [data-id='${data.id}']` );
647 item.querySelector( `.page-name` ).innerHTML = r.title;
648 item.querySelector( `.page-name` ).setAttribute( "href", r.base_path + r.url );
649 update_home();
650 item.querySelector( `input[name='title']` ).value = r.title;
651 item.querySelector( `input[name='url']` ).value = r.url;
652 item.querySelector( `input[name='seo_title']` ).value = data.seo_title;
653 item.querySelector( `textarea[name='description']` ).value = data.description;
654 item.querySelector( `textarea[name='tags']` ).value = data.tags;
655
656 // Выставить шаблон в плашке в списке страниц
657 let select = item.querySelector( `.template-select-grid` );
658 select_switch_to( select, data.template );
659 item.querySelector( `.template-select-grid .field-select` ).setAttribute( "data-old-template", data.template );
660
661 item.querySelector( `input[name='date']` ).value = data.date;
662 item.querySelector( `input[name='time']` ).value = data.time;
663 if ( r.planned ) {
664 item.querySelector( `.page-date` ).classList.add( "future" );
665 } else {
666 item.querySelector( `.page-date` ).classList.remove( "future" );
667 }
668
669 main_div.querySelector( ".page-editor > textarea" ).setAttribute( "data-modified", r.modified );
670 main_div.querySelector( ".close-page-button" ).setAttribute( "data-changed", "false" );
671 main_div.querySelector( ".page-editor-grid" ).setAttribute( "data-changed", "false" );
672 // edit marker
673 main_div.querySelectorAll( ".pages-grid > div" ).forEach( function( item ) {
674 item.classList.remove( "last-edited" );
675 } );
676 item.classList.add( "last-edited" );
677 // close editor after save
678 if ( main_div.querySelector( ".save-page-button" ).getAttribute( "data-close" ) === "true" ) {
679 main_div.querySelector( ".save-page-button" ).setAttribute( "data-close", "false" );
680 main_div.querySelector( ".close-page-button" ).click();
681 }
682 // highlight save button
683 main_div.querySelector( ".save-page-button" ).classList.add( "saved" );
684 setTimeout( function() {
685 main_div.querySelector( ".save-page-button" ).classList.remove( "saved" );
686 }, 1000 );
687
688 notify( r.info_text, r.info_class, r.info_time );
689
690 // update event for menu
691 if ( r.update_menu == "true" ) {
692 let event = new Event( "update_menu" );
693 document.body.dispatchEvent( event );
694 }
695 }
696 if ( r.ok == "false" ) {
697 // highlight save button
698 main_div.querySelector( ".save-page-button" ).classList.add( "error" );
699 setTimeout( function() {
700 main_div.querySelector( ".save-page-button" ).classList.remove( "error" );
701 }, 1000 );
702
703 notify( r.info_text, r.info_class, r.info_time );
704 }
705 } );
706 } );
707 } );
708
709 // transliterate file name
710 function __tr_file( str ) {
711 let ext = str.match( /\.[^\.]+$/, "" );
712 str = str.replace( /\.[^\.]+$/, "" );
713 let sp = cms.tr[" "];
714 cms.tr[" "] = "_";
715 for ( let i in cms.tr ) {
716 let re = new RegExp( i, "g" );
717 str = str.replace( re, cms.tr[i] );
718 }
719 if ( sp === undefined ) {
720 delete cms.tr[" "];
721 } else {
722 cms.tr[" "] = sp;
723 }
724 str = str.replace( /[^-A-Za-z0-9_]+/g, "" );
725 if ( ext[0] ) {
726 str = str + ext[0];
727 }
728 str = str.toLowerCase();
729 return str;
730 }
731
732 // Upload files
733 let upload_btn = document.querySelector( "#pages .upload-files input[type=file]" );
734 if ( upload_btn ) upload_btn.addEventListener( "change", async function( event ) {
735 const formData = new FormData();
736 let id = document.querySelector( "#pages .save-page-button" ).getAttribute( "data-id" );
737 formData.append( "id", id );
738 formData.append( "fn", "upload_files" );
739 let n = 0;
740 for ( let i = 0; i < this.files.length; i++ ) {
741 formData.append( "myfile[]", this.files[i] );
742 let f = `${cms.base_path}uploads/${id}/` + __tr_file( this.files[i].name );
743 let f_exists = document.querySelector( `#pages .file-block [data-src="${f}"]` );
744 if ( f_exists ) { n++; }
745 }
746 let google_chrome_fix = this;
747 if ( n ) {
748 let c = confirm( _( "same_files" ) + ` - ${n} ` + _( "pc" ) + "\n" + _( "confirm_replace" ) );
749 if ( ! c ) {
750 google_chrome_fix.value = "";
751 return c;
752 }
753 }
754 let bar = document.querySelector( "#pages .upload-progress" );
755
756
757 let ajax = new XMLHttpRequest();
758
759 ajax.upload.addEventListener( "progress", function( event ) {
760 let percent = Math.round( (event.loaded / event.total) * 100 );
761 bar.style.width = percent + "%";
762 }, false );
763
764 ajax.addEventListener( "error", function( event ) {
765 notify( _( "error_upload_file" ), "info-error", 3600000 );
766 bar.style = "";
767 }, false );
768
769 ajax.addEventListener( "abort", function( event ) {
770 notify( _( "error_upload_file" ), "info-error", 3600000 );
771 bar.style = "";
772 }, false );
773
774 ajax.addEventListener( "load", function( event ) {
775 bar.style = "";
776 google_chrome_fix.value = "";
777 if ( event.target.status == 413 ) {
778 notify( _( "too_large" ), "info-error", 5000 );
779 } else {
780 let r = JSON.parse( event.target.responseText );
781 if ( r.info_text ) {
782 notify( r.info_text, r.info_class, r.info_time );
783 if ( r.info_class == "info-success" ) {
784
785 // удалить файлы которые были обновлены
786 let tmp = document.createElement( "div" );
787 tmp.innerHTML = r.flist;
788 let imgs = tmp.querySelectorAll( "img" );
789 imgs.forEach( function( img ) {
790 let file = img.getAttribute( "data-src" );
791 let exists_file = document.querySelector( `#pages .file-block [data-src="${file}"]` );
792 if ( exists_file ) {
793 exists_file.parentElement.remove();
794 }
795 } );
796
797 let container = document.querySelector( "#pages .mediateka-files-grid" );
798 container.innerHTML = r.flist + container.innerHTML;
799
800 // images checkboxes
801 container.querySelectorAll( "input[type=checkbox]" ).forEach( function( checkbox ) {
802 checkbox.addEventListener( "dblclick", img_check_dblclick );
803 checkbox.addEventListener( "change", img_rechecked );
804 } );
805
806 // open lightbox
807 container.querySelectorAll( "img" ).forEach( function( img ) {
808 img.addEventListener( "dblclick", img_lbox );
809 } );
810
811 // generate link
812 container.querySelectorAll( ".file-block" ).forEach( function( file_block ) {
813 file_block.addEventListener( "click", img_click );
814 } );
815
816 // select last uploaded
817 container.querySelector( ".file-block" ).click();
818 }
819 }
820 }
821 }, false );
822
823 ajax.open( "POST", cms.api );
824 ajax.send( formData );
825
826 } );
827
828 // Close Editor
829 document.querySelectorAll( "#pages .close-page-button" ).forEach( function( button ) {
830 button.addEventListener( "click", function( e ) {
831
832 // hide mediateka
833 if ( ! document.querySelector( "#pages .page-editor-panel" ).classList.contains( "hidden" ) ) {
834 document.querySelector( "#pages .open-mediateka" ).click();
835 }
836
837 // hide editor
838 document.querySelector( "#pages .page-editor-bg" ).classList.add( "hidden" );
839 document.body.classList.remove( "editor" );
840
841 document.documentElement.removeEventListener( "keydown", CtrlS );
842
843 // detach
844 if ( window.cm !== undefined ) {
845 if ( this.getAttribute( "data-changed" ) === "true" ) {
846 if ( confirm( _( "confirm_save" ) ) ) {
847 document.querySelector( "#pages .save-page-button" ).setAttribute( "data-close", "true" );
848 document.querySelector( "#pages .save-page-button" ).click();
849 return;
850 }
851 }
852 window.cm.toTextArea();
853 window.cm = null;
854 }
855
856 } );
857 } );
858
859 // Create Page
860 document.querySelectorAll( "#pages .add-page-btn" ).forEach( function( btn ) {
861 btn.addEventListener( "click", function ( e ) {
862 // Отложенный вызов на случай если нужно очистить поиск
863 cms.create_page_fn = function() {
864 api( { fn: "create_page" }, function( r ) {
865 if ( r.info_text ) {
866 notify( r.info_text, r.info_class, r.info_time );
867 }
868 if ( r.pages ) {
869 let grid = document.querySelector( "#pages .pages-grid" );
870 grid.insertAdjacentHTML( "afterbegin", r.pages[0].html );
871 // Подкрутить список страниц в начало
872 document.querySelector( "#pages .main-main" ).scrollTop = 0;
873
874 let page_box = grid.querySelector( `[data-id="${r.pages[0].id}"]` );
875
876 set_controls( page_box );
877
878 let counter = document.querySelector( "#pages .main-footer .count" );
879 counter.innerText = +counter.innerText + 1;
880
881 let showed_pages_el = document.querySelector( "#pages .main-footer .counters input" );
882 if ( showed_pages_el.value === get_cookie( "pages_pager" ) ) {
883 document.querySelector( "#pages .pages-grid > div:last-child" ).remove();
884 } else {
885 showed_pages_el.value = +showed_pages_el.value + 1;
886 }
887 }
888 } );
889 }
890 // Если сейчас не результаты поиска отображены,
891 // и если мы видим первый пейджер
892 // то сразу выполнить создание страницы
893 let empty_search = document.querySelector( "#pages .page-search" ).getAttribute( "data-result-of" ) === "";
894 let offset_zero = +document.querySelector( "#pages .main-footer .counters input" ).getAttribute( "data-offset" ) === 0;
895 if ( empty_search && offset_zero ) {
896 cms.create_page_fn();
897 cms.create_page_fn = null;
898 } else {
899 document.querySelector( "#pages .reset" ).click();
900 // Создание страницы произведет функция set_pages_list()
901 }
902 } );
903 } );
904
905 // Open Properties
906 document.querySelector( "#pages .open-properties" ).addEventListener( "click", function( e ) {
907 document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "properties" );
908 document.querySelector( "#pages .page-properties" ).classList.toggle( "hidden" );
909 if ( window.cm ) {
910 let cursor = window.cm.getCursor();
911 window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
912 }
913 if ( document.querySelector( "#pages .page-editor-grid" ).classList.contains( "properties" ) ) {
914 document.querySelector( "#pages .page-editor-grid" ).classList.remove( "mediateka" );
915 document.querySelector( "#pages .page-editor-panel" ).classList.add( "hidden" );
916 }
917 } );
918
919 // Open Mediateka
920 document.querySelector( "#pages .open-mediateka" ).addEventListener( "click", function( e ) {
921 document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "mediateka" );
922 document.querySelector( "#pages .page-editor-panel" ).classList.toggle( "hidden" );
923 if ( window.cm ) {
924 let cursor = window.cm.getCursor();
925 window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
926 }
927 if ( document.querySelector( "#pages .page-editor-grid" ).classList.contains( "mediateka" ) ) {
928 document.querySelector( "#pages .page-editor-grid" ).classList.remove( "properties" );
929 document.querySelector( "#pages .page-properties" ).classList.add( "hidden" );
930 }
931 cm.focus();
932 } );
933
934 // Replace Dialog Toggle
935 document.querySelector( "#pages .codemirror-replace" ).addEventListener( "click", function( e ) {
936 let dialog = document.querySelector( "#pages .CodeMirror-dialog" );
937 if ( dialog ) {
938 dialog.remove();
939 } else {
940 let mediateka = ! document.querySelector( "#pages .page-editor-panel" ).classList.contains( "hidden" );
941 if ( mediateka && window.innerWidth < 1024 ) {
942 document.querySelector( "#pages .open-mediateka" ).click();
943 }
944 window.cm.execCommand( "replace" );
945 }
946 } );
947
948 // generate link to clicked file
949 function img_click() {
950 this.parentElement.querySelectorAll( ".file-block" ).forEach( function( block ) {
951 block.classList.remove( "active-file" );
952 } );
953 this.classList.add( "active-file" );
954 let i = this.querySelector( "img" );
955 let t = i.getAttribute( "data-type" );
956 let link = i.getAttribute( "data-src" );
957 let w = i.getAttribute( "width" );
958 let h = i.getAttribute( "height" );
959 let e = link.replace( /.*\./, "" );
960 let img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ];
961 let mus = [ "mp3", "ogg", "m4a", "flac" ];
962 let vid = [ "mp4", "mkv", "webm" ];
963 let a = `<a href="${link}" target=_blank>${link}</a>`;
964 let tag = this.closest( ".mediateka-grid" ).querySelector( ".link-file-tag" );
965 if ( img.indexOf( e ) >= 0 ) {
966 link = `&lt;img alt="" src="${a}"`;
967 if ( w ) {
968 link += ` width="${w}"`;
969 }
970 if ( h ) {
971 link += ` height="${h}"`;
972 }
973 link += ` loading="lazy"`;
974 link += "&gt;";
975 tag.innerHTML = link;
976 } else if ( mus.indexOf( e ) >= 0 ) {
977 link = `&lt;audio src="${a}" controls>&lt;/audio>`;
978 tag.innerHTML = link;
979 } else if ( vid.indexOf( e ) >= 0 ) {
980 link = `&lt;video src="${a}" poster="" controls preload="none">&lt;/video>`;
981 tag.innerHTML = link;
982 } else {
983 link = `&lt;a href="${a}"&gt;TEXT&lt;/a&gt;`;
984 tag.innerHTML = link;
985 }
986 let inner_link = tag.querySelector( "a" );
987 inner_link.addEventListener( "click", file_link_click );
988 cm.focus();
989 }
990
991 function file_link_click( e ) {
992 e.preventDefault();
993 let tmp = document.createElement( "textarea" );
994 document.body.appendChild( tmp );
995 tmp.value = e.target.getAttribute( "href" );
996 tmp.select();
997 let r = document.execCommand( "copy" );
998 tmp.remove();
999 if ( r ) {
1000 notify( _( "copyed" ), "info-success", 5000 );
1001 } else {
1002 notify( _( "copy_error" ), "info-error", 5000 );
1003 }
1004 cm.focus();
1005 }
1006
1007 // enable or disable delete files button
1008 function img_rechecked() {
1009 let checked = document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]:checked" );
1010 if ( checked.length ) {
1011 document.querySelector( "#pages .del-uploaded-files" ).classList.remove( "disabled" );
1012 } else {
1013 document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" );
1014 }
1015 }
1016
1017 // Выбор всех картинок двойным кликом
1018 function img_check_dblclick( e ) {
1019 let stat = ! this.checked;
1020 document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]" ).forEach( function( chbox ) {
1021 chbox.checked = stat;
1022 } );
1023 img_rechecked();
1024 }
1025
1026 // view in lightbox
1027 function img_lbox() {
1028 let src = this.getAttribute( "data-src" );
1029 let e = src.replace( /.*\./, "" );
1030 let img = [ "webp", "tiff", "jpeg", "jpg", "png", "svg", "gif", "bmp", "ico" ];
1031 let mus = [ "mp3", "ogg", "m4a", "flac" ];
1032 let vid = [ "mp4", "mkv", "webm" ];
1033 let t;
1034 if ( document.querySelector( "#lbox-window" ) == null ) {
1035 if ( img.indexOf( e ) >= 0 ) {
1036 t = document.createElement( "img" );
1037 } else if ( mus.indexOf( e ) >= 0 ) {
1038 t = document.createElement( "audio" );
1039 t.setAttribute( "controls", true );
1040 } else if ( vid.indexOf( e ) >= 0 ) {
1041 t = document.createElement( "video" );
1042 t.setAttribute( "controls", true );
1043 }
1044 if ( t !== undefined ) {
1045 t.src = src;
1046 let d = document.createElement( "div" );
1047 d.id = "lbox-window";
1048 d.appendChild( t );
1049 document.body.appendChild( d );
1050 d.addEventListener( "click", function( e ) {
1051 this.remove();
1052 } );
1053 }
1054 }
1055 }
1056
1057
1058 // Delete files
1059 document.querySelector( "#pages .del-uploaded-files" ).addEventListener( "click", function( e ) {
1060 if ( ! this.classList.contains( "disabled" ) ) {
1061 let flist = [];
1062 document.querySelectorAll( "#pages .mediateka-files-grid input[type=checkbox]:checked" ).forEach( function( e ) {
1063 let f = e.closest( ".file-block" ).querySelector( "img" ).getAttribute( "data-src" );
1064 flist.push( f );
1065 } );
1066 let data = {
1067 fn: "del_files",
1068 flist: flist
1069 };
1070 api( data, function( r ) {
1071 if ( r.info_text ) {
1072 document.querySelector( "#pages .link-file-tag" ).innerHTML = "";
1073 notify( r.info_text, r.info_class, r.info_time );
1074 if ( r.info_class == "info-success" ) {
1075 for ( let f in flist ) {
1076 document.querySelector( `#pages .mediateka-files-grid img[data-src="${flist[f]}"]` ).parentElement.remove();
1077 }
1078 document.querySelector( "#pages .del-uploaded-files" ).classList.add( "disabled" );
1079 }
1080 }
1081 } );
1082 }
1083 } );
1084
1085 // prevent hide cursor when window resize
1086 window.addEventListener( "resize", function() {
1087 if ( window.cm ) {
1088 let cursor = window.cm.getCursor();
1089 window.cm.scrollIntoView( { line:cursor.line, ch:cursor.ch } );
1090 }
1091 } );
1092
1093 // show/hide tags
1094 let tags_btn = document.querySelector( "#pages .tags-helper" );
1095 if ( tags_btn ) tags_btn.addEventListener( "click", function( e ) {
1096 document.querySelector( "#pages .page-editor-grid" ).classList.toggle( "tags-opened" );
1097 cm.focus();
1098 cm.refresh();
1099 } );
1100
1101 // for tags
1102 document.querySelectorAll( "#pages .tags-grid [data-type='wrap']" ) .forEach( function( btn ) {
1103 btn.addEventListener( "click", function( e ) {
1104 let otag = this.getAttribute( "data-otag" );
1105 let ctag = this.getAttribute( "data-ctag" );
1106 let len = this.getAttribute( "data-len" );
1107 let ch = this.getAttribute( "data-ch" );
1108 let line = this.getAttribute( "data-line" );
1109
1110 //wrap_selections( otag, ctag, len, line, ch );
1111 let cursor = cm.getCursor();
1112 let selections = cm.getSelections();
1113 let replacements = [];
1114 for ( let i = 0; i < selections.length; i++ ) {
1115 replacements[i] = otag + selections[i] + ctag;
1116 }
1117 cm.replaceSelections( replacements );
1118 // Прятять панельку на мобильнике
1119 if ( window.innerWidth < 1024 ) {
1120 //document.querySelector( "#pages .tags-helper" ).click();
1121 let grid = this.closest( ".editor-grid" );
1122 grid.classList.remove( "tags-opened" );
1123 }
1124 if ( selections.length < 2 ) {
1125 if ( line ) {
1126 cursor.line += +line;
1127 cursor.ch = +ch;
1128 } else if ( len ) {
1129 cursor.ch += +len;
1130 }
1131 cm.setCursor( cursor );
1132 }
1133 cm.focus();
1134 cm.refresh();
1135 } );
1136 } );
1137 // for <a> tag
1138 document.querySelectorAll( "#pages .tags-grid [data-type='wrap-a']" ) .forEach( function( btn ) {
1139 btn.addEventListener( "click", function( e ) {
1140 let cursor = cm.getCursor();
1141 let selections = cm.getSelections();
1142 let replacements = [];
1143
1144 for ( let i = 0; i < selections.length; i++ ) {
1145 if ( selections[i].match( /https?:\/\// ) ) {
1146 replacements[i] = `<a href="${selections[i]}" target=_blank>${selections[i]}</a>`;
1147 } else {
1148 replacements[i] = `<a href="" target=_blank>${selections[i]}</a>`;
1149 }
1150 }
1151
1152 cm.replaceSelections( replacements );
1153
1154 if ( selections.length == 1 && selections[0] === "" ) {
1155 cursor.ch += 9;
1156 cm.setCursor( cursor );
1157 }
1158
1159 if ( window.innerWidth < 1024 ) {
1160 //document.querySelector( "#pages .tags-helper" ).click();
1161 let grid = this.closest( ".editor-grid" );
1162 grid.classList.remove( "tags-opened" );
1163 }
1164
1165 cm.focus();
1166 cm.refresh();
1167 } );
1168 } );
1169 // for tags <ul> and <ol>
1170 document.querySelectorAll( "#pages .tags-grid [data-type='wrap-list']" ) .forEach( function( btn ) {
1171 btn.addEventListener( "click", function( e ) {
1172 let tag = this.getAttribute( "data-tag" );
1173 let selections = cm.getSelections();
1174 let replacements = [];
1175
1176 if ( selections.length == 1 && selections[0] === "" ) {
1177 replacements[0] = `<${tag}>\n <li></li>\n</${tag}>`;
1178 } else if ( selections.length == 1 ) {
1179 let lines = selections[0].split( "\n" );
1180 replacements[0] = `<${tag}>\n <li>` + lines.join( "</li>\n <li>" ) + `</li>\n</${tag}>`;
1181 } else {
1182 let n = selections.length - 1;
1183 for ( let i = 0; i <= n; i++ ) {
1184 replacements[i] = ` <li>${selections[i]}</li>`;
1185 }
1186 replacements[0] = `<${tag}>\n` + replacements[0];
1187 replacements[n] = replacements[n] + `\n</${tag}>`;
1188 }
1189
1190 cm.replaceSelections( replacements );
1191
1192 if ( window.innerWidth < 1024 ) {
1193 //document.querySelector( "#pages .tags-helper" ).click();
1194 let grid = this.closest( ".editor-grid" );
1195 grid.classList.remove( "tags-opened" );
1196 }
1197
1198 cm.focus();
1199 cm.refresh();
1200 } );
1201 } );
1202
1203 // fix glitches codemirror
1204 let fix = document.querySelector( "aside a[href='#pages']" );
1205 if ( fix ) fix.addEventListener( "click", function( e ) {
1206 setTimeout( function( e ) {
1207 if ( window.cm ) {
1208 cm.refresh();
1209 cm.focus();
1210 }
1211 }, 50 );
1212 } );
1213
1214 // Транслитерация URL
1215 let tr_url = document.querySelector( "#pages .page-editor-grid .url-translit" );
1216 if ( tr_url ) tr_url.addEventListener( "click", function( e ) {
1217 let url = document.querySelector( "#pages .page-editor-grid .page-properties input[name='title']" ).value;
1218 let tr_url = url_translit( url );
1219 this.previousElementSibling.value = tr_url;
1220 } );
1221 function url_translit( url ) {
1222 url = url.toLowerCase();
1223 for ( let i in cms.tr ) {
1224 let re = new RegExp( i, "g" );
1225 url = url.replace( re, cms.tr[i] );
1226 }
1227 url = url.replace( / +/g, "-" );
1228 url = url.replace( /[^-a-z0-9_]+/g, "" );
1229 url = url.replace( /^[-_]+|[-_]+$/g, "" );
1230 return url;
1231 }
1232
1233 function update_home() {
1234 document.querySelectorAll( `#pages .pages-grid [data-id]` ).forEach( function( page ) {
1235 if ( page.querySelector( `.page-name[href="${cms.base_path}"]` ) ) {
1236 page.classList.add( "home" );
1237 } else {
1238 page.classList.remove( "home" );
1239 }
1240 } );
1241 }
1242
1243
1244 // Замена текста на всех страницах
1245 document.querySelectorAll( "#pages-utils .replace-btn" ).forEach( function( button ) {
1246 button.addEventListener( "click", function( e ) {
1247 let data = {
1248 fn: "replace_in_pages",
1249 table: document.querySelector( "#pages-utils input[name='table']" ).value,
1250 id_col: document.querySelector( "#pages-utils input[name='id_col']" ).value,
1251 column: document.querySelector( "#pages-utils input[name='column']" ).value,
1252 search_regex: document.querySelector( "#pages-utils input[name='search_regex']" ).value,
1253 replace: document.querySelector( "#pages-utils input[name='replace']" ).value,
1254 };
1255 if ( data.search_regex && confirm( _( "replace_in_pages_confirm" ) ) ) {
1256 api( data, function( r ) {
1257 if ( r.info_text ) {
1258 notify( r.info_text, r.info_class, r.info_time );
1259 }
1260 } );
1261 }
1262 } );
1263 } );
1264
1265 } );