1 2// admin_shared.js 3// SdÃlené funkce pro administraci (ostrou i inline) - pÅenositelné s adminem 4 5// Force cache bust for CKEditor configuration and plugins 6if (typeof CKEDITOR !== 'undefined') { 7 CKEDITOR.timestamp = 'v20260325_4'; 8} 9 10/** 11 * Inicializace CKEditoru s poÄÃtadlem znaků a sanitizacà 12 * @param {string} editorId - ID textarea elementu 13 * @param {string} counterId - ID inputu pro zobrazenà poÄtu znaků 14 * @param {number} maxChars - Maximálnà povolený poÄet znaků (0 = bez limitu) 15 * @param {string} type - Typ editoru ('micro', 'mini', 'full') - default 'mini' 16 * @returns {object} Instance editoru 17 */ 18function initCkEditorWithCount(editorId, counterId, maxChars, type) { 19 if (typeof CKEDITOR === 'undefined') return null; 20 21 // Pokud instance již existuje, zniÄit ji (prevence problémů pÅi opÄtovném otevÅenà modálnÃho okna) 22 if (CKEDITOR.instances[editorId]) { 23 try { 24 CKEDITOR.instances[editorId].destroy(true); 25 } catch (e) { 26 console.warn('NepodaÅilo se zniÄit instanci CKEditoru:', e); 27 } 28 } 29 30 type = type || 'mini'; 31 var toolbarName = 'full'; // default fallback 32 33 // Konfigurace toolbarů dle typu (odkazuje na definice v config.js) 34 if (type === 'micro') { 35 toolbarName = 'micro'; 36 } else if (type === 'mini') { 37 toolbarName = 'mini'; 38 } else if (type === 'full') { 39 toolbarName = 'full'; 40 } 41 42 // Nastavenà konfigurace instance 43 var config = { 44 customConfig: '/admin/ckeditor/config.js?v=20260325_24', 45 language: 'cs', 46 // Toolbar reference defined in config.js 47 toolbar: toolbarName, 48 removePlugins: 'elementspath,sharedspace', 49 elementspath: false, // Explicitly disable elementspath 50 extraPlugins: 'thvlozeni', 51 resize_enabled: false, // Generally disable resize handle bar 52 // Konfigurace KCFinderu (pro upload obrázků) - platà obecnÄ 53 filebrowserBrowseUrl: 'ckeditor/plugins/kcfinder/browse.php?type=soubory&lang=cs', 54 filebrowserImageBrowseUrl: 'ckeditor/plugins/kcfinder/browse.php?type=obrazky&lang=cs', 55 filebrowserFlashBrowseUrl: 'ckeditor/plugins/kcfinder/browse.php?type=files&lang=cs', 56 filebrowserUploadUrl: 'ckeditor/plugins/kcfinder/upload.php?type=soubory&lang=cs', 57 filebrowserImageUploadUrl: 'ckeditor/plugins/kcfinder/upload.php?type=obrazky&lang=cs', 58 filebrowserFlashUploadUrl: 'ckeditor/plugins/kcfinder/upload.php?type=flash&lang=cs' 59 }; 60 61 // Custom height overrides and resize settings 62 if (type === 'micro') { 63 config.height = 80; 64 config.resize_enabled = false; // Disable resize handle for micro editor 65 config.removePlugins += ',elementspath,resize'; // Ensure resize plugin is removed to hide handle 66 } else if (type === 'mini') { 67 config.height = 150; 68 config.resize_enabled = false; 69 config.removePlugins += ',resize'; 70 } else { 71 config.height = 300; 72 } 73 74 var editor = CKEDITOR.replace(editorId, config); 75 76 // --- LOGIKA POÄÃTADLA A SANITIZACE --- 77 78 // Funkce pro náhradu problematických znaků (pevné mezery atd.) 79 function sanitizeText(content) { 80 if (!content) return ""; 81 let replaceChars = { 82 "\u2009": " ", "\u2002": " ", "\u2003": " ", "\u2004": " ", 83 "\u2005": " ", "\u2006": " ", "\u2007": " ", "\u2008": " ", 84 "\u202F": " ", "\u205F": " ", "\u3000": " " 85 }; 86 for (let char in replaceChars) { 87 content = content.replace(new RegExp(char, "g"), replaceChars[char]); 88 } 89 return content; 90 } 91 92 // Aktualizace poÄÃtadla 93 function updateCounter() { 94 if (!editor || !editor.getData) return; // Ochrana proti volánà pÅed inicializacà 95 96 // ZÃskánà Äistého textu (vÄetnÄ HTML tagů, jak uživatel požadoval) 97 let content = editor.getData().trim(); 98 content = sanitizeText(content); 99 100 let contentLength = content.length; 101 102 // ZkusÃme najÃt element poÄÃtadla podle ID, nebo pokud je to 'small' tag v okolà textarea 103 let charCountInput = document.getElementById(counterId); 104 if (!charCountInput) { 105 // Fallback: Pokud ID nenalezeno, zkusÃme najÃt element s ID 'count_message' (což je hardcoded v ajax-modal-novinky.php) 106 charCountInput = document.getElementById('count_message'); 107 } 108 109 if (charCountInput) { 110 // Pokud je to input/textarea/select, použijeme value, jinak innerText (pro small/span/div) 111 if (charCountInput.tagName === 'INPUT' || charCountInput.tagName === 'TEXTAREA') { 112 charCountInput.value = contentLength; 113 } else { 114 charCountInput.innerText = "PoÄet znaků: " + contentLength + (maxChars > 0 ? " / " + maxChars : ""); 115 } 116 117 // Validace Max Length 118 if (maxChars > 0) { 119 if (contentLength > maxChars) { 120 charCountInput.classList.add('text-danger', 'font-weight-bold'); 121 } else { 122 charCountInput.classList.remove('text-danger', 'font-weight-bold'); 123 } 124 } 125 } 126 return content; 127 } 128 129 // Bind events 130 editor.on('instanceReady', function (evt) { 131 updateCounter(); 132 }); 133 134 editor.on('paste', function (evt) { 135 evt.data.dataValue = sanitizeText(evt.data.dataValue); 136 setTimeout(updateCounter, 10); 137 }); 138 139 editor.on('change', function () { 140 updateCounter(); 141 }); 142 143 // Bind Form Submit Validation (pokud existuje rodiÄovský formuláÅ) 144 let textArea = document.getElementById(editorId); 145 if (textArea && textArea.form) { 146 textArea.form.addEventListener('submit', function (event) { 147 editor.updateElement(); // Sync data to textarea 148 let content = updateCounter(); // Check count 149 150 if (maxChars > 0 && content.length > maxChars) { 151 event.preventDefault(); 152 event.stopPropagation(); 153 alert('Text je pÅÃliÅ¡ dlouhý! Maximálnà povolená délka je ' + maxChars + ' znaků (vÄetnÄ HTML).'); 154 } 155 }); 156 } 157 158 return editor; 159} 160 161// --- ADMIN CLIPBOARD FUNKCE --- 162function copyToClipboard(element) { 163 var $temp = $("<input>"); 164 $("body").append($temp); 165 $temp.val($(element).text()).select(); 166 document.execCommand("copy"); 167 $temp.remove(); 168} 169
170window.copyUrlToClipboard = function (inputId) { 171 var textToCopy = "/" + $("#" + inputId).val(); 172 var copySuccess = function () { 173 var $btn = $("#" + inputId).closest('.input-group').find('button'); 174 var oldHtml = $btn.html(); 175 $btn.html('<i class="fa fa-check text-success"></i>'); 176 setTimeout(function () { $btn.html(oldHtml); }, 1500); 177 }; 178 if (navigator.clipboard && window.isSecureContext) { 179 navigator.clipboard.writeText(textToCopy).then(copySuccess).catch(function () { fallbackCopyTextToClipboard(textToCopy, copySuccess); }); 180 } else { 181 fallbackCopyTextToClipboard(textToCopy, copySuccess); 182 } 183}; 184 185function fallbackCopyTextToClipboard(text, successCallback) { 186 var textArea = document.createElement("textarea"); 187 textArea.value = text; 188 textArea.style.top = "0"; 189 textArea.style.left = "0"; 190 textArea.style.position = "fixed"; 191 document.body.appendChild(textArea); 192 textArea.focus(); 193 textArea.select(); 194 try { 195 var successful = document.execCommand('copy'); 196 if (successful) successCallback(); 197 } catch (err) { 198 console.error('Fallback: KopÃrovánà selhalo', err); 199 } 200 document.body.removeChild(textArea); 201} 202 203// --- GLOBAL HTML PREVIEW MODAL --- 204window.showHtmlPreview = function (element, titleStr) { 205 var title = titleStr || "Náhled obsahu"; 206 var htmlContent = $(element).attr('data-content'); 207 var $modal = $('#htmlPreviewModal'); 208 if (!$modal.length) { 209 var modalHtml = '<div class="modal fade" id="htmlPreviewModal" tabindex="-1" role="dialog" aria-hidden="true">' + 210 '<div class="modal-dialog modal-lg modal-dialog-centered" role="document">' + 211 '<div class="modal-content">' + 212 '<div class="modal-header">' + 213 '<h5 class="modal-title font-weight-bold"></h5>' + 214 '<button type="button" class="close" data-dismiss="modal" aria-label="ZavÅÃt"><span aria-hidden="true">×</span></button>' + 215 '</div>' + 216 '<div class="modal-body" style="overflow-x:auto; background: #fdfdfd;"></div>' + 217 '<div class="modal-footer bg-light">' + 218 '<button type="button" class="btn btn-secondary px-4 shadow-sm" data-dismiss="modal">ZAVÅÃT</button>' + 219 '</div>' + 220 '</div>' + 221 '</div>' + 222 '</div>'; 223 $('body').append(modalHtml); 224 $modal = $('#htmlPreviewModal'); 225 } 226 $modal.find('.modal-title').text(title); 227 $modal.find('.modal-body').html(htmlContent); 228 $modal.modal('show'); 229}; 230 231$(document).ready(function () { 232 // --- GRID EDITOR --- 233 var $grid = $('#myGrid'); 234 if ($grid.length) { 235 $grid.find('.ge-mainControls, .ge-addRowGroup, .ge-tools-drawer, .ge-content-type-bar, .ge-layout-mode, .ge-ui').remove(); 236 } 237 238 if ($.isFunction($.fn.gridEditor) && $('#myGrid').length) { 239 $('#myGrid').gridEditor({ 240 new_row_layouts: [[12], [6, 6], [9, 3], [3, 9], [3, 6, 3], [3, 3, 3, 3]], 241 content_types: ['ckeditor'], 242 row_classes: [ 243 { label: 'Å¡edé pozadÃ', cssClass: 'bg-sede-row' }, 244 { label: 'AOS: Fade Up', cssClass: 'aos-init aos-animate', data: { 'aos': 'fade-up' } }, 245 { label: 'AOS: Fade Down', cssClass: 'aos-init aos-animate', data: { 'aos': 'fade-down' } }, 246 { label: 'AOS: Fade Right', cssClass: 'aos-init aos-animate', data: { 'aos': 'fade-right' } }, 247 { label: 'AOS: Fade Left', cssClass: 'aos-init aos-animate', data: { 'aos': 'fade-left' } }, 248 { label: 'AOS: Zoom In', cssClass: 'aos-init aos-animate', data: { 'aos': 'zoom-in' } } 249 ], 250 col_classes: [ 251 { label: 'Å¡edé pozadÃ', cssClass: 'bg-sede-col' }, 252 { label: 'druhé pozadÃ', cssClass: 'bg-druhe-col' }, 253 { label: 'AOS: Fade Up', cssClass: 'aos-init aos-animate', data: { 'aos': 'fade-up' } }, 254 { label: 'AOS: Zoom In', cssClass: 'aos-init aos-animate', data: { 'aos': 'zoom-in' } } 255 ], 256 ckeditor: { 257 config: { 258 customConfig: '/admin/ckeditor/config.js?v=20260325_24', 259 filebrowserBrowseUrl: '/admin/ckeditor/plugins/kcfinder/browse.php?type=files', 260 filebrowserImageBrowseUrl: '/admin/ckeditor/plugins/kcfinder/browse.php?type=images', 261 filebrowserFlashBrowseUrl: '/admin/ckeditor/plugins/kcfinder/browse.php?type=flash', 262 filebrowserUploadUrl: '/admin/ckeditor/plugins/kcfinder/upload.php?type=files', 263 filebrowserImageUploadUrl: '/admin/ckeditor/plugins/kcfinder/upload.php?type=images', 264 filebrowserFlashUploadUrl: '/admin/ckeditor/plugins/kcfinder/upload.php?type=flash' 265 } 266 } 267 }); 268 } 269 270 $(document).on('click', '.gm-fullscreen', function () { 271 $('body').toggleClass('ge-fullscreen-mode'); 272 }); 273 274 $(document).keyup(function (e) { 275 if (e.key === "Escape" && $('body').hasClass('ge-fullscreen-mode')) { 276 $('body').removeClass('ge-fullscreen-mode'); 277 } 278 }); 279 280 if (typeof CKEDITOR !== 'undefined') { 281 CKEDITOR.config.autoParagraph = false;
282 CKEDITOR.on("instanceReady", function (event) { 283 event.editor.on("beforeCommandExec", function (event) { 284 if (event.data.name == "paste") { 285 event.editor._.forcePasteDialog = true; 286 } 287 if (event.data.name == "pastetext" && event.data.commandData.from == "keystrokeHandler") { 288 event.cancel(); 289 } 290 }) 291 }); 292 } 293 294 // --- MODAL WINDOWS FOR ADMIN EDITING --- 295 $("body").on("shown.bs.modal", function (event) { 296 if ($.fn.draggable) { 297 $(this).find(".modal-dialog").draggable({ 298 handle: ".modal-header", 299 cursor: "move" 300 }); 301 $(this).find(".modal-header").css("cursor", "move"); 302 } 303 }); 304 305 $("body").on("hidden.bs.modal", function (event) { 306 $(this).find(".modal-dialog").css({ top: 0, left: 0 }); 307 }); 308 309 /* MODAL CONTENT LOADING - Global Handler */ 310 $(document).on('show.bs.modal', '.modal', function (e) { 311 if ($(this).attr('id') === 'clanek_preview_Modal') return; 312 var modal = $(this); 313 modal.data('needs-reload', false); 314 315 var button = $(e.relatedTarget); 316 if (button.length > 0 && button.attr('href') && button.attr('href') !== '#' && button.attr('href').indexOf('#') !== 0 && button.attr('href').indexOf('javascript') === -1) { 317 var url = button.attr('href'); 318 319 if (url.indexOf('src_in_window.php') !== -1) { 320 modal.find('.modal-content').html('<div class="p-5 text-center"><i class="fa fa-spinner fa-spin fa-3x text-muted"></i><br><br>NaÄÃtám...</div>'); 321 modal.find('.modal-content').load(url, function (response, status, xhr) { 322 if (status == "error") { 323 modal.find(".modal-content").html('<div class="alert alert-danger m-3">Chyba pÅi naÄÃtánÃ: ' + xhr.status + " " + xhr.statusText + '</div>'); 324 } 325 }); 326 } else if (url.indexOf('ajax-modal-') !== -1 || url.indexOf('modal') !== -1) { 327 var targetElement = modal.find('.modal-body').length > 0 ? modal.find('.modal-body') : modal.find('.modal-content'); 328 if(modal.attr('id') !== 'anketa_vysledky_Modal') { 329 targetElement.html('<div class="p-5 text-center"><i class="fa fa-spinner fa-spin fa-3x text-muted"></i><br><br>NaÄÃtám formuláÅ...</div>'); 330 } 331 targetElement.load(url, function (response, status, xhr) { 332 if (status == "error") { 333 targetElement.html('<div class="alert alert-danger m-3">Chyba pÅi naÄÃtánÃ: ' + xhr.status + " " + xhr.statusText + '</div>'); 334 } 335 }); 336 } else { 337 modal.find('.modal-content').load(url); 338 } 339 } 340 }); 341 342 $(document).on('hidden.bs.modal', '.modal', function (e) { 343 var modal = $(this); 344 if (modal.data('needs-reload') === true || modal.hasClass('needs-reload')) { 345 location.reload(); 346 } else { 347 // Reset soubory modals to default loading spinner to prevent nested modal-body wrapping on second load 348 var modalId = modal.attr('id'); 349 if (modalId === 'soubory_edit_Modal' || modalId === 'soubory_add_Modal') { 350 modal.find('.modal-content').html('<div class="text-center p-5"><i class="fa fa-spinner fa-spin fa-3x text-muted"></i><br><br>NaÄÃtám formuláÅ...</div>'); 351 } else if (modalId === 'soubor_delete_Modal') { 352 modal.find('.modal-content').html('<div class="text-center p-5"><i class="fa fa-spinner fa-spin fa-3x text-muted"></i><br><br>NaÄÃtám...</div>'); 353 } 354 } 355 }); 356 357 // Global toggle password logic 358 $(document).on('click', '.toggle-password', function () { 359 var $this = $(this); 360 var $icon = $this.is('i') ? $this : $this.find('i'); 361 var $input = $this.closest('.input-group, .input-with-icon, .form-group').find('input'); 362 363 if ($input.length > 0) { 364 if ($input.attr("type") === "password") { 365 $input.attr("type", "text"); 366 $icon.removeClass("fa-eye").addClass("fa-eye-slash"); 367 } else { 368 $input.attr("type", "password"); 369 $icon.removeClass("fa-eye-slash").addClass("fa-eye"); 370 } 371 } 372 }); 373 374 // Delegated SUBMIT handlers for forms loaded via AJAX in modals 375 var delegatedForms = "#form_novinky, #form_clanky, #form_edit_novinky, #form_edit_clanky, #form_delete_novinky, #form_menu, #form_delete_clanek, #form_edit_menu, #form_edit_uzivatel, #form_edit_rostlina, #form_delete_rostlina, #form_edit_ankety, #form_edit_soubory, #form_delete_newsletter, #form_delete_order, #form_delete_soubory, #form_edit_akce, #form_delete_akce"; 376 377 $(document).on("submit", delegatedForms, function (e) { 378 e.preventDefault(); 379 380 var $form = $(this); 381 382 // Clean previous validations 383 $form.find('.is-invalid').removeClass('is-invalid');
384 $form.find('.invalid-feedback').remove(); 385 386 // 1. Sync CKEditor if present 387 if (typeof CKEDITOR !== 'undefined') { 388 for (var instance in CKEDITOR.instances) { 389 if (CKEDITOR.instances[instance]) { 390 CKEDITOR.instances[instance].updateElement(); 391 } 392 } 393 } 394 395 var formIsValid = true; 396 397 // 2. Custom validation for required fields 398 $form.find('input[required], select[required], textarea[required]').each(function() { 399 var $field = $(this); 400 if ($field.val().trim() === '') { 401 formIsValid = false; 402 $field.addClass('is-invalid'); 403 404 var feedbackText = 'Tento údaj je povinný.'; 405 if ($field.attr('id') === 'nadpis') { 406 feedbackText = 'VyplÅte nadpis.'; 407 } else if ($field.attr('id') === 'obsah') { 408 feedbackText = 'VyplÅte text.'; 409 } else if ($field.attr('id') === 'nazev_clanku') { 410 feedbackText = 'VyplÅte nadpis Älánku.'; 411 } 412 413 if ($field.parent().hasClass('input-group')) { 414 $field.parent().after('<div class="invalid-feedback d-block">' + feedbackText + '</div>'); 415 } else { 416 $field.after('<div class="invalid-feedback">' + feedbackText + '</div>'); 417 } 418 } 419 }); 420 421 if (!formIsValid) { 422 e.stopPropagation(); 423 return false; 424 } 425 426 var $modal = $form.closest('.modal'); 427 var $btn = $form.find('button[type="submit"]'); 428 var originalBtnHtml = $btn.length ? $btn.html() : ''; 429 430 if($btn.length) $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin mr-1"></i> UKLÃDÃM...'); 431 432 // Auto-fill/validate URL if present in form before serialization 433 var $urlField = $form.find('#url'); 434 if ($urlField.length) { 435 testField($urlField[0]); 436 } 437 438 var postData = $form.serializeArray(); 439 var formURL = $form.attr("action"); 440 441 $.ajax({ 442 url: formURL, 443 type: "POST", 444 data: postData, 445 success: function (data, textStatus, jqXHR) { 446 if ($modal.length) { 447 $modal.data('needs-reload', true); 448 $modal.addClass('needs-reload'); 449 if ($modal.find('.modal-body').length > 0 && formURL && formURL.indexOf('ajax-modal-') !== -1) { 450 $modal.find('.modal-body').html(data); 451 } else if ($modal.find('.modal-content').length > 0) { 452 $modal.find('.modal-content').html(data); 453 } else { 454 $modal.html(data); 455 } 456 } 457 }, 458 error: function (jqXHR, textStatus, errorThrown) { 459 if($btn.length) $btn.prop('disabled', false).html(originalBtnHtml); 460 alert("Chyba pÅi ukládánÃ: " + textStatus); 461 } 462 }); 463 }); 464 465 $("#clanek_preview_Modal").on("show.bs.modal", function (e) { 466 var link = $(e.relatedTarget); 467 var title = link.data('title') || 'Náhled Älánku'; 468 var id = link.data('id') || ''; 469 var url = link.attr("href"); 470 471 $(this).find(".modal-title").html('Náhled Älánku: <span class="font-weight-normal">' + title + '</span> <small class="text-muted ml-2">#' + id + '</small>'); 472 473 var $body = $(this).find(".modal-body"); 474 $body.html('<div class="d-flex justify-content-center align-items-center h-100 flex-column text-muted"><i class="fa fa-spinner fa-spin fa-3x mb-3"></i>NaÄÃtám živý náhled...</div>'); 475 476 var iframeHtml = '<iframe src="' + url + '" frameborder="0" width="100%" height="100%" style="display:none; border-radius: 4px;"></iframe>'; 477 var $iframe = $(iframeHtml); 478 479 $body.append($iframe); 480 481 $iframe.on('load', function() { 482 $body.find('.fa-spinner').parent().remove(); 483 $(this).fadeIn(); 484 }); 485 }); 486 $("#clanek_preview_Modal").on("hidden.bs.modal", function (e) {
487 $(this).find(".modal-body").empty(); 488 }); 489 490 // KCFinder handler 491 $("#kcf").on("show.bs.modal", function (e) { 492 var button = e.relatedTarget; 493 var data_url = $(button).attr("data-url"); 494 if(data_url){ 495 data_url += (data_url.indexOf('?') !== -1 ? '&' : '?') + "t=" + new Date().getTime(); 496 $(this).find(".modal-body").empty().html('<div id="kcfinder_div" class="modal_kcfinder" style="height:100%"><iframe name="kcfinder_iframe" src="' + data_url + '" frameborder="0" width="100%" height="100%" style="width:100%;height:100%;" marginwidth="0" marginheight="0" scrolling="no"></iframe></div>'); 497 } 498 499 window.KCFinder = { 500 callBack: function (url) { 501 window.KCFinder = null; 502 $(button).parent().next('input').val(url); 503 $("#kcf").modal('hide'); 504 } 505 }; 506 }); 507 508 $("#kcf").on("hidden.bs.modal", function () { 509 $(this).find(".modal-body").empty(); 510 }); 511 512 513 // --- OBNOVENà LOGIKA Z ADMINU A INLINE --- 514 515 // Ukládánà a odeslánà do iframe (archiv & uloženà clanku) 516 $("#save").click(function () { 517 var html = $('#myGrid').gridEditor('getHtml'); 518 var id = $('#id_clanky').val(); 519 520 $("#vysledek_sql").html('<i class="fa fa-spinner fa-spin"></i> Ukládám...'); 521 522 $.ajax({ 523 url: "inline_uloz_obsah_clanku.php", 524 type: "POST", 525 data: { id: id, content: html }, 526 success: function (data) { 527 $("#vysledek_sql").html(data); 528 setTimeout(function () { $("#vysledek_sql").html(''); }, 3000); 529 }, 530 error: function () { 531 $("#vysledek_sql").html('<span class="text-danger">Chyba ukládánÃ!</span>'); 532 } 533 }); 534 }); 535 536 // NAÄTENà ARCHIVU (historie verzÃ) 537 function loadHistory() { 538 var id = $('#id_clanky').val(); 539 if (id && id > 0) { 540 $("#vysledek_archiv").html('<i class="fa fa-spinner fa-spin"></i>'); 541 $.ajax({ 542 url: "inline_historie_clanku.php", 543 type: "POST", 544 data: { id: id }, 545 success: function (data) { 546 $("#vysledek_archiv").html(data); 547 }, 548 error: function (jqXHR, textStatus, errorThrown) { 549 $("#vysledek_archiv").html('<span class="text-danger small">Chyba: ' + textStatus + '</span>'); 550 } 551 }); 552 } 553 } 554 555 if($('#vysledek_archiv').length) { 556 loadHistory(); 557 } 558 559 $(document).on('change', '#history_select', function () { 560 // Implementace výbÄru archivu 561 }); 562 563 // --- GLOBAL URL GENERATION HANDLER --- 564 $(document).on('blur', '#nazev_clanku, #nazev', function () { 565 var $url = $(this).closest('form').find('#url'); 566 if ($url.length && !$url.val().trim()) $url.val(make_url(this.value)); 567 }); 568 569 // --- CODEMIRROR TAG SELECTION --- 570 $(document).on('mousedown', '.CodeMirror', function (e) { 571 var cm = this.CodeMirror; 572 if (!cm) { 573 cm = $(this).find('*').filter(function() { return !!this.CodeMirror; }).get(0); 574 if (cm) cm = cm.CodeMirror; 575 } 576 577 if (!cm) return; 578 579 // EMERGENCY: Pokud addon stále chybÃ, pokusÃme se ho "vnutit" z globálnÃho prostoru 580 if (!cm.findMatchingTag && typeof CodeMirror !== 'undefined' && CodeMirror.prototype.findMatchingTag) { 581 cm.findMatchingTag = CodeMirror.prototype.findMatchingTag; 582 } 583 584 var pos = cm.coordsChar({ left: e.clientX, top: e.clientY }, "window"); 585 var token = cm.getTokenAt(pos); 586 587 // Funkce se spustà pouze pokud klikneme na tag (název nebo závorky), ne na atributy 588 if (token && token.type && /\btag\b/.test(token.type)) { 589 if (typeof cm.findMatchingTag === 'function') { 590 var match = cm.findMatchingTag(pos); 591 if (match) { 592 var from, to; 593 if (match.at === 'open' && match.close) { 594 from = match.open.from; 595 to = match.close.to; 596 } else if (match.at === 'close' && match.open) { 597 from = match.open.from; 598 to = match.close.to; 599 } 600 601 if (from && to) { 602 setTimeout(function() { 603 cm.setSelection(from, to, { scroll: false });
604 cm.focus(); 605 }, 50); 606 } 607 } 608 } 609 } 610 }); 611 612}); 613 614// --- GLOBÃLNà FUNKCE (mimo document.ready) --- 615 616function testField(field) { 617 if (!field) return; 618 619 // Automatically fill URL if empty 620 if (field.value.trim().length == 0) { 621 // Look for title ONLY within the same form/context to avoid picking up old data from hidden modals 622 var $form = $(field).closest('form'); 623 var $titleField = $form.find('#nazev_clanku, #nazev'); 624 if ($titleField.length) { 625 field.value = make_url($titleField.val()); 626 } 627 } 628 629 var regExpr = new RegExp("^[a-z0-9\\-]*$"); 630 if (!regExpr.test(field.value)) { 631 alert("Nelze použÃt URL '" + field.value + "' (povoleny jsou pouze malá pÃsmena, ÄÃsla a pomlÄky)"); 632 field.classList.add('is-invalid'); 633 } else { 634 field.classList.remove('is-invalid'); 635 } 636} 637 638var nodiac = { 'á': 'a', 'Ä': 'c', 'Ä': 'd', 'é': 'e', 'Ä': 'e', 'Ã': 'i', 'Å': 'n', 'ó': 'o', 'Å': 'r', 'Å¡': 's', 'Å¥': 't', 'ú': 'u', 'ů': 'u', 'ý': 'y', 'ž': 'z' }; 639function make_url(s) { 640 if (!s) return ""; 641 s = s.toLowerCase(); 642 var s2 = ''; 643 for (var i = 0; i < s.length; i++) { 644 s2 += (typeof nodiac[s.charAt(i)] != 'undefined' ? nodiac[s.charAt(i)] : s.charAt(i)); 645 } 646 // Changed: Remove underscores to match testField regex (^[a-z0-9\-]*$) 647 return s2.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); 648} 649 650function make_friendly_url(u) { 651 // This is now redundant due to the global handler, but kept for legacy inline onblur calls 652 var $urlField = $('#url'); 653 if ($urlField.length && $urlField.val().trim().length == 0) { 654 $urlField.val(make_url(u)); 655 } 656} 657 658function isDateorNull(theElement) { 659 if (!theElement) return true; 660 var inpDate = theElement.value; 661 if (inpDate.length == 0) return true; 662 return true; 663} 664 665function valid(form) { 666 var field = form.datum_clanku; 667 if (isDateorNull(field)) { 668 return true; 669 } else { 670 return false; 671 } 672} 673 674/* Czech initialisation for the jQuery UI date picker plugin. */ 675(function (factory) { 676 if (typeof define === "function" && define.amd) { 677 define(["../widgets/datepicker"], factory); 678 } else { 679 if(typeof jQuery.datepicker !== "undefined") { 680 factory(jQuery.datepicker); 681 } 682 } 683}(function (datepicker) { 684 datepicker.regional.cs = { 685 closeText: "ZavÅÃt", prevText: "<DÅÃve", nextText: "PozdÄji>", currentText: "NynÃ", 686 monthNames: ["leden", "únor", "bÅezen", "duben", "kvÄten", "Äerven", "Äervenec", "srpen", "záÅÃ", "ÅÃjen", "listopad", "prosinec"], 687 monthNamesShort: ["led", "úno", "bÅe", "dub", "kvÄ", "Äer", "Ävc", "srp", "záÅ", "ÅÃj", "lis", "pro"], 688 dayNames: ["nedÄle", "pondÄlÃ", "úterý", "stÅeda", "Ätvrtek", "pátek", "sobota"], 689 dayNamesShort: ["ne", "po", "út", "st", "Ät", "pá", "so"], dayNamesMin: ["ne", "po", "út", "st", "Ät", "pá", "so"], 690 weekHeader: "Týd", dateFormat: "dd.mm.yy", firstDay: 1, isRTL: false, showMonthAfterYear: false, yearSuffix: "" 691 }; 692 datepicker.setDefaults(datepicker.regional.cs); 693 return datepicker.regional.cs; 694}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.