1((w, d) => { 2 "use strict"; 3 if (!w || !d) return; 4 5 if (w['_frontendEditDisabled']) return; 6 7 var storageElements = sessionStorage && sessionStorage.getItem('fe_edit'); 8 var getElements; 9 if (storageElements === 'all') { 10 getElements = 'all'; 11 } else if (storageElements) { 12 try { 13 getElements = JSON.parse(storageElements); 14 } catch (e) { 15 getElements = []; 16 } 17 } else { 18 getElements = []; 19 } 20 const allowedElements = getElements; 21 22 23 let lgs = { 24 de: { 25 editContent: 'Inhalt bearbeiten', 26 edit20: 'Artikel bearbeiten', 27 edit29: 'Proxy bearbeiten', 28 edit54: 'Galerie bearbeiten', 29 edit57: 'CST Element bearbeiten', 30 edit87: 'Media Einzelelement bearbeiten', 31 edit94: 'Klon bearbeiten', 32 edit102: 'Social bearbeiten', 33 editmodules: 'Gruppe bearbeiten', 34 edit116: 'Karte bearbeiten', 35 editCst: 'CST bearbeiten', 36 editRoom: "Zimmer bearbeiten", 37 editOffer: "Angebot bearbeiten", 38 editProgram: "Zusatzleistung bearbeiten", 39 editHotel: "Hotel bearbeiten" 40 }, 41 en: { 42 editContent: 'Edit content', 43 edit20: 'Edit article', 44 edit29: 'Edit proxy', 45 edit54: 'Edit gallery', 46 edit57: 'Edit CST element', 47 edit87: 'Edit media single element', 48 edit102: 'Edit social', 49 editmodules: 'Edit group', 50 edit116: 'Edit map', 51 editCst: 'Edit CST', 52 editRoom: "Edit room", 53 editOffer: "Edit offer", 54 editProgram: "Edit additional service", 55 editHotel: "Edit hotel" 56 } 57 } 58 lgs = lgs.de; 59 60 let currentTarget = null; 61 let editBtn = null; 62 let overlay = null; 63 let hideTimeout = null; 64 65 let currentTargetCst = null; 66 let editBtnCst = null; 67 let overlayCst = null; 68 let hideTimeoutCst = null; 69 let isSuspended = false; 70 let supportPickOverlay = null; 71 let persistentSupportOverlay = null; 72 let isSupportPickMode = false; 73 let _supportPickHandlers = null; 74 let _supportPickEligible = null; 75 let stylesElement = null; 76 77 const windowOpener = (cid) => { 78 if (!cid) return; 79 w.open('/condeon/frontend.php?type=in&page_content=' + cid, '_blank'); 80 }; 81 82 const windowOpenerCst = (cstid, hotelid, csttype) => { 83 if (!hotelid || !csttype) return; 84 85 let base = 'https://cst-pro.viomassl.com/hotel/' + hotelid + '/'; 86 let addition = ''; 87 88 if (cstid && csttype === 'room') { 89 addition = 'hotel_room_type?id=' + cstid; 90 } 91 else if (cstid && csttype === 'offer') { 92 addition = 'hotel_package?id=' + cstid; 93 } 94 else if (cstid && csttype === 'program') { 95 addition = 'hotel_program?id=' + cstid; 96 } 97 else if (cstid && csttype === 'job') { 98 addition = 'hotel_job?id=' + cstid; 99 } 100 w.open(base + addition, '_blank'); 101 }; 102 103 const isEditAllowed = (el) => { 104 if (!el || !el.dataset) return false; 105 if (allowedElements === 'all') return true; 106 if (Array.isArray(allowedElements) && allowedElements.length > 0) { 107 const pct = Number(el.dataset.pct); 108 return allowedElements.includes(pct); 109 } 110 return false; 111 }; 112 113 const getEditableCidElements = () => { 114 return Array.from(d.querySelectorAll('[data-cid][data-pct]:not(.grp-single)')).filter(isEditAllowed); 115 }; 116 117 const getSupportCidElements = () => { 118 return Array.from(d.querySelectorAll('[data-cid]:not(.grp-single):not(.frontend-edit__btn)')); 119 }; 120 121 const suspendFrontendEdit = () => { 122 isSuspended = true; 123 if (hideTimeout) clearTimeout(hideTimeout); 124 if (hideTimeoutCst) clearTimeout(hideTimeoutCst); 125 hideTimeout = null; 126 hideTimeoutCst = null; 127 hideEditButton(); 128 hideEditButtonCst(); 129 d.documentElement.classList.add('frontend-edit--nooutline'); 130 }; 131 132 const resumeFrontendEdit = () => { 133 isSuspended = false; 134 d.documentElement.classList.remove('frontend-edit--nooutline'); 135 }; 136 137 const disableStyles = () => { 138 if (stylesElement) { 139 stylesElement.remove(); 140 stylesElement = null; 141 } 142 }; 143 144 const enableStyles = () => { 145 if (!stylesElement) { 146 styles(); 147 } 148 }; 149 150 const disable = () => { 151 isSuspended = true; 152 if (hideTimeout) clearTimeout(hideTimeout); 153 if (hideTimeoutCst) clearTimeout(hideTimeoutCst); 154 hideTimeout = null; 155 hideTimeoutCst = null; 156 hideEditButton(); 157 hideEditButtonCst(); 158 d.documentElement.classList.add('frontend-edit--nooutline'); 159 disableStyles(); 160 if (persistentSupportOverlay) { 161 persistentSupportOverlay.remove(); 162 persistentSupportOverlay = null; 163 } 164 if (supportPickOverlay) { 165 supportPickOverlay.remove(); 166 supportPickOverlay = null; 167 } 168 d.documentElement.classList.remove('fe-support-pick-mode'); 169 }; 170 171 const enable = () => { 172 isSuspended = false;
173 d.documentElement.classList.remove('frontend-edit--nooutline'); 174 enableStyles(); 175 }; 176 177 const changeBtnText = (el) => { 178 var cls = el.classList; 179 switch (true) { 180 case cls.contains('grp-modules'): 181 editBtn.textContent = lgs.editmodules; 182 break; 183 case cls.contains('grp-mem-20'): 184 editBtn.textContent = lgs.edit20; 185 break; 186 case cls.contains('grp-mem-29'): 187 editBtn.textContent = lgs.edit29; 188 break; 189 case cls.contains('grp-mem-54'): 190 editBtn.textContent = lgs.edit54; 191 break; 192 case cls.contains('grp-mem-57'): 193 editBtn.textContent = lgs.edit57; 194 break; 195 case cls.contains('grp-mem-87'): 196 editBtn.textContent = lgs.edit87; 197 break; 198 case cls.contains('grp-mem-102'): 199 editBtn.textContent = lgs.edit102; 200 break; 201 case cls.contains('grp-mem-116'): 202 editBtn.textContent = lgs.edit116; 203 break; 204 default: 205 editBtn.textContent = lgs.editContent; 206 } 207 } 208 209 const changeBtnTextCst = (el, type) => { 210 switch (type) { 211 case 'room': 212 editBtnCst.textContent = lgs.editRoom; 213 break; 214 case 'offer': 215 editBtnCst.textContent = lgs.editOffer; 216 break; 217 case 'program': 218 editBtnCst.textContent = lgs.editProgram; 219 break; 220 case 'hotel': 221 editBtnCst.textContent = lgs.editHotel; 222 break; 223 default: 224 editBtnCst.textContent = lgs.editCst; 225 } 226 }; 227 228 const createEditButton = () => { 229 const btn = d.createElement('button'); 230 btn.className = 'frontend-edit__btn'; 231 btn.textContent = lgs.editContent; 232 btn.addEventListener('click', () => { 233 if (currentTarget) windowOpener(currentTarget.dataset.cid); 234 }); 235 return btn; 236 }; 237 238 const createEditButtonCst = () => { 239 const btn = d.createElement('button'); 240 btn.className = 'frontend-edit__btn frontend-edit__btn--cst'; 241 btn.textContent = lgs.editCst; 242 btn.addEventListener('click', () => { 243 if (currentTargetCst) windowOpenerCst(currentTargetCst.dataset.cstid, currentTargetCst.dataset.csthotel, currentTargetCst.dataset.csttype); 244 }); 245 return btn; 246 }; 247 248 const createOverlay = () => { 249 const ov = d.createElement('div'); 250 ov.className = 'frontend-edit__overlay'; 251 editBtn = createEditButton(); 252 ov.appendChild(editBtn); 253 d.body.appendChild(ov); 254 return ov; 255 }; 256 257 const createOverlayCst = () => { 258 const ov = d.createElement('div'); 259 ov.className = 'frontend-edit__overlay frontend-edit__overlay--cst'; 260 editBtnCst = createEditButtonCst(); 261 ov.appendChild(editBtnCst); 262 d.body.appendChild(ov); 263 return ov; 264 }; 265 266 const showOverlay = (el) => { 267 if (isSuspended) return; 268 if (!overlay) overlay = createOverlay(); 269 if (!isEditAllowed(el)) return; 270 271 const rect = el.getBoundingClientRect(); 272 changeBtnText(el); 273 overlay.style.display = 'flex'; 274 overlay.style.position = 'absolute'; 275 overlay.style.left = (rect.left + window.scrollX - 3) + 'px'; 276 overlay.style.top = (rect.top + window.scrollY - 3) + 'px'; 277 overlay.style.width = (rect.width + 6) + 'px'; 278 overlay.style.height = (rect.height + 6) + 'px'; 279 overlay.style.zIndex = 2999; 280 editBtn.dataset.cid = el.dataset.cid; 281 }; 282 283 const showOverlayCst = (el) => { 284 if (isSuspended) return; 285 if (!overlayCst) overlayCst = createOverlayCst(); 286 const rect = el.getBoundingClientRect(); 287 changeBtnTextCst(el, el.dataset.csttype); 288 overlayCst.style.display = 'flex'; 289 overlayCst.style.position = 'absolute'; 290 overlayCst.style.left = (rect.left + window.scrollX - 3) + 'px'; 291 overlayCst.style.top = (rect.top + window.scrollY - 3) + 'px'; 292 overlayCst.style.width = (rect.width + 6) + 'px'; 293 overlayCst.style.height = (rect.height + 6) + 'px'; 294 overlayCst.style.zIndex = 2999; 295 editBtnCst.dataset.cstid = el.dataset.cstid; 296 editBtnCst.dataset.csttype = el.dataset.csttype; 297 }; 298 299 const hideOverlay = () => { 300 if (overlay) overlay.style.display = 'none'; 301 }; 302 303 const hideOverlayCst = () => { 304 if (overlayCst) overlayCst.style.display = 'none'; 305 }; 306 307 const showEditButton = (el) => { 308 if (isSuspended) return; 309 if (hideTimeout) { 310 clearTimeout(hideTimeout); 311 hideTimeout = null; 312 } 313 currentTarget = el; 314 showOverlay(el); 315 }; 316 317 const showEditButtonCst = (el) => { 318 if (isSuspended) return; 319 if (hideTimeoutCst) { 320 clearTimeout(hideTimeoutCst); 321 hideTimeoutCst = null; 322 } 323 currentTargetCst = el; 324 showOverlayCst(el); 325 }; 326 327 const hideEditButton = () => { 328 currentTarget = null; 329 hideOverlay(); 330 }; 331 332 const hideEditButtonCst = () => { 333 currentTargetCst = null; 334 hideOverlayCst(); 335 }; 336 337 const delayedHide = () => { 338 if (hideTimeout) clearTimeout(hideTimeout); 339 hideTimeout = setTimeout(() => { 340 hideEditButton(); 341 }, 300); 342 }; 343 344 const delayedHideCst = () => { 345 if (hideTimeoutCst) clearTimeout(hideTimeoutCst); 346 hideTimeoutCst = setTimeout(() => { 347 hideEditButtonCst(); 348 }, 300); 349 }; 350 351 const mouseMover = () => { 352 let timeout = null; 353 let timeouttime = 1500; 354 d.body.addEventListener('mousemove', e => { 355 if (isSuspended) { 356 if (timeout) { 357 clearTimeout(timeout); 358 timeout = null; 359 } 360 return; 361 } 362 // Outline hider logic 363 const isOverEditBtn = e.target.closest('.frontend-edit__btn'); 364 if (timeout) { 365 clearTimeout(timeout); 366 timeout = null; 367 } 368 // Nur entfernen, wenn Maus nicht über einem Edit-Button ist 369 if (!isOverEditBtn) { 370 d.documentElement.classList.remove('frontend-edit--nooutline'); 371 timeout = setTimeout(() => { 372 // Nur setzen, wenn Maus nicht über einem Edit-Button ist 373 if (!document.querySelector(':hover.frontend-edit__btn')) { 374 d.documentElement.classList.add('frontend-edit--nooutline'); 375 } 376 }, timeouttime); 377 } 378 379 // Overlay hide logic 380 if (overlay && overlay.style.display !== 'none' && currentTarget) { 381 const rect = currentTarget.getBoundingClientRect(); 382 const ovRect = overlay.getBoundingClientRect(); 383 const x = e.clientX, y = e.clientY; 384 const inTarget = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; 385 const inOverlay = x >= ovRect.left && x <= ovRect.right && y >= ovRect.top && y <= ovRect.bottom; 386 if (!inTarget && !inOverlay) delayedHide(); 387 } 388 if (overlayCst && overlayCst.style.display !== 'none' && currentTargetCst) { 389 const rect = currentTargetCst.getBoundingClientRect(); 390 const ovRect = overlayCst.getBoundingClientRect(); 391 const x = e.clientX, y = e.clientY; 392 const inTarget = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom; 393 const inOverlay = x >= ovRect.left && x <= ovRect.right && y >= ovRect.top && y <= ovRect.bottom; 394 if (!inTarget && !inOverlay) delayedHideCst(); 395 } 396 }); 397 } 398 399 const styles = () => { 400 if (stylesElement) return; // Already added 401 const style = d.createElement('style'); 402 style.textContent = ` 403 :root { 404 --edit-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ffffff"><path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/></svg>'); 405 --edit-icon-cst: url('data:image/svg+xml,<path xmlns="http://www.w3.org/2000/svg" d="M42.964 4.697h-5.907V.385H53.33l-.009 4.313h-4.919v14.916h-5.439V4.697h0zm-27.581 8.544c-1.245 1.502-2.756 2.253-4.532 2.253-1.044 0-1.973-.229-2.788-.687s-1.447-1.103-1.896-1.937-.673-1.79-.673-2.87.224-2.037.673-2.87 1.081-1.479 1.896-1.937 1.744-.687 2.788-.687c1.776 0 3.287.751 4.532 2.253l2.203-4.426c-.669-.562-1.421-1.028-2.258-1.398C13.918.312 12.334 0 10.576 0 8.561 0 6.753.426 5.151 1.278S2.289 3.315 1.374 4.835 0 8.076 0 9.999s.457 3.644 1.374 5.164 2.174 2.705 3.777 3.557 3.411 1.278 5.425 1.278c1.758 0 3.342-.312 4.752-.934.836-.369 1.589-.835 2.258-1.397l-2.203-4.426zm7.746 6.18c-1.466-.384-2.656-.897-3.571-1.538l1.948-3.906c.861.568 1.696.921 2.831 1.269s2.253.522 3.351.522c2.088 0 3.132-.522 3.132-1.566 0-.549-.298-.957-.893-1.223s-1.552-.544-2.87-.838c-1.447-.311-2.656-.645-3.626-1.002s-1.804-.929-2.499-1.717-1.044-1.85-1.044-3.187a5.51 5.51 0 0 1 .962-3.173c.64-.943 1.597-1.689 2.87-2.239s2.834-.825 4.684-.825a16.51 16.51 0 0 1 3.736.426c1.226.284 2.307.7 3.242 1.25l-1.96 3.94c-1.831-.989-3.324-1.385-5.044-1.385-1.081 0-1.868.161-2.362.481s-.742.738-.742 1.25.293.897.879 1.154 1.529.522 2.83.797c1.465.312 2.678.645 3.64 1.003a6.29 6.29 0 0 1 2.5 1.703c.705.779 1.058 1.836 1.058 3.173 0 1.154-.321 2.198-.961 3.132s-1.603 1.68-2.884 2.239-2.839.838-4.67.838c-1.558-.002-3.069-.194-4.534-.578z"/>'); 406 --editblue: #2196F3; 407 --editblue-hover: #136bb2; 408 }
409 [data-cid]:not(.frontend-edit__btn):not(.grp-single) { 410 outline: 2px dashed var(--editblue); 411 min-height: 36px; 412 transition: all .3s ease-out; 413 } 414 [data-cstid][data-csttype]:not(.frontend-edit__btn) { 415 outline: 2px dashed var(--editblue-hover); 416 min-height: 36px; 417 } 418 .frontend-edit__btn { 419 position: sticky; 420 top: 10px; 421 right: 10px; 422 margin-inline: auto 10px; 423 display: flex; 424 align-items: center; 425 width: 0px; 426 height: 36px; 427 box-sizing: border-box; 428 font-family: system-ui, sans-serif; 429 font-size: .875rem; 430 border: none; 431 background: var(--editblue); 432 color: #fff; 433 cursor: pointer; 434 font-weight: bold; 435 z-index: 100; 436 text-transform: uppercase; 437 pointer-events: auto; 438 padding: 0 0 0 36px; 439 white-space: nowrap; 440 transition: all .3s ease-out; 441 interpolate-size: allow-keywords; 442 line-height: 40px; 443 overflow: hidden; 444 border-radius: .25rem; 445 } 446 447 .frontend-edit__btn:hover { 448 width: auto; 449 padding-inline: 42px 16px; 450 } 451 452 .frontend-edit__btn::before { 453 content:''; 454 display: block; 455 width: 26px; 456 height: 26px; 457 background: var(--edit-icon) no-repeat center center; 458 background-size: contain; 459 position: absolute; 460 inset: 5px; 461 } 462 .frontend-edit__btn:hover, .frontend-edit__btn:focus { 463 background: var(--editblue-hover); 464 outline: none; 465 } 466 .frontend-edit__overlay { 467 display: none; 468 padding: 10px; 469 border: 3px solid var(--editblue); 470 background: rgba(33,150,243,0.1); 471 background: color-mix(in srgb, var(--editblue) 10%, transparent); 472 box-sizing: border-box; 473 z-index: 3000; 474 transition: all .25s; 475 position: absolute; 476 pointer-events: none; 477 } 478 .frontend-edit__overlay:has(~.frontend-edit__overlay[style*="display: flex"]) { 479 --editblue: transparent; 480 --editblue-hover: transparent; 481 opacity: 0; 482 } 483 .frontend-edit__overlay--cst { 484 --editblue: #83BB26; 485 --editblue-hover: #83BB26; 486 z-index: 3010; 487 } 488 .frontend-edit__btn--cst { 489 position: absolute; 490 --editblue: #fff; 491 --editblue-hover: #fff;
492 color: #000; 493 padding-left: 50px; 494 } 495 496 .frontend-edit__btn--cst::before { 497 background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" id="Ebene_1" viewBox="0 0 70.409 19.999"><defs><style>.cls-1{fill:%2383bb26;}.cls-2{fill:%237aae24;}</style></defs><path d="m42.964,4.697h-5.907V.385h16.273l-.009,4.313h-4.919v14.916h-5.439V4.697h0Z"/><path d="m15.383,13.241c-1.245,1.502-2.756,2.253-4.532,2.253-1.044,0-1.973-.229-2.788-.687-.815-.458-1.447-1.103-1.896-1.937-.449-.833-.673-1.79-.673-2.87s.224-2.037.673-2.87c.448-.833,1.081-1.479,1.896-1.937.815-.458,1.744-.687,2.788-.687,1.776,0,3.287.751,4.532,2.253l2.203-4.426c-.669-.562-1.421-1.028-2.258-1.398-1.41-.623-2.994-.935-4.752-.935-2.015,0-3.823.426-5.425,1.278-1.603.851-2.862,2.037-3.777,3.557-.916,1.52-1.374,3.241-1.374,5.164s.457,3.644,1.374,5.164c.915,1.52,2.174,2.705,3.777,3.557,1.602.851,3.411,1.278,5.425,1.278,1.758,0,3.342-.312,4.752-.934.836-.369,1.589-.835,2.258-1.397l-2.203-4.426Z"/><path d="m23.129,19.421c-1.466-.384-2.656-.897-3.571-1.538l1.948-3.906c.861.568,1.696.921,2.831,1.269,1.135.348,2.253.522,3.351.522,2.088,0,3.132-.522,3.132-1.566,0-.549-.298-.957-.893-1.223-.595-.265-1.552-.544-2.87-.838-1.447-.311-2.656-.645-3.626-1.002-.971-.357-1.804-.929-2.499-1.717-.697-.787-1.044-1.85-1.044-3.187,0-1.172.32-2.229.962-3.173.64-.943,1.597-1.689,2.87-2.239,1.272-.549,2.834-.825,4.684-.825,1.264,0,2.509.142,3.736.426,1.226.284,2.307.7,3.242,1.25l-1.96,3.94c-1.831-.989-3.324-1.385-5.044-1.385-1.081,0-1.868.161-2.362.481-.494.321-.742.738-.742,1.25s.293.897.879,1.154c.586.256,1.529.522,2.83.797,1.465.312,2.678.645,3.64,1.003.962.357,1.794.925,2.5,1.703.705.779,1.058,1.836,1.058,3.173,0,1.154-.321,2.198-.961,3.132-.641.934-1.603,1.68-2.884,2.239-1.283.558-2.839.838-4.67.838-1.558-.002-3.069-.194-4.534-.578Z"/><path class="cls-2" d="m66.304.385h4.105v4.094l-.397.516c-1.139,1.48-2.167,3.071-3.057,5.511-.89,2.448-1.411,4.902-1.545,7.292l-.102,1.807h-5.402l.031-1.945c.023-1.459.253-3.165.683-5.072.428-1.895,1.025-3.328,1.773-5.042.218-.501,1.148-2.385,1.378-2.846h-7.888V.385h10.421Z"/><path class="cls-1" d="m66.304.385c.822-.002,4.105,0,4.105,0v4.094l-.397.516c-1.139,1.48-2.167,3.071-3.057,5.511-.89,2.448-1.411,4.902-1.545,7.292l-.102,1.807h-5.402l.031-1.945c.023-1.459.253-3.165.683-5.072.428-1.895,1.025-3.328,1.773-5.042.218-.501.954-2.02,1.378-2.846.425-.826,1.704-2.906,2.533-4.314Z"/></svg>'); 498 background-size: 40px auto; 499 width: 40px; 500 border-radius: .25em; 501 } 502 .frontend-edit__btn--cst:hover { 503 padding-left: 72px; 504 } 505 506 .frontend-edit__btn--cst:hover::after { 507 content: ""; 508 position: absolute; 509 width: 1px; 510 height: 1em; 511 background: rgba(0, 0, 0, .16); 512 transform: translateX(-11px); 513 } 514 515 body #site :is([data-cstid][data-csttype]:not(.frontend-edit__btn), [data-cid]:not(.frontend-edit__btn)) { 516 transition: all .3s ease-out; 517 } 518 519 html:not(.frontend-edit--nooutline) #site :is([data-cstid][data-csttype]:not(.frontend-edit__btn), [data-cid]:not(.frontend-edit__btn)) { 520 border-radius: 0; 521 } 522 523 .frontend-edit__btn--cst:hover::before { 524 width: 50px; 525 } 526 527 @starting-style { 528 .frontend-edit__overlay, 529 .frontend-edit__overlay--cst { 530 opacity: 0; 531 } 532 } 533 534 .frontend-edit--nooutline .frontend-edit__overlay { 535 opacity: 0; 536 pointer-events: none; 537 } 538 539 .frontend-edit--nooutline :is( 540 [data-cstid][data-csttype]:not(.frontend-edit__btn), 541 [data-cid]:not(.frontend-edit__btn) 542 ) { 543 outline-color: transparent; 544 } 545 546 /* Support pick mode */ 547 .frontend-edit__overlay--support { 548 border: 3px solid #e07b00 !important; 549 background: rgba(224,123,0,0.14) !important; 550 padding: 0; 551 box-shadow: 0 0 0 1px rgba(0, 0, 0, .08), 0 8px 24px rgba(0, 0, 0, .20); 552 pointer-events: none; 553 } 554 .frontend-edit__overlay--support::before { 555 content: 'Dieses Element markieren'; 556 position: absolute; 557 top: -32px; 558 left: 0; 559 padding: 5px 10px; 560 border-radius: 4px; 561 background: #e07b00; 562 color: #fff; 563 font-size: 12px; 564 font-weight: 700; 565 line-height: 1.2; 566 white-space: nowrap; 567 letter-spacing: .01em; 568 } 569 #frontend-edit-support-bar { 570 position: fixed; 571 inset-inline: 0; 572 bottom: 0; 573 z-index: 9998; 574 display: flex; 575 align-items: center; 576 gap: 8px; 577 padding: 10px 16px; 578 background: #fff; 579 border-top: 2px solid #e07b00; 580 font-family: system-ui, sans-serif; 581 font-size: .875rem; 582 box-shadow: 0 -4px 16px rgba(0,0,0,.18); 583 } 584 #frontend-edit-support-bar > span { 585 flex: 1; 586 color: #444; 587 font-weight: 500; 588 } 589 #frontend-edit-support-bar button { 590 padding: 6px 14px; 591 border-radius: 4px; 592 border: none; 593 cursor: pointer; 594 font-size: .875rem; 595 font-weight: 600; 596 font-family: inherit; 597 } 598 #frontend-edit-support-bar .fe-support-btn-nocid { background: #f3f4f6; color: #333; } 599 #frontend-edit-support-bar .fe-support-btn-cancel { background: #fee2e2; color: #b91c1c; } 600 #frontend-edit-support-bar .fe-support-btn-nocid:hover { background: #e5e7eb; } 601 #frontend-edit-support-bar .fe-support-btn-cancel:hover { background: #fecaca; } 602 body.fe-support-pick-mode [data-cid]:not(.grp-single):not(.frontend-edit__btn) { 603 outline-style: dashed !important; 604 outline-width: 2px !important;
605 outline-color: #e07b00 !important; 606 cursor: crosshair !important; 607 } 608 body.fe-support-pick-mode .frontend-edit__overlay--support { 609 opacity: 1 !important; 610 pointer-events: none !important; 611 } 612 613 `; 614 d.head.appendChild(style); 615 stylesElement = style; 616 }; 617 618 const showSupportPickOverlay = (el) => { 619 if (!supportPickOverlay) { 620 supportPickOverlay = d.createElement('div'); 621 supportPickOverlay.className = 'frontend-edit__overlay frontend-edit__overlay--support'; 622 d.body.appendChild(supportPickOverlay); 623 } 624 const rect = el.getBoundingClientRect(); 625 supportPickOverlay.style.display = 'block'; 626 supportPickOverlay.style.position = 'fixed'; 627 supportPickOverlay.style.left = (rect.left - 3) + 'px'; 628 supportPickOverlay.style.top = (rect.top - 3) + 'px'; 629 supportPickOverlay.style.width = (rect.width + 6) + 'px'; 630 supportPickOverlay.style.height = (rect.height + 6) + 'px'; 631 supportPickOverlay.style.zIndex = 4000; 632 }; 633 634 const hideSupportPickOverlay = () => { 635 if (supportPickOverlay) supportPickOverlay.style.display = 'none'; 636 }; 637 638 const getEligibleSupportTarget = (startNode) => { 639 let node = startNode && startNode.nodeType === 1 ? startNode : null; 640 while (node) { 641 if (node.matches && node.matches('[data-cid]') && _supportPickEligible && _supportPickEligible.has(node)) { 642 return node; 643 } 644 node = node.parentElement; 645 } 646 return null; 647 }; 648 649 const stopSupportPickMode = () => { 650 if (!isSupportPickMode) return; 651 isSupportPickMode = false; 652 _supportPickEligible = null; 653 if (_supportPickHandlers) { 654 d.removeEventListener('mousemove', _supportPickHandlers.onMouseMove, true); 655 d.removeEventListener('click', _supportPickHandlers.onClick, true); 656 d.removeEventListener('scroll', _supportPickHandlers.onScroll, true); 657 d.removeEventListener('keydown', _supportPickHandlers.onKeyDown, true); 658 _supportPickHandlers = null; 659 } 660 if (supportPickOverlay) { supportPickOverlay.remove(); supportPickOverlay = null; } 661 d.getElementById('frontend-edit-support-bar')?.remove(); 662 d.body.classList.remove('fe-support-pick-mode'); 663 resumeFrontendEdit(); 664 }; 665 666 const setPersistentSupportOverlay = (el) => { 667 if (!persistentSupportOverlay) { 668 persistentSupportOverlay = d.createElement('div'); 669 persistentSupportOverlay.className = 'frontend-edit__overlay frontend-edit__overlay--support'; 670 persistentSupportOverlay.setAttribute('data-persistent', 'true'); 671 d.body.appendChild(persistentSupportOverlay); 672 } 673 const rect = el.getBoundingClientRect(); 674 persistentSupportOverlay.style.display = 'block'; 675 persistentSupportOverlay.style.position = 'absolute'; 676 persistentSupportOverlay.style.left = (rect.left + window.scrollX - 3) + 'px'; 677 persistentSupportOverlay.style.top = (rect.top + window.scrollY - 3) + 'px'; 678 persistentSupportOverlay.style.width = (rect.width + 6) + 'px'; 679 persistentSupportOverlay.style.height = (rect.height + 6) + 'px'; 680 persistentSupportOverlay.style.zIndex = 3999; 681 }; 682 683 const clearPersistentSupportOverlay = () => { 684 if (persistentSupportOverlay) { persistentSupportOverlay.remove(); persistentSupportOverlay = null; } 685 }; 686 687 const startSupportPickMode = (onPicked, onNoCid, onCancelled, eligibleElements) => { 688 if (isSupportPickMode) stopSupportPickMode(); 689 clearPersistentSupportOverlay(); 690 suspendFrontendEdit(); 691 isSupportPickMode = true; 692 _supportPickEligible = new Set(eligibleElements || getSupportCidElements()); 693 d.body.classList.add('fe-support-pick-mode'); 694 695 const bar = d.createElement('div'); 696 bar.id = 'frontend-edit-support-bar'; 697 bar.innerHTML = 698 '<span>Klicken Sie auf die Problemstelle auf der Seite</span>' + 699 '<button class="fe-support-btn-nocid" type="button">Ohne Element fortfahren</button>' + 700 '<button class="fe-support-btn-cancel" type="button">Abbrechen\u00a0(Esc)</button>'; 701 d.body.appendChild(bar); 702 703 bar.querySelector('.fe-support-btn-nocid').addEventListener('click', () => { 704 stopSupportPickMode(); 705 if (onNoCid) onNoCid(); 706 }); 707 bar.querySelector('.fe-support-btn-cancel').addEventListener('click', () => { 708 stopSupportPickMode(); 709 if (onCancelled) onCancelled(); 710 }); 711 712 const onMouseMove = (e) => { 713 if (e.target.closest('#frontend-edit-support-bar')) { hideSupportPickOverlay(); return; } 714 const eligible = getEligibleSupportTarget(e.target); 715 if (eligible) showSupportPickOverlay(eligible); 716 else hideSupportPickOverlay(); 717 }; 718 719 const onClick = (e) => { 720 if (e.target.closest('#frontend-edit-support-bar')) return; 721 const eligible = getEligibleSupportTarget(e.target); 722 if (eligible) { 723 e.preventDefault(); 724 e.stopPropagation(); 725 setPersistentSupportOverlay(eligible); 726 const cb = onPicked; 727 stopSupportPickMode(); 728 if (cb) cb(eligible); 729 } 730 }; 731 732 const onScroll = () => { hideSupportPickOverlay(); }; 733 734 const onKeyDown = (e) => { 735 if (e.key === 'Escape') { 736 stopSupportPickMode(); 737 if (onCancelled) onCancelled(); 738 } 739 }; 740 741 d.addEventListener('mousemove', onMouseMove, true); 742 d.addEventListener('click', onClick, true); 743 d.addEventListener('scroll', onScroll, true); 744 d.addEventListener('keydown', onKeyDown, true); 745 _supportPickHandlers = { onMouseMove, onClick, onScroll, onKeyDown }; 746 }; 747 748 const autoscroll = () => { 749 if (location && location.hash && location.hash.startsWith('#cid-')) { 750 const cid = location.hash.replace('#cid-', ''); 751 const el = d.querySelector('[data-cid="' + cid + '"]'); 752 if (el) { 753 setTimeout(() => { 754 const rect = el.getBoundingClientRect(); 755 const scrollTop = window.scrollY + rect.top - 200; 756 window.scrollTo({ top: scrollTop, behavior: 'smooth' }); 757 showEditButton(el); 758 }, 500); 759 } 760 } 761 }; 762 763 const init = () => { 764 const condeonElements = d.querySelectorAll('[data-cid][data-pct]:not(.grp-single)'); 765 const cstElements = d.querySelectorAll('[data-cstid][data-csttype]'); 766 if ((!condeonElements || condeonElements.length === 0) && (!cstElements || cstElements.length === 0)) return; 767
768 condeonElements.forEach(el => { 769 el.addEventListener('mouseenter', () => showEditButton(el)); 770 el.addEventListener('mouseleave', (e) => { 771 const related = e.relatedTarget; 772 let parentGroup = el.closest('.grp-modules'); 773 if (parentGroup && parentGroup !== el && parentGroup.contains(related)) { 774 showEditButton(parentGroup); 775 return; 776 } 777 if (!overlay || (!overlay.contains(related))) { 778 delayedHide(); 779 } 780 }); 781 }); 782 cstElements.forEach(el => { 783 el.addEventListener('mouseenter', () => showEditButtonCst(el)); 784 el.addEventListener('mouseleave', (e) => { 785 const related = e.relatedTarget; 786 if (!overlayCst || (!overlayCst.contains(related))) { 787 delayedHideCst(); 788 } 789 }); 790 }); 791 if (!overlay) overlay = createOverlay(); 792 overlay.addEventListener('mouseleave', (e) => { 793 const related = e.relatedTarget; 794 let enteringCondeon = false; 795 condeonElements.forEach(el => { 796 if (el.contains(related)) enteringCondeon = true; 797 }); 798 if (!enteringCondeon) { 799 delayedHide(); 800 } 801 }); 802 if (!overlayCst) overlayCst = createOverlayCst(); 803 overlayCst.addEventListener('mouseleave', (e) => { 804 const related = e.relatedTarget; 805 let enteringCst = false; 806 cstElements.forEach(el => { 807 if (el.contains(related)) enteringCst = true; 808 }); 809 if (!enteringCst) { 810 delayedHideCst(); 811 } 812 }); 813 mouseMover(); 814 autoscroll(); 815 816 w.__condeonAssist = w.__condeonAssist || {}; 817 w.__condeonAssist.frontendEdit = { 818 isEditAllowed, 819 getEditableCidElements, 820 getSupportCidElements, 821 suspend: suspendFrontendEdit, 822 resume: resumeFrontendEdit, 823 startSupportPickMode, 824 stopSupportPickMode, 825 enableStyles, 826 disableStyles, 827 disable, 828 enable, 829 }; 830 831 // Apply initial state from sessionStorage 832 if (sessionStorage.getItem('fe_edit_enabled') === 'false') { 833 disable(); 834 } else { 835 enableStyles(); 836 } 837 838 839 }; 840 841 init(); 842 843})(window, document);
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.