1// 2// Sicherstellen, dass es auch in älteren Browsern eine trim()-Methode gibt. 3// 4if (!String.trim) 5{ 6 String.prototype.trim = function() 7 { 8 return this.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); 9 }; 10} 11 12// 13// Für elegantere Abfragen nach leeren Zeichenkette, wird das 14// String-Objekt um eine isEmpty()-Methode ergänzt. 15// 16if (!String.isEmpty) 17{ 18 String.prototype.isEmpty = function() 19 { 20 return this.length <= 0; 21 }; 22} 23 24/** 25 * Funktion ruft die übergebene URL per Ajax auf. 26 * 27 * @param url Die Adresse, die aufgerufen werden soll. 28 * @param domDest Element, oder die Id eines Elements, dessen 29 * Inhalt mit dem Ergebnis des Ajax-Aufrufs überschrieben werden soll. 30 * @param config Weitere Konfigurationsparameter: 31 * execJS: Führt in der Antwort enthaltene JavaScript-Blöcke aus. 32 * Wird nur beachtet, wenn ein Ziel-Element über domDest 33 * angegeben wurde. 34 * Standard: true 35 * callBack: Diese Funktion wird am Ende der Verabeitung des Response 36 * aufgerufen, wenn der Call mit Status 200 abgeschickt werden konnte. 37 * Die Textanwort wird als Parameter übergeben. 38 * Standard: keine 39 * error: Diese Funktion wird am Ende der Verabeitung des Response 40 * aufgerufen, wenn es einen Statuscode größer 300 gab. 41 * Der genaue Statuscode wird als Parameter übergeben. 42 * Standard: keine 43 * onReady: Wenn mit einer Funktion gesetzt, ersetzt diese Funktion 44 * weitestgehend die Verarbeitung der Serverantwort. 45 * Funktion erhält dafür auch das gesamte XMLHttpRequest-Objekt. 46 * Standard: keine 47 * method: 'POST', 48 * keepAlive: Falls true, wird der Request nicht vom Browser abgeräumt, auch wenn 49 * die Webpage, die den Request initiiert hat, selbst schon abgeräumt wurde. 50 * Standard: false 51 * timeout: Nur bei keepAlive = false: Zeit in Sekunden, nach der der Aufruf 52 * abgebrochen werden soll. 53 * Standard: 0 (kein Abbruch) 54 * sendDaten: Zusätzliche Daten, die dem Request mitgeschickt werden sollen. 55 * event: Konfigurationsparameter für das Ajax-Event: 56 * name: Der Name des Ajax-Events. 57 * Standard: HREventNames.ajaxload. 58 * bubbles: Default: true. 59 * useStandard: Default: false. 60 * notifySelf: Default: true. 61 * notifyChildren: Default: true. 62 * notifyParents: Default: true. 63 * notifyAll: Default: true. 64 * @returns Der Response als Zeichenkette oder false, wenn der Aufruf fehlgeschlagen ist. 65 */ 66function HRSendRequest(url, domDest, config) 67{ 68 try 69 { 70 var resConfig = mergeSendConfig(config); 71 resConfig.url = url; 72 resConfig.domDest = domDest; 73 if (resConfig.keepAlive && typeof(fetch) === 'function') 74 { 75 return fetchImpl(resConfig); 76 } 77 else 78 { 79 return sendRequestImpl(resConfig); 80 } 81 } 82 catch (e) 83 { 84 if (typeof(HRLogError) == 'function') 85 HRLogError(e); 86 } 87 return false; 88} 89 90/** 91 * Funktion ruft die übergebene URL per Ajax auf und invalidiert den Aufruf über diejenige Anwendung, 92 * welche sich in der DOM-Hierarchie als nächstes zuständig fühlt. Dies ist i.A. Gruppe oder Webpage. 93 * 94 * @see @link{#HRSendRequest(url, domDest, config)} 95 */ 96function HRSendRequestAndInvalidate(url, sender, config) 97{ 98 config.sender = sender; 99 config.invalidate = true; 100 return HRSendRequest(url, null, config); 101} 102 103/** 104 * Funktion sendet die übergebene Form per Ajax an die Adresse, die im Action-Tag der Form steht. 105 * 106 * @param form Das Form-Objekt oder der Name bzw. Id der Form. 107 * @param domDest Id des Elements, oder das Element selbst, in das das Ergebnis des Request geschrieben wird. 108 * @param config Weitere Konfigurationsparameter: 109 * execJS: Führt in der Antwort enthaltene JavaScript-Blöcke aus. 110 * Wird nur beachtet, wenn ein Ziel-Element über domDest 111 * angegeben wurde. 112 * Standard: true 113 * callBack: Diese Funktion wird am Ende der Verabeitung des Response 114 * aufgerufen. Die Textanwort wird als Parameter übergeben. 115 * Standard: keine 116 * onRequestError: Diese Funktion wird am Ende der Verabeitung des Response 117 * aufgerufen, wenn es einen Statuscode größer 300 gab. 118 * Der genaue Statuscode wird als Parameter übergeben. 119 * Standard: keine 120 * onReady: Wenn mit einer Funktion gesetzt, ersetzt diese Funktion 121 * weitestgehend die Verarbeitung der Serverantwort. 122 * Funktion erhält dafür auch das gesamte XMLHttpRequest-Objekt. 123 * Standard: keine 124 * method: 'POST', 125 * keepAlive: Falls true, wird der Request nicht vom Browser abgeräumt, auch wenn 126 * die Webpage, die den Request initiiert hat, selbst schon abgeräumt wurde. 127 * Standard: false 128 * timeout: Nur bei keepAlive = false: Zeit in Sekunden, nach der der Aufruf 129 * abgebrochen werden soll. 130 * Standard: 0 (kein Abbruch) 131 * sendDaten: Zusätzliche Daten, die dem Request mitgeschickt werden sollen. 132 * Standard: keine 133 * invalidate: Falls true, wird der Aufruf mit der nächstmöglichen übergeordneten Anwendung invalidiert. 134 * Es wird dann das Template der invalidierenden Anwendung zurückgegegben. 135 * onErrors: Falls Fehlermeldungen als Header mitgeschickt werden, können diese über die Callbackfunktion weiter verarbeitet werden. 136 * @param errors Die Meldungen als Array. 137 * onWarnings: Falls Warnungen als Header mitgeschickt werden, können diese über die Callbackfunktion weiter verarbeitet werden. 138 * @param warnings Die Meldungen als Array. 139 * onInfos: Falls Info-Meldungen als Header mitgeschickt werden, können diese über die Callbackfunktion weiter verarbeitet werden. 140 * @param infos Die Meldungen als Array. 141 * onHeadersReceived: Callback-Funktion, die auf das Lesen der Response-Header reagiert. 142 * @param getHeader Funktion, die den Wert zum übergebenen Headernamen zurückgibt. 143 * @param name Der Headername. 144 * @param decodeBase64 [optional] Falls true, wird der Headerwert noc
144h Base-64-dekodiert. 145 * Standard: keine 146 * @returns Der Response als Zeichenkette oder false, wenn der Aufruf fehlgeschlagen ist. 147 */ 148function HRSendForm(form, domDest, config) 149{ 150 try 151 { 152 var resConfig = mergeSendConfig(config); 153 resConfig.form = form; 154 resConfig.domDest = domDest; 155 if (resConfig.keepAlive && typeof(fetch) === 'function') 156 { 157 return fetchImpl(resConfig); 158 } 159 else 160 { 161 return sendRequestImpl(resConfig); 162 } 163 } 164 catch (e) 165 { 166 if (typeof(HRLogError) == 'function') 167 HRLogError(e); 168 } 169 return false; 170} 171 172/** 173 * Funktion ruft die übergebene URL per Ajax auf und invalidiert den Aufruf über diejenige Anwendung, 174 * welche sich in der DOM-Hierarchie als nächstes zuständig fühlt. Dies ist i.A. Gruppe oder Webpage. 175 * 176 * @param sender Element, welches von der den Request sendenden und zu invalidierenden Subanwendung aufgerufen wird. 177 * @see @link{#HRSendForm(form, domDest, config)} 178 */ 179function HRSendFormAndInvalidate(form, sender, config) 180{ 181 config.sender = sender; 182 config.invalidate = true; 183 return HRSendForm(form, null, config); 184} 185 186/** 187 * Funktion baut aus den Elementen des übergebenen Form-Objekts 188 * einen QueryString zusammen, der dann z.B. für eine Get-URL 189 * verwendet werden kann. 190 * 191 * @param aForm Form-Objekt. 192 * @returns Zeichenkette mit dem QueryString aus den Name / Werte Paaren der Formelemente. 193 */ 194function HRQueryStringFromFormdata(aForm) 195{ 196 if (!aForm || typeof(aForm) != 'object') 197 return ""; 198 199 var queryString = ""; 200 try 201 { 202 for(var j = 0; j < aForm.elements.length; j++) 203 { 204 var element = aForm.elements[j]; 205 if (element) 206 { 207 var value = null; 208 if (element.nodeName && element.name && !element.name.trim().isEmpty()) 209 { 210 if (element.type && (element.type.toLowerCase() == "radio" || element.type.toLowerCase() == "checkbox")) 211 { 212 if (element.checked && element.value) 213 value = element.value; 214 } 215 else if (element.value) 216 value = element.value; 217 else 218 value = ""; 219 220 if (value != null) 221 { 222 if (queryString != "") 223 queryString += "&"; 224 225 queryString += element.name + "=" + encodeURIComponent(value); 226 } 227 } 228 } 229 } 230 } 231 catch (e) 232 { 233 if (typeof(HRLogError) == 'function') 234 HRLogError(e); 235 } 236 return queryString; 237} 238 239/** 240 * Interne Funktion, die alle Informationen für den Request aus der Config ermittelt und das XMLHttpRequest-Objekt verwendet. 241 * 242 * @param config Konfiguration des Requests. 243 * @returns 244 */ 245function sendRequestImpl(config) 246{ 247 try 248 { 249 var htmlRequest = createAjaxObj(); 250 var url = null; 251 var sendDaten = null; 252 var formQueryString = null; 253 if (config.form) 254 { 255 var aForm = null; 256 if (typeof(config.form) === 'string' || typeof(config.form) === 'number') 257 { 258 aForm = document.forms[config.form]; 259 if (aForm == null && typeof(config.form) !== 'number') 260 aForm = document.getElementById(config.form); 261 } 262 else if (typeof(config.form) === 'object') 263 { 264 aForm = config.form; 265 } 266 if (aForm) 267 { 268 url = aForm.action; 269 try 270 { 271 if (!config.sendDaten) 272 sendDaten = new FormData(aForm); 273 } 274 catch (e) 275 { 276 formQueryString = HRQueryStringFromFormdata(aForm); 277 } 278 } 279 } 280 if (config.url) 281 url = config.url; 282 283 if (config.sendDaten) 284 { 285 sendDaten = config.sendDaten; 286 } 287 else if (formQueryString) 288 { 289 if (url.indexOf("?") >= 0) 290 url += "&" + formQueryString; 291 else 292 url += "?" + formQueryString; 293 } 294 if (!config.keepAlive) 295 { 296 if (htmlRequest.timeout && config.timeout && config.timeout > 0) 297 htmlRequest.timeout = config.timeout; 298 299 if (config.onReady || config.callBack || config.domDest) 300 { 301 htmlRequest.onreadystatechange = function() 302 { 303 retrieveResponse(htmlRequest, config); 304 }; 305 } 306 } 307 htmlRequest.open(config.method, url, !config.keepAlive); 308 if (sendDaten && sendDaten instanceof FormData && typeof(sendDaten.get) == 'function') 309 { 310 try 311 { 312 // Nur bei internen Aufrufen (also relative Url oder übereinstimmende Domainnamen). 313 if (!sendDaten.get('IsAjaxCall') && url.trim().startsWith('/') || window.location.hostname === (new URL(url).hostname)) 314 sendDaten.set('IsAjaxCall', 'J'); 315 } 316 catch (e) 317 { 318 } 319 320 if (!sendDaten.get('__ENCODING__')) 321 sendDaten.set('__ENCODING__', 'UTF-8'); 322 323 // Alle Nicht-ISO-8859-1-Zeichen werden in HTML-Entitäten gewandelt. 324 const encodedFormData = new FormData(); 325 for (let [key, value] of sendDaten.entries()) 326 { 327 if (typeof(value) == 'string') 328 encodedFormData.append(key, HREncodeToHtmlEntities(value)); 329 else 330 encodedFormData.append(key, value); 331 } 332 sendDaten = encodedFormData; 333 } 334 335 // Soll der Aufruf invalidiert werden?
336 if (config.invalidate) 337 { 338 // Ermitteln der Invalidierungsurl. Diese wird im HTML-Code der invalidierenden 339 // Anwendung über das data-Attribut 'data-invalidation-action' gesetzt. Wir hangeln 340 // uns also im DOM so lange nach oben bis wir auf ein solches data-Attribut treffen. 341 let sender = config.sender; 342 if (sender) 343 { 344 if (typeof(config.sender) === 'string') 345 { 346 sender = document.getElementById(config.sender); 347 if (sender == null && document.querySelector) 348 sender = document.querySelector(config.sender); 349 } 350 351 if (sender) 352 { 353 // Kann das sendende Element selbst invalidieren oder müssen wir uns 354 // nach oben bis zum nächsten invalidierenden Element hangeln? 355 const invalidatingParent = sender.closest('[data-invalidation-action]'); 356 if (invalidatingParent && invalidatingParent.dataset.invalidationAction.length > 0) 357 { 358 sendDaten.set('Call.InvalidationAction', invalidatingParent.dataset.invalidationAction); 359 360 // Es wird nun das HTML des invalidierenden Parents ausgetauscht, nicht mehr das HTML der invalidierten Subanwendung. 361 config.domDest = invalidatingParent; 362 } 363 } 364 } 365 } 366 367 htmlRequest.send(sendDaten); 368 369 if (config.keepAlive) 370 return retrieveResponse(htmlRequest, config); 371 else 372 return true; 373 } 374 catch (e) 375 { 376 if (typeof(HRLogError) == 'function') 377 HRLogError(e); 378 } 379 return false; 380} 381 382/** 383 * Wandelt alle nicht-ISO-Zeichen in HTML-Entitäten um. 384 * 385 * @param Die Zeichenkette, in der in HTML-Entitäten umgewandelt werden soll. 386 * @param blacklist Ein Blacklist-Array mit Zeichen, die von der 387 * Umwandelung ausgeschlossen werden sollen. 388 * @return Die bearbeitete Zeichenkette. 389 */ 390function HREncodeToHtmlEntities(str, blacklist) 391{ 392 try 393 { 394 if (str) 395 { 396 return str.split(/(?:)/u).map(char => { 397 if (blacklist && blacklist.includes(char)) 398 return char; 399 else if (char.codePointAt(0) > 255) // Prüfen, ob das Zeichen außerhalb der ISO-8859-1-Range (0-255) liegt. 400 return '&#' + char.codePointAt(0) + ';'; 401 else 402 return char; 403 }).join(''); 404 } 405 } 406 catch (e) 407 { 408 if (typeof(HRLogError) === 'function') 409 HRLogError(e); 410 } 411 412 return str; 413} 414 415/** 416 * Interne Funktion, die alle Informationen für den Request aus der Config ermittelt und diese mit Hilfe eines Fetches abschickt. 417 * Mehr Informationen zum Fetch als modernen Ersatz für den XMLHttpRequest unter {@linkplain "https://github.github.io/fetch/"}. 418 * 419 * @param config Konfiguration des Requests. 420 * @returns 421 */ 422function fetchImpl(config) 423{ 424 try 425 { 426 var sendDaten = null; 427 var formQueryString = null; 428 if (config.form) 429 { 430 var aForm = null; 431 if (typeof(config.form) == 'string' || typeof(config.form) == 'number') 432 { 433 aForm = document.forms[config.form]; 434 if (aForm == null && typeof(config.form) != 'number') 435 aForm = document.getElementById(config.form); 436 } 437 else if (typeof(config.form) == 'object') 438 { 439 aForm = config.form; 440 } 441 if (aForm) 442 { 443 url = aForm.action; 444 try 445 { 446 sendDaten = new FormData(aForm); 447 } 448 catch (e) 449 { 450 formQueryString = HRQueryStringFromFormdata(aForm); 451 } 452 } 453 } 454 455 if (config.url) 456 url = config.url; 457 458 if (config.sendDaten) 459 { 460 sendDaten = config.sendDaten; 461 } 462 else if (formQueryString) 463 { 464 if (url.indexOf("?") >= 0) 465 url += "&" + formQueryString; 466 else 467 url += "?" + formQueryString; 468 } 469 470 if (sendDaten && sendDaten instanceof FormData && typeof(sendDaten.get) == 'function' && !sendDaten.get('__ENCODING__')) 471 sendDaten.set('__ENCODING__', 'UTF-8'); 472 473 // Soll der Aufruf invalidiert werden?
474 if (config.invalidate) 475 { 476 // Ermitteln der Invalidierungsurl. Diese wird im HTML-Code der invalidierenden 477 // Anwendung über das data-Attribut 'data-invalidation-action' gesetzt. Wir hangeln 478 // uns also im DOM so lange nach oben bis wir auf ein solches data-Attribut treffen. 479 let sender = config.sender; 480 if (sender) 481 { 482 if (typeof(config.sender) === 'string') 483 { 484 sender = document.getElementById(config.sender); 485 if (sender == null && document.querySelector) 486 sender = document.querySelector(config.sender); 487 } 488 489 if (sender) 490 { 491 const invalidatingParent = sender.closest('[data-invalidation-action]'); 492 if (invalidatingParent && invalidatingParent.dataset.invalidationAction.length > 0) 493 { 494 sendDaten.set('Call.InvalidationAction', invalidatingParent.dataset.invalidationAction); 495 496 // Es wird nun das HTML des invalidierenden Parents ausgetauscht, nicht mehr das HTML der invalidierten Subanwendung. 497 config.domDest = invalidatingParent; 498 } 499 } 500 } 501 } 502 503 fetch(url, { 504 method: config.method, 505 body: sendDaten, 506 keepalive: config.keepAlive 507 }).then(function (response) { 508 if (response.ok) 509 retrieveFetchResponse(response, config); 510 return Promise.resolve(response); 511 }).catch(function(response) { 512 if (typeof(HRLogError) == 'function') 513 HRLogError(response); 514 Promise.reject(response); 515 }); 516 517 return true; 518 } 519 catch (e) 520 { 521 if (typeof(HRLogError) == 'function') 522 HRLogError(e); 523 } 524 return false; 525} 526 527/** 528 * Liefert eine vollständige Konfiguration mit Defaultwerten 529 * und den Angaben durch den Aufrufer. 530 * 531 * @param userConfig Konfiguration durch Aufrufer. Überschreibt 532 * die Default-Angaben. 533 * @returns 534 */ 535function mergeSendConfig(userConfig) 536{ 537 var defaultConfig = {keepAlive: false, execJS: true, onReady: null, callBack: null, method: 'POST', domDest: null, form: null, timeout: 0, url: null, sendDaten: null}; 538 var config = defaultConfig; 539 if (userConfig) 540 { 541 for(key in userConfig) 542 { 543 config[key] = userConfig[key]; 544 } 545 } 546 return config; 547} 548 549/** 550 * Interne Funktion, um die Antwort aus dem Response 551 * zu verarbeiten. 552 */ 553function retrieveResponse(htmlRequest, config) 554{ 555 var content = ""; 556 try 557 { 558 if (htmlRequest.readyState == htmlRequest.HEADERS_RECEIVED) 559 { 560 // Error-Headers ermitteln. 561 const errorHeaderLine = htmlRequest.getResponseHeader('ErrorResponseHeader'); 562 if (errorHeaderLine) 563 window.HRResponseHeaderErrors = errorHeaderLine.split(',').map(header => atob(header)); // Messageheader sind immer Base-64-kodiert. 564 565 // Warning-Headers ermitteln. 566 const warningHeaderLine = htmlRequest.getResponseHeader('WarningResponseHeader'); 567 if (warningHeaderLine) 568 window.HRResponseHeaderWarnings = warningHeaderLine.split(',').map(header => atob(header)); // Messageheader sind immer Base-64-kodiert. 569 570 // Info-Headers ermitteln. 571 const infoHeaderLine = htmlRequest.getResponseHeader('InfoResponseHeader'); 572 if (infoHeaderLine) 573 window.HRResponseHeaderInfos = infoHeaderLine.split(',').map(header => atob(header)); // Messageheader sind immer Base-64-kodiert. 574 575 // Allgemeine Callback-Funktion für die Verarbeitung von Header-Informationen. 576 if (config.onHeadersReceived && typeof(config.onHeadersReceived) === 'function') 577 { 578 config.onHeadersReceived((name, decodeBase64) => { 579 if (htmlRequest.getResponseHeader(name)) 580 { 581 const headerLine = htmlRequest.getResponseHeader(name); 582 if (headerLine) 583 return headerLine.split(',').map(header => decodeBase64 ? atob(header) : header); 584 } 585 return []; 586 }); 587 } 588 } 589 else if (htmlRequest.readyState == htmlRequest.DONE) 590 { 591 if (!config.onReady) 592 { 593 if (htmlRequest.status == 200) 594 { 595 content = htmlRequest.responseText; 596 597 var destElement = null; 598 if (config.domDest) 599 { 600 if (typeof(config.domDest) === 'string') 601 { 602 destElement = document.getElementById(config.domDest); 603 if (destElement == null && document.querySelector) 604 destElement = document.querySelector(config.domDest); 605 } 606 else if (typeof(config.domDest) === 'object') 607 { 608 destElement = config.domDest; 609 } 610 } 611 if (destElement != null) 612 { 613 destElement.innerHTML = content; 614 if (config.execJS) 615 execJS(destElement); 616 } 617 if (config.callBack) 618 config.callBack(content); 619 620 // Ein eigenes load-Event lostreten. 621 if (HREventManager && typeof(HREventManager.dispatchEvent) === 'function') 622 { 623 var sender = window; 624 if (config.domDest) 625 { 626 sender = config.domDest; 627 if (typeof(config.domDest) === 'string') 628 sender = document.getElementById(config.domDest); 629 } 630 var eventConfig = {notifyChildren: true, notifyAll: true, bubbles: true, useStandard: false}; 631 if (config.event) 632 { 633 for (prop in config.event) 634 { 635 eventConfig[prop] = config.event[prop]; 636 } 637 } 638 639 HREventManager.dispatchEvent(sender, HREventNames.ajaxload, eventConfig); 640 } 641 642 // Übermittelte Nachrichten ausgeben. 643 if (config.onErrors && typeof(config.onErrors) === 'function' && window.HRResponseHeaderErrors) 644 { 645 config.onErrors(window.HRResponseHeaderErrors); 646 window.HRResponseHeaderErrors = undefined; 647 } 648 if (config.onWarnings && typeof(config.onWarnings) === 'function' && window.HRResponseHeaderWarnings) 649 { 650 config.onWarnings(window.HRResponseHeaderWarnings); 651 window.HRResponseHeaderWarnings = undefined; 652 } 653 if (config.onInfos && typeof(config.onInfos) === 'function' && window.HRResponseHeaderInfos) 654 { 655 config.onInfos(window.HRResponseHeaderInfos); 656 window.HRResponseHeaderInfos = undefined; 657 } 658 } 659 else if (htmlRequest.status >= 400 && config.onRequestError) 660 config.onRequestError(htmlRequest.status, htmlRequest.getResponseHeader('FehlerId'), htmlRequest.getResponseHeader('Fehlertext')); 661 } 662 else 663 config.onReady(htmlRequest); 664 } 665 } 666 catch (e) 667 { 668 if (typeof(HRLogError) == 'function') 669 HRLogError(e); 670 } 671 return content; 672} 673
674/** 675 * Interne Funktion, um die Antwort aus dem Response 676 * zu verarbeiten. 677 * 678 * @param response Das HTTP-Response-Objekt. Mehr Informationen unter {@linkplain "https://github.github.io/fetch/#Response"}. 679 * @param config Konfiguration des Requests. 680 */ 681function retrieveFetchResponse(response, config) 682{ 683 var content = ""; 684 try 685 { 686 if (!config.onReady) 687 { 688 if (response.status == 200) 689 { 690 content = response.text(); 691 692 var destElement = null; 693 if (config.domDest) 694 { 695 if (typeof(config.domDest) == 'string') 696 { 697 destElement = document.getElementById(config.domDest); 698 if (destElement == null && document.querySelector) 699 destElement = document.querySelector(config.domDest); 700 } 701 else if (typeof(config.domDest) == 'object') 702 { 703 destElement = config.domDest; 704 } 705 } 706 if (destElement != null) 707 { 708 destElement.innerHTML = content; 709 if (config.execJS) 710 execJS(destElement); 711 } 712 if (config.callBack) 713 config.callBack(content); 714 715 // Ein eigenes load-Event lostreten. 716 if (HREventManager && typeof(HREventManager.dispatchEvent) === 'function') 717 { 718 var sender = window; 719 if (config.domDest && document.getElementById(config.domDest)) 720 sender = document.getElementById(config.domDest); 721 722 var eventConfig = {notifyChildren: true, notifyAll: true, bubbles: true, useStandard: false}; 723 if (config.event) 724 { 725 for (prop in config.event) 726 { 727 eventConfig[prop] = config.event[prop]; 728 } 729 } 730 731 HREventManager.dispatchEvent(sender, HREventNames.ajaxload, eventConfig); 732 } 733 } 734 } 735 else 736 config.onReady(response); 737 } 738 catch (e) 739 { 740 if (typeof(HRLogError) == 'function') 741 HRLogError(e); 742 } 743 return content; 744} 745 746/** 747 * Hiermit wird die Anfrage an den Server durchgeführt. 748 * @param {String} url Der url der aufzurufenden Server-Anwendung/Modul-Methode 749 * @param {String} objId Die Id des DOM-Objektes, in das das Ergebnis des Aufrufs gesteckt werden soll. 750 * Die Id darf null sein, dann wird das Ergebnis nirgendwo eingebaut. 751 * @param {String} JSCodePath der Pfad inkl. Name der JS-Datei, die zusätzlich geladen werden soll 752 * embedded JS-Code in der zu ladenden Seite wird nämlich nicht vom IE verarbeitet 753 * @param {boolean} executeJavaScript Wenn true ist werden alle JavaScript-Tags aus dem Element der 754 * übergebenen ID gesucht und der JavaScriptCode aus geführt. 755 * @param {object} eventConfig: Konfigurationsparameter für das Ajax-Event: 756 * name: Der Name des Ajax-Events. 757 * Standard: HREventNames.ajaxload. 758 * bubbles: Default: true. 759 * useStandard: Default: false. 760 * notifySelf: Default: true. 761 * notifyChildren: Default: true. 762 * notifyParents: Default: true. 763 * notifyAll: Default: true. 764 */ 765function sendRequest(url, objId, JSCodePath, executeJavaScript, eventConfig) 766{ 767 var htmlRequest = createAjaxObj(); 768 // XMLHttpRequest-Objekt initialisieren 769 if (htmlRequest != null) 770 { 771 // onreadystatechange wird nach dem Ende des Aufrufs (unten) aufgerufen. 772 // Dann sollen, falls alles ok war, die Daten angezeigt werden. 773 htmlRequest.onreadystatechange = function() 774 { 775 if (htmlRequest.readyState == this.DONE) 776 { 777 if (htmlRequest.status != 200 && htmlRequest.status != 0) 778 { 779 return false; 780 } 781 // Das Ergebnis wird ins DOM gesteckt 782 if (objId != null) 783 { 784 updateDom(objId, htmlRequest); 785 if (executeJavaScript == true) 786 execJS(objId); 787 } 788 // JS-Code ausführen, falls erwünscht 789 if (JSCodePath != null && JSCodePath != "") 790 { 791 // Sript-Element erstellen 792 var oScript = document.createElement("script"); 793 oScript.src = JSCodePath; 794 795 // Script laden 796 document.body.appendChild(oScript); 797 } 798 799 // Ein eigenes load-Event lostreten. 800 if (HREventManager && typeof(HREventManager.dispatchEvent) === 'function') 801 { 802 var sender = window; 803 if (objId && document.getElementById(objId)) 804 sender = document.getElementById(objId); 805 806 var config = {notifyChildren: true, notifyAll: true, bubbles: true, useStandard: false}; 807 if (eventConfig) 808 { 809 for (prop in config.event) 810 { 811 config[prop] = eventConfig[prop]; 812 } 813 } 814 815 HREventManager.dispatchEvent(sender, HREventNames.ajaxload, config); 816 } 817 } 818 } 819 820 htmlRequest.open('POST', url, true); 821 htmlRequest.send(null); 822 } 823} 824 825/** 826 * Hiermit wird die Anfrage an den Server durchgeführt. 827 * @param {String} url Der url der aufzurufenden Server-Anwendung/Modul-Methode 828 * @param {String} objId Die Id des DOM-Objektes, in das das Ergebnis des Aufrufs gesteckt werden soll. 829 * Die Id darf null sein, dann wird das Ergebnis nirgendwo eingebaut. 830 * @param {function} callBackFunction Die Funktion die nach dem Aufruf ausgeführt werden soll. 831 * @param {boolean} executeJavaScript Wenn true ist werden alle JavaScript-Tags aus dem Element der 832 * übergebenen ID gesucht und der JavaScriptCode aus geführt. 833 */ 834function sendRequestAndCallBack(url, objId, callBackFunction, executeJavaScript) 835{ 836 var htmlRequest = createAjaxObj(); 837 if (htmlRequest != null) 838 { 839 //onreadystatechange wird nach dem Ende des Aufrufs (unten) aufgerufen. 840 htmlRequest.onreadystatechange = function () 841 { 842 if (htmlRequest.readyState == 4) 843 { 844 if (htmlRequest.status != 200 && htmlRequest.status != 0) 845 { 846 return false;
847 } 848 //Das Ergebnis wird ins DOM gesteckt 849 if (objId != null) 850 { 851 updateDom(objId, htmlRequest); 852 853 if (executeJavaScript == true) 854 execJS(objId); 855 } 856 //JS-Code ausführen, falls erwünscht 857 if (callBackFunction != null && callBackFunction != "") 858 { 859 callBackFunction(htmlRequest.responseText); 860 } 861 } 862 } 863 864 htmlRequest.open('POST', url, true); 865 htmlRequest.send(null); 866 } 867} 868 869 870/** 871 * @deprecated: Aus Usability-Gründen bitte nicht mehr verwenden. Moderne Browser stellen nach und nach die 872 * Unterstützung für synchrone Aufrufe ein und nahezu immer lassen sich die Vorteile eines synchronen Aufrufs 873 * über eine Folge von z.B. Callback-Funktionen erreichen! 874 * 875 * Hiermit wird eine synchrone Anfrage an den Server durchgeführt. 876 * @param url Der url der aufzurufenden Server-Anwendung/Modul-Methode 877 * @param objId Die Id des DOM-Objektes, in das das Ergebnis des Aufrufs gesteckt werden soll. 878 * Die Id darf null sein, dann wird das Ergebnis nirgendwo eingebaut. 879 */ 880 881function sendRequestSynchron(url, objId, executeJavaScript) 882{ 883 var htmlRequest = createAjaxObj(); 884 if (htmlRequest != null) 885 { 886 htmlRequest.open('POST', url, false); 887 htmlRequest.send(null); 888 if (htmlRequest.readyState == 4) 889 { 890 if (objId != null) 891 { 892 updateDom(objId, htmlRequest); 893 if (executeJavaScript == true) 894 execJS(objId); 895 } 896 return htmlRequest.responseText; 897 } 898 } 899 return ""; 900} 901 902/** 903 * Diese Funktion ruft den überegebenen URL ab und gibt den Inhalt des Response-Body 904 * als Text zurück. 905 * 906 * @param url Der URL, der abgefragt werden soll. 907 */ 908function sendRequestAndGetResponse(url) 909{ 910 var rueckgabe = null; 911 912 try 913 { 914 var htmlRequest = createAjaxObj(); 915 916 if (htmlRequest != null) 917 { 918 htmlRequest.open('POST', url, false); 919 htmlRequest.send(null); 920 921 if (htmlRequest.readyState == 4) 922 { 923 rueckgabe = htmlRequest.responseText; 924 } 925 } 926 } 927 catch (e) 928 { 929 if (typeof(HRLogError) == 'function') 930 HRLogError(e); 931 } 932 933 return rueckgabe; 934} 935 936/** 937 * Fügt die vom Server gelieferten Daten im Objekt mit der Id objID ein. 938 */ 939function updateDom(objId, htmlRequest) 940{ 941 var result = null; 942 if (htmlRequest == null || typeof(htmlRequest) != 'object') 943 { 944 return; 945 } 946 try 947 { 948 result = htmlRequest.responseText; 949 obj = document.getElementById(objId); 950 if (obj) 951 obj.innerHTML = result; 952 } 953 catch (e) 954 { 955 if (typeof(HRLogError) == 'function') 956 HRLogError(e); 957 } 958} 959 960/** 961 * Erzeugt ein neues HTTPRequest-Objekt je nach Browser 962 * und gibt es zurück. Schlägt die Erzeugung irgendwie fehl, 963 * wird null zurückgegeben. 964 */ 965function createAjaxObj() 966{ 967 var htmlRequest = null; 968 try 969 { 970 htmlRequest = new XMLHttpRequest(); 971 } 972 catch (w3c) 973 { 974 try 975 { 976 htmlRequest = new ActiveXObject("Msxml2.XMLHTTP"); 977 } 978 catch (msie) 979 { 980 try 981 { 982 htmlRequest = new ActiveXObject("Microsoft.XMLHTTP"); 983 } 984 catch (msie_old) 985 { 986 return null; 987 } 988 } 989 } 990 991 return htmlRequest; 992} 993 994/** 995 * Unsere eigene 'eval'-Funktion. Sie evaluiert eine übergebene Zeichenkette als Javascript-Code und führt diesen dann auch aus. 996 * 997 * Achtung: Die eval-Funktion wird in der Javascript-Community nicht unbedingt immer gerne gesehen: 998 * (a) schlechte Performance: es wird der JavaScript-Compiler aufgerufen. 999 * (b) Sicherheitsbedenken: eval evaluiert jede übergebene Zeichenkette mit den Rechten des Sendenden. 1000 * 1001 * @param jsString Die zu evaluierende Zeichenkette. 1002 * @return Die Rückgabe der eval-Funktion oder null, falls etwas schief gelaufen ist. 1003 */ 1004function HREval(jsString) 1005{ 1006 try 1007 { 1008 if (jsString) 1009 { 1010 // 1011 // Funktionsdefinitionen der Form "function doSth()" in für eval 1012 // verständliche Definition der Form "doSth = function()" überführen. 1013 // 1014 var tmp = jsString; 1015 var firstIdx = tmp.indexOf('function'); 1016 var idx = firstIdx + 8; 1017 while (idx >= 8) 1018 { 1019 // 1020 // Hinter dem Schlüsselwort 'function' muss mindestens ein 1021 // Whitespacezeichen folgen. 1022 // 1023 if (idx <= tmp.length - 1 && tmp.substring(idx, idx + 1).trim() === '') 1024 { 1025 var l = tmp.length - idx; 1026 if (l > 500) 1027 l = 500; // minimale Performanceoptimierung, um im Zweifel nicht alle Zeichen durchlaufen zu müssen. 1028 1029 var bezeichner = ''; 1030 var inBezeichner = false; // true, falls der Bezeichner der Funktion eingelesen wird. 1031 var params = ''; 1032 var inParam = false; // true, falls die Parameter der Funktion eingelesen werden. 1033 var lastIdx = -1; // Der Index des ')'-Zeichen markiert das Ende der Funktionsdefinition. 1034 for (var i = 0; i < l; i++) 1035 { 1036 var char = tmp.substring(idx + i, idx + i + 1); 1037 1038 if (inParam) 1039 { 1040 if (char === ')') 1041 { 1042 inParam = false;
1043 lastIdx = idx + i + 1; 1044 jsString = jsString.replace(tmp.substring(firstIdx, lastIdx), bezeichner + ' = function (' + params + ')'); 1045 break; 1046 } 1047 else 1048 params += char; 1049 } 1050 else if (!inBezeichner) 1051 { 1052 if (char.trim() !== '') // auf den Bezeichner gestoßen? 1053 { 1054 inBezeichner = true; 1055 bezeichner += char; 1056 } 1057 } 1058 else if (inBezeichner) 1059 { 1060 if (char === '(') 1061 { 1062 bezeichner = bezeichner.trim(); 1063 1064 // Der Bezeichner darf ausschließlich aus Buchstaben und Zahlen bestehen. 1065 if (bezeichner.length > 0 && bezeichner.match('^[A-Za-z0-9]+$')) 1066 { 1067 inBezeichner = false; 1068 inParam = true; 1069 } 1070 else 1071 break; // keine Funktionsdefinition der Form 'function doSth (props) {...}' 1072 } 1073 else 1074 bezeichner += char; 1075 } 1076 } 1077 } 1078 1079 tmp = tmp.substring(idx); 1080 firstIdx = tmp.indexOf('function'); 1081 idx = firstIdx + 8; 1082 } 1083 } 1084 1085 return eval(jsString); 1086 } 1087 catch (e) 1088 { 1089 if (jsString) 1090 e.ajaxStr = jsString; 1091 1092 if (typeof(HRLogError) === 'function') 1093 HRLogError(e); 1094 } 1095 1096 return null; 1097} 1098 1099/** 1100 * Ausführen von über Ajax nachgeladenem JS-Code. 1101 * 1102 * @param objId Element oder ID des DOM, ab dem die Suche nach JS-Code beginnen soll. 1103 */ 1104function execJS(objId) 1105{ 1106 var obj = objId; 1107 if (obj && typeof(objId) === 'string') 1108 obj = document.getElementById(objId); 1109 1110 if (obj) 1111 { 1112 var objScripts = obj.getElementsByTagName('script'); 1113 for (var execJSIdx = 0; execJSIdx < objScripts.length; execJSIdx++) 1114 { 1115 try 1116 { 1117 // JSON-Blöcke und Module werden übersprungen. 1118 const type = objScripts[execJSIdx].getAttribute('type'); 1119 if (type && (type.toLowerCase() === 'application/json' || type.toLowerCase() === 'module')) 1120 continue; 1121 1122 var scriptInnerHTML = ""; 1123 1124 // JavaScript-Includes in den head der Seite übernehmen. 1125 if (objScripts[execJSIdx].src && objScripts[execJSIdx].src.length > 0) 1126 { 1127 if (typeof(HRJavaScriptIncludesRegistry) === "object") 1128 { 1129 var head = document.getElementsByTagName("head")[0]; 1130 var found = false; 1131 var headScripts = head.getElementsByTagName('script'); 1132 for (var execJSIdx2 = 0; execJSIdx2 < headScripts.length && !found; execJSIdx2++) 1133 { 1134 if (headScripts[execJSIdx2].src && headScripts[execJSIdx2].src.length > 0 && objScripts[execJSIdx].src.indexOf(headScripts[execJSIdx2].src) >= 0) 1135 { 1136 found = true; 1137 break; 1138 } 1139 } 1140 if (!found) 1141 { 1142 for (var execJSIdx2 = 0; execJSIdx2 < HRJavaScriptIncludesRegistry.length && !found; execJSIdx2++) 1143 { 1144 if (objScripts[execJSIdx].src.indexOf(HRJavaScriptIncludesRegistry[execJSIdx2]) >= 0) 1145 found = true; 1146 } 1147 } 1148 if (!found) 1149 { 1150 var script=document.createElement("script"); 1151 script.src=objScripts[execJSIdx].src; 1152 head.appendChild(script); 1153 } 1154 } 1155 else if (HRAppendScriptIncludeToHead && typeof(HRAppendScriptIncludeToHead) === 'function') 1156 { 1157 HRAppendScriptIncludeToHead(objScripts[execJSIdx].src, null, true); 1158 } 1159 else 1160 { 1161 // 1162 // Kleines Sicherheitsnetz: Falls die DOM-Funktion aus irgendeinem Grund nicht 1163 // verfügbar sein sollte, erfolgt die Prüfung der Scriptblöcke und das ggf. 1164 // Setzen des neuen Script-Blocks von Hand. 1165 // 1166 var scripts = document.getElementsByTagName('script'); 1167 if (scripts) 1168 { 1169 var i = 0; 1170 var l = scripts.length; 1171 for (i = 0; i < scripts.length && !found; i++) 1172 { 1173 if (scripts[i].src && scripts[i].src.length > 0 && url.indexOf(scripts[i].src) >= 0) 1174 found = true; 1175 } 1176 1177 if (!found) 1178 { 1179 // Im Head das neue Script erzeugen. 1180 var newScript = document.createElement('script'); 1181 newScript.async = true; 1182 newScript.src = url; 1183 document.getElementsByTagName('head')[0].appendChild(newScript); 1184 } 1185 } 1186 } 1187 } 1188 else if(objScripts[execJSIdx].innerHTML) 1189 scriptInnerHTML = objScripts[execJSIdx].innerHTML; 1190 else if(objScripts[execJSIdx].textContent) 1191 scriptInnerHTML = objScripts[execJSIdx].textContent; 1192 else if(objScripts[execJSIdx].text) 1193 scriptInnerHTML = objScripts[execJSIdx].text; 1194 1195 if (scriptInnerHTML != null && scriptInnerHTML.length > 0) 1196 { 1197 var htmlKommentar = "<!--"; 1198 var indexOfKommentar = scriptInnerHTML.indexOf(htmlKommentar); 1199 if (indexOfKommentar >= 0) 1200 scriptInnerHTML = scriptInnerHTML.substring(indexOfKommentar + htmlKommentar.length); 1201 } 1202
1203 // Den JS-Code ausführen lassen. 1204 HREval(scriptInnerHTML); 1205 } 1206 catch(e) 1207 { 1208 if (typeof(HRLogError) == 'function') 1209 HRLogError(e); 1210 } 1211 } 1212 } 1213}
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.