1/* 2 ########################### anthrazit ag ############################ 3 ### +-----------------------------------------------------------+ ### 4 ### | Project Name: moPage | ### 5 ### | Author: Stalder, Lukas | ### 6 ### | Datum: 03.01.2012 | ### 7 ### | (c) anthrazit ag, Zuerich | ### 8 ### +-----------------------------------------------------------+ ### 9 ##################################################################### 10 */ 11 12// lazy-load the swisstopo / OpenLayers runtime on demand (idempotent). 13// Used by map previews that are not present at page load. 14window.loadSwissMapAssets = (function () { 15 var loading = false, queue = []; 16 return function (cb) { 17 if (window.SwissMap) { cb(); return; } 18 if (cb) queue.push(cb); 19 if (loading) return; 20 loading = true; 21 var css = document.createElement('link'); 22 css.rel = 'stylesheet'; 23 css.href = '/appl/css/openlayers.css'; 24 document.head.appendChild(css); 25 var s1 = document.createElement('script'); 26 s1.src = '/appl/js/node_modules/ol/dist/ol.js'; 27 s1.onload = function () { 28 var s2 = document.createElement('script'); 29 s2.src = '/appl/js/node_modules/ol-mapbox-style/dist/olms.js'; 30 s2.onload = function () { 31 var s3 = document.createElement('script'); 32 s3.src = '/appl/js/swissmap/swissmap.js'; 33 s3.onload = function () { 34 var s4 = document.createElement('script'); 35 s4.src = '/appl/js/swissmap/gllppicker.js'; 36 s4.onload = function () { queue.forEach(function (f) { f(); }); queue = []; }; 37 document.head.appendChild(s4); 38 }; 39 document.head.appendChild(s3); 40 }; 41 document.head.appendChild(s2); 42 }; 43 document.head.appendChild(s1); 44 }; 45})(); 46 47// JAVASCRIPT Lib 48 49 50var resetCount = 0; 51var theTitle = document.title; 52var resizeTimer; 53 54function round(value, decimals) { 55 return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); 56} 57 58function getElement(id) { 59 var obj; 60 if (document.getElementById) { 61 obj = document.getElementById(id); 62 } else if (document.all) { 63 obj = document.all.id; 64 } 65 return obj; 66} 67 68/** strip slashes 69 * @param str 70 * @returns {*} 71 */ 72function stripSlashes(str) { 73 return str.replace(/\\/g, ''); 74} 75 76/** 77 * Generate a string of random characters of the specified length 78 * 79 * @param int length Length of the string to generate 80 * @param bool nodupes Set to true if duplicate characters should not be allowed 81 * @return string 82 */ 83function getRandomString(length, nodupes) { 84 // "typecast" the length to an integer 85 length = parseInt(length, 10); 86 87 // make sure the output is at least one character long 88 if (length < 1) { 89 length = 1; 90 } 91 92 // list of characters to use 93 var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 94 95 // final output string 96 var output = ''; 97 98 // list of used characters (only used if nodupes === true) 99 var used = ''; 100 101 // make sure we don't have an infinite loop 102 if ((nodupes === true) && (length > chars.length)) { 103 length = chars.length; 104 } 105 106 // loop as many times as `length` defines 107 do { 108 // get a random number between 0 and length of `chars` 109 var randnum = Math.floor(Math.random() * chars.length) 110 111 // extract the random character 112 var chr = chars.charAt(randnum); 113 114 // check if we are not allowed to include duplicate characters 115 if (nodupes === true) { 116 // true if character already used 117 118 var added = (used.indexOf(chr) !== -1); 119 120 // skip the character if already used 121 if (added === true) { 122 continue; 123 } 124 125 // add character to the list of used ones 126 used += chr; 127 } 128 129 // add character to the output string 130 output += chr; 131 } while (output.length < length); 132 133 return output; 134} 135 136 137function countChars(obj, displayid) { 138 var mlength = obj.getAttribute ? parseInt(obj.getAttribute("maxlength")) : ""; 139 if (obj.getAttribute && obj.value.length > mlength) { 140 obj.value = obj.value.substring(0, mlength); 141 } 142 if (displayid) { 143 var disp = getElement(displayid); 144 disp.innerHTML = (mlength - obj.value.length); 145 } 146} 147 148 149// simple jquery seconds countdown 150if (typeof (jQuery) !== 'undefined') { 151 (function ($) { 152 153 $.fn.reloadafter = function (options) { 154 155 var settings = {seconds: 60}; 156 $.extend(settings, options); 157 158 var interval = 1000; 159 var secs = settings.seconds + 1; 160 var target = $(this); 161 162 var remainingTime = function () { 163 secs--; 164 if (secs < 1) { 165 counterStop(); 166 window.location.href = settings.url; 167 secs = 1; 168 } 169 170 var m = Math.floor(secs / 60); 171 var s = secs % 60; 172 173 174 if (m > 0) counter = m + " min " + s + " sek"; 175 else counter = secs + " sek "; 176 return counter; 177 } 178 179 var counterUpdate = function () { 180 target.html(remainingTime()); 181 } 182 183 184 var counterStart = function () { 185 counterUpdate(); 186 executer = setInterval(function () { 187 counterUpdate() 188 }, interval); 189 } 190 191 var counterStop = function () { 192 clearInterval(executer); 193 } 194 195 if (secs > 0) { 196 counterStart() 197 } 198 199 }; 200 201 })(jQuery); 202} 203 204function rawurldecode(str) { 205 // Decodes URL-encodes string 206 // 207 // version: 901.1411 208 // discuss at: http://phpjs.org/functions/rawurldecode 209 // + original by: Brett Zamir 210 // * example 1: rawurldecode('Kevin+van+Zonneveld%21'); 211 // * returns 1: 'Kevin+van+Zonneveld!' 212 // * example 2: rawurldecode('http%3A%2F%2Fkevin.vanzonneveld.net%2F'); 213 // * returns 2: 'http://kevin.vanzonneveld.net/' 214 // * example 3: rawurldecode('http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%2
2146client%3Dfirefox-a'); 215 // * returns 3: 'http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a' 216 var histogram = {}; 217 var ret = str.toString(); 218 219 var replacer = function (search, replace, str) { 220 var tmp_arr = []; 221 tmp_arr = str.split(search); 222 return tmp_arr.join(replace); 223 }; 224 225 // The histogram is identical to the one in urlencode. 226 histogram["'"] = '%27'; 227 histogram['('] = '%28'; 228 histogram[')'] = '%29'; 229 histogram['*'] = '%2A'; 230 histogram['~'] = '%7E'; 231 histogram['!'] = '%21'; 232 233 for (replace in histogram) { 234 search = histogram[replace]; // Switch order when decoding 235 ret = replacer(search, replace, ret) // Custom replace. No regexing 236 } 237 238 // End with decodeURIComponent, which most resembles PHP's encoding functions 239 ret = decodeURIComponent(ret); 240 241 return ret; 242} 243 244function setCoordsCookie(lat, long) { 245 var the_date = new Date(2038, 1, 1, 0, 0, 0, 0); 246 var now = new Date(); 247 248 var the_cookie = 'geoLatitude=' + lat + ';expires=' + the_date.toUTCString() + ';path=/; secure; samesite=none'; 249 window.document.cookie = the_cookie; 250 251 var the_cookie = 'geoLongitude=' + long + ';expires=' + the_date.toUTCString() + ';path=/; secure; samesite=none'; 252 window.document.cookie = the_cookie; 253 254 var the_cookie = 'geoLocationFetched=' + (now.getTime() / 1000) + ';expires=' + the_date.toUTCString() + ';path=/; secure; samesite=none'; 255 window.document.cookie = the_cookie; 256 257} 258 259 260function getGeoLocation(url_reload, msg_fail, msg_denied, url_setpos) { 261 if (navigator.geolocation) { 262 navigator.geolocation.getCurrentPosition(function (position) { 263 setCoordsCookie(position.coords.latitude, position.coords.longitude); 264 265 if (url_reload != false) { 266 window.location.href = url_reload; 267 } 268 }, 269 function (err) { 270 //alert(err.code + ' :: ' + err.message); 271 if (err.code == 1) { 272 //window.location.href = document.URL + '&msg=txt_msg_geo_denied'; 273 alert(msg_denied); 274 } else if (err.code == 2) { 275 alert(msg_fail); 276 if (typeof url_setpos !== 'undefined') { 277 window.location.href = url_setpos; 278 } 279 280 } 281 } 282 ); 283 284 } else { 285 alert(msg_fail); 286 //window.location.href = url_reload; 287 } 288} 289 290function SetNoPosCookie() { 291 var exp = new Date(); 292 exp.setMinutes(exp.getMinutes() + 3); 293 var the_cookie = 'geoLocationNoPos=true;expires=' + exp.toUTCString() + ';path=/; secure; samesite=none'; 294 window.document.cookie = the_cookie; 295 return true; 296} 297 298// try to get cords from current location and redirect to given URL and replace {lat} {long} by retrieved coords 299function getGeoLocationRedirectCoords(url_reload, msg_fail) { 300 if (navigator.geolocation) { 301 navigator.geolocation.getCurrentPosition( 302 function (position) { 303 var the_date = new Date(2038, 1, 1, 0, 0, 0, 0); 304 305 var the_cookie = 'geoLatitude=' + position.coords.latitude + '; expires=' + the_date.toGMTString() + '; path=/; secure; samesite=none'; 306 document.cookie = the_cookie; 307 308 var the_cookie = 'geoLongitude=' + position.coords.longitude + '; expires=' + the_date.toGMTString() + '; path=/; secure; samesite=none'; 309 document.cookie = the_cookie; 310 311 // redirect to given url and replace lat /long 312 if (url_reload != false) { 313 url_reload = url_reload.replace("{lat}", position.coords.latitude); 314 url_reload = url_reload.replace("{long}", position.coords.longitude); 315 window.location.href = url_reload; 316 } 317 }, 318 function (error) { 319 alert(msg_fail); 320 }, 321 {timeout: 1000, maximumAge: 1000} 322 ); 323 324 } else { 325 alert(msg_fail); 326 } 327} 328 329// get all cookies 330function get_cookies_array() { 331 var cookies = {}; 332 if (document.cookie && document.cookie != '') { 333 var split = document.cookie.split(';'); 334 for (var i = 0; i < split.length; i++) { 335 var name_value = split[i].split("="); 336 name_value[0] = name_value[0].replace(/^ /, ''); 337 cookies[decodeURIComponent(name_value[0])] = decodeURIComponent(name_value[1]); 338 } 339 } 340 return cookies; 341} 342 343 344function deleteStoredLocationCookie() { 345 document.cookie = 'locations' + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT; '; 346 return true; 347} 348 349/** 350 * determinefrontendid from screen width 351 * @param w 352 * @returns {number} 353 */ 354function getFrontendId(w, env) { 355 var sizes = []; 356 //if (env == 'cms') sizes.push([4, 1024]); 357 if (env == 'cms') sizes.push([4, 1112]); 358 sizes.push([6, 800]); 359 sizes.push([3, 320]); 360 361 for (i = 0; i < sizes.length; i++) { 362 var s = sizes[i]; 363 //if (w > (s[1] - 10)) { 364 if (w >= (s[1])) { 365 return s[0]; 366 } 367 } 368 return 3; 369} 370
371/** 372 * writes current windfow size in cookie 373 */ 374function writeWindowSizeInCookie(env) { 375 clearTimeout(resizeTimer); 376 resizeTimer = setTimeout(function () { 377 378 // get last stored screen width 379 let width = getCookie('currentWidth'); 380 let oldorientation = getCookie('orientation'); 381 382 // set new widths in cookies 383 setCookie('currentWidth', window.innerWidth); 384 setCookie('currentHeight', window.innerHeight); 385 setCookie('availWidth', screen.availWidth); 386 setCookie('availHeight', screen.availHeight); 387 if (typeof (appHeaders) !== 'undefined' && typeof (appHeaders['Moapp-Screen-Orientation']) !== 'undefined') setCookie('orientation', appHeaders['Moapp-Screen-Orientation']); 388 389 // reload page if resized more than 400px and frontendid has changed 390 let res = {}; 391 res.old = getFrontendId(width, env); 392 res.new = getFrontendId(window.innerWidth, env); 393 394 // write in footer for debugging 395 $('#_jsscreensize').html(width + ' > ' + window.innerWidth); 396 397 // check if in app 398 let reload = true; 399 if (typeof (appHeaders) !== 'undefined' && typeof (appHeaders['Moapp-Service-Id']) !== 'undefined' && getstr(appHeaders['Moapp-Device-Type']) == 'iphone') reload = false; 400 if ($('body').hasClass('noReload')) reload = false; 401 402 // trigger hidden reload page link at bottom of page 403 if (res.old != res.new && reload == true) { 404 document.getElementById('_reloadpagelink').click(); 405 } 406 }, 25); 407} 408 409function setCookie(name, value, days) { 410 value = String(value); 411 //console.log('cookiename: ' + name + ' value: ' + value + ' days: ' + days); 412 if (value.length > 0) { 413 if (typeof (days) != 'undefined') { 414 var the_date = new Date(); 415 the_date.setDate(the_date.getDate() + days); 416 } else { 417 var the_date = new Date(2038, 1, 1, 0, 0, 0, 0); 418 } 419 } else { 420 var the_date = new Date(1970, 1, 1, 0, 0, 0, 0); 421 } 422 var the_cookie = name + '=' + value + '; expires=' + the_date.toGMTString() + '; path=/; secure; samesite=none'; 423 document.cookie = the_cookie; 424} 425 426function setCookieBySec(name, value, sec) { 427 value = String(value); 428 if (value.length > 0) { 429 if (typeof (sec) != 'undefined') { 430 var the_date = new Date(); 431 the_date.setTime(the_date.getTime() + (sec * 1000)); 432 } else { 433 var the_date = new Date(2038, 1, 1, 0, 0, 0, 0); 434 } 435 } else { 436 var the_date = new Date(1970, 1, 1, 0, 0, 0, 0); 437 } 438 var the_cookie = name + '=' + value + '; expires=' + the_date.toGMTString() + '; path=/; secure; samesite=none'; 439 document.cookie = the_cookie; 440} 441 442function getCookie(cname) { 443 var name = cname + "="; 444 var ca = document.cookie.split(';'); 445 for (var i = 0; i < ca.length; i++) { 446 var c = ca[i]; 447 while (c.charAt(0) == ' ') c = c.substring(1); 448 if (c.indexOf(name) == 0) return c.substring(name.length, c.length); 449 } 450 return ""; 451} 452 453 454/** 455 * browser local notification 456 * @param title 457 * @param body 458 * @param url 459 */ 460var notify = function (title, body, url, icon) { 461 462 if (typeof (icon) == 'undefined') icon = null; 463 464 if (!'Notification' in window) { 465 return; 466 } 467 468 if (Notification.permission === 'default') { 469 Notification.requestPermission(function () { 470 notify(title, body, url); 471 }); 472 } 473 474 // If the user has granted permission for this domain to send notifications... 475 else if (Notification.permission === 'granted') { 476 var n = new Notification( 477 title, 478 { 479 'body': body, 480 'tag': title, 481 'icon': icon 482 } 483 ); 484 485 // Remove the notification from Notification Center when clicked. 486 n.onclick = function () { 487 if (url != null) location.href = url; 488 this.close(); 489 }; 490 491 // Callback function when the notification is closed. 492 n.onclose = function () { 493 // console.log('Notification closed'); 494 }; 495 } 496 // If the user does not want notifications to come from this domain... 497 else if (Notification.permission === 'denied') { 498 return; 499 } 500}; 501 502function triggerLink(id) { 503 document.getElementById(id).click(); 504} 505 506 507function checkDateTime(eDate, eTime) { 508 var date = eDate.val().split('-'); 509 var time = sanitizeTime(eTime.val()); 510 if (isDate(date[0], date[1], date[2])) { 511 eTime.val(time); 512 return true; 513 } 514 return false;
515} 516 517 518function getWeekday(date) { 519 var c = date.split('.'); 520 var d = new Date(c[2] + '-' + c[1] + '-' + c[0]); 521 var wd = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']; 522 return wd[d.getDay()]; 523} 524 525function isDate(y, m, d) { 526 y = parseInt(y); 527 m = parseInt(m); 528 d = parseInt(d); 529 var date = new Date(y, m - 1, d); 530 var convertedDate = 531 "" + date.getFullYear() + (date.getMonth() + 1) + date.getDate(); 532 var givenDate = "" + y + m + d; 533 return (givenDate == convertedDate); 534} 535 536function getCurrentDate() { 537 var d = new Date(); 538 return addZero(d.getDate()) + '.' + addZero(d.getMonth() + 1) + '.' + d.getFullYear(); 539} 540 541 542function addZero(i) { 543 if (i < 10) { 544 i = "0" + i; 545 } 546 return i; 547} 548 549function getCurrentTime() { 550 var d = new Date(); 551 return addZero(d.getHours()) + ':' + addZero(d.getMinutes()); 552} 553 554/** 555 * full screen alert msg box 556 * @param msg 557 * @returns {boolean} 558 */ 559function showAlert(msg) { 560 var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; 561 562 $('#topMsgIcon').html("<img src='/appl/grfx/alerts/info_c.png' alt='alert' border='0' class='iconAlert' />"); 563 $('#topMsgText').html(msg); 564 565 $('#topMsgOverlay').show();
566 //$('#topMsgOverlay').css(); 567 return true; 568} 569 570function showTopAlertBox(msg, msgtype, duration, el) { 571 572 if (typeof (msgtype) == 'undefined') msgtype = 2; 573 if (typeof (duration) == 'undefined') duration = 5000; 574 if (typeof (el) == 'undefined') el = '#dynTopMsgContainer'; 575 let html = ''; 576 577 // show differetn alert type in backend 578 if (isBackend === true) { 579 let types = { 580 2: 'info-circle', 581 3: 'check-circle', 582 4: 'exclamation-triangle', 583 5: 'exclamation-circle', 584 }; 585 586 // cosntruct html 587 html = "<div id='alertContainer' class='animate__animated animate__fadeInDownBig' data-exitclass='animate__fadeOutUpBig'><div class='wrapperBox'>"; 588 html += "<div class='tb'><div class='tr type" + msgtype + "'>"; 589 if (msgtype > 0) { 590 html += "<div class='td colIcon'><div class='wrapper'><span class='symbol fa fa-" + types[msgtype] + "'> </span></div></div>"; 591 } 592 html += "<div class='td colBody'><div class='wrapper'>" + msg + "</div></div>" 593 html += "</div></div></div></div>"; 594 595 // msg on frontend 596 } else { 597 let icons = { 598 2: 'circle-info', 599 3: 'circle-check', 600 4: 'triangle-exclamation', 601 5: 'hand', 602 6: 'comment' 603 }; 604 605 // construct msg 606 html = "<div class='elementInfoboxTop boxModel absolute' id='topMsg'>"; 607 html += "<div class='infobox tb boxModel msgtype" + msgtype + "'><div class='tr'>"; 608 if (icons[msgtype].length > 0) html += "<div class='td cellIcon'><span class='icon symbol fa fa-" + icons[msgtype] + "'></span></div>"; 609 html += "<div class='td'>" + msg + "</div>"; 610 html += "<div class='td closer'><a href='javascript:;' onclick=\"$('#topMsg').hide();\" class='close_' ><span class='symbol fa fa-xmark'></span></a></div>"; 611 html += "</div></div>"; 612 html += "</div>"; 613 } 614 615 //$(el).css({'position': 'fixed', 'top': '80px'}); 616 617 // already an open message? 618 if ($(el).is(':visible')) { 619 setTimeout(function () { 620 $(el).html(html).show().delay(duration).fadeOut(); 621 $('#topMsg').width($(el).width()); 622 }, 5000); 623 624 } else { 625 $(el).html(html).show().delay(duration).fadeOut(); 626 $('#topMsg').width($(el).width()); 627 } 628} 629 630function redrawCoordPicker() { 631 var currCenter = GlobalCoordPicker.getCenter(); 632 google.maps.event.trigger(GlobalCoordPicker, 'resize'); 633 GlobalCoordPicker.setCenter(currCenter); 634} 635 636function inIframe() { 637 try { 638 return window.self !== window.top; 639 } catch (e) { 640 return true; 641 } 642} 643 644function sanitizeTime(time) { 645 time = time.replace('.', ':'); 646 if (time == '') time = '00:00'; 647 if (time.indexOf(':') == -1) time += ':00'; 648 var tmp = time.split(':'); 649 if (parseInt(tmp[1]) < 10 && parseInt(tmp[1]) != 0) tmp[1] = '0' + parseInt(tmp[1]); 650 if (parseInt(tmp[1]) > 59) tmp[1] = '00'; 651 time = tmp[0] + ':' + tmp[1]; 652 return time; 653} 654 655function checkFileType(el, allowed, msgfail) { 656 //var type = el.files[0].type; 657 var type = document.getElementById(el).files[0].type; 658 var match = false; 659 660 for (var index = 0; index < allowed.length; ++index) { 661 if (type == allowed[index]) { 662 match = true; 663 } 664 } 665 666 if (match === false) { 667 alert(msgfail); 668 return false; 669 } else { 670 return true; 671 } 672} 673 674function closeDivOnClickOutside(elhide, elclear, eltriggerclick) { 675 var el = $(elhide); 676 var elcl = $(elclear); 677 var elclick = $(eltriggerclick); 678 679 // hide on clicked outside 680 $(document).mouseup(function (e) { 681 if (!el.is(e.target) && el.has(e.target).length === 0) { 682 if (eltriggerclick != null) { 683 elclick.trigger('click'); 684 } else { 685 el.hide(); 686 if (elclear != null) elcl.html(''); 687 } 688 $('#darkenerFull').hide(); 689 $('.desaturate').removeClass('desaturate'); 690 } 691 }); 692 693 // hide on hit esc 694 $(document).on('keydown', function (e) { 695 if (e.keyCode === 27) { // ESC 696 if (eltriggerclick != null) { 697 elclick.trigger('click'); 698 } else { 699 el.hide(); 700 if (elclear != null) elcl.html(''); 701 } 702 $('#darkenerFull').hide(); 703 } 704 }); 705} 706 707function showRichAlert(msg, title, okbutton, addclasswindow) {
708 if (typeof (title) == 'undefined') title = 'Hinweis'; 709 if (typeof (okbutton) == 'undefined') okbutton = true; 710 title = "<span class='symbol gi gii gi-info-sign'></span> " + title; 711 taskWindowHandler($('#mainWrapperMid'), msg, title, null, okbutton, false, false, addclasswindow); 712} 713 714function taskWindowHandler(el, data, title, addcssclass, okbutton, cancelbutton, urlok, addclasswindow, nocloseonclickoutside, winheight, reloadurlonclose) { 715 716 if (typeof (addclasswindow) == 'undefined' || addclasswindow == null) addclasswindow = ''; 717 if (typeof (addcssclass) == 'undefined' || addcssclass == null) addcssclass = ''; 718 if (typeof (okbutton) == 'undefined' || okbutton == false) okbutton = false; 719 if (typeof (cancelbutton) == 'undefined' || cancelbutton === false) { 720 cancelbutton = false; 721 } else okbutton = 'OK'; 722 if (typeof (nocloseonclickoutside) == 'undefined' || nocloseonclickoutside == null) { 723 nocloseonclickoutside = false; 724 } 725 if (typeof (winheight) == 'undefined' || winheight == null) { 726 winheight = 0.85; 727 } 728 729 // construct html task window 730 var html = "<div id='darkenerFull'><div class='tb boxModel'><div class='tr'><div class='td' id='clickToClose'>"; 731 html += "<div id='taskWindow' class='" + addclasswindow + "'>"; 732 html += "<div class='titleBar'><a class='autoWidth rightAuto' href='javascript:;' id='closerTaskWindow'><span class='symbol gi gi-remove-sign'></span></a><h3 class='backlink'>" + title + "</h3></div>"; 733 html += "<div id='taskWindowContentWrapper' class='" + addcssclass + "'>"; 734 html += "<div class='wrapperPadding'>"; 735 html += data; 736 737 if (cancelbutton !== false) { 738 html += "<div class='marginTop' align='right'>"; 739 html += "<a class='button autoWidth' href='javascript:;' onclick=\"$('#closerTaskWindow').trigger('click');\">" + cancelbutton + "</a> " 740 html += "<a class='button autoWidth' href='" + urlok + "'>" + okbutton + "</a>" 741 html += "<div class='clear'></div></div>"; 742 } else { 743 if (okbutton != false) { 744 oktext = (okbutton === true) ? 'OK' : okbutton; 745 html += "<div class='marginTop' align='right'><a class='button autoWidth' href='javascript:;' id='taskWindowOkButton' onclick=\"$('#closerTaskWindow').trigger('click');\">" + oktext + "</a></div>" 746 } 747 } 748 html += "</div></div></div></div></div></div></div>"; 749 750 // first remove old task window 751 $('#darkenerFull').remove(); 752 753 el.after(html); 754 $('html').addClass('modal-open'); 755 $('body').addClass('modal-open'); 756 closeTaskWindowListener(el, nocloseonclickoutside, reloadurlonclose); 757 $('#taskWindowOkButton').focus(); 758 759 // adjust task window height 760 // var _top = $('#taskWindow').position().top; 761 //console.log(window.innerHeight); 762 var h = (window.innerHeight - $('#taskWindow .titleBar').height() - 15) * winheight; 763 $('#taskWindowContentWrapper').css({"max-height": h + "px"}); 764} 765 766function taskWindowRemoveCloseListeners(appender) { 767 $(document).off("mouseup"); 768 //$(document).off("keydown"); 769 $('#closerTaskWindow').off("click"); 770 $(appender).trigger('change'); 771} 772 773function closeTaskWindowListener(appender, nocloseonclickoutside, reloadurlonclose) { 774 var el = $('#taskWindow'); 775 776 if (typeof (reloadurlonclose) == 'undefined') reloadurlonclose = false; 777 778 // hide on clicked outside 779 if (nocloseonclickoutside !== true) { 780 $(document).on("mouseup touchend", function (e) { 781 //console.log(e.target); 782 if (!el.is(e.target) && el.has(e.target).length === 0) { 783 closeTaskWindow(); 784 } 785 }); 786 } 787 788 /* 789 // hide on hit esc 790 $(document).on('keydown', function (e) { 791 if (e.keyCode === 27) { // ESC 792 $('#darkenerFull').remove(); 793 taskWindowRemoveCloseListeners(appender); 794 $('._content, .myFooter').removeClass('blurred'); 795 } 796 }); 797 */ 798 799 // close button hit 800 $('#closerTaskWindow').click(function () { 801 $('#darkenerFull').remove(); 802 taskWindowRemoveCloseListeners(appender); 803 $('._content, .myFooter').removeClass('blurred'); 804 $('body').removeClass('modal-open'); 805 $('html').removeClass('modal-open'); 806 if (reloadurlonclose == true) location.reload(); 807 }); 808} 809 810function closeTaskWindow() { 811 $('#closerTaskWindow').trigger('click'); 812} 813 814/** 815 * Displays an information window modal with a title, content, and optional buttons. 816 * 817 * @param {string} title The title to display in the information window. 818 * @param {string} content The HTML content to be displayed in the body of the information window. 819 * @param {Array<Array<string>>} [btns] An optional array of buttons where each button is represented as a two-element array. 820 * The first element is the button's URL and the second element is the button's label. 821 * @return {void} This function does not return a value; it injects the modal structure into the DOM and manages interactions. 822 */ 823function infoWindow(title, content, btns, id) { 824 let hidealerts = [];
825 let c = ''; 826 827 let hasid = (typeof id !== 'undefined' && id.length > 0); 828 829 // window id? if set > don't show again checkbox 830 if (hasid) { 831 c = getCookie('_hidealerts'); 832 if (c != '') { 833 hidealerts = JSON.parse(c); 834 835 // leave here if don't show again was checked earlier 836 if (hidealerts.indexOf(id) > -1) { 837 return false; 838 } 839 } 840 } 841 842 // construct html 843 let html = "<div class='infoWindow floating'>"; 844 html += "<div class='caption flex nowrap'><h3 class='backlink'>" + title + "</h3><a href='javascript:;' class='closer fa fa-xmark'></a></div>"; 845 html += "<div class='body'>"; 846 html += content; 847 html += "</div>"; 848 849 // window id? if set > don't show again checkbox 850 if (hasid) { 851 html += "<div class='checkboxWrapper'><input type='checkbox' id='infoWindowShowAgain' /><label for='infoWindowShowAgain'>Nicht mehr anzeigen</label></div>"; 852 } 853 854 // buttons 855 if (typeof btns !== 'undefined' && btns.length > 0) { 856 html += "<div class='btns flex nowrap'>"; 857 let id = ''; 858 for (let i = 0; i < btns.length; i++) { 859 id = (typeof btns[i][2] !== 'undefined') ? btns[i][2] : ''; 860 html += "<a class='button' href='" + btns[i][0] + "' id='" + id + "'>" + btns[i][1] + "</a>"; 861 } 862 html += "</div>"; 863 } 864 html += "</div>"; 865 866 html = "<div id='darkenerFull' class='flex center dynInfoWindow'>" + html + "</div>"; 867 868 $('#darkenerFull').remove(); 869 870 let el = $('#mainWrapperMid'); 871 el.after(html); 872 $('html').addClass('modal-open'); 873 $('body').addClass('modal-open'); 874 875 // close window again 876 let win = $('#darkenerFull .infoWindow'); 877 878 // hide on clicked outside 879 $(document).on("mouseup touchend", function (e) { 880 if (!win.is(e.target) && win.has(e.target).length === 0) { 881 win.find('.closer').trigger('click'); 882 } 883 }); 884 885 // button with # url clicked > close win 886 win.find('.btns a').click(function (e) { 887 if ($(this).attr('href') == '#') { 888 e.preventDefault(); 889 } 890 win.find('.closer').trigger('click'); 891 }); 892 893 // close button hit / clicked outside 894 win.find('.closer').click(function () { 895 896 // store don't show again in cookie 897 if (hasid) { 898 if (win.find('#infoWindowShowAgain').is(':checked')) hidealerts.push(id); 899 else hidealerts = removeByValue(hidealerts, id); 900 if (hidealerts.length > 0) { 901 c = JSON.stringify(uniqueArray(hidealerts)); 902 setCookie('_hidealerts', c, 365); 903 } else { 904 setCookie('_hidealerts', '', -1); 905 } 906 } 907 908 $('#darkenerFull').remove(); 909 $(document).off("mouseup"); 910 $(this).off("click"); 911 $(el).trigger('change'); 912 $('._content, .myFooter').removeClass('blurred'); 913 $('body').removeClass('modal-open'); 914 $('html').removeClass('modal-open'); 915 }); 916} 917 918function uniqueArray(arr) { 919 return [...new Set(arr)]; 920} 921 922function removeByValue(array, value) { 923 return array.filter(item => item !== value); 924} 925 926function removeByKey(obj, key) { 927 if (Array.isArray(obj)) { 928 // numeric index case (real array) 929 if (key >= 0 && key < obj.length) { 930 return obj.slice(0, key).concat(obj.slice(key + 1)); 931 } 932 return obj; // invalid index, return unchanged 933 } else if (obj !== null && typeof obj === "object") { 934 // object case (associative "array") 935 const {[key]: _, ...rest} = obj; 936 return rest; 937 } 938 return obj; // if not array or object, return unchanged 939} 940 941function geoGetInfoWindow(title, content, buttontext) { 942 if (buttontext == null) buttontext = 'Weiter'; 943 var html = "<table><tr><td class='alignTop'><strong>" + title + "</strong><br>" + content + "</td><td class='alignBottom alignRight'><span class='button autoWidth'>" + buttontext + "</span></td><td width='25'></td></tr></table>"; 944 return html; 945} 946 947function getLoadingWheel(msg, cssclass, el) { 948 if (typeof (el) == 'undefined') el = 'div'; 949 return "<" + el + " class='" + cssclass + "'><img src='/appl/grfx/mopage/waiting.gif' alt='activitywheel' border='0' class='imgWaiting'/> " + msg + "</" + el + ">"; 950} 951 952function getLoadingDots(msg, cssclass) { 953 return "<div class='" + cssclass + "'><img src='/appl/grfx/mopage/loadingdots.svg' alt='activitywheel' border='0' class='imgWaitingDots'/> " + msg + "</div>"; 954} 955 956function makeSameHeight(cssclass) { 957 var h = 0; 958 $('.' + cssclass).each(function () { 959 h = h > $(this).height() ? h : $(this).height(); 960 }); 961 $('.' + cssclass).height(h); 962} 963 964if (typeof ($.datepicker) !== 'undefined') { 965 $.datepicker._gotoToday = function (id) { 966 $(id).datepicker('setDate', new Date()).datepicker('hide').blur(); 967 $.datepicker._selectDate.apply(this, [id]); 968 }; 969} 970 971 972// Function to reveal lightbox and adding YouTube autoplay 973function revealVideo(div, video_id) { 974 var video = document.getElementById(video_id).src; 975 document.getElementById(video_id).src = video + '&autoplay=1'; // adding autoplay to the URL 976 document.getElementById(div).style.display = 'block'; 977} 978 979// Hiding the lightbox and removing YouTube autoplay 980function hideVideo(div, video_id) { 981 var video = document.getElementById(video_id).src; 982 var cleaned = video.replace('&autoplay=1', ''); // removing autoplay form url 983 document.getElementById(video_id).src = cleaned; 984 document.getElementById(div).style.display = 'none'; 985} 986 987function inArray(needle, haystack) { 988 var length = haystack.length; 989 for (var i = 0; i < length; i++) { 990 if (haystack[i] == needle) return true; 991 } 992 return false;
993} 994 995function scrollToAnchor(aid, addheight) { 996 if (typeof (addheight) == 'undefined') addheight = 0; 997 var aTag = $("a[name='" + aid + "']"); 998 $('html,body').animate({scrollTop: aTag.offset().top - addheight}, 'slow'); 999} 1000 1001function checkInView(container, elem, partial) { 1002 var contHeight = container.height(); 1003 var contTop = container.scrollTop(); 1004 var contBottom = contTop + contHeight; 1005 var elemTop = elem.offset().top - container.offset().top; 1006 var elemBottom = elemTop + elem.height(); 1007 var isTotal = (elemTop >= 0 && elemBottom <= contHeight); 1008 var isPart = ((elemTop < 0 && elemBottom > 0) || (elemTop > 0 && elemTop <= container.height())) && partial; 1009 return isTotal || isPart; 1010} 1011 1012 1013// ENCODE UTF8 1014function encode_utf8(s) { 1015 return unescape(encodeURIComponent(s)); 1016} 1017 1018// DECODE UTF8 1019function decode_utf8(s) { 1020 return decodeURIComponent(escape(s)); 1021} 1022 1023String.prototype.toHtmlEntities = function () { 1024 return this.replace(/./gm, function (s) { 1025 // return "&#" + s.charCodeAt(0) + ";"; 1026 return (s.match(/[a-z0-9\s]+/i)) ? s : "&#" + s.charCodeAt(0) + ";"; 1027 }); 1028}; 1029 1030function doFormLabels(el) { 1031 $(el).find('input,textarea,select').each(function () { 1032 let label = $(this).attr('placeholder'); 1033 if (typeof (label) !== 'undefined' && label.length > 0) { 1034 $(this).before("<label>" + label + "</label>"); 1035 $(this).parent().append("<div class='clear'></div>"); 1036 } 1037 }); 1038} 1039 1040var delay = (function () { 1041 var timer = 0; 1042 return function (cb, ms) { 1043 clearTimeout(timer); 1044 timer = setTimeout(cb, ms); 1045 }; 1046})(); 1047 1048 1049function copyPageLink() { 1050 1051 /* Get the text field */ 1052 var copyText = document.getElementById("currentPageLink"); 1053 1054 /* Select the text field */ 1055 copyText.select(); 1056 copyText.setSelectionRange(0, 99999); /* For mobile devices */ 1057 1058 /* Copy the text inside the text field */ 1059 navigator.clipboard.writeText(copyText.value); 1060 1061 /* Alert the copied text */ 1062 showTopAlertBox("Link wurde erfolgreich kopiert!", 3, 2000) 1063 //alert("Copied the text: " + copyText.value); 1064} 1065 1066function dump(data) { 1067 $.post('/appl/api.php?do=dump', data); 1068} 1069 1070function _currconv(val, idel) { 1071 let amount = val / 100; 1072 amount = amount.toLocaleString('de-CH', {style: 'currency', currency: 'CHF'}); 1073 $('#' + idel).text(amount); 1074} 1075 1076function getstr(val) { 1077 if (typeof (val) == 'undefined') return ''; 1078 return val; 1079} 1080 1081function hexToRgbA(hex, trnsp) { 1082 var c; 1083 trnsp = (typeof (trnsp) === 'undefined') ? trnsp = 1 : trnsp; 1084 if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) { 1085 c = hex.substring(1).split(''); 1086 if (c.length == 3) { 1087 c = [c[0], c[0], c[1], c[1], c[2], c[2]]; 1088 } 1089 c = '0x' + c.join(''); 1090 return 'rgba(' + [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(',') + ',' + trnsp + ')'; 1091 } 1092 // throw new Error('Bad Hex'); 1093} 1094 1095function getUnixTime(date = Date.now()) { 1096 return Math.floor(date / 1000) 1097} 1098 1099function debounce(fn, delay) { 1100 let timeout; 1101 return function () { 1102 clearTimeout(timeout); 1103 timeout = setTimeout(() => fn.apply(this, arguments), delay); 1104 }; 1105} 1106 1107function normalizeText(text) { 1108 const umlautMap = { 1109 'ä': 'ae', 'ö': 'oe', 'ü': 'ue', 1110 'Ã': 'ae', 'Ã': 'oe', 'Ã': 'ue', 1111 'Ã': 'ss' 1112 }; 1113 1114 return text 1115 .replace(/[äöüÃÃÃÃ]/g, match => umlautMap[match]) 1116 .toLowerCase() 1117 .replace(/[^a-z0-9]/g, ''); 1118} 1119 1120// ââ WebAuthn / Passkey helpers ââââââââââââââââââââââââââââââââââââââââââââââââ 1121 1122function passkeyB64ToBuffer(b64url) { 1123 const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/'); 1124 const bin = atob(b64); 1125 const buf = new Uint8Array(bin.length); 1126 for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i); 1127 return buf.buffer; 1128} 1129 1130function passkeyBufToB64(buf) { 1131 const bytes = new Uint8Array(buf); 1132 let bin = ''; 1133 bytes.forEach(b => bin += String.fromCharCode(b)); 1134 return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); 1135} 1136 1137function passkeyCredToJSON(cred) { 1138 const r = cred.response; 1139 const obj = { id: cred.id, rawId: passkeyBufToB64(cred.rawId), type: cred.type, response: {} }; 1140 if (r.clientDataJSON) obj.response.clientDataJSON = passkeyBufToB64(r.clientDataJSON); 1141 if (r.authenticatorData) obj.response.authenticatorData = passkeyBufToB64(r.authenticatorData); 1142 if (r.attestationObject) obj.response.attestationObject = passkeyBufToB64(r.attestationObject); 1143 if (r.signature) obj.response.signature = passkeyBufToB64(r.signature); 1144 if (r.userHandle) obj.response.userHandle = passkeyBufToB64(r.userHandle); 1145 if (cred.authenticatorAttachment) obj.authenticatorAttachment = cred.authenticatorAttachment; 1146 return obj; 1147} 1148 1149function passkeyAutoName(credential) { 1150 let os = ''; 1151 if (navigator.userAgentData?.platform) { 1152 os = navigator.userAgentData.platform; 1153 } else { 1154 const ua = navigator.userAgent; 1155 if (/iPhone/.test(ua)) os = 'iPhone'; 1156 else if (/iPad/.test(ua)) os = 'iPad'; 1157 else if (/Android/.test(ua)) os = 'Android'; 1158 else if (/Mac/.test(ua)) os = 'Mac'; 1159 else if (/Windows/.test(ua)) os = 'Windows'; 1160 else if (/Linux/.test(ua)) os = 'Linux'; 1161 } 1162 if (credential.authenticatorAttachment === 'cross-platform') return (os ? os + ' · ' : '') + 'Sicherheitsschlüssel'; 1163 return os || 'Passkey'; 1164} 1165 1166function passkeyInitLogin(apiUrl) { 1167 if (!window.PublicKeyCredential) return; 1168 $('#passkeyLoginWrapper').removeClass('hidden') 1169 1170 function showMsg(msg, isError) { 1171 const el = document.getElementById('passkeyLoginMsg'); 1172 el.textContent = msg; 1173 el.style.color = isError ? '#c00' : ''; 1174 el.style.display = ''; 1175 } 1176 1177 async function passkeyAuth() { 1178 const btn = document.getElementById('btnPasskeyLogin'); 1179 btn.disabled = true; 1180 showMsg('Passkey wird abgefragtâ¦'); 1181 try { 1182 const optRes = await fetch(apiUrl + '?do=passkeyAuthOptions'); 1183 const options = await optRes.json(); 1184 options.challenge = passkeyB64ToBuffer(options.challenge); 1185 if (options.allowCredentials) { 1186 options.allowCredentials = options.allowCredentials.map(c => ({ ...c, id: passkeyB64ToBuffer(c.id) })); 1187 } 1188 const credential = await navigator.credentials.get({ publicKey: options }); 1189 const stay = document.querySelector('[name=stayloggedin]')?.checked ? '1' : '0'; 1190 const verRes = await fetch(apiUrl + '?do=passkeyAuthVerify&stayloggedin=' + stay, { 1191 method: 'POST', 1192 headers: { 'Content-Type': 'application/json' }, 1193 body: JSON.stringify(passkeyCredToJSON(credential)) 1194 }); 1195 const result = await verRes.json(); 1196 if (result.ok) { 1197 showMsg('Erfolgreich â wird weitergeleitetâ¦'); 1198 window.location = result.redirect; 1199 } else { 1200 showMsg(result.error || 'Fehler bei der Authentifizierung.', true); 1201 btn.disabled = false;
1202 } 1203 } catch (e) { 1204 if (e.name !== 'NotAllowedError') showMsg('Fehler: ' + e.message, true); 1205 else showMsg(''); 1206 btn.disabled = false; 1207 } 1208 } 1209 1210 document.getElementById('btnPasskeyLogin').addEventListener('click', passkeyAuth); 1211 1212 if (PublicKeyCredential.isConditionalMediationAvailable) { 1213 PublicKeyCredential.isConditionalMediationAvailable().then(async available => { 1214 if (!available) return; 1215 const optRes = await fetch(apiUrl + '?do=passkeyAuthOptions'); 1216 const options = await optRes.json(); 1217 options.challenge = passkeyB64ToBuffer(options.challenge); 1218 options.allowCredentials = []; 1219 try { 1220 const credential = await navigator.credentials.get({ publicKey: options, mediation: 'conditional' }); 1221 const verRes = await fetch(apiUrl + '?do=passkeyAuthVerify', { 1222 method: 'POST', 1223 headers: { 'Content-Type': 'application/json' }, 1224 body: JSON.stringify(passkeyCredToJSON(credential)) 1225 }); 1226 const result = await verRes.json(); 1227 if (result.ok) window.location = result.redirect; 1228 } catch (e) { 1229 } 1230 }); 1231 } 1232} 1233 1234function passkeyInitManager(apiUrl) { 1235 if (!window.PublicKeyCredential) { 1236 $('#btnAddPasskey').addClass('hidden') 1237 return; 1238 } 1239 1240 function showMsg(msg, ok) { 1241 const el = document.getElementById('passkeyAddMsg'); 1242 el.textContent = msg; 1243 el.style.color = ok ? 'green' : '#c00'; 1244 $('#passkeyAddMsg').removeClass('hidden'); 1245 } 1246 1247 document.getElementById('btnAddPasskey').addEventListener('click', async () => { 1248 const btn = document.getElementById('btnAddPasskey'); 1249 btn.disabled = true; 1250 try { 1251 const optRes = await fetch(apiUrl + '?do=passkeyRegisterOptions'); 1252 const options = await optRes.json(); 1253 options.challenge = passkeyB64ToBuffer(options.challenge); 1254 options.user.id = passkeyB64ToBuffer(options.user.id); 1255 if (options.excludeCredentials) { 1256 options.excludeCredentials = options.excludeCredentials.map(c => ({ ...c, id: passkeyB64ToBuffer(c.id) })); 1257 } 1258 const credential = await navigator.credentials.create({ publicKey: options }); 1259 const name = passkeyAutoName(credential); 1260 const verRes = await fetch(apiUrl + '?do=passkeyRegisterVerify', { 1261 method: 'POST', 1262 headers: { 'Content-Type': 'application/json', 'X-Passkey-Name': name }, 1263 body: JSON.stringify(passkeyCredToJSON(credential)) 1264 }); 1265 const result = await verRes.json(); 1266 if (result.ok) { showMsg('Passkey erfolgreich gespeichert.', true); location.reload(); } 1267 else showMsg(result.error || 'Fehler beim Speichern.', false); 1268 } catch (e) { 1269 if (e.name !== 'NotAllowedError') showMsg('Fehler: ' + e.message, false); 1270 } 1271 btn.disabled = false; 1272 }); 1273 1274 window.passkeyDelete = async function (id, btn) { 1275 if (!confirm('Passkey wirklich löschen?')) return; 1276 btn.disabled = true; 1277 const fd = new FormData(); 1278 fd.append('id', id); 1279 await fetch(apiUrl + '?do=passkeyDelete', { method: 'POST', body: fd }); 1280 btn.closest('.theRow').remove(); 1281 if (!document.querySelectorAll('#passkeyList .theRow').length) location.reload(); 1282 }; 1283} 1284 1285function onceVisible(el, callback) { 1286 el = el instanceof jQuery ? el[0] : el; 1287 1288 // already visible? just measure now 1289 if (el.offsetParent !== null) { 1290 callback(el.offsetWidth); 1291 return; 1292 } 1293 1294 // find the nearest ancestor that's actually hiding it 1295 let target = el.parentElement; 1296 while (target && getComputedStyle(target).display !== 'none') { 1297 target = target.parentElement; 1298 } 1299 if (!target) target = document.body; 1300 1301 const observer = new MutationObserver(() => { 1302 if (el.offsetParent !== null) { 1303 observer.disconnect(); 1304 callback(el.offsetWidth); 1305 } 1306 }); 1307 1308 observer.observe(target, { 1309 attributes: true, 1310 attributeFilter: ['style', 'class'], 1311 subtree: true // in case a different ancestor toggles 1312 }); 1313} 1314 1315$.fn.onceVisible = function (callback) { 1316 return this.each(function () { 1317 onceVisible(this, callback.bind(this)); 1318 }); 1319}; 1320 1321function resizeMapContainer(frontendid){ 1322 $(document).ready(function() { 1323 var h = $('#_vertical_').offset().top; 1324 if (frontendid == 6){ 1325 $('#theMapContainer').css({top: h}); 1326 } else { 1327 h = window.innerHeight - h; 1328 if ($('.elementStickyButtonBottom').length > 0 && $('.elementStickyButtonBottom').is(':hidden') == false) { 1329 h = h - $('.elementStickyButtonBottom').height(); 1330 $('#theMapContainer').css({bottom: $('.elementStickyButtonBottom').height()}); 1331 } 1332 $('#theMapContainer').height(h - 1); 1333 } 1334 }); 1335} 1336 1337function getFullHeight(el) { 1338 if (el instanceof jQuery) el = el[0]; 1339 const style = getComputedStyle(el); 1340 const marginTop = parseFloat(style.marginTop); 1341 const marginBottom = parseFloat(style.marginBottom); 1342 return el.offsetHeight + marginTop + marginBottom; 1343}
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.