1/** 2 * @copyright (c) Kufer Software GmbH, OderstraÃe 7, D-84453 Mühldorf 3 */ 4 5if (typeof KuferTools == 'undefined') KuferTools = {}; 6if (typeof KuferTools.Utils == 'undefined') KuferTools.Utils = {}; 7 8/** 9 * Fuegt einem jquery Objekt (ziel) ein select mit den angegebenen Optionen hinzu 10 * BeispielAufruf: 11 * var options=[{"val": "wert1", "text": "text1","farbe": '#00FFFF'}, {"val": "wert2", "text": "text2", "farbe": "yellow"}]; 12 * KuferTools.Utils.addSelect($('#testTabelle'), 'name', 'selectId', 'selectClass', 'wert2', options); 13 */ 14KuferTools.Utils.addSelect = function (ziel, name, id, classname, selectedValue, options, disabled) { 15 //Die neue jQuery-Version (1.9) wirft bei $('#') fehler 16 if (id != '') 17 ziel.find('#' + id).remove(); 18 var $select = $('<select name="' + name + '" id="' + id + '" class="' + classname + '"' + (disabled ? ' disabled' : '') + '></select>'); 19 ziel.append($select); 20 jQuery.each(options, function (val, item) { 21 //*DS: umgebaut auf den String, weil ansonsten das select mit showMessage nicht(!!!) funktioniert hat 22 var option = '<option value="' + item.val + '"'; 23 24 if (item.val == selectedValue) { 25 option += ' selected'; 26 if (item.farbe != '') 27 $select.css('background-color', item.farbe); 28 } 29 if (item.farbe != '') { 30 option += ' style="background-color: ' + item.farbe + '"'; 31 } 32 33 option += '>' + item.text + '</option>'; 34 35 $select.append($(option)); 36 }); 37} 38 39/** 40 * Liefert false, wenn nicht alle Selects mit der Klasse pKlasse den gleichen Wert 41 * gewählt haben, ansonsten den bei allen gewählten Wert. 42 */ 43KuferTools.Utils.getValueAllerSelectsMitKlasse = function (pKlasse) { 44 var selektierteOptionen = jQuery('select.' + pKlasse + ' option:selected'); 45 46 // sind alle selektierten Optionen gleich ? 47 for (var i = 1; i < selektierteOptionen.length; ++i) { 48 if ($(selektierteOptionen[i]).val() != $(selektierteOptionen[i - 1]).val()) { 49 return false; //nein => false zurückgeben 50 } 51 } 52 53 return jQuery(selektierteOptionen[0]).val(); 54} 55 56/** 57 * Speichert das Formular des Inputbuttons per AJAX Request! 58 * Ruft mit dem Rückgabewert von Ajax die angegebene callBackFunction auf 59 * 60 * event: submit des Formulars 61 * callBackFunction(data): wird mit der Rückgabe von jQuery.post aufgerufen. 62 */ 63KuferTools.Utils.ajaxPost = function (event) { 64 event.preventDefault(); 65 var form = $(event.currentTarget); 66 var link = form.prop('action'); 67 return KuferTools.Utils.doAjaxPost(form, link); 68} 69 70KuferTools.Utils.doAjaxPost = function (form, link) { 71 const formData = new FormData(); 72 formData.set('ajax', 'content'); 73 74 // Versteckte Eingabefelder 75 form.find('input[type=hidden]').each(function () { 76 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 77 }); 78 // Eingabefelder 79 form.find('input:text').each(function () { 80 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 81 }); 82 // Passwortfelder 83 form.find('input[type=password]').each(function () { 84 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 85 }); 86 // Absendebutton 87 form.find('input[type=submit]').each(function () { 88 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 89 }); 90 // Angewählte Checkboxen 91 form.find('input[type=radio]').each(function () { 92 if (this.checked) { 93 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 94 } 95 }); 96 // Angewählte Radio-Groups 97 form.find('input[type=checkbox]').each(function () { 98 if (this.checked) { 99 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 100 } 101 }); 102 // Textarea 103 form.find('textarea').each(function () { 104 if (typeof (jQuery(this).prop('name')) != 'undefined' && jQuery(this).prop('name') !== '') { 105 jQuery(this).css('display', 'block'); 106 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 107 } 108 }); 109 // Select 110 form.find('select').each(function () { 111 if (typeof (jQuery(this).prop('name')) != 'undefined' && jQuery(this).prop('name') !== '') { 112 formData.set(jQuery(this).prop('name'), jQuery(this).val()); 113 } 114 }); 115 116 //Falls der ReloadSchutz aktiv ist, muss die PostID hochgesetzt werden, da ein zweiter Submit 117 //vom Reloadschutz abgefangen wird. 118 if (typeof (KuferTools.ReloadSchutz) != 'undefined' && typeof (KuferTools.ReloadSchutz.PostID) != 'undefined') 119 KuferTools.ReloadSchutz.PostID++; 120 121 KuferTools.Utils.AjaxLadebildschirm.Start(); 122 123 return fetch(link, { 124 method: 'POST', 125 body: formData, 126 headers: new Headers({ 127 'X-Requested-With': 'XMLHttpRequest'
128 }) 129 }).finally(() => { 130 KuferTools.Utils.AjaxLadebildschirm.Stop(); 131 }); 132} 133 134/** 135 * Schickt ein Post-Request ab. Kein AJAX, es wird nach dem Absenden eine neue Seite angezeigt. 136 * 137 * @param string pAction Zieladresse 138 * @param object pDataObj Attributnamen werden Key, Werte werden Value für Post 139 * Beispiel: {"schlüssel1": 1, "schlüssel2": 2} 140 */ 141KuferTools.Utils.Post = function (pAction, pDataObj) { 142 var formStr = '<form method="post" action="' + pAction + '">'; 143 144 jQuery.each(pDataObj, function (key, value) { 145 formStr += '<input type="hidden" name="' + key + '" value="">'; 146 }); 147 formStr += '</form>'; 148 149 var $form = jQuery(formStr); 150 151 jQuery('body').append($form); 152 153 //*TH: Hier per jQuery bei den Hidden-Inputs die Werte setzen, anstatt es oben direkt im HTML zusammenzubauen, 154 //damit die Characters escaped werden. Falls wer eine bessere Lösung weiÃ, gerne umsetzen. 155 jQuery.each(pDataObj, function(key, value) { 156 jQuery('input[name="' + key + '"]').val(value); 157 }); 158 159 $form.trigger('submit'); 160}; 161 162/** 163 * Gibt einen Fehlermeldungsdialog aus, falls vom Server fehlerhafte Daten empfangen wurden 164 * 165 * @param {Object} pLoadedObj 166 * @param {string} pLink 167 * @param {Object|undefined} [pAbbruchButton=undefined] 168 * @returns Null 169 */ 170KuferTools.Utils.showAjaxErrorDialog = function (pLoadedObj, pLink, pAbbruchButton) { 171 // Falls kein oder ein fehlerhaftes Objekt vom Server zurückgegeben wird (z.B. wegen einer 172 // Exception in PHP), wird eine Fehlermeldung ausgegeben.
173 if (!KuferTools.Utils.isAjaxObjectCorrect(pLoadedObj)) { 174 175 var abbruchButton; 176 if (typeof pAbbruchButton !== 'undefined') { 177 abbruchButton = pAbbruchButton; 178 } 179 else { 180 abbruchButton = { 181 "Abbrechen": function () { $(this).dialog("close"); } 182 }; 183 } 184 185 var meldungsText = 'Fehlerhafte Daten vom Server empfangen. '; 186 if (typeof pLoadedObj === 'string' && $(pLoadedObj).hasClass('accessDenied')) { 187 // Meldung: Sie haben keinen Zugriff. 188 meldungsText = $(pLoadedObj).html(); 189 } 190 meldungsText += 'Bitte setzen Sie sich mit der Schulungseinrichtung in Verbindung. '; 191 meldungsText += 'Dies kann passieren, wenn Sie sich ausgeloggt haben oder ausgeloggt wurden. '; 192 meldungsText += ''; 193 meldungsText += '<p style="color: red">Ãnderungen die gespeichert werden sollten, konnten nicht übernommen werden.</p>'; 194 console.log('Falsche Daten in der Ajax-Response zum Ajax-Request mit dem Link ' + pLink + '. '); 195 196 if (typeof KuferTools.showMessage !== 'undefined') { 197 KuferTools.showMessage({ meldung: meldungsText, title: 'Achtung', buttons: abbruchButton }); 198 } else { //in den alten Mitarbeitertools gibt es die Funktion KuferTools.showMessage nicht 199 showMessage(meldungsText, 'Achtung', abbruchButton); //TODO: entfernen, wenn die alten KuferTools gelöscht werden 200 } 201 KuferTools.Utils.AjaxLadebildschirm.Stop(); 202 // Achtung: wird ausgewertet, um aus der aufrufenden Funktion auszusteigen; daher ist hier true 203 // für die Rückgabe nötig 204 return true; 205 } 206 return; 207} 208 209 210/** 211 * Prüft ob das vom Server empfangene Ajax Response Objekt korrekt ist 212 * 213 * Falls der Inhalt des Ajax Response Objekts auf Serverseite leer ist, wird am Client ein Objekt der Form 214 * {page: ''} erzeugt, das für eine Fehlerausgabe im Dialog benutzt wird. 215 * 216 * @param {Object} pLoadedObj 217 * @returns {Boolean} true, falls das Objekt ein korrekte Form hat. 218 */
219KuferTools.Utils.isAjaxObjectCorrect = function (pLoadedObj) { 220 if (typeof pLoadedObj !== 'object' || isempty(pLoadedObj) || 221 (typeof pLoadedObj.page !== 'undefined' && isempty(pLoadedObj.page))) 222 return false; 223 return true; 224} 225 226/** 227 * Gibt einen Dialog für Zugriff verweigert aus 228 * 229 * Wird ähnlich zu KuferTools.Utils.showAjaxErrorDialog verwendet; Allerdings wird hier kein 230 * Objekt sondern nur ein String mit dem Sichteninhalt vom Server empfangen und nur der Fall einer 231 * Zugriffsverletzung ausgegeben 232 * 233 * @param string pData 234 * @returns {undefined|Boolean} 235 */ 236KuferTools.Utils.showAccessDeniedDialog = function (pData) { 237 if (typeof pData === 'string' && $(pData).find('.accessDenied').length > 0) { 238 // Meldung: Sie haben keinen Zugriff. 239 var meldungsText = $(pData).html(); 240 var abbruchButton = { 241 "Abbrechen": function () { $(this).dialog("close"); } 242 }; 243 if (typeof KuferTools.showMessage !== 'undefined') { 244 KuferTools.showMessage({ meldung: meldungsText, title: 'Hinweis', buttons: abbruchButton }); 245 } else { //in den alten Mitarbeitertools gibt es die Funktion KuferTools.showMessage nicht 246 showMessage(meldungsText, 'Hinweis', abbruchButton); //TODO: entfernen, wenn die alten KuferTools gelöscht werden 247 } 248 KuferTools.Utils.AjaxLadebildschirm.Stop(); 249 // Achtung: wird ausgewertet, um aus der aufrufenden Funktion auszusteigen; daher ist hier true 250 // für die Rückgabe nötig 251 return true; 252 } 253 return; 254}; 255 256/** 257 * Gibt einen Dialog für nicht eingeloggt aus 258 * 259 * Wird ähnlich zu KuferTools.Utils.showAjaxErrorDialog verwendet; Allerdings wird hier kein 260 * Objekt sondern nur ein String mit dem Sichteninhalt vom Server empfangen. 261 * 262 * @param string pData 263 * @returns {undefined|Boolean} 264 */ 265KuferTools.Utils.showNotLoggedInDialog = function (pData) { 266 if (typeof pData === 'string' && $(pData).find('.notLoggedIn').length > 0) { 267 var meldungsText = $(pData).html(); 268 var abbruchButton = { 269 "Abbrechen": function () { $(this).dialog("close"); } 270 }; 271 if (typeof KuferTools.showMessage !== 'undefined') { 272 KuferTools.showMessage({ meldung: meldungsText, title: 'Hinweis', buttons: abbruchButton }); 273 } else { //in den alten Mitarbeitertools gibt es die Funktion KuferTools.showMessage nicht 274 showMessage(meldungsText, 'Hinweis', abbruchButton); //TODO: entfernen, wenn die alten KuferTools gelöscht werden 275 } 276 KuferTools.Utils.AjaxLadebildschirm.Stop(); 277 // Achtung: wird ausgewertet, um aus der aufrufenden Funktion auszusteigen; daher ist hier true 278 // für die Rückgabe nötig 279 return true; 280 } 281 return; 282}; 283 284 285/** 286 * Allgemeine Funktionen zum Senden eine Ajax Requests und Handeln der AjaxResponse vom Server (im Responsive Stand) 287 * 288 * Die Ajax Response wird auf Serverseite von der Funktion getAjaxObject($pView), die im entsprechenden Presenter 289 * (z.B. VerhaltensListeAuswahlPresenter) aufgerufen wird, aufgebaut. Ein solcher spezieller Presenter zum Bearbeiten eines 290 * Ajax Requests gibt die für eine Ajax Response notwendigen Informationen in einem Std Objekt zurück (also u.a. zusätzlich zur 291 * Sicht noch benötigte .js und .css Files) 292 * 293 * @param string pActionLink 294 * @param button pButtons 295 * @param string pWidth 296 * @param array(function) callBackFunctionAry ermöglicht ggf. spezielle Handlings beim Bearbeiten der Ajax response 297 * @param function postHookFunction 298 * Folgende Parameter werden direkt an showMessage weitergeleitet: pButtons, pWidth 299 */ 300KuferTools.Utils.loadAndDisplayPage4Ajax = function (pActionLink, pButtons, pWidth, callBackFunctionAry, postHookFunction) { 301 302 KuferTools.Utils.AjaxLadebildschirm.Start(); 303 304 305 //schickt ein Ajax Request an den ActionLink und bearbeitet die Ajax Response vom Server; empfängt hierbei ein Datenobjekt (data), 306 //das die HTMML Daten der Seite (bzw. Sicht) und zusätzl.Informationen (wie css u. js Dateien u. Deklarationen) enthält 307 308 jQuery.post(pActionLink, function (data) { 309 KuferTools.Utils.AjaxLadebildschirm.Stop(); 310 //wird ggf. in Fehlerfällen gebraucht 311 var abbruchButton = { 312 "Abbrechen": function () { $(this).dialog("close"); } 313 }; 314 315 var loadedObject = KuferTools.Utils.getObjectFromJson(data); 316 317 // Falls kein oder ein fehlerhaftes Objekt zurückgegeben wird, wird eine Fehlermeldung ausgegeben. 318 if (KuferTools.Utils.showAjaxErrorDialog(loadedObject, pActionLink, abbruchButton)) 319 return; 320 321 //CSS Dateien für die gerade geladene Page einbinden 322 if (jQuery.isArray(loadedObject.css)) { 323 KuferTools.Utils.loadCssFiles(loadedObject.css); 324 } 325 //JS Dateien für die gerade geladene Page einbinden 326 if (jQuery.isArray(loadedObject.js)) { 327 //noch nicht geladene JS Dateien einbinden 328 KuferTools.Utils.loadJsFiles(loadedObject.js); 329 } 330 if (jQuery.trim(loadedObject.jsdeclarations) !== '') { 331 eval(loadedObject.jsdeclarations); 332 } 333 registerNamespace("KuferTools.Inhalt"); 334 335 //Achtung: die Seite loadedObject.inhalt enthält den Seiteninhalt 336 KuferTools.Inhalt = $(loadedObject.inhalt); 337 338 //Callback Funktionen, die vor der Ausgabe ausgeführt werden sollen, z.B. zum verändern von Eingabefeldern 339 if (typeof (callBackFunctionAry) != 'undefined') { 340 var callbackLen = callBackFunctionAry.length; 341 for (var i = 0; i < callbackLen; i++) { 342 var callBackFunction = callBackFunctionAry[i]; 343 callBackFunction(); //ist hier z.B. spezielles Handling für Fach- und Teilnehmeroptionen 344 } 345 } 346 347 // Hier keine Validierung von Formularelementen (Input-, Selectfeldern etc.) einbauen; Formular hat hier nämlich nichts mit dem 348 // Sightbuilder zu tun; daher gibt es z.B. auch keine Pflichtfelder die rot umrandet sein müssen 349 350 //Falls eine Fehlermeldung mitgeschickt wurde: diese ausgeben 351 if (loadedObject.error) { 352 353 //Beschreibung des Fehlers befindet sich in loadedObject.error 354 showMessage(loadedObject.error, 'Fehler aufgetreten'); 355 } 356 else { 357 if (!isempty(loadedObject.inhalt)) { 358 //kein Fehler: Ausgabe des Formulars 359 KuferTools.showMessage({ meldung: KuferTools.Inhalt, title: loadedObject.title, buttons: pButtons, width: pWidth }); 360 // Funktionen, die nach der Ausgabe des Dialogs/Formulars ausgeführt werden sollen; z.B. Validierungsfunktion für die 361 // Eingabefelder. Dazu müssen die Felder bereits vorhanden sein und das Formular via jQuery Selektor angesprochen 362 // werden 363 if (typeof (postHookFunction) === 'function') { 364 postHookFunction(); 365 } 366 } 367 else { 368 var meldungsText = 'Die Eingabemaske für den Dialog ist leer. Hier müssen Eingabefelder hinzugefügt werden. Bitte setzen Sie sich mit der ' + 369 'Schulungseinrichtung in Verbindung.'; 370 371 372 KuferTools.showMessage({ meldung: meldungsText, title: 'Fehler', buttons: abbruchButton }); 373 } 374 } 375 }); //end jQuery.post(pActionLink, function(data) {... 376 377}//end KuferTools.Utils.loadAndDisplayPage4Ajax 378 379 380/** 381 * Lädt eine Page aus den KuferTools nach, bindet dann deren CSS und JS Dateien ein und 382 * zeigt die Page dann als Dialog an. Während des Ladevorgangs wird der übliche Ladeeffekt angezeigt. 383 * Ist z.B. für Ausgaben des Sightbuilders geeignet. 384 * Folgende Parameter werden direkt an showMessage weitergeleitet: 385 * pButtons, pWidth, pPosition 386 */ 387KuferTools.Utils.loadAndDisplayPage = function (pLink, pDataString, pButtons, pWidth, pPosition, pDoAfterDisplay) { 388 if (typeof (KuferTools.ReloadSchutz) != 'undefined' && typeof (KuferTools.ReloadSchutz.PostID) != 'undefined') 389 KuferTools.ReloadSchutz.PostID++; 390 391 392 KuferTools.Utils.AjaxLadebildschirm.Start(); 393 394 //entspricht jQuery.ajax; d.h. die Methode verwendet Ajax Mechanismus 395 jQuery.post(pLink, pDataString, function (data) { 396 397 KuferTools.Utils.AjaxLadebildschirm.Stop(); 398 399 var loadedPage = KuferTools.Utils.getObjectFromJson(data); 400 401 //CSS Dateien für die gerade geladene Page einbinden 402 if (jQuery.isArray(loadedPage.css)) { 403 KuferTools.Utils.loadCssFiles(loadedPage.css); 404 } 405 //JS Dateien für die gerade geladene Page einbinden 406 if (jQuery.isArray(loadedPage.js)) { 407 //noch nicht geladene JS Dateien einbinden 408 KuferTools.Utils.loadJsFiles(loadedPage.js); 409 } 410 if (jQuery.trim(loadedPage.jsdeclarations) != '') { 411 eval(loadedPage.jsdeclarations); 412 } 413 registerNamespace("KuferTools.Page"); 414 415 //Achtung: die Seite loadedPage.page muss vom Sightbuilder erzeugt sein, damit die Validierung korrekt funktioniert ( siehe 416 // Serverseitige Methode getAjaxObject4Tab() in TabPageBase bzw. Methode getAjaxResponse() (z.B. in tooladressdaten.php) 417 KuferTools.Page = $(loadedPage.page); 418 419 var $formObj = KuferTools.Page.find('input, select, textarea'); 420 421 //Falls eine Fehlermeldung mitgeschickt wurde: diese ausgeben 422 if (loadedPage.error) { 423 showMessage(loadedPage.error, 'Fehler aufgetreten'); //Beschreibung des Fehlers befindet sich in loadedPage.error 424 } 425 else { 426 //Ausgabe des Formulars, nur falls es mit passenden Eingabefeldern vom Server geschickt wurde 427 if (!isempty($formObj) && $formObj.length !== 0) { 428 //validiert das nachgeladene SightBuilder Formular: das muà immer passieren; dadurch werden die Pflichtfelder mit roter 429 // Umrandung angezeigt; der Rückgabewert wird hier NICHT ausgewertet; 430 validateForm($formObj); 431 showMessage(KuferTools.Page, loadedPage.header, pButtons, pWidth, pPosition); 432 if (typeof (pDoAfterDisplay) != 'undefined') { 433 pDoAfterDisplay(); 434 } 435 } 436 // Fehlermeldungen müssten eigentlich in der PHP-Datei über page.error übergeben werden. 437 // Der folgende Block ist dafür verantwortlich, dass mit loadAndDisplayPage derzeit nur Formulare ausgegeben werden können. 438 else if ($formObj.length == 0) { 439 showMessage('Die Eingabemaske ist leer, hier müssen Eingabefelder hinzugefügt werden. Bitte setzen Sie sich mit einem Administrator in Verbindung.', 'Fehler aufgetreten'); 440 } 441 else 442 showMessage('<div>Fehler: leeres oder ungültiges Formular vom Server empfangen. Bitte prüfen Sie die Sicht zu den ' + 443 loadedPage.header + ' in den Zentralen Einstellungen des Tools.</div>', 'Warnung'); 444 } 445 }); 446}; //end KuferTools.Utils.loadAndDisplayPage 447 448/** 449 * Liefert die bereits auf der Seite vorhandenen CSS Files 450 * 451 * @returns {Array|KuferTools.Utils.getLoadedCssFiles.result} 452 */ 453KuferTools.Utils.getLoadedCssFiles = function () { 454 var result = new Array(); 455 jQuery('link[rel=stylesheet]').each(function (index, elem) { 456 var href = jQuery(elem).prop('href'); 457 if (href !== undefined) 458 result.push(href); 459 }); 460 return result; 461} //end KuferTools.Utils.getLoadedCssFiles 462 463/** 464 * Fügt die CSS Dateien aus pCssFiles in die Seite ein, die noch nicht da w
464aren. 465 * 466 * @param {Array} pCssFiles 467 */ 468KuferTools.Utils.loadCssFiles = function (pCssFiles) { 469 //erstmal die bereits geladenen CSS Dateien raussuchen 470 var alreadyLoadedCss = KuferTools.Utils.getLoadedCssFiles(); 471 var versionStr = 'version=' + KuferTools.Version; // also z.B. version=4.20.17.01 472 473 474 //noch nicht geladene CSS Dateien einbinden 475 jQuery.each(pCssFiles, function (index, elem) { 476 477 //Falls der Skriptname nicht im Array der bereits geladenen CSS Skripte enthalten ist, wird er angehängt 478 // statt: if (jQuery.inArray(elem, alreadyLoadedCss) === -1) { 479 if (!KuferTools.Utils.isScriptinArray(elem, alreadyLoadedCss)) { 480 481 //Ein noch nicht vorhandenes CSS File in den Header der Seite einhängen; dazu: letztes Element mit <link href="..." im 482 //Header finden und dort das neugefundene Element als Link anhängen 483 jQuery('head').find('link[href]:last').after('<link rel="stylesheet" type="text/css" href="' + elem + '?' + versionStr + '"/>'); 484 alreadyLoadedCss.push(elem); 485 } 486 }); // end jQuery.each(..) 487} //end KuferTools.Utils.loadCssFiles 488 489/** 490 * Liefert die bereits auf der Seite vorhandenen JS Files 491 * 492 * @returns {Array|KuferTools.Utils.getLoadedJsFiles.alreadyLoadedScripts} 493 */ 494KuferTools.Utils.getLoadedJsFiles = function () { 495 var alreadyLoadedScripts = new Array(); 496 jQuery('script').each(function (index, elem) { 497 var src = jQuery(elem).prop('src'); 498 if (src !== undefined) 499 alreadyLoadedScripts.push(src); 500 }); 501 return alreadyLoadedScripts; 502} //end KuferTools.Utils.getLoadedJsFiles 503 504 505/** 506 * Fügt die JS Dateien aus pJsFiles in die Seite ein, die noch nicht da waren. 507 * 508 * @param {Array} pJsFiles 509 */ 510KuferTools.Utils.loadJsFiles = function (pJsFiles) { 511 var alreadyLoadedScripts = KuferTools.Utils.getLoadedJsFiles(); 512 513 var versionStr = 'version=' + KuferTools.Version; // also z.B. version=4.20.17.01 514 515 jQuery.each(pJsFiles, function (index, elem) { 516 // zunächst das Script als Stringdarstellung ermitteln 517 var addLoadElem = ''; 518 if (typeof (elem) === 'object') { 519 addLoadElem = elem.link; 520 } 521 else if (typeof (elem) === 'string') { 522 addLoadElem = elem; 523 } 524 //Falls der Skriptname nicht im Array der bereits geladenen Skripte enthalten ist, wird er angehängt 525 // statt: if (jQuery.inArray(addLoadElem, alreadyLoadedScripts) === -1) { 526 if (!KuferTools.Utils.isScriptinArray(addLoadElem, alreadyLoadedScripts)) { 527 // Bisher: 528 // jQuery.getScript(elem); 529 // Das lädt ein noch nicht vorhandene Javascript File via GET Request vom Server nach; Achtung??: Wurde hier wohl falsch 530 // verwendet!!!. Müsste via getScrip(url) aufgerufen werden 531 532 // Aber viel besser ist folgendes (ohne Nachladen per Ajax) 533 //letztes Element mit <script src="..." im Body finden und dort das neugefundene Element als Script anhängen 534 jQuery('body').find('script[src]:last').after('<script charset="UTF-8" src="' + addLoadElem + '?' + versionStr + '">'); 535 alreadyLoadedScripts.push(addLoadElem); 536 } 537 }); //end jQuery.each(..) 538} // end KuferTools.Utils.loadJsFiles 539 540 541/** 542 * Gibt an, ob ein Script String im Array von Script Strings enthalten ist 543 * 544 * @param string pSearchScript 545 * @param Array(string) pScriptAry 546 * @returns boolean true falls der Suchstring im ScriptArray enthalten ist 547 */ 548KuferTools.Utils.isScriptinArray = function (pSearchScript, pScriptAry) { 549 var isInside = false; 550 // pSearchScript ist relativ zum Pfad (z.B. https://localhost/develop/kufertools ) angegeben: also z.B. 551 // ../jquery/jqueryXXmin.js oder z.B. settings/sys/layout/js/project.js 552 // die Elemente aus dem Script Array haben hingegen folgende absolute Darstellung (mit Pfad und Version): 553 // https://localhost/develop/jquery/jqueryXXmin.js?version=4.20.17.01 oder 554 // https://localhost/develop/kufertools/settings/sys/layout/js/project.js?version=4.20.17.01 555 556 // statt: if (jQuery.inArray(pSearchScript, pScriptAry) === -1) isInside = false; 557 558 var searchScript = pSearchScript.replace(/^(\.\.\/)+/, ""); 559 //prüft, ob z.B. jquery/jqueryXXmin.js im ScriptArray enthalten ist, via search von regulären Ausdrücken 560 $.each(pScriptAry, function (index, elem) { 561 if (elem.search(searchScript) != -1 && !isInside) { 562 isInside = true; 563 } 564 }); 565 return isInside; 566} //end KuferTools.Utils.isScriptinArray 567 568 569 570 571/** 572 * wandelt erstes Zeichen des Strings GroÃschreibung um 573 * Rest beleibt gleich (d.h. klein oder groÃ) 574 * @param string string 575 * @returns string 576 */ 577KuferTools.Utils.ucFirst = function (string) { 578 return string.substring(0, 1).toUpperCase() + string.substring(1); 579} 580 581/** 582 * wandelt erstes Zeichen des Strings GroÃschreibung um 583 * Rest wird in Kleinschreibung umgewandelt 584 * @param string string 585 * @returns string 586 */ 587KuferTools.Utils.ucFirstLc = function (string) { 588 return string.substring(0, 1).toUpperCase() + string.substring(1).toLowerCase(); 589} 590 591/** 592 * Wandelt jedes Zeichen in ein HtmlEntitie um. 593 * 594 * Vorsicht: einige jQuery-Funktionen encoden automatisch und prüfen nicht auf doppeltes Encoden. 595 * Z. B. .val und .attr führen selbst HTML-Encode durch. After und AppendTo nicht, da dort auch HTML-Tags enhalten sein dürfen. 596 * 597 * Weitere Tips: .text statt .html verwenden, wenn kein html erwartet wird. 598 * 599 * @returns string 600 */ 601KuferTools.Utils.htmlEncode = function (string) { 602 if (typeof(string) !== 'undefined' && string !== null) { 603 return string.toString().replace(/./g, function (e) { return "&#" + e.charCodeAt(0) + ";"; }); 604 } 605 return ''; 606}; 607 608/** 609 * Testet zwei Variablen auf inhaltliche Gleichheit - Arrays und Objekte werden gleich behandelt, indem die einzelnen 610 * Member durchgegangen werden. 611 * @param mixed a 612 * @param mixed b 613 * @return bool 614 */ 615function equals(a, b) { 616 if (typeof a != typeof b) 617 return false; 618 if (a == null && b != null) 619 return false; 620 if (a != null && b == null) 621 return false; 622 if (typeof a == 'object') {//für Objekte und Arrays 623 if (a.length != b.length) 624 return false; 625 //for (var i = 0 ; i < a.length ; i++) { 626 for (var i in a) { 627 if (!equals(a[i], b[i])) 628 return false; 629 } 630 return true; 631 } 632 633 return a == b; 634} 635 636//pads left 637String.prototype.lpad = function (padString, length) { 638 var str = this; 639 while (str.length < length) 640 str = padString + str; 641 return str; 642} 643 644//pads right 645String.prototype.rpad = function (padString, length) { 646 var str = this; 647 while (str.length < length) 648 str = str + padString; 649 return str; 650} 651 652/**
653 * Entfernt whitespaces (also Leerzeichen etc) 654 * (entspricht trimstr in PHP ) 655 * s. auch trim() (project.js) 656 */ 657KuferTools.Utils.trimS = function (str) { 658 if (typeof (str) == 'undefined') 659 return ''; 660 str = str.replace(/^\s+/, ''); 661 for (var i = str.length - 1; i >= 0; i--) { 662 if (/\S/.test(str.charAt(i))) { 663 str = str.substring(0, i + 1); 664 break; 665 } 666 } 667 return str; 668} 669 670/** 671 * Entfernen von umgebendem HTML-Gedoehns 672 * entfernt alle HTML Tags ausser die im exceptiontag angegebenen 673 */ 674KuferTools.Utils.stripHTML = function (str, exceptiontag) { 675 if (exceptiontag != undefined) 676 //entfernt alle HTML Tags ausser z.B. <img> ..</img> oder <a href..>..</a>(unabhängig von Klein/GroÃschreibung 677 // wg. i = ignore case) 678 regexpression = new RegExp('<[^' + exceptiontag + ']\/?[^' + exceptiontag + '][^>]+(>|$)', "gi"); 679 else 680 regexpression = /<\/?[^>]+(>|$)/g; 681 str = str.replace(regexpression, ""); 682 str = str.replace(" ", " "); 683 return str; 684} 685 686let renderCounter = 0; 687/** 688 * Fässt mehrere Ãnderungen an einen Seitenabschnitt in einem Renderschritt zusammen. 689 * Kann stark die Performance verbessern, wenn in einer Auflistung alle Elemente einzeln geändert werden, und jedesmal 690 * ein Seiten-Rendern anstöÃt 691 * 692 * Vorsicht: 693 * 1. Es kann dazu führen, dass Trigger auf den Elementen nicht angestoÃen werden 694 * 2. Die Elemente im Abschnitt können nicht neu per Selector geladen werden, bestehende Selectoren funktionieren weiterhin 695 * 696 * @param $element jQuery-Selector für den Abschnitt mit den Ãnderungen. Falls der Selector mehrere Elemente findet, wird dies nur für das erste Element durchgeführt. 697 * @param func die Funktion mit den Ãnderungen ohne Parameter. (Funktionen mit Parametern können in eine anonyme Funktion ohne Parameter geändert werden) 698 */ 699KuferTools.Utils.renderInEinenSchritt = function($element, func) { 700 renderCounter++; 701 702 const idName = 'utils-platzhalter-' + renderCounter; 703 const $parent = $element.first().parent(); 704 $parent.after('<div id="'+idName+'" style="display: none;"></div>'); 705 $parent.detach(); 706 707 func(); 708 709 $('#' + idName).after($parent); 710 $('#' + idName).remove(); 711 712 713} 714 715/** 716 * Liefert einen bestimmten Eintrag aus einem Array, wenn pValueName angegeben ist, 717 * wird die entsprechende Eigenschaft des Objekts im Array verglichen 718 * wird das gesuchte Element nicht gefunden, wird null zurückgegeben 719 * Beispiele: var b = new Array({"id":"3"},{"id":"4"}); 720 * getFromArray(b, 3, "id") => liefert das erste Objekt aus dem Array 721 * var a = [1,2,3]; 722 * getFromArray(a, 2) => liefert das zweite Element aus dem Array 723 */ 724function getFromArray(pArray, pValue, pValueName) { 725 if (pArray == null || (typeof pArray.length !== "number")) 726 return null; 727 if (pValueName != null && typeof (pValueName) === "string") 728 for (var x in pArray) { 729 if (pArray[x][pValueName] == pValue) 730 return pArray[x]; 731 } 732 else { 733 for (var x in pArray) { 734 if (x == pValue) 735 return x; 736 } 737 } 738 739 return null; 740} 741 742/* Array Funktionen */ 743/** 744 * Entfernt das index te Element aus Array array. => man kann hier auch wunderbar splice verwenden 745 */ 746function removeFromArray(array, index) { 747 if (typeof (array) == 'object' && (array instanceof Array)) { 748 if (index == 0) 749 return array.slice(1); 750 if (index < array.length) { 751 return array.slice(0, index).concat(array.slice(index + 1)); 752 } 753 else { 754 return array; 755 } 756 } 757 else 758 return null; 759} 760 761/** 762 * Prüft ob item in arr enthalten ist 763 */ 764function in_array(item, arr) { 765 if (arr == null || !(typeof (arr) == 'object' && (arr instanceof Array))) 766 return false; 767 for (var p = 0; p < arr.length; p++) if (item == arr[p]) return true; 768 return false; 769} 770 771 772var _tmplCache = {} 773parseTemplate = function (str, data) { 774 /// <summary> 775 /// Client side template parser that uses <#= #> and <# code #> expressions. 776 /// and # # code blocks for template expansion. 777 /// NOTE: chokes on single quotes in the document in some situations 778 /// use &rsquo; for literals in text and avoid any single quote 779 /// attribute delimiters. 780 /// </summary> 781 /// <param name="str" type="string">The text of the template to expand</param> 782 /// <param name="data" type="var"> 783 /// Any data that is to be merged. Pass an object and 784 /// that object's properties are visible as variables. 785 /// </param> 786 /// <returns type="string" /> 787 var err = ""; 788 try { 789 var func = _tmplCache[str]; 790 if (!func) {
791 var strFunc = 792 "var p=[],print=function(){p.push.apply(p,arguments);};" + 793 "with(obj){p.push('" + 794 // str 795 // .replace(/[\r\t\n]/g, " ") 796 // .split("<#").join("\t") 797 // .replace(/((^|#>)[^\t]*)'/g, "$1\r") 798 // .replace(/\t=(.*?)#>/g, "',$1,'") 799 // .split("\t").join("');") 800 // .split("#>").join("p.push('") 801 // .split("\r").join("\\'") + "');}return p.join('');"; 802 803 str.replace(/[\r\t\n]/g, " ") 804 .replace(/'(?=[^#]*#>)/g, "\t") 805 .split("'").join("\\'") 806 .split("\t").join("'") 807 .replace(/<#=(.+?)#>/g, "',$1,'") 808 .split("<#").join("');") 809 .split("#>").join("p.push('") 810 + "');}return p.join('');"; 811 812 //alert(strFunc); 813 func = new Function("obj", strFunc); 814 _tmplCache[str] = func; 815 } 816 return func(data); 817 } catch (e) { err = e.message; } 818 return "< # ERROR: " + err + " # >"; 819 //return "< # ERROR: " + err.htmlEncode() + " # >"; 820} 821 822/** 823 * Erweiterte typeof Funktion => damit kann man Arrays von Objekten unterscheiden 824 * liefert: 'array', 'null' oder typeof value 825 * siehe auch: jQuery.isArray() 826 */ 827KuferTools.Utils.typeOf = function (value) { 828 var s = typeof value; 829 if (s === 'object') { 830 if (value) { 831 if (value instanceof Array) { 832 s = 'array'; 833 } 834 } else { 835 s = 'null'; 836 } 837 } 838 return s; 839} 840 841/* 842 * Schneidet die dargestellten Textinhalte so ab, dass sie in das umgebende Span passen. 843**/ 844KuferTools.Utils.kuerzeInhaltAufZeile = function (klasse) { 845 846 var $spansToHandle = $('span.' + klasse);//.css('display','none'); 847 if ($spansToHandle.length == 0) 848 return; 849 850 $spansToHandle.each(function (index, element) { 851 var schrittweite = 3; 852 var $element = $(element); 853 //alert("Elem: " + $element.html() + ' Anz. HTML Tags: ' + $element.find('*').length); 854 //checkt ob innerhalb des Elements noch irgendein HTML Tag gefunden wird; falls ja ist di length > 0 855 // und es wird mit dem nächsten Element weitergemacht (return true entspr. continue) 856 if ($element.find(':not(br)').length > 0) 857 return true; 858 859 // Betrifft z.B. das Feld kurstag_medien 860 if ($element.css('overflow-y').toLowerCase() == 'scroll') { 861 return true; 862 } 863 864 // Hoehe einer Zelle wird nicht benötigt 865 var hoeheEinzeilig = $element.css('line-height').match(/[0-9.]+/); 866 var vorgegebeneBreite = $element.width(); 867 868 // Höhe einer einzelnen Span Zelle: diese kann je nach Einstellung unterschiedlich sein und ist von 869 // verschieden zu der Hoehe eines Zeichens (hoeheeinzeilig) 870 var vorgegebeneHoehe = Math.max(hoeheEinzeilig, $element.height()); 871 872 //Title bei allen Elementen setzen (für den Mouseover Effekt) 873 if ($element.prop("title") == "" || typeof ($element.prop("title")) == 'undefined') 874 $element.prop("title", $element.text()); 875 876 //++++++++ Schritt 1: Wörter, welche Breiter als die maximale Breite sind werden gekürzt +++++++++++ 877 878 var elemHtml = $element.html(); 879 //Fügt um den Inhalt des Spans noch ein Span ein. Wenn das innere Span nun 880 //gröÃer als das äuÃere ist, dann ist im Span ein Wort länger als das Span. 881 //hier genügt es nicht die width auf auto zu setzen, da sonst die Zeilenumbrüche verrutschen können 882 $element.html('<span class="widthTest">' + elemHtml + '</span>'); 883 if (vorgegebeneBreite < $element.find('span.widthTest').width()) { 884 885 //Holt sich alle Wörter des entsprechenden Spans 886 var woerter = elemHtml.match(/(\w)+/g); 887 888 //Geht jedes Wort durch, und überprüft, ob es zu lang ist. 889 for (var i = 0; i < woerter.length; i++) { 890 $element.html('<span class="widthTest">' + woerter[i] + '</span>'); 891 //Falls das Wort zu lange ist, kürze es, und prüfe die Breite erneut. 892 if (vorgegebeneBreite < $element.find('span.widthTest').width()) { 893 var originalWort = woerter[i]; 894 while (vorgegebeneBreite < $element.find('span.widthTest').width()) { 895 woerter[i] = woerter[i].substring(0, woerter[i].length - schrittweite); 896 $element.html('<span class="widthTest">' + woerter[i] + '</span>'); 897 } 898 //Ersetze das gekürzte Wort in elemHtml, ersetzt dabei noch die letzten drei Zeichen durch ... 899 elemHtml = elemHtml.replace(originalWort, woerter[i].substring(0, woerter[i].length - 3) + '...'); 900 } 901 } 902 } 903 $element.html(elemHtml); 904 905 // ++++++++ Schritt 2: Text so kürzen, sodass die Höhe des Spans nicht überschritten wird. 906 907 908 //Damit wird die Höhe des Elements auf die wirkliche Höhe gesetzt Z.B. von 16 auf 32 falls für die Darstellung 909 // mehrere Zeilen benötigt werden 910 $element.css('height', 'auto'); 911 912 //Nur dann abschneiden, wenn es zu viele Zeilen sind (d.h. Höhe einer Zeile < Höhe des Spans) 913 if (vorgegebeneHoehe < $element.height()) { 914 var origText = $element.html(); 915 var step = origText.length; 916 var aktTextLength = origText.length; 917 918 // BRs müssen gesondert behandelt werden 919 if ($element.find('br').length > 0) { 920 921 // einige Nicht-Druckbare Zeichen wie Zeilenumbrüche entfernen 922 origText = origText.replace(/[\x00-\x1F]/gi, ''); 923
924 // Zunächst BRs vereinheitlichen, dann splitten 925 var zeilenAry = origText.replace(/<br[^>]>/gi, '<br>').split('<br>'); 926 var zeilenAryCount = zeilenAry.length; 927 var tmpText = ''; 928 for (var i = 0; i < zeilenAryCount; i++) { 929 var textVorher = tmpText; 930 if (i > 0) { 931 tmpText += '<br>'; 932 } 933 tmpText += zeilenAry[i]; 934 $element.html(tmpText); 935 if ($element.height() > vorgegebeneHoehe) { 936 origText = tmpText; 937 aktTextLength = tmpText.length; 938 step = aktTextLength - textVorher.length; 939 break; 940 } 941 } 942 } 943 KuferTools.Utils.KuerzeAufZeileRekursiv(origText, $element, vorgegebeneHoehe, aktTextLength, step); 944 // '...' kann under doofen Umständne breiter als die letzten drei abgeschnittenen Zeichen sein, 945 // deshalb wird ein zusätzliches Zeichen entfernt 946 $element.html(origText.substring(0, $element.html().replace(/<br>$/, '').length - 4) + '...'); 947 $element.css('height', vorgegebeneHoehe); 948 } 949 }); //end each-function 950 951}; // end kuerzeInhaltAufZeile 952 953/** 954 * Kürzt den Inhalt einer Tabelle so, dass alle Zeilen einzeilig werden. 955 * @param Selecter $pTable Selekter für die Tabelle 956 * @param bool pEinzeilig true: Zeilen werden gekürzt, false: Kürzung wird rückgängig gemacht. 957 */ 958KuferTools.Utils.KuerzeTabelleAufZeile = function ($pTable, pEinzeilig) { 959 var $tdsInColumnAry = []; 960 var $span = $pTable.find('tbody tr td span'); 961 var hoeheEinzeiligCache = {}; 962 $span.each(function () { 963 964 // Falls Das Span noch ein A-Tag enthält, muss das gewählt werden, da sonst das schlieÃende </a> 965 // weggekürzt werden kann. 966 var $element = $(this); 967 var $aTag = $element.find('a'); 968 if ($aTag.length > 0) { 969 $element = $aTag; 970 } 971 if (pEinzeilig) { 972 973 // Die einzilige Höhe kann im Chrome oder IE leider nicht ohne Test-Item ermittelt werden, da die 'normal' zurückgeben, 974 // statt der höhe. Aber ich gehe frecherweise davon aus, dass die Line-Height in einer Spalte immer gleich ist, 975 // sodass ich nur einmal pro Spalte das Testitem setze 976 // Muss nicht auch bei kuerzeInhaltAufZeile angepasst werden, da geben die Browser nomal die line-height zurück 977 var hoeheEinzeilig = $element.css('line-height').match(/[0-9.]+/); 978 if (!jQuery.isNumeric(hoeheEinzeilig)) { 979 var classes = $element.parents('td').prop('class'); 980 if (hoeheEinzeiligCache.hasOwnProperty(classes)) { 981 hoeheEinzeilig = hoeheEinzeiligCache[classes]; 982 } else { 983 var $testItem = $('<span class="testItem">M</span>'); 984 $element.append($testItem); 985 hoeheEinzeilig = $testItem.height(); 986 hoeheEinzeiligCache[classes] = hoeheEinzeilig; 987 $testItem.remove(); 988 } 989 } 990 991 //Nur dann abschneiden, wenn auch wirklich mehrere Zeilen vorhanden sind (d.h. Höhe einer Zeile < Höhe des Spans) 992 if (hoeheEinzeilig < $element.height()) { 993 994 //var anzahlZeichenInDiesemSpan = anzahlZeichen - schrittweite; 995 var origText; 996 if (!$element.data('origText')) {//sonst wird der originale Text gelöscht, wenn zweimal hintereinander auf "einzeilig" geklickt wird 997 origText = $element.text(); 998 $element.data('origText', origText); 999 } 1000 else 1001 origText = $element.data('origText'); 1002 KuferTools.Utils.KuerzeAufZeileRekursiv(origText, $element, hoeheEinzeilig, origText.length, origText.length); 1003 } 1004 } 1005 // Handling für mehrzeilig 1006 else { 1007 var origText = $element.data('origText'); 1008 if (origText != '') 1009 $element.text(origText); 1010 } 1011 }); 1012}; 1013 1014/** 1015 * Rekursive Funktion, welche den Text im Target auf die optimale Länge stutzt. 1016 * Am Ende enthält pTarget den gekürzten Text 1017 * 1018 * @param pText: Originaltext 1019 * @param $pTarget: Selector auf das aktuelle Zielelement, welcher den Text enthält 1020 * @param pMaxHeight: Maximale Höhe des Elements 1021 * @param pAktTextLength: Aktuell untersuchte Textlänge. Variiert bei jedem Durchlauf. Empfohlener Startwert: pText.length 1022 * @param pStep: Schrittweite, um welche pAktTextLength bei jedem Durchlauf vergröÃert oder verkleinert wird. 1023 * Wird bei jedem Durchlauf halbiert (ggf. abgerundet). Empfohlener Startwert: pText.length 1024 */ 1025KuferTools.Utils.KuerzeAufZeileRekursiv = function (pText, $pTarget, pMaxHeight, pAktTextLength, pStep) { 1026 // Abbruchbedingung: Schrittweite ist bei 0 angelangt 1027 if (pStep <= 0) { 1028 // Es kann sein, dass man beim Abbrechen um einen Buchstaben zu weit ist. 1029 if ($pTarget.height() > pMaxHeight) { 1030 $pTarget.html(pText.substring(0, pAktTextLength - 1)); 1031 } 1032 return; 1033 } 1034 pStep = Math.floor(pStep / 2); 1035 $pTarget.html(pText.substring(0, pAktTextLength)); 1036 // Höhe testen. Wenn zu GroÃ: um Step verkleinern, sonst um Step vergröÃern. 1037 // Es kann an dieser Stelle nicht getestet werden, ob die Optimale länge ereicht wurde, 1038 // Daher die Zusatzbedingung in der Abbruchbedingung 1039 if ($pTarget.height() > pMaxHeight) { 1040 KuferTools.Utils.KuerzeAufZeileRekursiv(pText, $pTarget, pMaxHeight, pAktTextLength - pStep, pStep); 1041 } 1042 else if ($pTarget.height() <= pMaxHeight) { 1043 KuferTools.Utils.KuerzeAufZeileRekursiv(pText, $pTarget, pMaxHeight, pAktTextLength + pStep, pStep); 1044 } 1045}; 1046 1047var spanEigentschaftenCache = []; 1048/* 1049 * liefert die Breite und Höhe eines Zeichens im Span und die Gesamtbreite des Spams 1050**/ 1051KuferTools.Utils.getSpanEigenschaften = function ($pElement) { 1052 //wir brauchen die Breite pro Zeichen => ein M; dazu: 1053 //Wegen einiger Firefoxversionen musste die Berechnung umgestellt werden 1054 //(Probleme beim berechnen der Höhe verschachtelter Spans): 1055 //Das Span wird geklont, die höhe und breite auf auto gesetzt, 1056 //und das Testzeichen direkt im Span eingefügt. 1057
1058 //Cached die Span-Eigenschaften, da diese bei Ãbersichtsseiten bei allen 1059 //Spans mit gleichen Klassen Identisch sind. 1060 var classes = $pElement.prop('class'); 1061 if (typeof (spanEigentschaftenCache[classes]) != 'undefined') 1062 return spanEigentschaftenCache[classes]; 1063 1064 var $cloneelem = $pElement.clone(false); 1065 $cloneelem.html("M"); 1066 $cloneelem.css('visibility', 'hidden').css('height', 'auto').css('width', 'auto'); 1067 //ans Elternelement hängen 1068 $pElement.parent().append($cloneelem); 1069 var breiteProZeichen = $cloneelem.width(); 1070 var hoeheEinzeilig = $cloneelem.height(); 1071 $cloneelem.remove(); 1072 1073 1074 //padding-left berücksichtigen, kommt als xpx => px abschneiden 1075 var breite = $pElement.width(); //.width() ist bereits ohne Padding! 1076 1077 var spanProperties = []; 1078 spanProperties[0] = breite; 1079 spanProperties[1] = breiteProZeichen; 1080 spanProperties[2] = hoeheEinzeilig; 1081 1082 spanEigentschaftenCache[classes] = spanProperties; 1083 1084 return spanProperties; 1085} //end getSpanEigenschaften 1086 1087 1088/** 1089 * Gibt die Eingabeelemente eines Bereichs zurück. 1090 * 1091 * Berücksichtigt: 1092 * inputs ohne type= image, submit, reset, button, hidden 1093 * textarea 1094 * select 1095 * 1096 * Disabled und versteckte Felder werden ebenfalls nicht zurückgegeben. 1097 * 1098 * @param $pTarget jQery-Selector 1099 * @return jQery-Selector 1100 */ 1101KuferTools.Utils.getInputableElements = function ($pTarget) { 1102 var $elements = $(); 1103 1104 $elements = $elements.add($pTarget.find('input').filter('[type!="image"]').filter('[type!="button"]') 1105 .filter('[type!="submit"]').filter('[type!="reset"]') 1106 .filter('[type!="hidden"]')); 1107 1108 $elements = $elements.add($pTarget.find(':is(textarea, select)')); 1109 1110 $elements = $elements.add($pTarget.find('.mnlist')); 1111 1112 $elements = $elements.filter(':not( :disabled)'); 1113 //eine disabled Klasse check_disabled wieder hinzufügen: wird beim Validieren gebraucht um ein 1114 //form_error Element zu erzeugen 1115 $elements = $elements.add($pTarget.find('input.check_disabled:disabled')); 1116 1117 1118 return $elements; 1119}; 1120 1121 1122/** 1123 * Ãberschreibt die Werte aus obj1 mit denen aus obj2 u. fügt die Werte aus obj2 hinzu (falls sie in obj1 nicht existieren) 1124 * @param obj1 1125 * @param obj2 1126 * @returns obj3 neues object, das auf obj1 und obj2 basiert 1127 */ 1128KuferTools.Utils.mergeObjects = function (obj1, obj2) { 1129 var obj3 = {}; 1130 for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } 1131 for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } 1132 return obj3; 1133} 1134 1135 1136/** Ab hier meine n-m List Implementierung */ 1137NMList = function () { 1138 //public variables 1139 this.data = [];//muss eine Kopie der tatsächlichen Daten sein! //Zeilen! 1140 this.rowTemplate = '';//template für die einzelnen Zeilen 1141 this.colGroup = ''; //Colgroup für die Tabelle um Spalten mit unterschiedlichen Breiten ausgeben zu können 1142 this.rowHeader = '';//Zeile mit der Headerzeile (<tr><th>spalte1</th>...</tr>) 1143 this.prefix = '';//Präfix für die Tabelle, ... nötig, wenn mehr als eine NMList auf einer Seite sind 1144 this.uiBezeichnung = '';//Text, der vor einfügen, löschen usw. eingefügt werden soll 1145 this.$target = null;//div, in das die Tabelle und die Buttons eingehängt werden sollen 1146 this.readOnly = false;//wenn true, werden keine Buttons angezeigt 1147 // wenn true, wird der Bearbeiten Button nicht angezeigt und ein Double-Click Event auf die Elemente aus der Liste 1148 // ist auch nicht möglich (da sie nicht bearbeitbar sein sollen) 1149 this.noUpdate = false; 1150 //wenn true, wird der Details Subscreen aus einer Hinterlegung befüllt; dann ist auch kein Bearbeiten mgl. 1151 // d.h. this.noUpdate ist auch true 1152 this.subscreenfromHL = false; 1153 //ist true, wenn die Tabellen sich in der Breite flexibel an das Elementfeld anpassen soll, wenn das Element z.B. 1154 //in den Zentr. Einstellungen (z.B. Kennzeichen Element) festgelegt wird; Tabelle muss dann in ein übergeordnetes 1155 //div eingebettet werden 1156 this.flexibleWidth = false; 1157 // Daten aus der Hinterlegung für den Details Subscreen (wird z.B. für die Kennzeichenliste im Tool Teilnehmerinfo oder 1158 // die Anwesenheitsliste im Dialog zum Terminkalender im Dozententool verwendet) 1159 this.hldata = []; 1160 // Daten die bereits aus der Hinterlegung im Details Subscreen selektiert wurden; mit Hilfe dieses Arrays wird ein mehrmaliges 1161 // Auswählen desselben Eintrags in die Haupttabelle verhindert (wird bisher nur für Anwesenheiten im Dialog zum Terminkalender verwendet 1162 this.selectedhldata = []; 1163 // wenn true, wird zusätzlich ein Button ausgegeben, um alle Einträge auf einmal aus der NMList zu löschen, und die Funktionalität hierfür 1164 // bereitgestellt 1165 this.deleteAll = false; 1166 //Image zum Button zum Löschen aller Einträge aus der NMList; kann von PHP aus besetzt werden 1167 this.deleteAllImg = ''; 1168 1169 //öffentliche/privilegierte Methoden, die überschrieben werden müssen 1170 this.getNewObject = function () { return null; } //Funktion, die ein Objekt liefert, das neu eingefügt wird 1171 this.showSubscreen = function (pData, pNewItem) { }; //Detailbildschirm für Bearbeiten/Hinzufügen eines Datensatzes: 1172 //pNewItem: boolean ob Element neu angelegt wurde oder bearbeiten 1173 this.restoreSubscreenData = function (pData, $dialog) { }; //Daten aus dem Detailbildschirm für einen Datensatz zurückschreiben 1174 this.canDelete = function (pData) { return true; };//Funktion ob ein Löschen für diesen Datensatz möglich ist (manchmal sollen nur neue Elemente geändert werden können. 1175 this.cannotDelete = function () { }; 1176 this.beforeDelete = function (pData) { };//wird vor dem Löschen aufgerufen 1177 this.postDelete = function () { };//wird nach dem Löschen und vor dem darauffolgenden Rendern aufgerufen 1178 1179 //private variables 1180 var selectedIndex = null; 1181 var _$targetTbody = null; 1182 var _initialized = false; 1183 var _tableId = 'nmList'; 1184 var _tableRowClass = 'nmRow'; 1185 1186 //privileged methods - can access the private variables and methods, and is itself accessible to the public methods and the outside 1187 this._renderData = function () { 1188 //if (!_initialized) { 1189 _initialize(this); 1190 //} 1191 _$targetTbody.remove('tr'); 1192 if (this.data && this.data.length > 0) { 1193 var tabellenInhalt = ''; 1194 for (var i = 0; i < this.data.length; i++) { 1195 1196 var aktData = this.data[i]; 1197 var htmlEncodedData = Object.keys(aktData).reduce(function (previous, current) { 1198 previous[current] = (typeof (aktData[current]) == 'string') ? KuferTools.Utils.htmlEncode(aktData[current]) : aktData[current]; 1199 return previous; 1200 }, {}); 1201 1202 var row = parseTemplate(this.rowTemplate, htmlEncodedData); 1203 tabellenInhalt += row; 1204 } 1205 _$targetTbody.append(tabellenInhalt); 1206 //den Rows noch die Klasse verpassen 1207 _$targetTbody.find('tr').addClass(_tableRowClass); 1208 if (selectedIndex >= this.data.length) 1209 selectedIndex = null; 1210 this.highlight(); 1211 } 1212 }; 1213 1214 this.getCurrentData = function () { 1215 if (this.data && this.data.length > selectedIndex) { 1216 return this.data[selectedIndex]; 1217 } 1218 } 1219 1220 this._activateButtons = function () { 1221 }; 1222 this.highlight = function () { //durchaus dazu gedacht, von auÃen aufgerufen zu werden 1223 var $trs = _$targetTbody.find('tr.' + _tableRowClass); 1224 $trs.filter(':odd').removeClass('even active').addClass('odd'); 1225 $trs.filter(':even').removeClass('odd active').addClass('even'); 1226 if (!isNaN(parseFloat(selectedIndex)) && isFinite(selectedIndex)) 1227 $trs.eq(selectedIndex).addClass('active'); 1228 }; 1229 this.showDetailDialog = function (extraAnw) { 1230 }; 1231 1232 //private methods => hier gibts bei Vererbung keinen Zugriff auf this mehr, deshalb als Parameter param übergeben 1233 var _initialize = function (param) { 1234 if (param.$target) { 1235 //Buttons bauen, falls nicht readOnly 1236 1237 //zunächst leeres Div 1238 var $buttons = $('<div id="buttonleiste_vert"></div>'); 1239 if (!param.readOnly) { 1240 var divString = '<div style="margin-left: 5px; margin-top: 20px; height: 35px; resize: none;"><img src="layout/button_hinterlegung.gif" id="button_insert" alt="' + param.uiBezeichnung + ' einfügen" title="' + param.uiBezeichnung + ' einfügen"></div>'; 1241 1242 //Bearbeiten Button nur hinzufügen, falls das Update erlaubt ist, ansonsten die Höhe der Buttons vermindern 1243 if (param.noUpdate) 1244 $buttons.css('height', '-=35'); 1245 else { 1246 divString += '<div style="margin-left: 5px; margin-top: 5px; height: 35px; resize: none;"><img src="images/edit.gif" id="button_update" alt="' + param.uiBezeichnung + ' bearbeiten" title="' + param.uiBezeichnung + ' bearbeiten"></div>'; 1247 } 1248 divString += '<div style="margin-left: 5px; margin-top: 5px; height: 35px; resize: none;"><img src="images/loeschen.gif" id="button_delete" alt="' + param.uiBezeichnung + ' löschen" title="' + param.uiBezeichnung + ' löschen"></div>'; 1249 //var $buttons = $('<div id="buttonleiste_vert">' + divString + '</div>' + '</div>'); 1250 1251 if (param.deleteAll) { 1252 $buttons.css('height', '+=35'); 1253 divString += '<div style="margin-left: 5px; margin-top: 5px; height: 35px; resize: none;">' + param.deleteAllImg + '</div>'; 1254 //divString += '<div style="margin-left: 5px; margin-top: 5px; height: 35px; resize: none;"><img src="images/loeschen.gif" id="button_deleteAll" alt="Alle '+param.uiBezeichnung+' löschen" title="Alle '+param.uiBezeichnung+' löschen"></div>'; 1255 } 1256 $buttons.append(divString); 1257 } 1258 1259 var tablename = param.prefix + _tableId; 1260 //Tabelle bauen 1261 var $table = $('<table id="' + tablename + '"></table>'); 1262 if (param.colGroup) { 1263 $table.append('<colgroup>' + param.colGroup + '</colgroup>'); 1264 } 1265 if (param.rowHeader) { 1266 $table.append('<thead>' + param.rowHeader + '</thead>'); 1267 } 1268 _$targetTbody = jQuery('<tbody></tbody>'); 1269 $table.append(_$targetTbody); 1270 param.$target.empty();//leeren, da die initialize Methode ja nicht nur einmal aufgerufen wird 1271 param.$target.append($buttons); 1272 1273 // Tabelle ggf. in ein div packen (um sie flexblel in der Breite vergrössern zu können (falls 1274 //das Feld in den Zentr. Einst. erweitert wird) 1275 var $appendObject = $table; 1276 if (param.flexibleWidth) { 1277 //Id ist dann z.B. kennzListDiv 1278 $appendObject = $('<div id="' + param.prefix + 'ListDiv"></div>'); 1279 $appendObject.append($table); 1280 } 1281 param.$target.append($appendObject); 1282 1283 //selectedIndex = 0;//ersten Datensatz automatisch auswählen? 1284 1285 if (!param.readOnly) { //bei readonly gibts keine Buttons! 1286 //hier noch die onclick Handler für die Buttons 1287 //-löschen 1288 $buttons.find('#button_delete').on('click', function () { 1289 if (selectedIndex != null) { 1290 if (param.canDelete(param.data[selectedIndex])) { 1291 param.beforeDelete(param.data[selectedIndex]); 1292 param.data.splice(selectedIndex, 1);//=> 1 Element an Index selectedIndex aus dem Array param.data entfernen 1293 1294 //den gelöschten Wert ggf. auch aus dem Array der bereits selektierten Werte (aus der Hinterlegung) entfernen 1295 // wird nur in Klassen verwendet, die sich die selektierten werte im Array merken (z.B. in AnwesenheitList) 1296 if (param.selectedhldata.length > 0) 1297 param.selectedhldata.splice(selectedIndex, 1); 1298 1299 param.selectedIndex = null; 1300 //Hook methode zum Nachbearbeiten der Dateninhalte in den abgeleiteten Klassen (ist z.B. in Dokumentelist wg. der 1301 // Reihenfolge notwendig) 1302 param.postDelete(); 1303 param.renderData(); 1304 } 1305 else 1306 param.cannotDelete(); 1307 } 1308 }); 1309 1310 $buttons.find('#button_update').on('click', function () { 1311 if (selectedIndex != null && !isNaN(selectedIndex) && selectedIndex >= 0 && selectedIndex < param.data.length) { 1312 param.showSubscreen(param.data[selectedIndex], false); 1313 } 1314 else 1315 showMessage('Sie müssen erst durch Klicken eine Zeile auswählen.', 'Hinweis'); 1316 }); 1317 $buttons.find('#button_insert').on('click', function () { 1318 //Par. param ist hier das aktuelle Objekt this (also die NMList) 1319 param.$target.find('#' + tablename + ' tbody'); 1320 param.data.push(param.getNewObject()); 1321 selectedIndex = param.data.length - 1; 1322 param.renderData(); 1323 1324 //Standard: Subscreen (Details) zum aktuell gewählten Eintrag 1325 var subscreendata = param.data[selectedIndex]; 1326 // Subscreen wird fest aus einer Hinterlegung gefüllt 1327 if (param.subscreenfromHL) 1328 subscreendata = param.hldata; 1329 1330 param.showSubscreen(subscreendata, true); 1331 }); 1332 1333 //Nur, falls deleteAll auch erlaubt ist den Klickhandler hierfür hinzufügen 1334 if (param.deleteAll) { 1335 //Klickhandler für deleteall 1336 $buttons.find('#button_deleteAll').on('click', function () { 1337 //hier ist param.canDelete für alle Eelmente true, sonst macht deleteAll ja keinen Sinn 1338 param.data.splice(0); // => ab Index 0 alle Elemente aus dem Array param.data entfernen 1339 // ggf. auch das Array der bereits selektierten Werte (aus der Hinterlegung) löschen 1340 // wird nur in Klassen verwendet, die sich die selektierten Werte im Array merken (z.B. in AnwesenheitList) 1341 if (param.selectedhldata.length > 0) 1342 param.selectedhldata.splice(0); 1343 param.renderData(); 1344 }); //end Klickhandler für deleteall 1345 }// end if (param.deleteAll) 1346 } //end if if (!param.readOnly) { 1347 1348 //Für die Tabelle 1349 /** Handling der Klick-Events: Bei einfachem Klick nur die gewählte Tabellenzelle highlighten (markieren) 1350 /** bei Doppelklick: Zelle markieren und Dialog aufrufen 1351 /** hierbei: eventhandler an tbody knüpfen; dann muss NICHT fuer jedes neu erzeugte tr Element 1352 ein Eventhandler angehängt werden; 1353 Achtung: 1354 Auch bereits gespeicherte Werte werden bearbeitet 1355 */ 1356 _$targetTbody.on('click', function (event) { 1357 var $eventTarget = $(event.target); 1358 //selectedIndex muss vor param.highlight ausgeführt werden. 1359 selectedIndex = $eventTarget.parents('tr.nmRow').index(); 1360 param.highlight(); 1361 }); 1362 1363 _$targetTbody.on('dblclick', function (event) { 1364 var $eventTarget = $(event.target); 1365 //Wird durch das Clickevent bereits abgedeckt 1366 //selectedIndex = $eventTarget.parents('tr.nmRow').index(); 1367 //param.highlight(); 1368 //Doppelklick ist nur im Bearbeiten Modus möglich d.h. wenn auch der Bearbeiten Button angezeigt wird 1369 if (!param.readOnly && !param.noUpdate) 1370 param.showSubscreen(param.data[selectedIndex]); 1371 }); 1372 1373 _initialized = true; 1374 } 1375 else { 1376 throw 'InvalidState: $target ist nicht angegeben'; 1377 } 1378 } //end _initialize = function(param)... 1379} //end NMList 1380 1381 1382/** public methods for NMList */ 1383/** Lädt die Tabelle neu aus Data */ 1384NMList.prototype.renderData = function () { 1385 this._renderData(); 1386} 1387NMList.prototype.removeLast = function () { 1388 this.data.splice(this.data.length - 1, 1); 1389} 1390 1391NMList.prototype.removeAll = function () { 1392 this.data.splice(0, this.data.length); 1393} 1394 1395/** 1396 * Wandelt JSON-Strings, welche mit JsonOperations erzeugt wurden, in Objekte um. 1397 * Gibt bei ungültigem JSON den String direkt zurück. Kann dazu verwendet werden, 1398 * um Fehlermeldungen von seitens PHP auszugeben. 1399 * 1400 * Verwendet die potentiell unsichere Methode eval, dafür muss json2.js nicht eingebunden werden. 1401 */ 1402KuferTools.Utils.getObjectFromJson = function (pJson) { 1403 if (typeof pJson === 'object') { 1404 return pJson; // Ist bereits ein Objekt 1405 } 1406
1407 pJson = KuferTools.Utils.trimS(pJson); 1408 var toDecode = pJson; 1409 var result = { 'page': '' }; 1410 // Beim Abfangen von Exceptions wird die entspr. Exception Meldung (immer ein String) ausgegben 1411 if (!isempty(toDecode)) { 1412 try { 1413 result = JSON.parse(toDecode); 1414 } 1415 catch (e) { 1416 result = toDecode; 1417 } 1418 } 1419 return result; 1420}; 1421 1422/** 1423 * Erwartet einen mit JsonOperations erzeugen JSON-String, welcher anschlieÃend base64 encoded wurde 1424 * 1425 * das base64-encoding erleichtert die Handhabung mit Sonder- und Steuerzeichen 1426 * base64.js muss eingebunden sein. 1427 */ 1428KuferTools.Utils.getObjectFromJsonBase64 = function (pBase64Json) { 1429 return KuferTools.Utils.getObjectFromJson(Base64.decode(pBase64Json)); 1430}; 1431/** 1432 * Wandelt ein Opjekt zu seiner JSON-String-Repräsentation um. 1433 * 1434 * Falls es als Value in einem Hidden-Input verwendet werden soll, sollte lieber KuferTools.Utils.getJsonFromObjectBase64 1435 * verwendet werden, da JSON sonst Probleme mit Steuer- und Sonderzeichen macht. 1436 * json2.js muss eingebunden sein 1437 */ 1438KuferTools.Utils.getJsonFromObject = function (pObject) { 1439 return JSON.stringify(pObject); 1440}; 1441 1442/** 1443 * Wandelt ein Opjekt zu seiner JSON-String-Repräsentation um, und codiert es anschlieÃend auf base64 1444 * 1445 * Ideal um JSON-Strings in Values von z. B. Hidden-Inputs zu stecken, da die Sonder- und Steuerzeichen 1446 * von JSON Probleme machen. 1447 */ 1448KuferTools.Utils.getJsonFromObjectBase64 = function (pObject) { 1449 return Base64.encode(KuferTools.Utils.getJsonFromObject(pObject)); 1450}; 1451 1452registerNamespace('KuferTools.Utils.Tabs'); 1453/** 1454 * Gibt die ID des aktiven Tabs zurück. Wenn kein aktiver Tab gefunden wird, wird ein Leerstring zurückgegeben 1455 * 1456 * Die ID kann als Anker für Links verwendet werden, dass der entsprechende Tab beim Laden geöffnet wird. 1457 * 1458 * @returns String 1459 */ 1460KuferTools.Utils.Tabs.GetIdFromActiveTab = function () { 1461 var $activeTab = KuferTools.Utils.Tabs.GetActiveTab(); 1462 if ($activeTab.length > 0) { 1463 return $activeTab.prop('id'); 1464 } 1465 return ''; 1466}; 1467 1468/** 1469 * Gibt den aktiven Tab zurück. 1470 * 1471 * @returns String 1472 */ 1473KuferTools.Utils.Tabs.GetActiveTab = function () { 1474 return $('div[id^="tabs-"]:visible'); 1475};
1476 1477/** 1478 * Liefert false, wenn pString nicht in ein Datum umformatiert werden kann, 1479 * oder ein ungültiges Datum darstellt, 1480 * String im Format TT.MM.JJJJ sonst. 1481 */ 1482registerNamespace('KuferTools.Utils.Date'); 1483KuferTools.Utils.Date.formatDate = function (pString) { 1484 if (pString == null) return false; 1485 1486 //Damit auch Fr. 21.03.13 gefunden wird. 1487 var tmpDate = pString.match(/[1-9][0-9.]*/); 1488 if (tmpDate) { 1489 pString = tmpDate[0]; 1490 } else { 1491 return false; 1492 } 1493 var date = pString.split('.'); 1494 if (date.length < 2 || date.length > 3) { 1495 return false; 1496 } 1497 var day = getIntFromDatePart(date[0]); 1498 var month = getIntFromDatePart(date[1]); 1499 var year = getIntFromDatePart(date[2]); 1500 if (year.toString().length != 4) { 1501 if (year.toString().length > 4) 1502 return false; 1503 year = '2' + year.toString().lpad('0', 3); 1504 year = getIntFromDatePart(year); 1505 } 1506 var dateString = date[0].toString().lpad('0', 2) + "." + date[1].toString().lpad('0', 2) + "." + year.toString(); 1507 if (!(dateString.match(/^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$/) && 1508 day >= 1 && day <= 31 && 1509 month >= 1 && month <= 12)) 1510 return false; 1511 //Ãberprüft das Datum auf Monatslängen und Schaltjahre 1512 //Fängt beim Monat bei 0 zu zählen an! Konvertiert Daten wie 31.04.2010 zu 01.05.2010! 1513 var dateObject = new Date(year, month - 1, day); 1514 if (year != dateObject.getFullYear() 1515 || month != (dateObject.getMonth() + 1) 1516 || day != dateObject.getDate()) 1517 return false; 1518 return dateString; 1519} 1520 1521/** 1522 * Gibt true zurück, falls dateBefore vor dateAfter liegt, sonst false 1523 * Es erfolgt keine weitere Prüfung auf das korrekte Datumsformat (d.m.Y) 1524 */ 1525KuferTools.Utils.Date.isDateBefore = function (dateBefore, dateAfter) { 1526 var dateBeforeAry = dateBefore.split('.'); 1527 var dateAfterAry = dateAfter.split('.'); 1528 1529 //Vergleich nacheinander Jahr, Monat, Tag, und bricht ab, sobald das Ergebnis eindeutig ist. 1530 for (var i = 2; i >= 0; i--) { 1531 var beforeTemp = parseInt(dateBeforeAry[i].replace(/^0+/, '')); 1532 var afterTemp = parseInt(dateAfterAry[i].replace(/^0+/, '')); 1533 if (beforeTemp > afterTemp) 1534 return false; 1535 else if (beforeTemp < afterTemp) { 1536 return true; 1537 } 1538 } 1539 //Datumswerte sind identisch 1540 return false; 1541}; 1542 1543KuferTools.Utils.Date.isDateBeforeOrEqual = function (dateBefore, dateAfter) { 1544 return dateBefore == dateAfter || KuferTools.Utils.Date.isDateBefore(dateBefore, dateAfter); 1545}; 1546 1547KuferTools.Utils.isTimeBeforeOrEqual = function (timeBefore, timeAfter) { 1548 return timeBefore.lpad('0', 5) <= timeAfter.lpad('0', 5); 1549}; 1550 1551/** 1552 * Gibt anhand eines Javascript-Date-Objekts die Stringrepräsentation zurück 1553 * DD.MM.YYYY 1554 */ 1555KuferTools.Utils.Date.getDateString = function (pDateObj) { 1556 return KuferTools.Utils.Date.formatDate( 1557 pDateObj.getDate() + '.' + (pDateObj.getMonth() + 1) + '.' + pDateObj.getFullYear() 1558 ); 1559} 1560 1561/** 1562 * Gibt ein DateObjekt relativ zum übergebenen Datum zurück. Kann auch in die Vergangenheit gehen. 1563 * daysToAdd 0: heute 1564 * daysToAdd 1: morgen 1565 * daysToAdd -1: gestern 1566 */ 1567KuferTools.Utils.Date.addDays = function (pDateObj, daysToAdd) { 1568 var date = new Date(pDateObj.getTime()); //Deep copy 1569 date.setDate(date.getDate() + daysToAdd); // Monats und Jahresumbrüche werden automatisch behandelt. 1570 return date; 1571} 1572 1573/** 1574 * Gibt ein DateObjekt auf den ersten Wochentag des übergebenen Datums zurück (Montag). 1575 */ 1576KuferTools.Utils.Date.getFirsDayOfWeek = function (pDateObj) { 1577 var date = new Date(pDateObj.getTime()); //Deep copy 1578 //getDay(): Sonntag = 0, Montag = 1 usw. 1579 //Mathematischer Trick: 0=>6, 1=>0, 2=>1, 3=>2... entspricht die Anzahl der Tage zwischen dem 1580 //Datum und dem letzten Montag 1581 var daysFor = (date.getDay() + 6) % 7; 1582 date.setDate(date.getDate() - (daysFor)); 1583 return date; 1584} 1585 1586/** 1587 * Gibt ein DateObjekt auf den letzten Wochentag des übergebenen Datums zurück (Sonntag) 1588 */ 1589KuferTools.Utils.Date.getLastDayOfWeek = function (pDateObj) { 1590 //Benutzt getFirsDayOfWeek auf ein Datum nächster Woche, und geht dann einen Tag zurück. 1591 var date = new Date(pDateObj.getTime()); //Deep copy 1592 date.setDate(date.getDate() + 7); 1593 date = KuferTools.Utils.Date.getFirsDayOfWeek(date); 1594 date.setDate(date.getDate() - 1); 1595 return date; 1596} 1597 1598/** 1599 * Gibt ein DateObjekt auf den ersten Tag des übergebenen Monats zurück 1600 */ 1601KuferTools.Utils.Date.getFirstDayOfMonth = function (pDateObj) { 1602 var date = new Date(pDateObj.getTime()); //Deep copy 1603 date.setDate(1); 1604 return date; 1605} 1606 1607/** 1608 * Gibt ein DateObjekt auf den letzten Tag des übergebenen Monats zurück 1609 */ 1610KuferTools.Utils.Date.getLastDayOfMonth = function (pDateObj) { 1611 //Trick: Setzt Monat auf nächsten Monat, den Tag jedoch auf 0 (= letzter Tag des vormonats) 1612 return new Date(pDateObj.getFullYear(), pDateObj.getMonth() + 1, 0); 1613} 1614 1615KuferTools.Utils.Date.NameOfMonth = function(pDateObj) { 1616 let month = pDateObj.getMonth(); 1617 1618 // In JS werden Monate ab 0 gezählt 1619 switch(month) { 1620 default: 1621 case 0: return 'Januar'; 1622 case 1: return 'Februar'; 1623 case 2: return 'März'; 1624 case 3: return 'April'; 1625 case 4: return 'Mai'; 1626 case 5: return 'Juni'; 1627 case 6: return 'Juli'; 1628 case 7: return 'August'; 1629 case 8: return 'September'; 1630 case 9: return 'Oktober'; 1631 case 10: return 'November'; 1632 case 11: return 'Dezember'; 1633 } 1634}; 1635 1636KuferTools.Utils.Date.getFirstDayOfYear = function (pDateObj) { 1637 var date = new Date(pDateObj.getTime()); //Deep copy 1638 date.setDate(1); 1639 date.setMonth(0); 1640 return date; 1641} 1642 1643KuferTools.Utils.Date.getLastDayOfYear = function (pDateObj) { 1644 // Monate beginnen mit 0, Tage mit 1 1645 return new Date(pDateObj.getFullYear(), 11, 31); 1646} 1647 1648/** 1649 * Gibt ein JS-Dateobj anhand eines Strings im deutschen Format au
1649s. 1650 */ 1651KuferTools.Utils.Date.getDateObj = function (pDateString) { 1652 var parts = pDateString.match(/(\d+)/g); 1653 // zero-based-Monat, daher -1 1654 return new Date(parts[2], parts[1] - 1, parts[0]); 1655} 1656 1657/** 1658 * Wandelt einen String rgb( r, g, b ) in #RRGGBB um 1659 */ 1660KuferTools.Utils.RgbToHex = function (pRgb) { 1661 var rgb = pRgb.match(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/); 1662 function hex(x) { 1663 return ("0" + parseInt(x).toString(16)).slice(-2); 1664 } 1665 return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); 1666}; 1667 1668KuferTools.Utils.getMinutesProUE = function () { 1669 var minutesProUe = 45; 1670 if (KuferTools.Kursplanung && KuferTools.Kursplanung.MinutesProUe) { 1671 minutesProUe = KuferTools.Kursplanung.MinutesProUe; 1672 } 1673 return minutesProUe; 1674} 1675 1676registerNamespace("KuferTools.Utils.UiFunctions"); 1677KuferTools.Utils.UiFunctions.setzeCheckboxNachChanged = function (pSelektorChanger, pSelektorCheckBox, pMitHinterlegung) { 1678 jQuery(pSelektorChanger).on('change', function () { 1679 jQuery(pSelektorCheckBox).prop('checked', true); 1680 }); 1681 //man kann nur Custom-Events über jQuery ansteuern => hier den Event fromHLwindow 1682 //so kann, man z.B. Checkboxen setzen, wenn der Uhrzeit Wert aus der Hinterlegung geändert wurde. 1683 if (pMitHinterlegung) { 1684 jQuery(pSelektorChanger).on('fromHLwindow', function () { 1685 jQuery(pSelektorCheckBox).prop('checked', true); 1686 }); 1687 } 1688}; 1689/** 1690 * Wandelt Minuten in UE um, berücksichtigt hierbei abweichende minProUe des Kurses und 1691 * 22/45 = 0,5 UE (KuferSQL/Zentrale Einstellungen/Organisation 22 Minuten von 45 Minuten gelten als 0,5 UE ) 1692 * 1693 * Hierzu sollte KuferTools.Kursplanung.MinutesProUe und KuferTools.KurstagPlanung.HALBUE gesetzt sein 1694 */ 1695KuferTools.Utils.minToUe = function (pMinuten) { 1696 pMinuten *= 1; //Damit pMinuten nicht als String behandelt wird. 1697 var minutesProUe = KuferTools.Utils.getMinutesProUE(); 1698 //sicherheitshalber mal 0 UEs zurückgeben bei weniger als 0 Minuten 1699 if (pMinuten <= 0) 1700 return 0; 1701 1702 var halbue = false; 1703 if (KuferTools.KurstagPlanung.HALBUE == "W") 1704 halbue = true; 1705 var result; 1706 if (halbue && minutesProUe == 45) { 1707 var min45stel = Math.floor(pMinuten) % 45; 1708 if (min45stel == 11) 1709 result = (pMinuten + 0.25) / minutesProUe; 1710 else if (min45stel == 12) 1711 result = (pMinuten - 0.75) / minutesProUe; 1712 else if (min45stel == 22) 1713 result = (pMinuten + 0.5) / minutesProUe; 1714 else if (min45stel == 23) 1715 result = (pMinuten - 0.5) / minutesProUe; 1716 else if (min45stel == 33) 1717 result = (pMinuten + 0.75) / minutesProUe; 1718 else if (min45stel == 34) 1719 result = (pMinuten - 0.25) / minutesProUe; 1720 else 1721 result = pMinuten / minutesProUe; 1722 } 1723 else 1724 result = pMinuten / minutesProUe; 1725 return Math.round(result * 100) / 100; 1726}; 1727 1728/** 1729 * Wandelt UE in Minuten um, berücksichtigt hierbei abweichende minProUe des Kurses und 1730 * 22/45 = 0,5 UE (KuferSQL/Zentrale Einstellungen/Organisation 22 Minuten von 45 Minuten gelten als 0,5 UE ) 1731 * 1732 * Hierzu sollte KuferTools.Kursplanung.MinutesProUe und KuferTools.KurstagPlanung.HALBUE gesetzt sein 1733 */ 1734KuferTools.Utils.UeToMin = function (pUe) { 1735 var minutesProUe = KuferTools.Utils.getMinutesProUE(); 1736 1737 var halbue = false; 1738 if (KuferTools.KurstagPlanung.HALBUE == "W") 1739 halbue = true; 1740 var result; 1741 if (halbue && minutesProUe == 45) { 1742 var ganzeUe = Math.floor(pUe); 1743 var teilUe = Math.round((pUe - ganzeUe) * 100) / 100; 1744 if (teilUe == 0.25) 1745 result = ganzeUe * minutesProUe + 11; 1746 else if (teilUe == 0.5) 1747 result = ganzeUe * minutesProUe + 22; 1748 else if (teilUe == 0.75) 1749 result = ganzeUe * minutesProUe + 33; 1750 else 1751 result = pUe * minutesProUe; 1752 } 1753 else 1754 result = pUe * minutesProUe; 1755 1756 return KuferTools.Utils.Math.kuferSQLRound(result); 1757}; 1758 1759/** 1760 * Lasst Das Script ms Millisekunden warten 1761 */ 1762KuferTools.Utils.Pause = function (ms) { 1763 ms += new Date().getTime(); 1764 while (new Date() < ms) { } 1765} 1766 1767registerNamespace('KuferTools.Utils.Math'); 1768/** 1769 * Rundet zunächst auf 2 stellen hinter dem Komma genau, wenn genau 1770 * ",50" steht, wird auf die nächste GERADE Zahl gerunden, sonst kaufmännisch. 1771 * z.B. 6,50 -> 6; 7,50 -> 8 1772 * 1773 * Entsprechende PHP-Funktion: MathOperations::kuferSQLRound 1774 */ 1775KuferTools.Utils.Math.kuferSQLRound = function (pDouble) { 1776 var dtemp = Math.round(pDouble * 100); 1777 if (dtemp % 100 == 50) { 1778 dtemp = Math.floor(dtemp / 100); 1779 if (dtemp % 2 != 0) { 1780 dtemp++; 1781 } 1782 return dtemp; 1783 } 1784 return Math.round(pDouble); 1785}; 1786 1787/** 1788 * Prüft ob ein Wert eine Nummer ist 1789 */ 1790KuferTools.Utils.Math.isNumber = function (pVal) { 1791 return typeof pVal === 'number' && isFinite(pVal); 1792};
1793 1794KuferTools.Utils.Math.floatToString = function (pFloat, truncateDecimalplacesIfZero = false) { 1795 pFloat = Math.round(pFloat * 100); 1796 pFloat = String(pFloat); 1797 while (pFloat.length < 3) { 1798 pFloat = '0' + pFloat; 1799 } 1800 let decimalPlaces = pFloat.substring(pFloat.length - 2); 1801 if (truncateDecimalplacesIfZero && decimalPlaces === "00") { 1802 return pFloat.substring(0, pFloat.length - 2); 1803 } else { 1804 return pFloat.substring(0, pFloat.length - 2) + ',' + pFloat.substring(pFloat.length - 2); 1805 } 1806}; 1807 1808KuferTools.Utils.Math.stringToFloat = function (pString) { 1809 return parseFloat(pString.replace(/,/, '.')); 1810} 1811 1812registerNamespace('KuferTools.Utils.String'); 1813/** 1814 * Wandelt Sonderzeichen in die HTML-Repräsentation um. 1815 * 1816 * Achtung: 1. Nicht vollständig, kann aber jederzeit um die benötigten Zeichen erweitert werden. 1817 * 2. Falls zukünftig Anführungszeichen konvertiert werden, sollte in einem Parameter abgefragt werden, 1818 * ob diese mitkonvertiert werden sollen oder nicht. 1819 */ 1820KuferTools.Utils.String.HTMLEncode = function (pString) { 1821 var result = pString; 1822 result = result.replace(/ä/g, 'ä'); 1823 result = result.replace(/ü/g, 'ü'); 1824 result = result.replace(/ö/g, 'ö'); 1825 result = result.replace(/Ã/g, 'Ä'); 1826 result = result.replace(/Ã/g, 'Ü'); 1827 result = result.replace(/Ã/g, 'Ö'); 1828 result = result.replace(/Ã/g, 'ß'); 1829 return result; 1830} 1831 1832// Gibt true zurück, wenn der String mit dem angegebenen Suffix endet; gibt für ein leeres Suffix 1833// false zurück (d.h. ein String endet nicht mit Leerstring; notwendig für Vergleich beim check auf erlaubte dateiendungen 1834// beim Dokumentenupload 1835String.prototype.endsWith = function (suffix) { 1836 if (suffix === '') 1837 return false; 1838 return this.indexOf(suffix, this.length - suffix.length) !== -1; 1839}; 1840 1841/** 1842 * Funktionen für das Setzen und erhalten von Cursorpositionen 1843 */ 1844registerNamespace('KuferTools.Utils.Focus'); 1845 1846/** 1847 * Gibt die letzte Start-Position des Cursors von $pTarget zurück. 1848 * 1849 * Nur wenn ein Bereich markiert ist, unterscheiden sich Start- und Endposition 1850 * 1851 * ACHTUNG: Derzeit nicht für IE 1852 */ 1853KuferTools.Utils.Focus.getCursorStartPosition = function ($pTarget) { 1854 /* IE */ 1855 if (typeof (document.selection) != 'undefined') { 1856 var selection = getSelection($pTarget[0]); 1857 return selection.start; 1858 } 1859 /* FireFox, Chrome, Safari, Opera */ 1860 else if (typeof ($pTarget[0].selectionStart) != 'undefined') { 1861 return $pTarget[0].selectionStart; 1862 } 1863}; 1864 1865/** 1866 * Gibt die letzte End-Position des Cursors von $pTarget zurück. 1867 * 1868 * Nur wenn ein Bereich markiert ist, unterscheiden sich Start- und Endposition 1869 */ 1870KuferTools.Utils.Focus.getCursorEndPosition = function ($pTarget) { 1871 1872 /* IE */ 1873 if (typeof (document.selection) != 'undefined') { 1874 var selection = getSelection($pTarget[0]); 1875 return selection.end; 1876 } 1877 /* FireFox, Chrome, Safari, Opera */ 1878 else if (typeof ($pTarget[0].selectionEnd) != 'undefined') { 1879 return $pTarget[0].selectionEnd; 1880 } 1881}; 1882 1883/** 1884 * Von http://stackoverflow.com/questions/3622818/ies-document-selection-createrange-doesnt-include-leading-or-trailing-blank-li/3648244#3648244 1885 * 1886 * Vorsicht bei Textareas: Verschiedene Browser interpretieren den Zeilenumbruch als ein oder zwei Zeichen. 1887 * Code Modifiziert, damit beim IE Zeilenumbrüche nur als ein Zeichen zählen (wie beim maxlength-Attribut bei IE). 1888 * Das übergebene Element muss selectiert sein. Es darf kein jQuery-Selector sein. 1889 */ 1890function getSelection(el) { 1891 var start = 0, end = 0, normalizedValue, range, 1892 textInputRange, len, endRange; 1893 1894 if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { 1895 start = el.selectionStart; 1896 end = el.selectionEnd; 1897 } else { 1898 range = document.selection.createRange(); 1899 1900 if (range && range.parentElement() == el) { 1901 1902 normalizedValue = el.value.replace(/\r\n/g, "\n"); 1903 // Ãnderung: die Länge wird nun anhand des "normalizedValue" (ein Zeichen für ln) berechnet 1904 len = normalizedValue.length; 1905 1906 // Create a working TextRange that lives only in the input 1907 textInputRange = el.createTextRange(); 1908 textInputRange.moveToBookmark(range.getBookmark()); 1909 1910 // Check if the start and end of the selection are at the very end 1911 // of the input, since moveStart/moveEnd doesn't return what we want 1912 // in those cases 1913 endRange = el.createTextRange(); 1914 endRange.collapse(false); 1915 1916 if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { 1917 start = end = len; 1918 } else { 1919 start = -textInputRange.moveStart("character", -len); 1920 // Ãnderung: Die bisher nur einmal gezählten ln werden hier nicht ein 2. mal dazugezählt. 1921 //start += normalizedValue.slice(0, start).split("\n").length - 1; 1922 1923 if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { 1924 end = len; 1925 } else { 1926 end = -textInputRange.moveEnd("character", -len); 1927 // Ãnderung: Die bisher nur einmal gezählten ln werden hier nicht ein 2. mal dazugezählt. 1928 //end += normalizedValue.slice(0, end).split("\n").length - 1; 1929 } 1930 } 1931 } 1932 } 1933 1934 return { 1935 start: start, 1936 end: end 1937 }; 1938} 1939 1940/** 1941 * Ersetzt den markierten Bereich von $pTarget mit pReplaceText. (Derzeit nur für Input und Textarea vorgesehen) 1942 * 1943 * Wenn kein Bereich markiert ist, dann wird an der Stelle des Cursors pReplaceText einfach 1944 * nur eingefügt 1945 * 1946 * ACHTUNG: Für den Aufruf der Funktion mousedown statt click verwenden! IE zeigt ein SEHR seltsames Verhalten bei click: 1947 * Abhängig davon, wie lange das Listenelement gedrückt wird, wird der Text wo anders eingefügt. 1948 * 1949 * Tipp: Wenn mousedown verwendet wird 1950 * $(document).on( "mouseup", function(){$lastTarget.trigger('focus');$(document).unbind("mouseup"); } ); 1951 * innerhalb von mousedown{} einfügen. Damit wird das Textfeld anschlieÃend focusiert. 1952 */ 1953KuferTools.Utils.Focus.replaceSelected = function ($pTarget, pReplaceText) { 1954 1955 /* IE: Sonderlösung, da getCursorStartPosition usw. nicht für IE unterstützt werden. */ 1956 if (typeof (document.selection) != 'undefined') { 1957 $pTarget.trigger('focus'); 1958 var range = document.selection.createRange(); 1959 1960 //Wegen Bugs wird zuvor geprüft, ob die Range innerhalb eines Inputs oder Textareas ist. 1961 var parentElement = range.parentElement(); 1962 if (parentElement.tagName == 'TEXTAREA' || parentElement.tagName == 'INPUT') 1963 range.text = pReplaceText; 1964 1965 } 1966 else { 1967 var start = KuferTools.Utils.Focus.getCursorStartPosition($pTarget); 1968 var ende = KuferTools.Utils.Focus.getCursorEndPosition($pTarget); 1969 1970 //Nicht $pTarget.val(), da in Opera Zeilenumbrüche bei getCursorStartPosition 1971 //zwei zeichen sind, bei $pTarget.val() wird aus \n\r jedoch \n. 1972 var valuePart1 = $pTarget[0].value.substring(0, start); 1973 var valuePart2 = $pTarget[0].value.substring(ende); 1974 1975 $pTarget.val(valuePart1 + pReplaceText + valuePart2); 1976 KuferTools.Utils.Focus.setCursorPosition($pTarget, valuePart1.length + pReplaceText.length); 1977 } 1978}; 1979 1980/** 1981 * Setzt den Cursor an eine bestimmte Position innerhalb von $pTarget, und gibt 1982 * $pTarget den Focus 1983 * 1984 * ACHTUNG: Derzeit nicht für IE 1985 */ 1986KuferTools.Utils.Focus.setCursorPosition = function ($pTarget, pPos) { 1987 1988 /* IE */ 1989 if (typeof (document.selection) != 'undefined') { 1990 //TODO 1991 } 1992 /* FireFox, Chrome, Safari, Opera */ 1993 else if (typeof ($pTarget[0].setSelectionRange) != 'undefined') { 1994 $pTarget[0].trigger('focus'); 1995 $pTarget[0].setSelectionRange(pPos, pPos); 1996 } 1997}; 1998 1999/** 2000 * Erlaubt bei einem Input nur bestimmte Eingaben. Vorgabe mit regulären Ausdruck. Die im Pattern gefundenen Zeichen werden entfernt. 2001 * Beachte: Der reguläre Ausdruck wird derzeit nicht automatisch mit /g (ersetze alle) erweitert. 2002 * 2003 * Noch nicht mit Textareas und Zeilenumbrüchen getestet. Müsste wendern in verschiedenen Browsern getestet werden. 2004 */ 2005KuferTools.Utils.Focus.InputForbidPattern = function ($pTarget, $pPatternZuErsetzen) { 2006 2007 var start = KuferTools.Utils.Focus.getCursorStartPosition($pTarget); 2008 2009 var val = $pTarget.val(); 2010 var lengthBefore = val.length; 2011 val = val.replace($pPatternZuErsetzen, '', val); 2012 var lengthAfter = val.length; 2013 2014 $pTarget.val(val); 2015 KuferTools.Utils.Focus.setCursorPosition($pTarget, start - (lengthBefore - lengthAfter)); 2016}; 2017 2018/****************************************** 2019 * HIER FUNKTIONEN FÃR ALLGEMEINE DIALOGE * 2020 *****************************************/ 2021 2022registerNamespace("KuferTools.Utils.Dialoge.Uebersicht.PersonMarkierDialog.ButtonHandling"); 2023 2024/*** UEBERSICHTEN PERSONEN MARKIERUNG ***/ 2025/** 2026 * Macht aus dem im DOM vorhandenen Dialog #dialog_markierenneu einen Dialog 2027 * und hängt die entsprechenden Eventhandler an die darin enthaltenen Elemente 2028 * ".button_span". 2029 */ 2030KuferTools.Utils.Dialoge.Uebersicht.PersonMarkierDialog.Prepare = function (pTitle) { 2031 var $dialogmarkieren = $('#dialog_markierenneu'); 2032 2033 // Dialog mit der Abfrage nach markierten Dozenten; wird statt showMessage(..) verwendet, da hier das '#dialogmarkieren' Element 2034 // nicht aus dem DOM entfernt werden darf (via remove) 2035 $dialogmarkieren.dialog({ 2036 autoOpen: false, 2037 title: pTitle + ' markieren:', 2038 width: 350, 2039 modal: true, 2040 buttons: { 2041 "Abbrechen": function () { $(this).dialog("close"); } 2042 } 2043 }); 2044 2045 $dialogmarkieren.find('.button_span') 2046 .on('click', KuferTools.Utils.Dialoge.Uebersicht.PersonMarkierDialog.ButtonHandling) 2047 // Farbwechsel beim focus auf die Buttons 2048 .on('hover', function () { 2049 var $this = $(this); 2050 $this.css('color', 'red'); 2051 }, function () { 2052 var $this = $(this); 2053 $this.css('color', 'black'); 2054 });
2055 2056 /* Nur Kommentar; waere bei erfolgreicher Verwendung von showMessage() relevant; das ist aber nicht der Fall 2057 //Aus dem DOM Baum aushängen sonst hängt es nach Klick auf den "alleMarkieren" Button 2mal drin 2058 if ($dialogmarkieren.html() !== '') 2059 $dialogmarkieren.detach(); 2060 */ 2061}; 2062 2063/** 2064 * Vorher muss KuferTools.Utils.Dialoge.Uebersicht.PersonMarkierDialog.Prepare aufgerufen werden! 2065 */ 2066KuferTools.Utils.Dialoge.Uebersicht.PersonMarkierDialog.ButtonHandling = function (event) { 2067 var $this = $(this); //aktuell geklickter Button 2068 var idAttr = $this.prop('id'); 2069 var $dialogmarkieren = $('#dialog_markierenneu'); 2070 if (idAttr === 'markall' || idAttr === 'unmarkall') { 2071 2072 //falls &markerAction=... (aus vorheriger Markierungs Aktion) schon im Link vorhanden ist, wird es entfernt 2073 if (KuferTools.SelfLink.indexOf('&markerAction') !== -1) { 2074 var selfLinkParts = KuferTools.SelfLink.split('&markerAction'); 2075 KuferTools.SelfLink = selfLinkParts[0]; 2076 } 2077 2078 $dialogmarkieren.dialog('close'); 2079 if (idAttr === 'markall') 2080 window.location.href = KuferTools.SelfLink + '&markerAction=markiereAlle'; 2081 else //#unmarkall'' 2082 window.location.href = KuferTools.SelfLink + '&markerAction=loescheMarkierungen'; 2083 } 2084 else { // 'markside' oder 'unmarkside'' 2085 if (idAttr === 'markside') 2086 $('input.markable').prop('checked', true); 2087 else 2088 $('input.markable').prop('checked', false); 2089 //Dialog hier nach dem markieren schlieÃen 2090 $dialogmarkieren.dialog('close'); 2091 // $this.parent().dialog('close'); 2092 } //end else 2093}; 2094 2095/** 2096 * Funktionen, welche an jQuery.fn.dataTableExt.oSort übergeben werden können, um das Sortierverhalten 2097 * von bestimmten Datatables-Spalten festzulegen. 2098 */ 2099registerNamespace("KuferTools.Utils.DataTables"); 2100registerNamespace("KuferTools.Utils.DataTables.oSort"); 2101/** 2102 * Gibt True zurück, falls a vor b. Funktioniert auch mit z. B. "Fr., 23.12.12 14:13 Uhr" 2103 */ 2104KuferTools.Utils.DataTables.oSort.CompareDate = function (a, b) { 2105 a = KuferTools.Utils.stripHTML(a); 2106 b = KuferTools.Utils.stripHTML(b); 2107 if (a == '' || a == ' ') 2108 a = '30.12.1899'; 2109 if (b == '' || b == ' ') 2110 b = '30.12.1899'; 2111 var dateA = KuferTools.Utils.Date.formatDate(a); 2112 var dateB = KuferTools.Utils.Date.formatDate(b); 2113 2114 if (dateA && dateB) { 2115 var aVorB = KuferTools.Utils.Date.isDateBefore(dateA, dateB); 2116 var bVorA = KuferTools.Utils.Date.isDateBefore(dateB, dateA); 2117 // Falls das Datum gleich ist, wird auf Time verglichen, insofern vorhanden. 2118 // Zeit wird am : erkannt. 2119 if (!aVorB && !bVorA) { 2120 var timeA = a.match(/[0-9]*:[0-9]*:?[0-9]*?/); 2121 var timeB = b.match(/[0-9]*:[0-9]*:?[0-9]*?/); 2122 if (timeA && timeB) { 2123 var timeAryA = timeA[0].split(':'); 2124 var timeAryB = timeB[0].split(':'); 2125 for (var i = 0; i < 3; i++) { 2126 if (typeof (timeAryA[i]) != 'undefined' && typeof (timeAryB[i]) != 'undefined') { 2127 if (parseInt(timeAryA[i], 10) < parseInt(timeAryB[i], 10)) { 2128 return true; 2129 } else if (parseInt(timeAryA[i], 10) > parseInt(timeAryB[i], 10)) { 2130 return false; 2131 } 2132 } 2133 } 2134 } 2135 } 2136 return aVorB; 2137 } 2138}; 2139KuferTools.Utils.DataTables.oSort.DateAsc = function (a, b) { 2140 var aVorB = KuferTools.Utils.DataTables.oSort.CompareDate(a, b); 2141 return (aVorB) ? -1 : 1; 2142}; 2143KuferTools.Utils.DataTables.oSort.DateDesc = function (a, b) { 2144 var aVorB = KuferTools.Utils.DataTables.oSort.CompareDate(a, b); 2145 return (aVorB) ? 1 : -1; 2146}; 2147 2148/** 2149 * Erzeugt mit Hilfe von showMessage einen Dialog, und initialisiert anschlieÃend ein dataTable. 2150 * 2151 * Ist darauf Spezialisiert, dass das DataTable per Ajax geladen wird. 2152 * Mit Blättern und Filter kann umgegangen werden. 2153 * 2154 * Suchfelder müssen als Namen den per Ajax übergebenen Parameter haben, und als Klasse dataTableSearch. 2155 * Buttons zum Vorwärtsblättern müssen die Klasse dataTableNext besitzen 2156 * Buttons zum Rückwärtsblättern müssen die Klasse dataTablePrevious besitzen 2157 * Wenn vorwärts/rückwärts-blättern möglich ist, bekommt der entsprechende Button die Klasse active. 2158 * Falls die inaktiven Buttons ausgegraut werden sollen, kann statt img spans mit der entsprechenden Höhe/Breite und Hintergrundbild gearbeitet werden. 2159 * 2160 * @param {string} pMessage showMessage: Inhalt des Dialogs 2161 * @param {string} pTitle showMessage: Titel des Dialogs 2162 * @param {Record<string,function(): void>} pButtons showMessage: Button-Objekt für den Dialog 2163 * @param {string} pWidth showMessage: Breite des Dialogs 2164 * @param pPosition showMessage: Position des Dialogs als Array mit zwei werten. 2165 * @param {string} pDataTable jQuery-Selector-String (ohne $(STRING) ), mit welchen das Datatable in der Message angesprochen wird. KEIN SELEKTOR möglich, da das datatable zum Zeitpunkt der Ãbergabe noch nicht existiert. 2166 * @param {number} pDataPerPage Anzahl der Datensätze pro Seite. Wird für Blätterfunktionen benötigt. 2167 * @param pScrollY Höhe der Datatable. Ist diese höher, wird ein Scrollbalken angeboten. 2168 * @param {string|URL} pUrl4Ajax URL, mit der Per Ajax die Datatable gefüllt wird. 2169 * @return {Promise<jQuery>} 2170 */ 2171KuferTools.Utils.DataTables.showMessageWithDataTable4Ajax = function (pMessage, pTitle, pButtons, pWidth, pPosition, pDataTable, pDataPerPage, pScrollY, pUrl4Ajax, afterDrawTable) { 2172 showMessage(pMessage, pTitle, pButtons, pWidth, pPosition); 2173 var $dataTable = $(pDataTable, pMessage); 2174 //Falls die Datatable bereits initialisiert wurde, liegt die Tabelle innerhalb der Klasse dataTables_scrollBody 2175 let result = undefined; 2176 if ($('.dataTables_scrollBody .dataTable_tnUebersicht', pMessage).length === 0) { 2177 result = new Promise((resolve, reject) => {
2178 try { 2179 $dataTable.dataTable({ 2180 "oLanguage": { "sUrl": "../jquery/plugins/jquery.dataTables.de_DE.txt" }, 2181 "sScrollY": "300px", //Scrollbalken nach unten, angezeigt: 300px (IE) 2182 "bFilter": false, 2183 "bInfo": false, //z.B. showing 1 to 10 from 57 entries 2184 "bScrollCollapse": true, 2185 "bPaginate": false, 2186 "bAutoWidth": false, 2187 "bSort": false, // Serverseitige Sortierung ist nicht für alle Spalten möglich 2188 "bServerSide": true, 2189 "iDisplayLength": pDataPerPage, 2190 "iDisplayStart": 0, 2191 "fnServerParams": function (aoData) { 2192 2193 // Searchfield soll ein Obj sein: name: callback oder wert. 2194 $('.dataTableSearch', pMessage).each(function () { 2195 aoData.push({ "name": $(this).prop('name'), "value": $(this).val() }); 2196 }); 2197 }, 2198 "fnInitComplete": function (_settings, _json) { 2199 resolve($dataTable); 2200 }, 2201 "fnDrawCallback": function (oSettings) { 2202 2203 if(typeof(afterDrawTable) === 'function' ) { 2204 afterDrawTable(); 2205 } 2206 2207 KuferTools.Utils.AjaxLadebildschirm.Stop(); 2208 2209 if (oSettings._iDisplayStart <= 0) { // TODO anders verallgemeinern! sonst müsste man fast die img ebenfalls setzen. obwohl das per obj gut möglich wäre 2210 //$( '.dataTablePrevious', pMessage ).prop('src', 'layout/button_rueckwaertsg_small.gif'); 2211 $('.dataTablePrevious', pMessage).removeClass('active'); 2212 $('i.fa-arrow-left', pMessage).css("color", "#333"); 2213 } else { 2214 //$( '.dataTablePrevious', pMessage ).prop('src', 'layout/button_rueckwaerts_small.gif'); 2215 $('.dataTablePrevious', pMessage).addClass('active'); 2216 $('i.fa-arrow-left', pMessage).css("color", "#5cb85c"); 2217 } 2218 2219 if (oSettings._iDisplayLength + oSettings._iDisplayStart >= oSettings._iRecordsDisplay) { 2220 //$( '.dataTableNext', pMessage ).prop('src', 'layout/button_vorwaertsg_small.gif'); 2221 $('.dataTableNext', pMessage).removeClass('active'); 2222 $('i.fa-arrow-right', pMessage).css("color", "#333"); 2223 } else { 2224 //$( '.dataTableNext', pMessage ).prop('src', 'layout/button_vorwaerts_small.gif'); 2225 $('.dataTableNext', pMessage).addClass('active'); 2226 $('i.fa-arrow-right', pMessage).css("color", "#5cb85c"); 2227 } 2228 2229 // Hier ggf. die Blätterbuttons ausblenden. Später nur ausgrauen 2230 }, 2231 "sAjaxSource": pUrl4Ajax, 2232 "sServerMethod": "POST", 2233 "aaSorting": [] // Anfangs wird nicht sortiert, damit die Sortierung aus den Einstellungen erhalten bleibt. 2234 }); 2235 } catch (err) { 2236 reject(err); 2237 } 2238 }); 2239 } else { 2240 result = new Promise((resolve, _) => { 2241 resolve($dataTable); 2242 }); 2243 } 2244 2245 //var searchCounter = 0; 2246 /** 2247 * Felder im Suchformular. Werden 1 Sekunde nach der Eingabe des letzten Zeichens abgesendet. 2248 */ 2249 /* 2250 * Wird nicht mehr verwendet, da es viel mehr Probleme gemacht hat, als geholfen. 2251 * 2252 * $('.dataTableSearch', pMessage).on('keyup', function() { 2253 // Erst wenn eine Sekunde lang keine Eingaben kommen, wird die Suchanfrage abgesetzt. 2254 searchCounter++; 2255 window.setTimeout( function() { 2256 searchCounter--; 2257 if(searchCounter == 0) { 2258 $dataTable.fnPageChange('first'); 2259 } 2260 }, 1000); 2261 });*/ 2262 2263 $('.dataTableSearch', pMessage).on('keypress', function (e) { 2264 if (e.which == 13) { 2265 $('.dataTableSearchButton', pMessage).trigger('click'); 2266 } 2267 }); 2268 2269 $('.dataTableSearchButton', pMessage).on('click', function () { 2270 2271 KuferTools.Utils.AjaxLadebildschirm.Start(); 2272 2273 $dataTable.fnPageChange('first'); 2274 }); 2275 2276 /** 2277 * Buttons fürs Vorwärtsblättern 2278 */ 2279 $('.dataTableNext', pMessage).on('click', function () { 2280 if ($(this).hasClass('active')) { 2281 2282 KuferTools.Utils.AjaxLadebildschirm.Start(); 2283 2284 $dataTable.fnPageChange('next'); 2285 } 2286 }); 2287 /** 2288 * Buttons fürs Zurückblättern 2289 */ 2290 $('.dataTablePrevious', pMessage).on('click', function () { 2291 if ($(this).hasClass('active')) { 2292 2293 KuferTools.Utils.AjaxLadebildschirm.Start(); 2294 2295 $dataTable.fnPageChange('previous'); 2296 } 2297 }); 2298 2299 return result; 2300}; 2301 2302 2303/******************************************************************************************************************* 2304 * jQuery.fn.extend wird hier verwendet, um eine Sammlung von eigen definierten also proprietäten jQuery Funktionen 2305 * anzulegen; sie MÃSSEN hierbei als Attribute eines Objektes $.fn.extend abgelegt werden; Innerhalb jQuery wird hier 2306 * nicht zwischen Funktionen und Methoden, wie an manchen Stellen in den jQuery Foren unterschieden; dort wird folgende 2307 * Unterscheidung getroffen: Im Unterschied zu Funktionen wird auf Methoden direkt vom DOM Baum aus zugegriffen; d.h. 2308 * Funktionen werden immer zusammen mit jQuery Elementen verwendet also z.B.: $('div').meineFunktion(); 2309 * jQuery Methoden werden wie folgt verwendet: $.meineMethode(). 2310 * Diese Unterscheidung macht für unsere Zwecke für proprietäre Methoden keinen Sinn; anstatt eine Methode, die beliebig 2311 * im DOM Baum aufgerufen wird und nicht an ein JQuery Element gebunden ist, in jQuery zu definieren, wird sie gleich 2312 * als globale Javascript Funktion unter KuferTools.Utils definiert; also wird verwendet: 2313 * 2314 * KuferTools.Utils.meineMethode1 (anstatt $.meineMethode1) 2315 * 2316 **************************************************************************************************************** 2317 * statt der Sammlung in einem Objekt wäre es auch möglich, die Funktionen bzw. Methoden einzeln zu definieren 2318 * also z.B 2319 jQuery.fn.hasId = function(id) { 2320 return this.prop('id') == id; 2321 }; 2322 * dies ist gleichbedeutend mit der folgenden Definition der Funktion unter $.fn.extend 2323 ******************************************************************************************************** 2324 2325 **************************************************************************************************************** 2326 * Enthält eine Sammlung von proprietären jQuery Funktionen; diese werden als Attribute eines einzelnen Objekts 2327 * dargestellt 2328 * Achtung: falls $.extend mehrere Objekte enthält, werden diese zusammen gemerged (siehe auch Anmerkung zu 2329 * function showMessage (in function.js)
2330 ************************************************************************************/ 2331jQuery.fn.extend({ 2332 //liefert true oder false 2333 hasId: function (id) { 2334 return this.prop('id') == id; 2335 }, 2336 // Hängt zusätzlich die Tabid (d.h. z.B &fromTab = tabs-2) des aktuellen Tabs an die Url; damit zeigt der Backlink gleich auf den 2337 // richtigen Tabreiter zurück (z.B. tabs-2 für belegte Kurse) 2338 addTab2Url: function () { 2339 var fromTabId = this.parents('.content.tab').prop('id'); 2340 //Anhängen des Tabs an die URL ist nur dann nötig, wenn die aktuelle Tab NICHT tabs-1 ist 2341 if (fromTabId !== 'tabs-1') { 2342 // this ist ein jQuery Element z.B. $('a') 2343 var link = this.prop('href'); 2344 // Aufsplitten nötig, falls der Link ein tab-Tag enthält z.B. z.B. &toolId=8&..&nr=K1502#tabs-4 2345 var tabTag = ''; 2346 if (link.indexOf('#') !== -1) { 2347 var linkParts = link.split('#'); 2348 link = linkParts[0]; 2349 tabTag = '#' + linkParts[1]; 2350 } 2351 link += '&fromTab=' + fromTabId; 2352 //ein bereits vorhandenes tab-Tag (z.B. #tabs-4) wird wieder hinten an die URL angehängt 2353 if (tabTag !== '') 2354 link += tabTag; 2355 this.prop('href', link); 2356 } //end if 2357 } //end function addTab2Url(..) 2358 2359 //TODO: weitere Funktionen definieren nach dem Schema 2360 // meineFunktion1: function(a,b) {...}, 2361 // meineFunktion2: function(x,y,z) {...}, ... 2362}); //end jQuery.fn.extend 2363 2364registerNamespace("KuferTools.Utils.Filter"); 2365 2366KuferTools.Utils.Filter.IsFilled = function (pValue) { 2367 return KuferTools.Utils.trimS(pValue) !== ''; 2368}; 2369 2370KuferTools.Utils.Filter.IsFilledButNotZero = function (pValue) { 2371 return KuferTools.Utils.trimS(pValue) !== '' && KuferTools.Utils.trimS(pValue) !== '0'; 2372}; 2373 2374KuferTools.Utils.Filter.IsFilledEmptyStringOk = function (pValue) { 2375 return KuferTools.Utils.trimS(pValue) !== '-1'; 2376} 2377 2378KuferTools.Utils.Filter.IsInt = function (pValue) { 2379 return pValue == parseInt(pValue); 2380}; 2381 2382KuferTools.Utils.Filter.IsFloatPunkt = function (pValue) { 2383 return !isNaN(pValue); 2384}; 2385 2386KuferTools.Utils.Filter.IsFloatKomma = function (pValue) { 2387 if (pValue.search(/\./) == -1) { 2388 return KuferTools.Utils.Filter.IsFloatPunkt(pValue.replace(/,/, '.')); 2389 } else { 2390 return false; 2391 } 2392}; 2393 2394KuferTools.Utils.Filter.IsDate = function (pValue) { 2395 var dateAry = pValue.split('.'); 2396 2397 // Erwartet Tag und Monat zweistellig 2398 if (!pValue.match(/^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$/)) { 2399 return false; 2400 } 2401 2402 var day = parseInt(dateAry[0], 10); 2403 var month = parseInt(dateAry[1], 10); 2404 var year = parseInt(dateAry[2], 10); 2405 2406 if (year < 1900) { 2407 return false; 2408 } 2409 2410 // Ãberprüfung auf Ãber- und Unterläufe: 31.04. wird im Dateobj zu 01.05. 2411 var dateObject = new Date(year, month - 1, day); 2412 if (year != dateObject.getFullYear() 2413 || month != (dateObject.getMonth() + 1) 2414 || day != dateObject.getDate()) { 2415 return false; 2416 } 2417 2418 return true; 2419}; 2420 2421KuferTools.Utils.Filter.IsDateJahrKurz = function (pValue) { 2422 2423 if (!pValue.match(/^[0-9]{2}\.[0-9]{2}\.[0-9]{2}$/)) { 2424 return false; 2425 } 2426 pValue = pValue.substring(0, 6) + '20' + pValue.substring(6, 8); 2427 2428 return KuferTools.Utils.Filter.IsDate(pValue); 2429}; 2430 2431KuferTools.Utils.Filter.IsTime = function (pValue) { 2432 if (!pValue.match(/^[0-9]{1,2}\:[0-9]{2}$/)) { 2433 return false; 2434 } 2435 var timeAry = pValue.split(':'); 2436 var hour = timeAry[0]; 2437 var min = timeAry[1]; 2438 2439 return hour >= 0 && hour <= 23 && min >= 0 && min <= 59; 2440}; 2441 2442KuferTools.Utils.Filter.IsOneOrNull = function (pValue) { 2443 return (pValue == "1" || pValue == "0"); 2444}; 2445 2446KuferTools.Utils.Filter.IsJOrN = function (pValue) { 2447 return (pValue == "j" || pValue == "J" || pValue == "n" || pValue == "N"); 2448}; 2449 2450/** 2451 * Für E-Mail-Adressen gibt es sehr viel Spielraum. Es ist nahezu alles Korrekt, sobald es genau ein @ hat. 2452 * Laut Wikipedia erlaubte Zeichen im Lokalteil: A-Za-z0-9.!#$%&'*+-/=?^_`{|}~ 2453 * Gibt auch ohne Top-Lvl-Domain true zurück. 2454 * Gibt bei Angabe von Kommentaren, oder den Absendernamen und ähnliche Sonderspässe false zurück. 2455 */ 2456KuferTools.Utils.Filter.IsEmail = function (pValue) { 2457 return pValue.search(/^[A-Za-z0-9.!#$%&'*+-\/=?^_`{|}~]+@[A-Za-z0-9.!#$%&'*+-\/=?^_`{|}~]+$/) != -1; 2458};
2459 2460/** 2461 * Bei Teilnehmernamen ist "TN N", "TN M", "TN W" nicht erlaubt 2462 */ 2463KuferTools.Utils.Filter.IsNotNeutralerTN = function (pValue) { 2464 return pValue.search(/^TN N|TN M|TN W$/) == -1; 2465}; 2466 2467KuferTools.Utils.Filter.IsImageJPEG = function (pValue) { 2468 const von = pValue.lastIndexOf('.'); 2469 const bis = pValue.length; 2470 const endung = pValue.slice(von, bis).toLowerCase(); 2471 return (endung === '.jpg' || endung === '.jpeg'); 2472}; 2473 2474KuferTools.Utils.Filter.IsDateTime = function (pValue) { 2475 var dateTimeAry = pValue.split(' '); 2476 var result = KuferTools.Utils.Filter.IsDate(dateTimeAry[0]); 2477 if (result) { 2478 result = typeof dateTimeAry[1] === 'undefined' || KuferTools.Utils.Filter.IsTime(dateTimeAry[1]); 2479 } 2480 2481 return result; 2482}; 2483 2484KuferTools.Utils.Filter.Mandatory = 1; 2485KuferTools.Utils.Filter.Integer = 2; 2486KuferTools.Utils.Filter.Float_Punktsepariert = 4; 2487KuferTools.Utils.Filter.Float_Kommasepariert = 8; 2488KuferTools.Utils.Filter.Date = 16; 2489KuferTools.Utils.Filter.Date_Jahrkurz = 32; 2490KuferTools.Utils.Filter.Time = 64; 2491KuferTools.Utils.Filter.EinsNull = 128; 2492KuferTools.Utils.Filter.JN = 256; 2493KuferTools.Utils.Filter.Email = 512; 2494KuferTools.Utils.Filter.MandatoryNoZero = 1024; 2495KuferTools.Utils.Filter.ImageJPEG = 2048; 2496KuferTools.Utils.Filter.NeutralerTN = 4096; 2497KuferTools.Utils.Filter.DateTime = 8192; 2498KuferTools.Utils.Filter.MandatoryEmptyStringOk = 16384; 2499 2500/** 2501 * Funktion um mehrere Filterkriterien auf einmal zu prüfen. 2502 * 2503 * Gibt true zurück, falls Leer, und kein Pflichtfeld 2504 * 2505 * @param pValue zu prüfender Wert 2506 * @param pModus Nach was gefiltert wird, bitweise codiert. Hierzu können die Konstanten Mandatory, Integer... 2507 * verwendet werden. Bei mehreren Kriteren müssen diese per Bitweises ORing (x | y) verknüpft werden 2508 */ 2509KuferTools.Utils.Filter.FilterValue = function (pValue, pModus) { 2510 2511 var isOk = true; 2512 // Per bitweises ANDing ( x & y ) wird festgestellt, welche der Filterkriterien in Modus angegeben wurden. 2513 // Hinweis: != bindet stärker als &, deshalb ist eine zusützliche Klammerung nötig 2514 if (isOk && ((pModus & KuferTools.Utils.Filter.Mandatory) != 0)) { 2515 isOk = isOk && KuferTools.Utils.Filter.IsFilled(pValue); 2516 } 2517 2518 if (isOk && ((pModus & KuferTools.Utils.Filter.MandatoryNoZero) != 0)) { 2519 isOk = KuferTools.Utils.Filter.IsFilledButNotZero(pValue); 2520 } 2521 2522 if (isOk && ((pModus & KuferTools.Utils.Filter.MandatoryEmptyStringOk) != 0)) { 2523 isOk = KuferTools.Utils.Filter.IsFilledEmptyStringOk(pValue); 2524 } 2525 2526 // Gibt true zurück, wenn Value leer ist, und kein Mandatoryfeld. 2527 if (isOk && pValue == "") { 2528 return true; 2529 } 2530 2531 if (isOk && ((pModus & KuferTools.Utils.Filter.Integer) != 0)) { 2532 isOk = KuferTools.Utils.Filter.IsInt(pValue); 2533 } 2534 2535 if (isOk && ((pModus & KuferTools.Utils.Filter.Float_Punktsepariert) != 0)) { 2536 isOk = KuferTools.Utils.Filter.IsFloatPunkt(pValue); 2537 } 2538 2539 if (isOk && ((pModus & KuferTools.Utils.Filter.Float_Kommasepariert) != 0)) { 2540 isOk = KuferTools.Utils.Filter.IsFloatKomma(pValue); 2541 } 2542 2543 if (isOk && ((pModus & KuferTools.Utils.Filter.Date) != 0)) { 2544 isOk = KuferTools.Utils.Filter.IsDate(pValue); 2545 } 2546 2547 if (isOk && ((pModus & KuferTools.Utils.Filter.Date_Jahrkurz) != 0)) { 2548 isOk = KuferTools.Utils.Filter.IsDateJahrKurz(pValue); 2549 } 2550 2551 if (isOk && ((pModus & KuferTools.Utils.Filter.Time) != 0)) { 2552 isOk = KuferTools.Utils.Filter.IsTime(pValue); 2553 } 2554 2555 if (isOk && ((pModus & KuferTools.Utils.Filter.EinsNull) != 0)) { 2556 isOk = KuferTools.Utils.Filter.IsOneOrNull(pValue); 2557 } 2558 2559 if (isOk && ((pModus & KuferTools.Utils.Filter.JN) != 0)) { 2560 isOk = KuferTools.Utils.Filter.IsJOrN(pValue); 2561 } 2562 2563 if (isOk && ((pModus & KuferTools.Utils.Filter.Email) != 0)) { 2564 isOk = KuferTools.Utils.Filter.IsEmail(pValue); 2565 } 2566 2567 if (isOk && ((pModus & KuferTools.Utils.Filter.ImageJPEG) != 0)) { 2568 isOk = KuferTools.Utils.Filter.IsImageJPEG(pValue); 2569 } 2570 2571 if (isOk && ((pModus & KuferTools.Utils.Filter.NeutralerTN) != 0)) { 2572 isOk = KuferTools.Utils.Filter.IsNotNeutralerTN(pValue); 2573 } 2574 2575 if (isOk && ((pModus & KuferTools.Utils.Filter.DateTime) != 0)) {
2576 isOk = KuferTools.Utils.Filter.IsDateTime(pValue); 2577 } 2578 2579 return isOk; 2580 2581}; 2582 2583KuferTools.Utils.Filter.IsDateEarlierOrEqual = function (dateLater) { 2584 2585 return function (dateEarlier) { 2586 if (dateLater.length > 0 && KuferTools.Utils.Filter.IsDate(dateLater) && dateEarlier.length > 0 && KuferTools.Utils.Filter.IsDate(dateEarlier)) { 2587 return KuferTools.Utils.Date.isDateBeforeOrEqual(dateEarlier, dateLater); 2588 } 2589 return true; 2590 }; 2591}; 2592 2593KuferTools.Utils.Filter.IsDateLaterOrEqual = function (dateEarlier) { 2594 2595 return function (dateLater) { 2596 if (dateEarlier.length > 0 && KuferTools.Utils.Filter.IsDate(dateEarlier) && dateLater.length > 0 && KuferTools.Utils.Filter.IsDate(dateLater)) { 2597 return KuferTools.Utils.Date.isDateBeforeOrEqual(dateEarlier, dateLater); 2598 } 2599 return true; 2600 }; 2601}; 2602 2603KuferTools.Utils.Filter.IsTimeEarlierOrEqual = function (timeLater) { 2604 return function (timeEarlier) { 2605 if (timeLater.length > 3 && KuferTools.Utils.Filter.IsTime(timeLater) && timeEarlier.length > 3 && KuferTools.Utils.Filter.IsTime(timeEarlier)) { 2606 return KuferTools.Utils.isTimeBeforeOrEqual(timeEarlier, timeLater); 2607 } 2608 return true; 2609 }; 2610}; 2611 2612KuferTools.Utils.Filter.IsTimeLaterOrEqual = function (timeEarlier) { 2613 return function (timeLater) { 2614 if (timeEarlier.length > 3 && KuferTools.Utils.Filter.IsTime(timeEarlier) && timeLater.length > 3 && KuferTools.Utils.Filter.IsTime(timeLater)) { 2615 return KuferTools.Utils.isTimeBeforeOrEqual(timeEarlier, timeLater); 2616 } 2617 return true; 2618 }; 2619}; 2620 2621KuferTools.Utils.Filter.FilterByArry = function (value, filterArray) { 2622 var filterLength = filterArray.length; 2623 for (var i = 0; i < filterLength; i++) { 2624 if (!filterArray[i](value)) { 2625 return false; 2626 } 2627 } 2628 return true; 2629}; 2630 2631/** 2632 * Gibt ein Objekt zurück, mit dessen Hilfe mehrere Felder per jQuerySelector und Modus auf einmal geprüft werden können. 2633 * Die Selektoren mit fehlerhaften Eingaben werden zurückgegeben. 2634 * 2635 * z. B. 2636 * var filterObj = KuferTools.Utils.Filter.FilterSelector(); 2637 * filterObj.addSelector( $('#test1'), KuferTools.Utils.Filter.Mandatory ) . 2638 * addSelector( $('#test2'), KuferTools.Utils.Filter.Mandatory | KuferTools.Utils.Filter.Integer ) ; 2639 * var wrongFilledSelectors = filterObj.filter(); 2640 */ 2641KuferTools.Utils.Filter.FilterSelector = function () { 2642 /** 2643 * Array mit den zu prüfenden Selektoren, und den jeweiligen Modus. 2644 * 2645 * { selector: , modus: } 2646 */ 2647 var filterSettings = []; 2648 var result = {}; 2649 /** 2650 * Fügt ein weiteres zu prüfendes Element hinzu 2651 * 2652 * @param $pSelector des zu prüfenden Elements. 2653 * @param pModus Nach was gefiltert wird, bitweise codiert. Hierzu können die Konstanten Mandatory, Integer... 2654 * verwendet werden. Bei mehreren Kriteren müssen diese per Bitweises ORing (x | y) verknüpft werden 2655 */ 2656 result.addSelector = function ($pSelector, pModus) { 2657 filterSettings[filterSettings.length] = { selector: $pSelector, modus: pModus }; 2658 return this; 2659 }; 2660 2661 /** 2662 * Gibt ein Array mit den fehlerhaften Selektoren zurück. 2663 */ 2664 result.filter = function () { 2665 var result = []; 2666 var filterLength = filterSettings.length; 2667 for (var i = 0; i < filterLength; i++) { 2668 if (!KuferTools.Utils.Filter.FilterValue(filterSettings[i].selector.val(), filterSettings[i].modus)) { 2669 result[result.length] = filterSettings[i].selector; 2670 } 2671 } 2672 return result; 2673 }; 2674 2675 return result; 2676}; 2677 2678registerNamespace("KuferTools.Utils.AjaxLadebildschirm"); 2679 2680KuferTools.Utils.AjaxLadebildschirm.Start = function () { 2681 if (!document.body.querySelector('.loader_overlay')) { 2682 const element = document.createElement('div'); 2683 element.classList.add('loader_overlay'); 2684 element.ariaBusy = true; 2685 element.ariaLive = 'assertive'; 2686 element.role = 'alert'; 2687 2688 const innerElement = document.createElement('div'); 2689 innerElement.classList.add('loader_spinner'); 2690 innerElement.ariaLabel="Der Inhalt wird geladen."; 2691 element.appendChild(innerElement); 2692 2693 document.body.appendChild(element); 2694 } 2695}; 2696 2697/** 2698 * Ajaxloader nur für einen Teilausschnitt der Seite. 2699 * 2700 * Der Selector sollte Position absolute oder relative haben. 2701 */ 2702KuferTools.Utils.AjaxLadebildschirm.Partial = function ($selector) { 2703 $selector.append('<div class="loader_overlay partial" aria-live="assertive" aria-busy="true" role="alert"><div class="loader_spinner" aria-label="Der Inhalt wird geladen."></div></div>'); 2704}; 2705 2706KuferTools.Utils.AjaxLadebildschirm.Stop = function () { 2707 const loaderOverlays = document.body.querySelectorAll('.loader_overlay'); 2708 for (const loaderOverlay of loaderOverlays) { 2709 loaderOverlay.remove(); 2710 } 2711}; 2712 2713KuferTools.Utils.ClickOrEnter = function($selector, handler) 2714{ 2715 $selector.on('click', handler);
2716 $selector.on('keydown', function(event) { 2717 2718 if (event.key !== "Enter") { 2719 return; 2720 } 2721 // Der Timeout verhindert, dass durch das Keydown-Event gleich sich ggf. öffnende Dialogfenster gleich wieder schlieÃen. 2722 setTimeout(() => { handler(event); }, 10); 2723 }); 2724};
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.