Mercurial
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 = `<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 += ">"; | |
975 tag.innerHTML = link; | |
976 } else if ( mus.indexOf( e ) >= 0 ) { | |
977 link = `<audio src="${a}" controls></audio>`; | |
978 tag.innerHTML = link; | |
979 } else if ( vid.indexOf( e ) >= 0 ) { | |
980 link = `<video src="${a}" poster="" controls preload="none"></video>`; | |
981 tag.innerHTML = link; | |
982 } else { | |
983 link = `<a href="${a}">TEXT</a>`; | |
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 } ); |