1/* ************************************************************************** */ 2// Firma: Hehner Reus Systems GmbH 3// Projekt: com.cerno.basis 4// Datei: HRIBox.js 5// Erstellung: 16.12.2025 6// Verwendung: Erzeugt eine i-Box und bietet bereits verschiedene vorgefertigte 7// Signaturen, um diversen Content über die i-Box anzeigen zu lassen. 8/* ************************************************************************** */ 9 10/** 11 * Enumeration für die Themes der i-Box 12 */ 13var HRIBoxThemes = { 14 Default: 'default', 15 Popup: 'popup' 16} 17 18/** 19 * Enumeration für die möglichen Richtungen des Popups. 20 */ 21var HRPopupDirection = { 22 /* 23 * Keine Richtung. 24 */ 25 none: 'none', 26 27 /* 28 * Popup fährt von unten nach oben. 29 */ 30 Up: 'up', 31 32 /* 33 * Popup fährt von oben nach unten. 34 */ 35 Down: 'down', 36 37 /* 38 * Popup fährt von rechts nach links. 39 */ 40 Left: 'left', 41 42 /* 43 * Popup fährt von rechts nach links. 44 */ 45 Right: 'right' 46} 47 48/** 49 * Konstruktor für eine neue i-Box. 50 * 51 * @param config [optional] Kapselt optionale Konfigurationsparameter 52 * <ul> 53 * <li>draggable: true, falls Drag and Drop der i-Box ermöglicht werden soll. Default: true.</li> 54 * <li>htmlElement: Darzustellendes HTML-Element oder ID des darzustellenden HTML-Elementes. Default: null.</li> 55 * <li>url: Der Content der Seite wird in der i-Box dargestellt. Default: null.</li> 56 * <li>closeButton: true, falls ein Schließen-Button ergänzt werden soll. Default: false.</li> 57 * <li>closeButtonTagName: Gibt an, was für ein Tag-Namen der Schließen-Button haben soll. Default: div.</li> 58 * <li>closeButtonAsFirstElement: Sorgt dafür, dass der Schließen-Button das erste Element der i-Box ist. Default: false.</li> 59 * <li>imagesNextPrevAsButtons: Sorgt dafür, dass der die Vor- und Zurück-Buttons der i-Box mit dem button-Tag erzeugt werden. Default: false.</li> 60 * <li>imagesTabNavigationAsButtons: Sorgt dafür, dass der die Tabnavigation der i-Box mit button-Tags erzeugt werden. Default: false.</li> 61 * <li>cssSuffix: CSS-Klasse, die als Suffix an alle i-Box-HTML-Elemente ergänzt wird. Default: ''.</li> 62 * <li>additionalIBoxClass: Zusätzliche CSS-Klasse, die an das äußerste i-Box-Div gehängt wird. Default: ''.</li> 63 * <li>additionalIBoxContentClass: Zusätzliche CSS-Klasse, die an das den Content darstellende Div gehängt wird. Default: ''.</li> 64 * <li>bodyClass: CSS-Klasse, die an den HTML-Body gehängt wird. Default: 'overlay-open'.</li> 65 * <li>onOpen: Callback-Funktion, die nach dem Öffnen der i-Box aufgerufen wird. Default: null.</li> 66 * <li>onClose: Callback-Funktion, die nach dem Schließen der i-Box aufgerufen wird. Default: null.</li> 67 * <li>onEscape: Callback-Funktion, die bei Escape aufgerufen wird. Default: null.</li> 68 * <li>onContentLoaded: Callback-Funktion, die aufgerufen wird, wenn der Content der i-Box geladen wurde. Es wird das äußerste Div der i-Box als Parameter angeboten. Default: null.</li> 69 * <li>alignX: Horizontale Ausrichtung der i-Box. Default: center.</li> 70 * <li>alignY: Vertikale Ausrichtung der i-Box. Default: center.</li> 71 * <li>parentDiv: In dieses Element wird die i-box hineingesetzt. Default: null.</li> 72 * <li>width: Breite der i-Box. Dient dem Übersteuern der durch CSS gesetzten Breite. Default: null.</li> 73 * <li>height: Höhe der i-Box. Dient dem Übersteuern der durch CSS gesetzten Höhe. Default: null.</li> 74 * <li>widthUnit: Einheit der gesetzten Breite der i-Box. Default: 'px'.</li> 75 * <li>heightUnit: Einheit der gesetzten Breite der i-Box. Default: 'px'.</li> 76 * <li>redirectUrlOnClose: Url, auf die beim Schließen der URL verwiesen wird.</li> 77 * <li>blackOverlay: Erzeugt einen schwarz-transparenten Hintergrund zum Abdunkeln. Default: false.</li> 78 * <li>removeByBlackOverlayClick: Entfernt die i-Box, wenn auf das Black-Overlay geklickt wird. Default: true.</li> 79 * <li>singleton: Wenn aktiv, ist diese i-Box die Einzige ("Highlander-Modus"). Alle weiteren i-Boxes werden unterdrückt und alle bestehenden i-Boxen entfernt. Default: false.</li> 80 * <li>replaceAll: Etwas schwächer als 'singleton'. Entfernt lediglich vor der eigenen Darstellung alle bestehenden Instanzen der i-Box. Default: false.</li> 81 * <li>theme: Möglichkeit die i-Box in einem bestimmten Theme anzuzeigen. Beispielsweise als Popup. Default: 'default'. Siehe Enum 'HRIBoxThemes'.</li> 82 * <li>modal: Implementierung als modaler Dialog. Hier wird insbesondere das Focus-Trapping ermöglicht. Default: false.</li> 83 * <li>popupConfig: Konfigurationsobjekt für alle Einstellungen rund um das Popup-Theme. 84 * <ul> 85 * <li>showAfter: startet die Anzeigeanimation des Popups verzögert nach der angegebenen Zeit [ms]. Default: 250 ms.</li> 86 * <li>hideAfter: lässt das Popup verzögert nach der angegebenen Zeit [ms] verschwinden. Default: keine verzögertes Verstecken.</li> 87 * <li>direction: legt die "Sliderichtung" fest. Default: Klassischer Popup, d.h. 'up'. Siehe Enum 'HRPopupDirection'.</li> 88 * </ul> 89 * </li> 90 * </ul> 91 */ 92HRIBox = function(config) 93{ 94 /* 95 * Eine UUID, um die Komponenten der i-Box eindeutig bestimmbar zu machen. 96 */ 97 this.m_UUID = HRCrypt.getUUID(); 98 99 // Konfigurationen 100 this.m_Draggable = true; 101 this.m_Url = null; 102 this.m_CloseButton = false;
103 this.m_CloseButtonTagName = 'div'; 104 this.m_CloseButtonAsFirstElement = false; 105 this.m_ImagesNextPrevAsButtons = false; 106 this.m_ImagesTabNavigationAsButtons = false; 107 this.m_OnEscape = null; 108 this.m_CSSSuffix = ''; 109 this.m_AdditionalIBoxClass = ''; 110 this.m_AdditionalIBoxContentClass = ''; 111 this.m_BodyClass = 'overlay-open'; 112 this.m_OnOpen = null; 113 this.m_OnClose = null; 114 this.m_OnContentLoaded = null; 115 this.m_ParentDiv = null; 116 this.m_AlignX = 'center'; 117 this.m_AlignY = 'center'; 118 this.m_Width = null; 119 this.m_WidthUnit = 'px'; 120 this.m_Height = null; 121 this.m_HeightUnit = 'px'; 122 this.m_RedirectUrlOnClose = null; 123 this.m_BlackOverlay = false; 124 this.m_RemoveByBlackOverlayClick = true; 125 this.m_Singleton = false; 126 this.m_ReplaceAll = false; 127 this.m_Theme = HRIBoxThemes.Default; 128 this.m_Modal = false; 129 this.m_PopupConfig = {}; 130 131 // HTML-Struktur der i-Box 132 this.m_IBox; 133 134 /* 135 * Member für die Darstellung von HTML-Content. 136 */ 137 this.m_HtmlElement = null; 138 139 /* 140 * Ein temporärer Wrapper um das HTML-Element. Wird gebraucht, um das Element 141 * beim Schließen der i-Box wieder an die ursprüngliche Stelle im DOM zu bekommen. 142 */ 143 this.m_HtmlElementTmpWrapper = null; 144 145 /* 146 * Merkt sich das zuletzt fokussierte Element. Dieses wird erneut fokussiert, wenn die i-Box geschlossen wird. 147 */ 148 this.m_LastFocusedElement = document.activeElement; 149 150 /* 151 * Member für die Darstellung von Bildern. 152 */ 153 this.m_ImageSources = null; 154 this.m_ImageAlttexts = null; 155 this.m_ImageCaptions = null; 156 this.m_ImageTitles = null; 157 this.m_ImageLinks = null; 158 this.m_ImageLinkTargets = null; 159 this.m_ImageMaxWidth = Math.round(HRGetViewPortWidth() * 0.8); 160 this.m_ImageMaxHeight = Math.round(HRGetViewPortHeight() * 0.8); 161 this.m_ImageIdx = 0; 162 this.m_ImageAddTabNavigation = true; 163 this.m_ImageSrcAsBackgroundImage = true; 164 165 /* 166 * Member für die Darstellung eines Prompts. 167 */ 168 this.m_Prompt = false; 169 this.m_PromptText = ''; 170 this.m_PromptDefaultText = ''; 171 this.m_PromptCallBack = function(returnValue){return true;}; 172 this.m_PromptOkayText = 'Ok'; 173 this.m_PromptCancelText = 'Abbrechen'; 174 this.m_PromptSaveResultInCookie = false; 175 this.m_PromptSaveResultInLocalStorage = false; 176 this.m_PromptConfigureInputHTML = null; 177 178 /* 179 * Member für die Darstellung eines Hinweistextes. 180 */ 181 this.m_Note = false; 182 this.m_NoteState = 'none'; 183 184 /* 185 * Aktuelle Breite des window-Objektes. 186 * 187 * Brauchen wir für folgende Problematik: Unter iOS wird ein resize-Event ausgelöst, wenn 188 * - Virtuelle Tastatur eingeblendet wird, 189 * - Scroll- oder Aufklappmenüs, 190 * - Zooms, Systemgesten, 191 * - Scrollen (!) 192 * Den Resize wollen wir nur dann ausführen, wenn es effektiv auch eine Änderung in der 193 * Breite des window-Objektes gab. 194 */ 195 this.m_CurrentWindowWidth = window.innerWidth; 196 197 // 198 // (Optionale) Konfigurationen auslesen. 199 // 200 if (config) 201 { 202 if (!config.draggable) 203 this.m_Draggable = false; 204 205 // Wurde HTML-Element oder ID des darzustellenden Contents angegeben? 206 this.m_HtmlElement = config.htmlElement; 207 if (config.htmlElement && typeof config.htmlElement === 'string') 208 this.m_HtmlElement = document.getElementById(config.htmlElement); 209 210 if (config.url) 211 this.m_Url = url; 212 213 if (config.closeButton && config.closeButton === true) 214 this.m_CloseButton = true; 215 216 if (config.closeButtonTagName && typeof config.closeButtonTagName === 'string') 217 this.m_CloseButtonTagName = config.closeButtonTagName; 218 219 if (config.closeButtonAsFirstElement && config.closeButtonAsFirstElement === true) 220 this.m_CloseButtonAsFirstElement = true; 221 222 if (config.imagesNextPrevAsButtons && config.imagesNextPrevAsButtons === true) 223 this.m_ImagesNextPrevAsButtons = true; 224 225 if (config.imagesTabNavigationAsButtons && config.imagesTabNavigationAsButtons === true) 226 this.m_ImagesTabNavigationAsButtons = true; 227 228 if (config.onEscape && typeof(config.onEscape) === 'function') 229 this.m_OnEscape = config.onEscape; 230 231 if (config.cssSuffix) 232 this.m_CSSSuffix = config.cssSuffix; 233 234 if (config.additionalIBoxClass) 235 this.m_AdditionalIBoxClass = config.additionalIBoxClass; 236 237 if (config.additionalIBoxContentClass) 238 this.m_AdditionalIBoxContentClass = config.additionalIBoxContentClass; 239 240 if (config.bodyClass) 241 this.m_BodyClass = config.bodyClass; 242 243 if (config.onOpen && typeof(config.onOpen) === 'function') 244 this.m_OnOpen = config.onOpen; 245
246 if (config.onClose && typeof(config.onClose) === 'function') 247 this.m_OnClose = config.onClose; 248 249 if (config.onContentLoaded && typeof(config.onContentLoaded) === 'function') 250 this.m_OnContentLoaded = config.onContentLoaded; 251 252 this.m_ParentDiv = config.parentDiv; 253 if (config.parentDiv && typeof config.parentDiv === 'string') 254 this.m_ParentDiv = document.getElementById(config.parentDiv); 255 256 if (config.alignX) 257 this.m_AlignX = config.alignX; 258 259 if (config.alignY) 260 this.m_AlignY = config.alignY; 261 262 if (config.width) 263 { 264 this.m_Width = config.width; 265 266 if (typeof(config.width) === 'string') 267 { 268 if (config.widthUnit && typeof(config.width) === 'string') 269 this.m_WidthUnit = config.widthUnit; 270 else 271 { 272 // Hat sonst die Breitenangabe bereits eine Einheit? 273 const unit = HRCSS.getUnit(config.width); 274 if (unit) 275 this.m_WidthUnit = unit; 276 } 277 this.m_Width = parseInt(config.width); 278 } 279 } 280 281 if (config.height) 282 { 283 this.m_Height = config.height; 284 if (typeof(config.height) === 'string') 285 { 286 if (config.heightUnit && typeof(config.height) === 'string') 287 this.m_HeightUnit = config.heightUnit; 288 else 289 { 290 // Hat sonst die Höhenangabe bereits eine Einheit? 291 const unit = HRCSS.getUnit(config.height); 292 if (unit) 293 this.m_HeightUnit = unit; 294 } 295 this.m_Height = parseInt(config.height); 296 } 297 } 298 299 if (config.redirectUrlOnClose) 300 this.m_RedirectUrlOnClose = config.redirectUrlOnClose; 301 302 if (config.blackOverlay && config.blackOverlay === true) 303 this.m_BlackOverlay = true; 304 else if (!config.bodyClass) 305 this.m_BodyClass = ""; 306 307 if (config.removeByBlackOverlayClick === false) 308 this.m_RemoveByBlackOverlayClick = false; 309 310 if (config.singleton && config.singleton === true) 311 this.m_Singleton = true; 312 313 if (config.replaceAll && config.replaceAll === true) 314 this.m_ReplaceAll = true; 315 316 if (config.theme) 317 this.m_Theme = config.theme; 318 319 if (config.modal && config.modal === true) 320 this.m_Modal = config.modal; 321 322 if (config.popupConfig) 323 this.m_PopupConfig = config.popupConfig; 324 } 325} 326 327/** 328 * Erzeugt und öffnet die iBox. 329 */ 330HRIBox.prototype.open = function() 331{ 332 const _this = this; 333
334 // Bestehende Instanzen schließen. 335 if (this.m_Singleton || this.m_ReplaceAll) 336 HRCloseAllIBoxes(); 337 338 let existingSingleton = false; 339 let isParentIBox = false; 340 if (window.HRIBoxRegistry) 341 { 342 window.HRIBoxRegistry.forEach(ibox => { 343 if (ibox.m_Singleton && ibox != this) 344 { 345 existingSingleton = true; 346 347 // Noch prüfen, ob der Singleton ein parent-Element der i-Box ist. 348 // Dazu schauen wir uns an, ob das HTML-ELement dieser i-Box unterhalb der Singleton-i-Box liegt. 349 // Funktioniert aktuell also nicht für i-Boxen, die ihren Content über ein i-Frame rendern. 350 isParentIBox = this.m_HtmlElement && ibox.m_HtmlElement && ibox.m_HtmlElement.contains(this.m_HtmlElement); 351 } 352 }); 353 } 354 355 /* 356 * Die i-Box nur dann öffnen, wenn es keine andere Box mit der Singleton-Eigenschaft gibt oder aber die neue 357 * i-Box aus der Singleton-Box heraus geöffnet wird. Ein Use-Case von letzterem ist bspw. der Consent-Manager. Unter 358 * diesem können die Erklärungstexte zu den einzelnen Cookie-Einstellungen wahlweise auch über eine i-Box geöffnet werden. 359 * Der Consent-Manager ist ein Singleton und die i-Boxen legen sich dann über diesen. Dieser Fall sollte aber die Ausnahme 360 * bleiben, weil geschachtelte i-Boxen generell keine gute UX darstellen. 361 */ 362 if (!existingSingleton || isParentIBox) 363 { 364 this.addEventListener(); 365 366 // I-Box-Skelett erzeugen. 367 this.createMinimalSkeleton(); 368 369 // Listener für das Laden des DOM-Contents. 370 if (typeof(HREventManager.addListener) === 'function') 371 HREventManager.addListener(this.m_IBox, 'HRIBoxContentLoaded', this.domContentLoadedHandler.bind(this), {useStandard: false, notifiedByChildren: false}); 372 373 // Body erhält zusätzliche Klasse. 374 if (this.m_BodyClass) 375 HRAddBodyCSSClass(this.m_BodyClass); 376 377 if (!this.m_CloseButtonAsFirstElement && this.m_CloseButton) 378 this.createIBoxCloseButton(); 379 380 // Content setzen. 381 if (this.m_HtmlElement) 382 this.setIBoxContentHtmlElement(); 383 else if (this.m_Url) 384 this.setIBoxContentUrl(); 385 else if (this.m_ImageSources) 386 this.showImage(this.m_ImageIdx); 387 388 // Zusätzlich zu einem Prompt machen? 389 if (this.m_Prompt) 390 this.createPrompt(); 391 392 // Hintergrund schwarz-transparent abdunkeln. 393 if (this.m_BlackOverlay) 394 this.createBlackOverlay(); 395 396 if (this.m_AlignX) 397 this.alignIBoxHorizontalTo(this.m_AlignX); 398 399 if (this.m_AlignY) 400 this.alignIBoxVerticalTo(this.m_AlignY); 401 402 // Initialisiert das gewählte Theme 403 this.initTheme() 404 405 // Der Fokus wird initial auf den Schließen-Button gelegt, sofern vorhanden. 406 if (this.m_CloseButton) 407 { 408 const _this = this; 409 setTimeout(function(){ 410 if (document.getElementById(_this.getUID('idIBoxDivClose'))) 411 document.getElementById(_this.getUID('idIBoxDivClose')).focus(); 412 }, 500); 413 } 414 415 // Die i-Box im window-Objekt merken. 416 if (!window.HRIBoxRegistry) 417 window.HRIBoxRegistry = new Array(); 418 419 window.HRIBoxRegistry.push(this); 420 421 if (this.m_OnOpen && typeof(this.m_OnOpen) === 'function') 422 this.m_OnOpen(); 423 } 424} 425 426/** 427 * Reagiert auf das Laden des DOM-Contents. 428 */ 429HRIBox.prototype.domContentLoadedHandler = function(event) 430{ 431 // ggf. nochmal Optimierung der Positionierung der i-Box 432 // anhand des nun geladenen Contents. 433 if (this.m_AlignX) 434 this.alignIBoxHorizontalTo(this.m_AlignX); 435 436 if (this.m_AlignY) 437 this.alignIBoxVerticalTo(this.m_AlignY); 438 439 // Der Fokus wird initial auf das erste fokussierbare Element gelegt. 440 if (!this.m_CloseButton && event.detail) 441 { 442 const focusableEl = HRDOM.getFirstFocusableDescendant(event.detail); 443 if (focusableEl)
444 focusableEl.focus(); 445 } 446 447 if (this.m_OnContentLoaded && typeof(this.m_OnContentLoaded) === 'function') 448 this.m_OnContentLoaded(this.m_IBox); 449} 450 451/** 452 * Reagiert auf einen Resize der i-Box. 453 */ 454HRIBox.prototype.resizeHandler = function() 455{ 456 // Sicherstellen, dass unter iOS die window-Breite tatsächlich geändert wurde und 457 // der Resize nicht einfach nur durch ein Scroll-Event ausgelöst wird. 458 if (window.innerWidth != this.m_CurrentWindowWidth) 459 { 460 this.m_CurrentWindowWidth = window.innerWidth; 461 462 if (this.m_AlignX) 463 this.alignIBoxHorizontalTo(this.m_AlignX); 464 465 if (this.m_AlignY) 466 this.alignIBoxVerticalTo(this.m_AlignY); 467 } 468} 469 470HRIBox.prototype.escapeKeydownHandler = function(event) 471{ 472 event.preventDefault(); // sonst werden z.B. window.location.href unterbrochen. 473 474 if (typeof(this.m_OnEscape) === 'function') 475 { 476 if (window.HRIBoxRegistry) 477 { 478 let ibox = window.HRIBoxRegistry[window.HRIBoxRegistry.length - 1]; 479 if (this == ibox) 480 this.m_OnEscape(); 481 } 482 } 483 484 if (this.m_CloseButton || this.m_Prompt) 485 this.close(); 486 487 return false; 488} 489 490/** 491 * Das Nutzen der Escape-Taste zum Schließen der i-Box. 492 */ 493HRIBox.prototype.keydownHandler = function() 494{ 495 if (event.key === 'Escape') 496 { 497 this.escapeKeydownHandler(event); 498 } 499 else if (event.key === 'ArrowLeft') 500 { 501 // Durch Bilder navigieren 502 if (this.m_ImageSources && this.m_ImageSources.length > 1) 503 { 504 const previousButton = document.querySelector('[data-image-control-previous]'); 505 if (previousButton) 506 previousButton.click(); 507 } 508 } 509 else if (event.key === 'ArrowRight') 510 { 511 // Durch Bilder navigieren. 512 if (this.m_ImageSources && this.m_ImageSources.length > 1) 513 { 514 const nextButton = document.querySelector('[data-image-control-next]'); 515 if (nextButton) 516 nextButton.click(); 517 } 518 } 519} 520 521/** 522 * Behandelt die Events der i-Box. 523 * 524 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_value_of_this_within_the_handler 525 */ 526HRIBox.prototype.handleEvent = function(event) 527{ 528 switch (event.type) 529 { 530 case 'resize': 531 this.resizeHandler(); 532 break; 533 case 'keydown': 534 this.keydownHandler(); 535 break; 536 } 537} 538 539/** 540 * Ergänzt die globalen Event-Listener. 541 */ 542HRIBox.prototype.addEventListener = function() 543{ 544 HRAddEventListener(window, 'resize', this); 545 HRAddEventListener(window, 'keydown', this); 546} 547 548/** 549 * Entfernt die globalen Event-Listener. 550 */ 551HRIBox.prototype.removeEventListener = function() 552{ 553 HRRemoveEventListener(window, 'resize', this); 554 HRRemoveEventListener(window, 'keydown', this); 555} 556 557/** 558 * Öffnet den im übergebenen HTML-Element enthaltenen Content in einer i-Box. 559 * 560 * @param element Das HTML-Element mit dem darzustellenden Content. 561 */ 562HRIBox.prototype.openHtmlElement = function(element) 563{ 564 this.m_HtmlElement = element; 565 if (element && typeof element === 'string') 566 this.m_HtmlElement = document.getElementById(element); 567 568 this.open(); 569} 570 571/** 572 * Öffnet die durch die übergebene Url angesprochene Seite in einer i-Box. 573 * 574 * @param url Die Url der Seite, die angezeigt werden soll. 575 * 576 * Anmerkung: Über den Darstellungs-Parameter können Gips-Seiten auch ohne Rahmen 577 * angezeigt werden. 578 */ 579HRIBox.prototype.openUrl = function(url) 580{ 581 this.m_Url = url; 582 this.open(); 583} 584 585/** 586 * Öffnet eine Prompt-Box analog zur Javascript-prompt()-Methode. 587 * 588 * @param text Der Text des Prompts. 589 * @param defaultText (optional) 590 * @param callBack (optional) Callback-Funktion, die nach dem Akzeptieren des Prompts ausgelöst wird und den eingegebenen Wert des Nutzers übergibt. Die Funktion erwartet eine Boolean-Rückgabe. 591 * Wird false zurückgegeben, wird das Prompt nicht akzeptiert und bleibt stehen. Default: keine Verarbeitung der Eingabe. Das Popup wird akzeptiert. 592 * @param okayText (optional) Der Text der in dem 'Okay'-Button steht. Default: 'Ok'. 593 * @param cancelText (optional) Der Text der in dem 'Cancel'-Button steht. Default: 'Abbrechen'. 594 * @param saveResultInCookie (optional) Wenn true, dann wird ein Cookie mit dem Inhalt des Eingabefelds gesetzt. Default: false. 595 * @param saveResultInLocalStorage (optional) Wenn true, dann wird der Inhalt des Inputfelds im LocalStorage gespeichert. Default: false. 596 * @param configureInputHTML Callback-Funktion, um den erzeugten Promptinhalt in Spez
596ialfällen noch verändern zu können. 597 */ 598HRIBox.prototype.openPrompt = function(text, defaultText, callBack, okayText, cancelText, saveResultInCookie, saveResultInLocalStorage, configureInputHTML) 599{ 600 if (text) 601 { 602 this.m_Prompt = true; 603 604 this.m_PromptText = text; 605 this.m_PromptDefaultText = defaultText; 606 if (callBack) 607 this.m_PromptCallBack = callBack; 608 if (okayText) 609 this.m_PromptOkayText = okayText; 610 if (cancelText) 611 this.m_PromptCancelText = cancelText; 612 this.m_PromptSaveResultInCookie = saveResultInCookie; 613 this.m_PromptSaveResultInLocalStorage = saveResultInLocalStorage; 614 this.m_PromptConfigureInputHTML = configureInputHTML; 615 616 /* 617 * Spezialität für Prompts: Schließen des Fensters nicht manuell ermöglichen. 618 */ 619 this.m_CloseButton = false; 620 this.m_RemoveByBlackOverlayClick = false; 621 622 this.open(); 623 } 624} 625 626/** 627 * Stellt den übergebenen Text als Hinweis mit einem OK-Button dar. 628 * 629 * @param text Der darzustellende Hinweistext. 630 * @param state [optional] Der Status des Hinweises (none, info, warning, error). Default: none. 631 * @param buttonText [optional] Ein abweichender Text für den OK-Button. Default: OK. 632 */ 633HRIBox.prototype.openNote = function(text, state, buttonText) 634{ 635 if (text) 636 { 637 this.m_Note = true; 638 this.m_NoteState = state || 'none'; 639 640 // Es handelt sich hier um ein Prompt, dessen Cancel-Button fehlt. 641 this.openPrompt(text, null, null, buttonText); 642 } 643} 644 645/** 646 * Öffnet ein Bild in der i-Box. 647 * 648 * @param source Bildquelle: Absolute oder relative URL 649 * @param caption Unterschrift des Bildes (hier ist auch HTML erlaubt, die Unterschrift wird per innerHTML gesetzt) 650 * @param title Titel des Bildes 651 * @param link Verlinkung des Bildes 652 * @param linkTarget Das Target (_blank, _self, _parent, _top) 653 */ 654HRIBox.prototype.openImage = function(source, caption, title, link, linkTarget) 655{ 656 this.openImages(new Array(source), new Array(caption), new Array(title), new Array(link), new Array(linkTarget), null, null, 0); 657} 658 659/** 660 * Öffnet die übergebenen Bilder in der i-Box. 661 * 662 * @param sources [Array] Bildquellen: Absolute oder relative URLs 663 * @param captions [Array] Unterschriften der Bilder (hier ist auch HTML erlaubt, die Unterschrift wird jeweils per innerHTML gesetzt) 664 * @param titles [Array] Titel der Bilder 665 * @param links [Array] Verlinkung der Bilder 666 * @param linkTargets [Array] Die Targets der Links (_blank, _self, _parent, _top) 667 * @param maxWidth maximale von den Bildern eingenommene Breite 668 * @param maxHeight maximale von den Bildern eingenommene Höhe 669 * @param first Index oder Quelle desjenigen Bildes, welches initial angezeigt werden soll 670 * @param addTabNavigation Ergänzt eine Tab-Navigation unter den Bildern. 671 * @param setAsBackground Setzt das Bild als Hintergrundbild eines umgebenden Divs ein. 672 */ 673HRIBox.prototype.openImages = function(sources, captions, titles, links, linkTargets, maxWidth, maxHeight, first, addTabNavigation, setAsBackground, alttexts) 674{ 675 this.m_ImageSources = sources; 676 this.m_ImageAlttexts = alttexts; 677 this.m_ImageCaptions = captions; 678 this.m_ImageTitles = titles; 679 this.m_ImageLinks = links; 680 this.m_ImageLinkTargets = linkTargets; 681 if (!addTabNavigation) 682 this.m_ImageAddTabNavigation = false; 683 if (maxWidth) 684 this.m_ImageMaxWidth = maxWidth; 685 if (maxHeight) 686 this.m_ImageMaxHeight = maxHeight; 687 if (setAsBackground && setAsBackground == false) 688 this.m_ImageSrcAsBackgroundImage = false; 689 690 if (this.m_ImageSources) 691 { 692 /* 693 * Bestimme Index des initial anzuzeigenden Bildes. 694 */ 695 if (this.isUnsignedInteger(first)) 696 { 697 this.m_ImageIdx = first; 698 } 699 else 700 { 701 if (typeof first === 'string') 702 { 703 var i; 704 var l = sources.length; 705 for (var i = 0; i < l; i++) 706 { 707 if (sources[i] && sources[i] == first) 708 { 709 this.m_ImageIdx = i; 710 break; 711 } 712 } 713 } 714 } 715 716 this.open(); 717 } 718} 719 720/** 721 * Erzeugt die minimale Struktur der i-Box. 722 */ 723HRIBox.prototype.createMinimalSkeleton = function() 724{ 725 /* 726 * Ist schon eine I-Box geöffnet? Dann schmeißen wir diese erst weg. 727 */ 728 if (this.m_IBox) 729 {
730 let contentNode; 731 732 // i-Box-Content darf mit dem Wegwerfen der i-Box nicht wegfallen. 733 if (document.getElementById(this.getUID('idIBoxContent'))) 734 contentNode = document.getElementById(this.getUID('idIBoxContent')).firstChild; 735 736 this.removeDOMElement(this.m_IBox); 737 738 // Hänge den Content wieder an den Body. 739 if (contentNode) 740 { 741 contentNode.style.display = 'none'; 742 document.getElementsByTagName('body')[0].appendChild(contentNode); 743 } 744 } 745 746 /* 747 * Erzeuge i-Box 748 */ 749 this.m_IBox = document.createElement('div'); 750 this.m_IBox.tabIndex = 0; 751 var basisCSSKlasse = 'HrSys-Gips-DivIBox'; 752 if (this.m_Theme === HRIBoxThemes.Popup) 753 basisCSSKlasse = 'hr-popup'; 754 else if (this.m_Prompt) 755 { 756 basisCSSKlasse = 'hr-prompt' + (this.m_Note ? '-note' : ''); 757 if (this.m_Note) 758 { 759 // Den Status noch ergänzen: none, info, warning, error. 760 if (this.m_NoteState && this.m_NoteState.trim() !== 'none') 761 basisCSSKlasse += ' ' + this.m_NoteState; 762 } 763 } 764 765 if (this.m_Modal) 766 { 767 this.m_IBox.ariaModal = true; 768 this.m_IBox.role = 'dialog'; 769 } 770 771 var alignmentXCSSKlasse = 'v-' + this.m_AlignX; 772 var alignmentYCSSKlasse = 'h-' + this.m_AlignY; 773 774 this.m_IBox.setAttribute('class', basisCSSKlasse + ' ' + alignmentXCSSKlasse + ' ' + alignmentYCSSKlasse + ' ' + this.m_CSSSuffix + ' ' + this.m_AdditionalIBoxClass); 775 776 if (this.m_BodyClass){ 777 this.m_IBox.setAttribute('data-hribox-bodyclass', this.m_BodyClass); 778 if(this.m_BodyClass == "consent-bg"){ 779 this.m_IBox.setAttribute('aria-labelledby', 'consent-dialog-title'); 780 this.m_IBox.setAttribute('aria-describedby', 'consent-dialog-desc'); 781 } 782 } 783 this.m_IBox.setAttribute('data-hribox-bodyclass', this.m_BodyClass); 784 785 this.m_IBox.setAttribute('id', this.getUID('idHrSysGipsDivIBox')); 786 787 if (!this.m_HtmlElement && !this.m_Url) 788 { 789 if (this.m_Width && this.m_Width > 0) 790 { 791 // Für Pixelangaben begrenzen wir die Breite auf maximal 80% des Viewports. Für 792 // andere Einheiten übernehmen wir einfach mal die Breite. 793 if (this.m_WidthUnit.trim() === 'px') 794 this.m_IBox.style.width = Math.min(this.m_Width, Math.round(HRGetViewPortWidth() * 0.85)) + this.m_WidthUnit; 795 else 796 this.m_IBox.style.width = this.m_Width + this.m_WidthUnit; 797 } 798 else 799 this.m_IBox.style.width = HRGetViewPortWidth() * 0.85 + 'px'; 800 801 if (this.m_Height && this.m_Height > 0) 802 this.m_IBox.style.height = this.m_Height + this.m_HeightUnit; 803 } 804 805 if (this.m_ParentDiv) 806 { 807 this.m_ParentDiv.appendChild(this.m_IBox); 808 this.m_ParentDiv.style.position = 'relative'; 809 } 810 else 811 { 812 // 813 // Positionierung: Wir benötigen für das korrekte Alignment eine fixierte Positionierung. 814 // 815 if (!getStyleValue(this.m_IBox, 'position') || getStyleValue(this.m_IBox, 'position').length <= 0) 816 this.m_IBox.style.position = 'fixed'; 817 818 // Als erstes einfügen, damit der Fokus sofort im Fenster ist. 819 HRDOM.insertAsFirstChild(this.m_IBox, document.body); 820 } 821 822 if (this.m_CloseButtonAsFirstElement && this.m_CloseButton) 823 this.createIBoxCloseButton(); 824 825 /* 826 * Erzeuge i-Box-Content 827 */ 828 var content = document.createElement('div'); 829 content.setAttribute('id', this.getUID('idIBoxContent')); 830 content.setAttribute('class', 'HrSys-Gips-iBoxDivContent' + ' ' + this.m_CSSSuffix + ' ' + this.m_AdditionalIBoxContentClass); 831 this.m_IBox.appendChild(content); 832 try 833 { 834 if (this.m_Draggable) 835 new Draggable(content.id); 836 } 837 catch(e) 838 { 839 } 840} 841 842/** 843 * Erzeugt einen Schließen-Button für die i-Box. 844 */ 845HRIBox.prototype.createIBoxCloseButton = function() 846{ 847 if (this.m_IBox) 848 { 849 var _this = this; 850 closeDiv = document.createElement(this.m_CloseButtonTagName); 851 closeDiv.setAttribute('id', this.getUID('idIBoxDivClose')); 852 closeDiv.setAttribute('class', 'HrSys-Gips-iBoxDivClose' + (this.m_ImageSources ? 'Image' : '')); 853 854 // Wenn der Schließen-Button den Tag-Namen: Button hat, dann werden 855 // die Events direkt auf dem Button ausgeführt. 856 if (this.m_CloseButtonTagName === 'button') 857 { 858 closeDiv.setAttribute('aria-label', 'i-Box schließen'); 859 closeDiv.addEventListener('mouseup', function(e) { 860 _this.close(); 861 return false;
862 }); 863 HRAddEventListener(closeDiv, 'keydown', (e) => { 864 if (event.key === 'Enter') 865 { 866 _this.close(); 867 event.preventDefault(); 868 return false; 869 } 870 }); 871 } 872 else 873 { 874 let closeElement = document.createElement('a'); 875 closeElement.setAttribute('href', '#'); 876 closeElement.setAttribute('aria-label', 'i-Box schließen'); 877 closeElement.addEventListener('mouseup', function(e) { 878 _this.close(); 879 return false; 880 }); 881 HRAddEventListener(closeElement, 'keydown', (e) => { 882 if (event.key === 'Enter') 883 { 884 _this.close(); 885 return false; 886 } 887 }); 888 closeDiv.appendChild(closeElement); 889 } 890 } 891 this.m_IBox.appendChild(closeDiv); 892} 893 894/** 895 * Erzeugt einen schwarz-transparenten Hintergrund zum Abdunkeln 896 */ 897HRIBox.prototype.createBlackOverlay = function() 898{ 899 var _this = this; 900 901 var blackOverlay = document.getElementById('idHrSysGipsDivBlackTransparentOverlay'); 902 if (blackOverlay) 903 { 904 this.removeDOMElement(blackOverlay); 905 } 906 907 var overlayWidth = (this.m_ParentDiv ? getElementWidthValue(this.m_ParentDiv) : this.getBodyWidth()); 908 var overlayHeight = (this.m_ParentDiv ? getElementHeightValue(this.m_ParentDiv) : this.getBodyHeight()); 909 910 // 911 // Erstelle das Overlay. Beachte: Das Overlay soll nicht eindeutig pro Instanz sein, s.d. die ID des repräsentierenden Divs nicht über eine UUID eindeutig gemacht wird. 912 // 913 blackOverlay = this.createFloatingElement('div', overlayWidth, overlayHeight, 0, 0, 'idHrSysGipsDivBlackTransparentOverlay'); 914 blackOverlay.className = 'HrSys-Gips-iBoxIFrameOverlay'; 915 blackOverlay.style.backgroundColor = '#000000'; 916 blackOverlay.style.visibility = 'visible'; 917 blackOverlay.style.opacity = '0.6'; 918 919 if (this.m_RemoveByBlackOverlayClick) 920 { 921 blackOverlay.onmouseup = function() 922 { 923 _this.close(); 924 } 925 } 926 else if (this.m_Modal) 927 { 928 HRAddEventListener(blackOverlay, 'click', () => { 929 _this.m_IBox.focus(); 930 }); 931 } 932 933 // Das Overlay soll den gesamten Body überdecken. 934 if (this.m_ParentDiv) 935 { 936 blackOverlay.style.width = getElementWidthValue(this.m_ParentDiv) + 'px'; 937 blackOverlay.style.height = getElementHeightValue(this.m_ParentDiv) + 'px'; 938 } 939 else 940 { 941 blackOverlay.style.width = _this.getBodyWidth() + 'px'; 942 blackOverlay.style.height = _this.getBodyHeight() + 'px'; 943 } 944 945 if (this.m_ParentDiv) 946 { 947 this.m_ParentDiv.appendChild(blackOverlay); 948 } 949 else 950 { 951 document.getElementsByTagName('body')[0].appendChild(blackOverlay); 952 } 953 954 this.m_IBox.setAttribute('data-hribox-overlay', 'J'); 955 956 // Beim Resize des Fensters werden die Dimensionen des Overlays angepasst. 957 window.onresize = function() 958 { 959 if (blackOverlay) 960 { 961 blackOverlay.style.width = _this.getBodyWidth() + 'px'; 962 blackOverlay.style.height = _this.getBodyHeight() + 'px'; 963 } 964 } 965} 966 967/** 968 * Setzt den darzustellenden Inhalt der i-Box: HTML-Content. 969 */ 970HRIBox.prototype.setIBoxContentHtmlElement = function() 971{ 972 if (this.m_HtmlElement) 973 { 974 // Wir legen zunächst um das ursprüngliche Element einen Wrapper, um beim Schließen 975 // der i-Box das Element wieder an seine ursprüngliche Stelle verschieben zu können. 976 this.m_HtmlElementTmpWrapper = document.createElement('div'); 977 this.m_HtmlElementTmpWrapper.style.display = 'none'; 978 HRWrap(this.m_HtmlElement, this.m_HtmlElementTmpWrapper); 979 980 this.m_HtmlElement.style.visibility = 'visible'; 981 this.m_HtmlElement.dataset.hriboxContent = 'J'; // Aktuell für das Schließen aller i-Boxen. 982 983 // 984 // Da häufig auch mit display: none; zum Verstecken von 985 // Divs gearbeitet wird, setzen wir ggfs auch diesen Schalter um. 986 // 987 if (this.m_HtmlElement.style.display == 'none') 988 this.m_HtmlElement.style.display = this.m_Prompt ? 'flex' : 'block'; // flex im Falle des Prompts 989 990 var contentDiv = document.getElementById(this.getUID('idIBoxContent')); 991 if (contentDiv) 992 { 993 contentDiv.appendChild(this.m_HtmlElement); 994 995 if (this.m_Width && this.m_Width > 0) 996 { 997 var contentWidth = getElementWidthValue(this.m_HtmlElement); 998 if (contentWidth && parseInt(contentWidth) > this.m_Width) 999 { 1000 contentDiv.style.overflowX = 'auto'; 1001 contentDiv.style.overflowY = 'hidden'; 1002 contentDiv.style.height = '100%'; 1003 } 1004 1005 // Für Pixelangaben begrenzen wir die Breite auf maximal 80% de
1005s Viewports. Für 1006 // andere Einheiten übernehmen wir einfach mal die Breite. 1007 if (this.m_WidthUnit.trim() === 'px') 1008 this.m_IBox.style.width = Math.min(this.m_Width, Math.round(HRGetViewPortWidth() * 0.85)) + this.m_WidthUnit; 1009 else 1010 this.m_IBox.style.width = this.m_Width + this.m_WidthUnit; 1011 } 1012 if (this.m_Height && this.m_Height > 0) 1013 { 1014 var contentHeight = getElementHeightValue(this.m_HtmlElement); 1015 if (contentHeight && parseInt(contentHeight) > this.m_Height) 1016 { 1017 contentDiv.style.overflowY = 'auto'; 1018 contentDiv.style.overflowX = 'hidden'; 1019 contentDiv.style.height = '100%'; 1020 } 1021 this.m_IBox.style.height = this.m_Height + this.m_HeightUnit; 1022 } 1023 1024 // Die i-Box als modalen Dialog setzen. 1025 if (this.m_Modal) 1026 HRDOM.trapFocus(this.m_IBox); 1027 1028 if (typeof HREventManager === 'object') 1029 HREventManager.dispatchEvent(this.m_IBox, 'HRIBoxContentLoaded', {useStandard: false, notifyParents: false, detail: this.m_IBox}); 1030 } 1031 } 1032} 1033 1034/** 1035 * Setzt den Seiteninhalt der übergebenen Url als Inhalt der i-Box. 1036 * 1037 * Wir verwenden dazu ein i-Frame. 1038 */ 1039HRIBox.prototype.setIBoxContentUrl = function() 1040{ 1041 if (this.m_Url) 1042 { 1043 try 1044 { 1045 var iframe = document.createElement('iframe'); 1046 iframe.src = this.m_Url; 1047 iframe.frameborder = 0; 1048 1049 // Die Breite des i-Frames wird gesetzt. Wird keine Breite übergeben, 1050 // wird das Fenster auf 85 % des Viewports gesetzt. Die Höhe dazu wird dann 1051 // später anhand des geladenen Inhalts bestimmt. 1052 if (this.m_Width && this.m_Width > 0) 1053 { 1054 // Für Pixelangaben begrenzen wir die Breite auf maximal 80% des Viewports. Für 1055 // andere Einheiten übernehmen wir einfach mal die Breite. 1056 if (this.m_WidthUnit.trim() === 'px') 1057 iframe.width = Math.min(this.m_Width, Math.round(HRGetViewPortWidth() * 0.85)) + this.m_WidthUnit; 1058 else 1059 iframe.width = this.m_Width + this.m_WidthUnit; 1060 } 1061 else 1062 iframe.width = Math.round(HRGetViewPortWidth() * 0.85) + 'px'; 1063 1064 document.getElementById(this.getUID('idIBoxContent')).appendChild(iframe); 1065 1066 // Für den Ladeprozess des externen Inhalts einen Spinner anzeigen. 1067 var spinner = showSpinner(this.m_IBox); 1068 1069 const _this = this; 1070 1071 iframe.onload = function () { 1072 if (spinner) 1073 { 1074 spinner.stop(); 1075 spinner = null; 1076 } 1077 1078 // Den keydown-Handler müssen wir auch an das content-Window hängen, um bspw. 1079 // das Schließen per Escape-Taste zu ermöglichen. 1080 HRAddEventListener(iframe.contentWindow, 'keydown', _this.keydownHandler.bind(_this)); 1081 1082 // Fokussierbarkeit und Barrierefreiheit. 1083 const iframeBody = iframe.contentWindow.document.body; 1084 if (iframeBody) 1085 { 1086 // Der Inhalt wurde geladen, jetzt können wir die Höhe anhand des Inhalts 1087 // und der fest gegebenen Breite ermitteln. Es wird aber maximal 85 % der 1088 // Höhe des Viewports angenommen. 1089 if (_this.m_Height && _this.m_Height > 0) 1090 iframe.height = _this.m_Height; 1091 else 1092 iframe.height = Math.round(HRGetViewPortHeight() * 0.85); 1093 1094 // Die i-Box als modalen Dialog setzen. 1095 if (_this.m_Modal) 1096 HRDOM.trapFocus(iframeBody); 1097 } 1098 1099 if (typeof HREventManager === 'object') 1100 HREventManager.dispatchEvent(_this.m_IBox, 'HRIBoxContentLoaded', {useStandard: false, notifyParents: false, detail: iframeBody}); 1101 }; 1102 } 1103 catch (e) 1104 { 1105 if (spinner) 1106 { 1107 spinner.stop(); 1108 spinner = null; 1109 } 1110 } 1111 } 1112} 1113 1114/** 1115 * Bildergallerie: Erzeugt die Navigationspfeile für den Bildwechsel. 1116 */ 1117HRIBox.prototype.createImageNavigation = function() 1118{ 1119 var _this = this; 1120 1121 var caption = document.getElementById(this.getUID('idIBoxDivCaption')); 1122 if (caption) 1123 { 1124 // Zurück-Button 1125 var previous = document.getElementById(this.getUID('idIBoxDivPrevious')); 1126 if (!previous) 1127 { 1128 if (this.m_ImagesNextPrevAsButtons) { 1129 previous = document.createElement("button"); 1130 } else { 1131 previous = document.createElement("div"); 1132 } 1133 previous.id = this.getUID('idIBoxDivPrevious'); 1134 previous.dataset.imageControlPrevious = true; 1135 previous.setAttribute('aria-label', 'Vorheriger Slide'); 1136 previous.setAttribute('aria-controls', _this.getUID('idIBoxDiv4Image')); 1137 1138 caption.appendChild(previous); 1139 } 1140 previous.onclick = function() { 1141 if (_this.m_ImageIdx != 0) 1142 { 1143 _this.showImage(--_this.m_ImageIdx); 1144 } 1145 }; 1146 1147 // Next-Button 1148 var next = document.getElementById(this.getUID('idIBoxDivNext')); 1149 if (!next) 1150 { 1151 if (this.m_ImagesNextPrevAsButtons) { 1152 next = document.createElement("button"); 1153 } else { 1154 next = document.createElement("div"); 1155 } 1156 next.id = this.getUID('idIBoxDivNext'); 1157 next.dataset.imageControlNext = true; 1158 next.setAttribute('aria-label', 'Nächster Slide'); 1159 next.setAttribute('aria-controls', _this.getUID('idIBoxDiv4Image')); 1160 caption.appendChild(next); 1161 } 1162 1163 next.onclick = function() { 1164 if (_this.m_ImageIdx != _this.m_ImageSources.length - 1) 1165 { 1166 _this.showImage(++_this.m_ImageIdx); 1167 } 1168 }; 1169 } 1170} 1171 1172/** 1173 * Bildergallerie: Erzeugt die Tabnavigation für den Bildwechsel. 1174 * 1175 * @param selectedIdx Der Index des selektierten Tabs. 1176 */ 1177HRIBox.prototype.createImageTabs = function(selectedIdx) 1178{ 1179 var _this = this; 1180 1181 var tabnavigation = document.getElementById(this.getUID('tabnavigation')); 1182 if (!tabnavigation) 1183 { 1184 if (this.m_ImagesTabNavigationAsButtons) { 1185 var tabnavigation = document.createElement('div'); 1186 } else { 1187 var tabnavigation = document.createElement('ul'); 1188 } 1189 tabnavigation.className = 'tab-navigation'; 1190 tabnavigation.id = this.getUID('tabnavigation'); 1191 tabnavigation.setAttribute('role', 'tablist'); 1192 tabnavigation.setAttribute('aria-label', 'Bildergalerie Navigation'); 1193 1194 // Pro Bild wird ein Tab erstellt. 1195 for (var i = 0; i < this.m_ImageSources.length; i++) 1196 { 1197 if (this.m_ImagesTabNavigationAsButtons) { 1198 var tab = document.createElement('button'); 1199 } else { 1200 var tab = document.createElement('li'); 1201 } 1202 tab.className = 'tab'; 1203 if (i === parseInt(selectedIdx)){ 1204 addCSSClass(tab, 'selected'); 1205 tab.setAttribute('aria-selected', 'true'); 1206 tab.setAttribute('tabindex', '0'); 1207 } else { 1208 removeCSSClass(tab, 'selected'); 1209 tab.setAttribute('aria-selected', 'false'); 1210 tab.setAttribute('tabindex', '-1'); 1211 } 1212 tab.dataset.idx = i; 1213 tab.onclick = function() { 1214 _this.m_ImageIdx = this.dataset.idx; 1215 toggleCSSClass(document.getElementById(_this.getUID('idIBoxContent')), 'transparent'); 1216 _this.showImage(this.dataset.idx); 1217 }; 1218 tabnavigation.appendChild(tab); 1219 } 1220 1221 this.m_IBox.appendChild(tabnavigation); 1222 } 1223 1224 // Noch das selektierte Tab ermitteln. 1225 for (var i = 0; i < this.m_ImageSources.length; i++) 1226 { 1227 if (i === parseInt(selectedIdx)){
1228 addCSSClass(tabnavigation.querySelector('[data-idx="' + i + '"]'), 'selected'); 1229 tabnavigation.querySelector('[data-idx="' + i + '"]').setAttribute('aria-selected', 'true'); 1230 tabnavigation.querySelector('[data-idx="' + i + '"]').setAttribute('tabindex', '0'); 1231 } else { 1232 removeCSSClass(tabnavigation.querySelector('[data-idx="' + i + '"]'), 'selected'); 1233 tabnavigation.querySelector('[data-idx="' + i + '"]').setAttribute('aria-selected', 'false'); 1234 tabnavigation.querySelector('[data-idx="' + i + '"]').setAttribute('tabindex', '-1'); 1235 } 1236 } 1237} 1238 1239/** 1240 * Erzeugt den inneren Caption-Bereich des Bildes: In diesem werden Titel, Beschreibung und ggf. Bildnummer dargestellt. 1241 */ 1242HRIBox.prototype.createImageInnerCaption = function() 1243{ 1244 var _this = this; 1245 1246 var caption = document.getElementById(this.getUID('idIBoxDivCaption')); 1247 if (caption) 1248 { 1249 var innerCaption = document.getElementById(this.getUID('idIBoxDivInnerCaption')); 1250 if (!innerCaption) 1251 { 1252 innerCaption = document.createElement("div"); 1253 innerCaption.setAttribute('id', this.getUID('idIBoxDivInnerCaption')); 1254 innerCaption.setAttribute('class', 'HrSys-Gips-iBoxDivInnerCaption'); 1255 caption.appendChild(innerCaption); 1256 } 1257 1258 // 1259 // Setzen der Bildunterschrift. 1260 // 1261 innerCaption.innerHTML = '<div id="' + this.getUID('idIBoxDivTitle') + '" class="HrSys-Gips-iBoxDivTitle">' 1262 + ' <div id="' + this.getUID('idIBoxDivNumber') + '" class="HrSys-Gips-iBoxDivNumber" aria-live="polite" aria-atomic="true"></div>' 1263 + '</div>' 1264 + '<div id="' + this.getUID('idIBoxDivDescription') + '" class="HrSys-Gips-iBoxDivDescription fade-in"></div>' 1265 + '<div id="' + this.getUID('idIBoxDivNumber') + '" class="HrSys-Gips-iBoxDivNumber"></div>'; 1266 } 1267} 1268 1269/** 1270 * Setter für die Image-Caption. Hier werden insbesondere im Falle mehrerer Bilder Vor- 1271 * und Zurückbutton für den Bildwechsel erzeugt. 1272 */ 1273HRIBox.prototype.createImageCaption = function() 1274{ 1275 var caption = document.getElementById(this.getUID('idIBoxDivCaption')); 1276 if (!caption) 1277 { 1278 caption = document.createElement('div'); 1279 caption.setAttribute('id', this.getUID('idIBoxDivCaption')); 1280 caption.setAttribute('class', 'HrSys-Gips-iBoxDivCaption' + this.m_CSSSuffix); 1281 this.m_IBox.appendChild(caption); 1282 } 1283} 1284 1285/** 1286 * Bildergallerie: Wechselt zum Bild des angegebenen Indexes. 1287 * 1288 * @param idx der Index des anzuzeigenden Bildes. 1289 */ 1290HRIBox.prototype.showImage = function(idx) 1291{ 1292 if ((this.m_ImageTitles && this.m_ImageTitles[idx]) || (this.m_ImageCaptions && this.m_ImageCaptions[idx]) || this.m_ImageSources.length > 1) 1293 this.createImageCaption(idx); 1294 1295 // Bildnavigation (Vor- und Zurückpfeile) erzeugen. 1296 if (this.m_ImageSources.length > 1) 1297 { 1298 if (this.m_ImageAddTabNavigation) 1299 this.createImageTabs(this.m_ImageIdx); 1300 this.createImageNavigation(); 1301 } 1302 1303 this.createImageInnerCaption(); 1304 1305 // Bildbeschreibung setzen. 1306 if (this.m_ImageCaptions && this.m_ImageCaptions[idx]) 1307 this.setImageDescription(this.m_ImageCaptions[idx]); 1308 1309 // Bildtitel setzen. 1310 if (this.m_ImageTitles && this.m_ImageTitles[idx]) 1311 this.setImageTitle(this.m_ImageTitles[idx]); 1312 1313 // Bildnummer setzen. 1314 if (this.m_ImageSources.length > 1) 1315 this.setImageNumber(idx + 1); // Anzeigenummer nicht null-basiert. 1316 1317 // CSS-Klasse für den Zurück-Button setzen. 1318 var prevButton = document.getElementById(this.getUID('idIBoxDivPrevious')); 1319 if (prevButton) 1320 { 1321 prevButton.setAttribute('class', 'HrSys-Gips-' + (this.m_ImageIdx != 0 ? 'iBoxDivPrevious' : 'iBoxDivPreviousInactive')); 1322 if (this.m_ImageIdx == 0) 1323 { 1324 prevButton.setAttribute('disabled', ''); 1325 } 1326 } 1327 1328 // CSS-Klasse für den Vor-Button setzen. 1329 var nextButton = document.getElementById(this.getUID('idIBoxDivNext')); 1330 if (nextButton) 1331 { 1332 nextButton.setAttribute('class', 'HrSys-Gips-' + (this.m_ImageIdx != this.m_ImageSources.length - 1 ? 'iBoxDivNext' : 'iBoxDivNextInactive')); 1333 if (this.m_ImageIdx == this.m_ImageSources.length - 1) 1334 { 1335 nextButton.setAttribute('disabled', ''); 1336 } 1337 1338 } 1339 1340 // 1341 // Den Content des Bildes setzen. 1342 // 1343 this.setImageContent(idx); 1344} 1345 1346/** 1347 * Setzt die Beschreibung des Bildes in der iBox. 1348 * 1349 * @param description Die Bildbeschreibung. Diese wird per innerHTML gesetzt, d.h. hier kann auch HTML wie Spans verwendet werden. 1350 */ 1351HRIBox.prototype.setImageDescription = function(description) 1352{ 1353 var descriptionElement = document.getElementById(this.getUID('idIBoxDivDescription')); 1354 1355 if (description && description.length > 0) 1356 { 1357 if (description.length > 60) 1358 this.m_minImageWidth = 450; 1359 else 1360 this.m_minImageWidth = 300; 1361 1362 descriptionElement.innerHTML = description; 1363 descriptionElement.style.display = "block"; 1364 } 1365 else 1366 { 1367 descriptionElement.innerHTML = ""; 1368 descriptionElement.style.display = "none"; 1369 } 1370} 1371 1372/** 1373 * Setter für den Bildtitel. 1374 * 1375 * @param title Der neue Titel. 1376 */ 1377HRIBox.prototype.setImageTitle = function(title) 1378{ 1379 var titleElement = document.getElementById(this.getUID('idIBoxDivTitle')); 1380 if (titleElement && title) 1381 { 1382 if (title.length > 0) 1383 { 1384 titleElement.innerHTML = title; 1385 titleElement.style.display = 'block'; 1386 } 1387 else 1388 { 1389 titleElement.innerHTML = ''; 1390 titleElement.style.display = 'none'; 1391 } 1392 } 1393} 1394 1395/** 1396 * Setzt die aktuelle Zahl bzw. den Index des anzuzeigenden Bildes. 1397 * 1398 * @param number Die zu setzende Bildnummer. 1399 */ 1400HRIBox.prototype.setImageNumber = function(number) 1401{ 1402 var numberDiv = document.getElementById(this.getUID('idIBoxDivNumber')); 1403 if (numberDiv) 1404 { 1405 numberDiv.innerHTML = number + ' von ' + this.m_ImageSources.length; 1406 } 1407} 1408 1409/** 1410 * Setzt den darzustellenden Inhalt der i-Box: Bilder. 1411 * 1412 * @param idx Der Index des anzuzeigenden Bildes. 1413 */ 1414HRIBox.prototype.setImageContent = function(idx) 1415{ 1416 _this = this; 1417 1418 if (this.m_ImageSources && this.m_ImageSources[idx]) 1419 { 1420 /* 1421 * Bevor nicht alle Einstellungen des Bildes gesetzt wurden, zeigen wir auch nicht */ 1422 this.m_IBox.style.visibility = 'hidden'; 1423 1424 var imageDiv = document.getElementById(this.getUID('idIBoxDiv4Image')); 1425 if (!imageDiv) 1426 { 1427 imageDiv = document.createElement('DIV'); 1428 imageDiv.setAttribute('id', this.getUID('idIBoxDiv4Image')); 1429 imageDiv.setAttribute('class', 'HrSys-Gips-iBoxDiv4Image'); 1430 } 1431 else 1432 { 1433 // Das alte Bild wird gelöscht, ... 1434 this.removeDOMElement(imageDiv.querySelector('[data-old]')); 1435 1436 // ... das aktuelle als alt markiert. 1437 var selectedImage = imageDiv.querySelector('[data-selected]'); 1438 if (selectedImage) 1439 { 1440 selectedImage.removeAttribute('data-selected'); 1441 selectedImage.setAttribute('data-old', 'J'); 1442 } 1443 } 1444 1445 var content = document.getElementById(this.getUID('idIBoxContent')); 1446 if (content) 1447 content.appendChild(imageDiv); 1448 1449 var img = document.createElement('img'); 1450 img.setAttribute('id', this.getUID('idIBoxContentImage')); 1451 img.setAttribute('class', 'HrSys-Gips-iBoxImage' + (imageDiv.querySelector('[data-old]') ? ' hide' : '')); 1452 img.setAttribute('data-selected', 'J'); 1453 if (this.m_ImageAlttexts && this.m_ImageAlttexts[idx]) 1454 img.setAttribute('alt', this.m_ImageAlttexts[idx]); 1455 img.tabIndex = "0"; 1456 1457 // ggf. das Bild als Hintergrundbild eines Divs setzen. 1458 var selectedImageDiv = null;
1459 if (this.m_ImageSrcAsBackgroundImage) 1460 { 1461 selectedImageDiv = document.getElementById(this.getUID('selectedimagecontainer')); 1462 if (!selectedImageDiv) 1463 { 1464 selectedImageDiv = document.createElement('div'); 1465 selectedImageDiv.id = this.getUID('selectedimagecontainer'); 1466 selectedImageDiv.style.backgroundImage = 'url(\'' + this.m_ImageSources[idx] + '\')'; 1467 selectedImageDiv.className = 'selected-image-container'; 1468 selectedImageDiv.appendChild(img); 1469 imageDiv.appendChild(selectedImageDiv); 1470 } 1471 } 1472 else 1473 imageDiv.appendChild(img); 1474 1475 var linkContainer = img; 1476 if (this.m_ImageSrcAsBackgroundImage) 1477 linkContainer = selectedImageDiv; 1478 1479 if (this.m_ImageLinks && this.m_ImageLinks[idx]) 1480 { 1481 const openImageLink = () => { 1482 if (_this.m_ImageLinks[idx].toLowerCase().indexOf('http') == 0 || (_this.m_ImageLinkTargets && _this.m_ImageLinkTargets[idx] == '_blank')) 1483 { 1484 /* 1485 * In neuem Browserfenster/ Tab öffnen. 1486 */ 1487 window.open(_this.m_ImageLinks[idx], '_blank'); 1488 HRCloseAllIBoxes(); 1489 } 1490 else 1491 { 1492 /* 1493 * In selbem Browserfenster/ Tab öffnen. 1494 */ 1495 window.location.href = _this.m_ImageLinks[idx]; 1496 } 1497 }; 1498 1499 linkContainer.onclick = openImageLink; 1500 linkContainer.onkeydown = (event) => { 1501 1502 if (event.key === 'Enter') 1503 openImageLink(); 1504 }; 1505 linkContainer.style.cursor = 'pointer'; 1506 } 1507 else 1508 { 1509 if (this.m_ImageIdx != this.m_ImageSources.length - 1) 1510 { 1511 linkContainer.onclick = function() 1512 { 1513 // Anzeige des nächsten Bildes, wenn die maximale Bildanzahl nicht überschritten wurde. 1514 if (_this.m_ImageIdx < _this.m_ImageSources.length - 1) 1515 _this.showImage(++_this.m_ImageIdx); 1516 } 1517 } 1518 } 1519 1520 img.src = this.m_ImageSources[idx]; 1521 1522 /* 1523 * Bildgröße ermitteln 1524 */ 1525 var dummyImg = new Image(); 1526 dummyImg.onload = function() 1527 { 1528 var currentContentWidth = dummyImg.width; 1529 var currentContentHeight = dummyImg.height; 1530 1531 if (_this.m_Height && _this.m_Height > 0) 1532 { 1533 currentContentHeight = _this.m_Height; 1534 1535 // 1536 // Wenn keine Breite gesetzt wurde, skalieren wir die Breite im richtigen Verhältnis mit. 1537 // 1538 if (!_this.m_Width) 1539 currentContentWidth = img.width / (img.height / _this.m_Height); 1540 } 1541 else 1542 { 1543 // Bild höher als erlaubt? 1544 if (_this.m_ImageMaxHeight && currentContentHeight > _this.m_ImageMaxHeight) 1545 { 1546 // Verkleinern und Seitenverhältnis erhalten 1547 currentContentHeight = _this.m_ImageMaxHeight; 1548 currentContentWidth = img.width / (img.height / _this.m_ImageMaxHeight); 1549 } 1550 } 1551 1552 if (_this.m_Width && _this.m_Width > 0) 1553 { 1554 currentContentWidth = _this.m_Width; 1555 1556 // 1557 // Wenn keine Höhe gesetzt wurde, skalieren wir die Höhe im richtigen Verhältnis mit. 1558 // 1559 if (!_this.m_Height) 1560 { 1561 currentContentHeight = img.height / (img.width / _this.m_Width); 1562 } 1563 } 1564 else 1565 { 1566 // Bild breiter als erlaubt 1567 if (_this.m_ImageMaxWidth && currentContentWidth > _this.m_ImageMaxWidth) 1568 { 1569 // verkleinern 1570 currentContentHeight = img.height / (img.width / _this.m_ImageMaxWidth); 1571 currentContentWidth = _this.m_ImageMaxWidth; 1572 } 1573 1574 // Breite zu klein? 1575 var divWidth = currentContentWidth; 1576 if (!this.m_Width && currentContentWidth < _this.m_ImageMinWidth) 1577 { 1578 divWidth = _this.m_ImageMinWidth; 1579 } 1580 // die Breite der Divs für das Bild und Titel/Beschreibung unter dem Bild 1581 if (content) 1582 content.style.width = divWidth + 'px'; 1583 1584 var caption = document.getElementById(_this.getUID('idIBoxDivCaption')); 1585 if (caption) 1586 caption.style.width = divWidth + 'px'; 1587 } 1588 1589 // Bild skalieren 1590 img.height = currentContentHeight; 1591 img.width = currentContentWidth; 1592 1593 // Bild dran hängen
1594 if (_this.m_ImageSrcAsBackgroundImage) 1595 selectedImageDiv.appendChild(img); 1596 else 1597 document.getElementById(_this.getUID('idIBoxDiv4Image')).appendChild(img); 1598 1599 // Fade-in-Transition. 1600 var oldImage = imageDiv.querySelector('[data-old]'); 1601 if (_this.m_ImageSrcAsBackgroundImage && selectedImageDiv && selectedImageDiv.querySelector('[data-old]')) 1602 oldImage = selectedImageDiv.querySelector('[data-old]'); 1603 1604 if (oldImage) 1605 { 1606 oldImage.style.display = 'none'; 1607 addCSSClass(oldImage, 'hide'); 1608 removeCSSClass(oldImage, 'fade-in'); 1609 } 1610 1611 if (img) 1612 { 1613 img.style.display = ''; 1614 removeCSSClass(img, 'hide'); 1615 addCSSClass(img, 'fade-in'); 1616 1617 // 1618 // ggf. noch das Hintergrundbild austauschen. 1619 // 1620 if (_this.m_ImageSrcAsBackgroundImage && selectedImageDiv) 1621 selectedImageDiv.style.backgroundImage = 'url(\'' + _this.m_ImageSources[idx] + '\')'; 1622 } 1623 1624 _this.alignIBoxVerticalTo('center'); 1625 _this.alignIBoxHorizontalTo('center'); 1626 _this.m_IBox.style.visibility = 'visible'; 1627 1628 // Die i-Box als modalen Dialog setzen. 1629 if (_this.m_Modal) 1630 HRDOM.trapFocus(_this.m_IBox); 1631 1632 if (typeof HREventManager === 'object') 1633 HREventManager.dispatchEvent(_this.m_IBox, 'HRIBoxContentLoaded', {useStandard: false, notifyParents: false, detail: _this.m_IBox}); 1634 }; 1635 1636 /* 1637 * Achtung: Für den IE ist es notwendig, dass das Setzen der 1638 * Source vor dem Zuweisen des onload stattfindet. 1639 */ 1640 dummyImg.src = this.m_ImageSources[idx]; 1641 } 1642} 1643 1644/** 1645 * Löscht und entfernt die i-Box. 1646 */ 1647HRIBox.prototype.close = function() 1648{ 1649 if (this.m_IBox) 1650 { 1651 // Das HTML-Element wieder an die ursprüngliche Stelle im DOM zurückschieben. 1652 if (this.m_HtmlElement) 1653 { 1654 this.m_HtmlElement.style.display = "none"; 1655 HRInsertAfter(this.m_HtmlElement, this.m_HtmlElementTmpWrapper); 1656 this.m_HtmlElementTmpWrapper.remove(); 1657 } 1658 1659 this.removeDOMElement(this.m_IBox); 1660 1661 // Entferne das Overlay, falls keine andere Instanz dieses mehr benötigt (prüfe entsprechendes data-Attribut). 1662 if (document.querySelectorAll('[data-hribox-overlay=J]').length <= 0) 1663 { 1664 this.removeDOMElement(document.getElementById('idHrSysGipsDivBlackTransparentOverlay')); 1665 window.onresize = ''; 1666 } 1667 1668 // Alle globalen Events wieder entfernen. 1669 this.removeEventListener(); 1670 1671 // Leitet auf gesetzte Url weiter, falls m_RedirectUrlOnClose einen nicht-leeren String enthaelt 1672 if (this.m_RedirectUrlOnClose && (typeof this.m_RedirectUrlOnClose === "string" || (typeof this.m_RedirectUrlOnClose === "object" && this.m_RedirectUrlOnClose.constructor === String)) && this.m_RedirectUrlOnClose != "") 1673 top.location.href = this.m_RedirectUrlOnClose; 1674 else if (this.m_LastFocusedElement) 1675 this.m_LastFocusedElement.focus(); 1676 1677 // Aufruf Callback-Funktion. 1678 if (this.m_OnClose && typeof(this.m_OnClose) === 'function') 1679 this.m_OnClose(); 1680 1681 // Entferne die Body-Klasse, falls keine andere Instanz die Klasse benötigt (prüfe entsprechendes data-Attribut). 1682 if (this.m_BodyClass && document.querySelectorAll('[data-hribox-bodyclass=' + this.m_BodyClass + ']').length <= 0) 1683 HRRemoveBodyCSSClass(this.m_BodyClass); 1684 1685 // Das Element wieder aus der window-Registry herausnehmen. 1686 const idx = window.HRIBoxRegistry.indexOf(this); 1687 if (idx > -1) 1688 window.HRIBoxRegistry.splice(idx, 1); 1689 } 1690} 1691 1692/** 1693 * Richtet die iBox vertikal aus. 1694 * 1695 * @param alignment Die Ausrichtungsart ('top', 'bottom', 'center'). 1696 */ 1697HRIBox.prototype.alignIBoxVerticalTo = function(alignment) 1698{ 1699 1700 if (alignment.toLowerCase() == 'top') 1701 { 1702 this.m_IBox.style.bottom = ''; 1703 this.m_IBox.style.top = (this.m_CloseButton ? 20 : 0) + 'px'; 1704 } 1705 else if (alignment.toLowerCase() == 'center') 1706 { 1707 // Bei absoluter Positionierung wird auch die Scrollposition ergänzt. 1708 // Für fixierte Positionierung entfällt dieses natürlich. 1709 let scrollYPosition = 0; 1710 if (getStyleValue(this.m_IBox, 'position') === 'absolute') 1711 scrollYPosition = window.scrollY || window.pageYOffset; 1712 1713 this.m_IBox.style.bottom = ''; 1714 if (this.m_ParentDiv) 1715 this.m_IBox.style.top = Math.max(((getElementHeightValue(this.m_ParentDiv) - this.m_IBox.offsetHeight) / 2), (this.m_CloseButton ? 20 : 0)) + scrollYPosition + 'px'; 1716 else 1717 this.m_IBox.style.top = Math.max(((HRGetViewPortHeight() - this.m_IBox.offsetHeight) / 2), (this.m_CloseButton ? 20 : 0)) + scrollYPosition + 'px'; 1718 } 1719 else if (alignment.toLowerCase() == 'bottom') 1720 { 1721 this.m_IBox.style.top = ''; 1722 this.m_IBox.style.bottom = '0%'; 1723 } 1724} 1725 1726/** 1727 * Richtet die i-Box horizontal aus. 1728 * 1729 * @param alignment Die Ausrichtungsart ('left', 'right', 'center'). 1730 */ 1731HRIBox.prototype.alignIBoxHorizontalTo = function(alignment) 1732{ 1733
1734 if (alignment.toLowerCase() == 'left') 1735 { 1736 this.m_IBox.style.right = ''; 1737 this.m_IBox.style.left = '0px'; 1738 } 1739 else if (alignment.toLowerCase() == 'center') 1740 { 1741 // Bei absoluter Positionierung wird auch die Scrollposition ergänzt. 1742 // Für fixierte Positionierung entfällt dieses natürlich. 1743 let scrollXPosition = 0; 1744 if (getStyleValue(this.m_IBox, 'position') === 'absolute') 1745 scrollXPosition = window.scrollX || window.pageXOffset; 1746 1747 this.m_IBox.style.right = ''; 1748 if (this.m_ParentDiv) 1749 this.m_IBox.style.left = Math.max(((getElementWidthValue(this.m_ParentDiv) - this.m_IBox.offsetWidth) / 2), 0) + scrollXPosition + 'px'; 1750 else 1751 this.m_IBox.style.left = Math.max(((HRGetViewPortWidth() - this.m_IBox.offsetWidth) / 2), 0) + scrollXPosition + 'px'; 1752 } 1753 else if (alignment.toLowerCase() == 'right') 1754 { 1755 this.m_IBox.style.left = ''; 1756 this.m_IBox.style.right = '0px'; 1757 } 1758} 1759 1760/** 1761 * Initialisiert das Theme der i-Box, nachdem dessen Grundgerüst bereits erzeugt wurde. 1762 */ 1763HRIBox.prototype.initTheme = function() 1764{ 1765 if (this.m_IBox) 1766 { 1767 switch(this.m_Theme) 1768 { 1769 case HRIBoxThemes.Default: 1770 // Default: Hier gibt es nichts zu tun. 1771 break; 1772 case HRIBoxThemes.Popup: 1773 this.initPopupTheme(); 1774 break; 1775 } 1776 } 1777} 1778 1779/** 1780 * Initialisiert das Popup-Theme. 1781 */ 1782HRIBox.prototype.initPopupTheme = function() 1783{ 1784 if (this.m_PopupConfig) 1785 { 1786 var direction = HRPopupDirection.Up; 1787 if (this.m_PopupConfig.direction) 1788 direction = this.m_PopupConfig.direction; 1789 1790 // Transition initialisieren. 1791 this.initPopupTransition(direction); 1792 1793 var showAfter = this.m_PopupConfig.showAfter; 1794 if (!showAfter) 1795 { 1796 showAfter = 250; 1797 } 1798 1799 // 1800 // Verzögertes Einblenden. 1801 // 1802 window.setTimeout(function(ibox, popupConfig) { 1803 if (direction === HRPopupDirection.Left) 1804 { 1805 ibox.style.transform = 'translateX(0)'; 1806 } 1807 else if (direction === HRPopupDirection.Up) 1808 { 1809 ibox.style.transform = 'translateY(0)'; 1810 } 1811 else if (direction === HRPopupDirection.Right) 1812 { 1813 ibox.style.transform = 'translateX(0)'; 1814 } 1815 else if (direction === HRPopupDirection.Down) 1816 { 1817 ibox.style.transform = 'translateY(0)'; 1818 } 1819 ibox.style.pointerEvents = 'all'; 1820 ibox.style.opacity = 1; 1821 }, showAfter, this.m_IBox, this.m_PopupConfig); 1822 1823 // 1824 // Verzögertes Ausblenden. 1825 // 1826 if (this.m_PopupConfig.hideAfter) 1827 { 1828 window.setTimeout(function(iboxObj) { 1829 iboxObj.initPopupTransition(direction); 1830 window.setTimeout(function(iboxObj) { 1831 iboxObj.close(); 1832 }, 1000, iboxObj); 1833 }, this.m_PopupConfig.hideAfter, this); 1834 } 1835 } 1836} 1837 1838/** 1839 * Initialisiert die Popup-Transition abhängig von der gewählten Slide-Richtung. 1840 * 1841 * Default: Up (von unten nach oben fahren). 1842 * 1843 * @param direction Die gewählte Slide-Richtung (@see HRPopupDirection) 1844 */ 1845HRIBox.prototype.initPopupTransition = function(direction) 1846{ 1847 if (direction === HRPopupDirection.Left) 1848 { 1849 this.m_IBox.style.transform = 'translateX(calc(100% + ' + this.m_IBox.getBoundingClientRect().left + 'px))'; 1850 } 1851 else if (direction === HRPopupDirection.Up) 1852 { 1853 this.m_IBox.style.transform = 'translateY(calc(100% + ' + this.m_IBox.getBoundingClientRect().top + 'px))'; 1854 } 1855 else if (direction === HRPopupDirection.Right) 1856 { 1857 this.m_IBox.style.transform = 'translateX(calc(-100% - ' + this.m_IBox.getBoundingClientRect().right + 'px))'; 1858 } 1859 else if (direction === HRPopupDirection.Down) 1860 { 1861 this.m_IBox.style.transform = 'translateY(calc(-100% - ' + this.m_IBox.getBoundingClientRect().bottom + 'px))'; 1862 } 1863 this.m_IBox.style.pointerEvents = 'none'; 1864 this.m_IBox.style.opacity = 0; 1865} 1866 1867/** 1868 * Erzeugt die HTML-Struktur des Hinweistextes. 1869 */ 1870HRIBox.prototype.createPrompt = function() 1871{ 1872 const _this = this; 1873 1874 const contentDiv = document.getElementById(this.getUID('idIBoxContent')); 1875 if (contentDiv) 1876 { 1877 if (this.m_PromptText) 1878 { 1879 const text = document.createElement('p'); 1880 text.innerHTML = this.m_PromptText; 1881 text.className = 'prompt-text'; 1882 contentDiv.appendChild(text); 1883 } 1884 1885 const inputDiv = document.createElement('div'); 1886 inputDiv.className = 'prompt-input'; 1887 1888 // Feldrahmen erzeugen. 1889 const promptFieldframe = document.createElement('div'); 1890 promptFieldframe.className = 'Feldrahmen';
1891 promptFieldframe.dataset.fieldFrame = ''; 1892 inputDiv.appendChild(promptFieldframe); 1893 1894 const promptInput = document.createElement('input'); 1895 promptInput.type = 'text'; 1896 promptInput.name = 'dummy'; 1897 promptInput.id = this.getUID('prompt_input'); 1898 promptInput.dataset.promptInput = ''; 1899 if (this.m_PromptDefaultText) 1900 promptInput.value = this.m_PromptDefaultText; 1901 promptFieldframe.appendChild(promptInput); 1902 1903 // Callback-Funktion, um den bestehenden Inhalt ggf. noch abändern zu können. 1904 if (this.m_PromptConfigureInputHTML && typeof(this.m_PromptConfigureInputHTML) === 'function') 1905 this.m_PromptConfigureInputHTML(inputDiv); 1906 1907 const buttonDiv = document.createElement('div'); 1908 buttonDiv.className = 'prompt-buttons'; 1909 const buttonOk = document.createElement('input'); 1910 buttonOk.type = 'button'; 1911 buttonOk.className = 'button-ok'; 1912 buttonOk.value = this.m_PromptOkayText; 1913 buttonOk.onclick = function ok() { 1914 const returnValue = promptInput.value; 1915 if (_this.m_PromptSaveResultInCookie) 1916 HRSetCookie('PromptReturn', returnValue, 'expires: -1'); 1917 1918 if (_this.m_PromptSaveResultInLocalStorage) 1919 localStorage.setItem('PromptReturn', returnValue); 1920 1921 if (_this.m_PromptCallBack) 1922 if (_this.m_PromptCallBack(returnValue)) 1923 _this.close(); 1924 }; 1925 buttonDiv.appendChild(buttonOk); 1926 1927 if (!this.m_Note) 1928 { 1929 const buttonCancel = document.createElement('input'); 1930 buttonOk.className = 'button-cancel'; 1931 buttonCancel.type = 'button'; 1932 buttonCancel.onclick = function cancel() { 1933 _this.close() 1934 }; 1935 buttonCancel.value = this.m_PromptCancelText; 1936 buttonDiv.appendChild(buttonCancel); 1937 } 1938 1939 contentDiv.appendChild(inputDiv); 1940 contentDiv.appendChild(buttonDiv); 1941 1942 // Die i-Box als modalen Dialog setzen. 1943 if (this.m_Modal) 1944 HRDOM.trapFocus(contentDiv); 1945 1946 if (typeof HREventManager === 'object') 1947 HREventManager.dispatchEvent(this.m_IBox, 'HRIBoxContentLoaded', {useStandard: false, notifyParents: false, detail: this.m_IBox}); 1948 } 1949} 1950 1951/** 1952 * Entfernt das übergebene HTML-Element und löscht es aus dem DOM. 1953 * 1954 * @param element Das zu löschende Element. 1955 */ 1956HRIBox.prototype.removeDOMElement = function(element) 1957{ 1958 if (element && element.parentNode) 1959 { 1960 element.parentNode.removeChild(element); 1961 } 1962} 1963 1964/** 1965 * Erstellt ein HTML-Element vom übergebenen Typ mit absoluter Positionierung. 1966 * 1967 * @param tagName Der Name des Tags. 1968 * @param width Die Breite des Elements. 1969 * @param height Die Höhe des Elements. 1970 * @param xpos Die x-Position des Elements. 1971 * @param ypos Die y-Position des Elements. 1972 * @param id die ID des Elements. 1973 */ 1974HRIBox.prototype.createFloatingElement = function(tagName, width, height, xpos, ypos, id) 1975{ 1976 var element = document.createElement(tagName); 1977 1978 element.id = id; 1979 element.style.position = 'absolute'; 1980 element.style.left = xpos + 'px'; 1981 element.style.top = ypos + 'px'; 1982 if (width) 1983 { 1984 element.style.width = width + 'px'; 1985 } 1986 if (height) 1987 { 1988 element.style.height = height + 'px'; 1989 } 1990 1991 return element; 1992} 1993 1994/** 1995 * Liefert die Breite des Body-Tags. Wenn die Fensterbreite größer als 1996 * der gerenderte Body ist, wird die Fensterbreite zurückgegeben. 1997 * 1998 * @returns Die Breite des Body-Tags in Pixeln. 1999 */ 2000HRIBox.prototype.getBodyWidth = function() 2001{ 2002 if (document.documentElement.scrollWidth) 2003 { 2004 return document.documentElement.scrollWidth; 2005 } 2006 else if (document.documentElement.offsetWidth) 2007 { 2008 return document.documentElement.offsetWidth; 2009 } 2010 2011 var widthValue = getElementWidthValue(document.getElementsByTagName("body")[0]); 2012 return Math.ceil(widthValue); 2013} 2014 2015/** 2016 * Liefert die Höhe des Body-Tags. Wenn die Fensterhöhe größer als 2017 * der gerenderte Body ist, wird die Fenstergröße zurückgegeben. 2018 * 2019 * @returns Die Höhe des Body-Tags in Pixeln. 2020 */ 2021HRIBox.prototype.getBodyHeight = function() 2022{ 2023 if (document.documentElement.scrollHeight) 2024 { 2025 return document.documentElement.scrollHeight; 2026 } 2027 else if (document.documentElement.offsetHeight) 2028 { 2029 return document.documentElement.offsetHeight; 2030 } 2031 2032 var heightValue = getElementHeightValue(document.getElementsByTagName("body")[0]); 2033 return Math.ceil(heightValue); 2034} 2035 2036/** 2037 * Erzeugt zu der gewünschten ID eine pro i-Boxinstanz eindeutige ID. 2038 * 2039 * @param id Die ID. 2040 * @return eine pro Instanz durch einen UUID-Suffix eindeutige ID. 2041 */ 2042HRIBox.prototype.getUID = function(id) 2043{ 2044 return id + '_' + this.m_UUID; 2045} 2046 2047/** 2048 * @param number Die zu prüfende Zahl 2049 * @return true, falls die übergeben Zahl eine positive ganze Zahl oder 0 ist. 2050 */ 2051HRIBox.prototype.isUnsignedInteger = function(number) 2052{ 2053 return (number.toString().search(/^[0-9]+$/) == 0); 2054} 2055 2056/** 2057 * Öffnet den im übergebenen HTML-Element enthaltenen Content in einer i-Box. 2058 * 2059 * @param element Das HTML-Element mit dem darzustellenden Content oder ein eindeutiger Selektor zu einem Element. 2060 * @param configuration Die (optionalen) Konfigurationen. 2061 * @return Die Instanz der neu geöffneten i-Box. 2062 */ 2063function HROpenHtmlElementInIbox(element, configuration) 2064{ 2065 if (element) 2066 { 2067 if (typeof(element) === 'string') 2068 element = document.querySelector(element); 2069 2070 if (element) 2071 { 2072 let config = configuration || {}; 2073 config.htmlElement = element; 2074 const ibox = new HRIBox(config); 2075 ibox.open(); 2076 return ibox; 2077 } 2078 } 2079 2080 return null; 2081} 2082 2083/** 2084 * Öffnet die Url in einer i-Box. 2085 * 2086 * @param url Die in der i-Box darzustellende Url. 2087 * @param configuration Die (optionalen) Konfigurationen. 2088 * @return Die Instanz der neu geöffneten i-Box. 2089 */ 2090function HROpenUrlInIbox(url, configuration) 2091{ 2092 const ibox = new HRIBox(configuration || {}); 2093 ibox.openUrl(url); 2094 return ibox; 2095} 2096 2097/** 2098 * Öffnet ein Bild in der i-Box. 2099 * 2100 * @param source Bildquelle: Absolute oder relative URL 2101 * @param caption Unterschrift des Bildes (hier ist auch HTML erlaubt, die Unterschrift wird per innerHTML gesetzt) 2102 * @param title Titel des Bildes 2103 * @param link Verlinkung des Bildes 2104 * @param linkTarget Das Target (_blank, _self, _parent, _top) 2105 * @param configuration Die (optionalen) Konfigurationen. 2106 * @return Die Instanz der neu geöffneten i-Box. 2107 */ 2108function HROpenImageInIbox(source, caption, title, link, linkTarget, configuration) 2109{ 2110 const ibox = new HRIBox(configuration || {}); 2111 ibox.openImage(source, caption, title, link, linkTarget); 2112 return ibox; 2113} 2114 2115/** 2116 * Öffnet die übergebenen Bilder in der i-Box. 2117 * 2118 * @param sources [Array] Bildquellen: Absolute oder relative URLs 2119 * @param captions [Array] Unterschriften der Bilder (hier ist auch HTML erlaubt, die Unterschrift wird jeweils per innerHTML gesetzt) 2120 * @param imagesConfig Weitere Konfigurationen für die Bilder. 2121 * <ul> 2122 * <li>titles: Array bestehend aus Titeln der Bilder.</li> 2123 * <li>links: Array bestehend aus Verlinkungen der Bilder.</li> 2124 * <li>linkTargets: Array bestehend aus den Targets der Links (_blank, _self, _parent, _top).</li> 2125 * <li>maxWidth: maximale von den Bildern eingenommene Breite.</li> 2126 * <li>maxHeight: maximale von den Bildern eingenommene Höhe.</li> 2127 * <li>first: Index oder Quelle desjenigen Bildes, welches initial angezeigt werden soll.</li> 2128 * <li>addTabNavigation: Ergänzt eine Tab-Navigation unter den Bildern.</li> 2129 * <li>
2129setAsBackground: Setzt das Bild als Hintergrundbild eines umgebenden Divs ein.</li> 2130 * <li>alttexts [Arrray]: Array bestehend aus den Alternativtexten der Bilder.</li> 2131 * </ul> 2132 * @param config Die (optionalen) Konfigurationen. 2133 * @return Die Instanz der neu geöffneten i-Box. 2134 */ 2135function HROpenImagesInIbox(sources, captions, imagesConfig, config) 2136{ 2137 const ibox = new HRIBox(config || {}); 2138 ibox.openImages(sources, captions, imagesConfig.titles, imagesConfig.links, imagesConfig.linkTargets, imagesConfig.maxWidth, imagesConfig.maxHeight, imagesConfig.first, imagesConfig.addTabNavigation, imagesConfig.setAsBackground, imagesConfig.alttexts); 2139 return ibox; 2140} 2141 2142/** 2143 * Stellt den übergebenen Text als Hinweis mit einem OK-Button dar. 2144 * 2145 * @param text Der darzustellende Hinweistext. 2146 * @param state [optional] Der Status des Hinweises (none, info, warning, error). Default: none. 2147 * @param buttonText [optional] Ein abweichender Text für den OK-Button. Default: OK. 2148 * @param configuration Die (optionalen) Konfigurationen. 2149 * @return Die Instanz der neu geöffneten i-Box. 2150 */ 2151function HROpenNoteInIBox(text, state, buttonText, configuration) 2152{ 2153 let config = configuration || {}; 2154 config.blackOverlay = true; 2155 config.removeByBlackOverlayClick = true; 2156 2157 const ibox = new HRIBox(config); 2158 ibox.openNote(text, state, buttonText); 2159 return ibox; 2160} 2161 2162/** 2163 * Öffnet eine Prompt-Box analog zur Javascript-prompt()-Methode. 2164 * 2165 * @param text Der Text des Prompts. 2166 * @param defaultText (optional) 2167 * @param callBack (optional) Callback-Funktion, die nach dem Akzeptieren des Prompts ausgelöst wird und den eingegebenen Wert des Nutzers übergibt. Die Funktion erwartet eine Boolean-Rückgabe. 2168 * Wird false zurückgegeben, wird das Prompt nicht akzeptiert und bleibt stehen. Default: keine Verarbeitung der Eingabe. Das Popup wird akzeptiert. 2169 * @param okayText (optional) Der Text der in dem 'Okay'-Button steht. Default: 'Ok'. 2170 * @param cancelText (optional) Der Text der in dem 'Cancel'-Button steht. Default: 'Abbrechen'. 2171 * @param saveResultInCookie (optional) Wenn true, dann wird ein Cookie mit dem Inhalt des Eingabefelds gesetzt. Default: false. 2172 * @param saveResultInLocalStorage (optional) Wenn true, dann wird der Inhalt des Inputfelds im LocalStorage gespeichert. Default: false. 2173 * @param configureInputHTML Callback-Funktion, um den erzeugten Promptinhalt in Spezialfällen noch verändern zu können. 2174 * @param configuration Die (optionalen) Konfigurationen. 2175 * @return Die Instanz der neu geöffneten i-Box. 2176 */ 2177HROpenPrompt = (text, defaultText, callBack, okayText, cancelText, saveResultInCookie, saveResultInLocalStorage, configureInputHTML, configuration) => { 2178 let config = configuration || {}; 2179 const ibox = new HRIBox(config); 2180 ibox.openPrompt(text, defaultText, callBack, okayText, cancelText, saveResultInCookie, saveResultInLocalStorage, configureInputHTML); 2181 return ibox; 2182} 2183 2184/** 2185 * Convenience-Funktion, um alle i-Boxen auf einen Schlag zu entfernen. 2186 */ 2187function HRCloseAllIBoxes() 2188{ 2189 if (window.HRIBoxRegistry) 2190 { 2191 for (let i = window.HRIBoxRegistry.length - 1; i >= 0; i--) 2192 { 2193 window.HRIBoxRegistry[i].close(); 2194 } 2195 2196 window.HRIBoxRegistry = undefined; 2197 } 2198 try 2199 { 2200 // Auch alte iBoxen schließen. Wenn alle Auftritte eine Versionsnr. > 12 haben, kann der Code entfallen. 2201 if (typeof(removeAllIBoxElements) === 'function') 2202 removeAllIBoxElements(); 2203 } 2204 catch(e) 2205 { 2206 } 2207}
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.