PageSourceSearch

https://www.vhs-tdf-ndk.de/fileadmin/kuferweb/webtools/js/project.js?version=4.20.92.06

js vhs-tdf-ndk.de collected 2026-10-04 00:30:48 UTC 86,342 bytes, 2,202 lines download raw bytes

1function registerNamespace(ns) {
2  var parts = ns.split(".");
3  var root = window;
4
5  for (var i = 0; i < parts.length; i++) {
6    if (typeof root[parts[i]] === "undefined")
7      root[parts[i]] = new Object();
8
9    root = root[parts[i]];
10  }
11}
12
13/** Konstanten, die an mehreren Stellen gebraucht werden */
14var CalendarDayNames = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
15var CalendarDayNamesShort = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
16/*************************************************************************************************************
17 Einfache Javascriptfunktionen die beim Auslesen der Jquery Events aufgerufen werden  
18*************************************************************************************************************/
19
20
21//Prüft ob Inhalt leer ist; nicht geeignet für jQuery Objekte also z.B. $('.identifier')
22function isempty(mixedvar) {
23  if (mixedvar === "" ||
24    mixedvar === "0" ||
25    mixedvar === null ||
26    mixedvar === false ||
27    typeof mixedvar === 'undefined'
28  ) {
29    return true;
30  }
31  // wenn irgeine Objektvariable enthalten ist, liefert die Methode false (da nichtleer);
32  // reagiert aber nicht richtig für jQuery Objekte, da diese IMMER eine length property 
33  // enthalten
34  if (typeof mixedvar == 'object') {
35    for (key in mixedvar) {
36      return false;
37    }
38    return true;
39  }
40  return false;
41}
42
43/*
44 * Gibt anhand einer Minutenanzahl eine Uhrzeit in form von HH:MM zurück
45 */
46function minutesToTime(p_minutes) {
47  //zuerst in Stunden und Minuten umwandeln
48  var hours = parseInt(p_minutes / 60);
49  var minutes = p_minutes - hours * 60;
50  //dann Std. modulo 24, da max. 24h am Tag
51  hours = hours % 24;
52
53  if (hours < 10) {
54    hours = '0' + hours;
55  }
56  if (minutes < 10) {
57    minutes = '0' + minutes;
58  }
59  return hours + ':' + minutes;
60}
61
62/*
63 * Gibt anhand einer Zeit in Form HH:MM die Minutenzahl zurück
64 */
65function timeToMinutes(p_Time) {
66  var hours = p_Time.split(':')[0];
67  var minutes = p_Time.split(':')[1];
68  return parseInt(hours * 60) + parseInt(minutes);
69}
70
71/*************************************************************************************************************
72 Jquery Events die beim Laden des Dokuments bereitgestellt werden und beim entspr. Handling (z.B. Anklicken)
73 ausgeloest werden 
74***************************************************************************************************************/
75
76
77//Methode zum Bereitstellen von Medienevents
78function loadJSHandling4Medien() {
79  /** Via Mediencontainer werden die Events und Funktionen zur Bearbeitung von Medien bereitgestellt */
80  /**************************************************************************************************/
81  var container = new MedienContainer();
82  container.initReadyhandling();
83}
84
85function trim(string) {
86  if (string != null) {
87    return string.replace(/^\s+/, '').replace(/\s+$/, '');
88  }
89  else {
90    return string;
91  }
92}
93
94function getIntFromDatePart(param) {
95  if (param.charAt(0) == '0' && param.length == 2) {
96    param = param.charAt(1);
97  }
98  return parseInt(param);
99}
100
101function updateWotag($input, dateValue, shortName) {
102  if ($input.length > 0) {
103    var parsedDate = $.datepicker.parseDate('dd.mm.yy', dateValue);
104    var value;
105    if (shortName) {
106      value = CalendarDayNamesShort[parsedDate.getDay()] + ".";
107    }
108    else {
109      value = CalendarDayNames[parsedDate.getDay()];
110    }
111
112    if ($input.is('input')) {
113      $input.val(value);
114    } else {
115      $input.text(value);
116    }
117  }
118}
119
120function updateDate($input, dateValue, dateForm) {
121  if ($input.length > 0) {
122    var parsedDate = $.datepicker.parseDate('dd.mm.yy', dateValue);
123
124    var day = parsedDate.getDate();
125    if (day < 10) {
126      day = "0" + day;
127    }
128
129    var month = (parsedDate.getMonth() + 1);
130    if (month < 10) {
131      month = "0" + month;
132    }
133
134    var year = parsedDate.getFullYear();
135    var value;
136    switch (dateForm) {
137      case 0: //dd.mm.yyyy
138        value = day + "." + month + "." + year;
139        break;
140      case 1: //dd.mm.
141        value = day + "." + month + ".";
142        break;
143      case 2: //dd.mm.yy
144        value = day + "." + month + "." + String(year).substring(2);
145        break;
146      case 3: //Wochentag, dd.mm.yyyy
147        value = CalendarDayNames[parsedDate.getDay()] + ", " + day + "." + month + "." + year;
148        break;
149      case 4: //Wotag., dd.mm.yyyy
150        value = CalendarDayNamesShort[parsedDate.getDay()] + "., " + day + "." + month + "." + year;
151        break;
152      case 5: //Wotag., dd.mm.yy
153        value = CalendarDayNamesShort[parsedDate.getDay()] + "., " + day + "." + month + "." + String(year).substring(2);
154        break;
155    }
156
157    if ($input.is('input')) {
158      $input.val(value);
159    } else {
160      $input.text(value);
161    }
162  }
163}
164
165function validateInputMultiSelect($target) {
166  let selector = 'option:selected';
167  if ($target.hasClass('multiSelectWithJs')) {
168    selector = 'option'; //alle Optionen werden vor dem Absenden automatisch markiert, deshalb ohne :selected
169  }
170
171  if ($target.hasClass('form-control') && $target.hasClass('form-control-multiple-fix')) {
172    // Klasse form-control-multiple-fix benötigt, da sonst getestete Annahmen
173    // woanders nicht mehr gelten
174    if (($target.hasClass('nicht_leer') || $target.hasClass('form_mandatory'))
175      && $target.find(selector).length === 0) {
176      $target.addClass('form_error');
177      $target.attr('aria-invalid', 'true');
178      return false;
179    }
180    else {
181      $target.removeClass('form_error');
182      $target.removeAttr('aria-invalid');
183      return true;
184    }
185  }
186
187  if ($target.find(selector).length === 0) {
188    $target.addClass('form_error');
189    $target.attr('aria-invalid', 'true');
190    return false;
191  } else {
192    $target.removeClass('form_error');
193    $target.removeAttr('aria-invalid');
194    return true;
195  }
196}
197
198function validateMnList($target) {
199  if (($target.hasClass('nicht_leer') || $target.hasClass('form_mandatory'))) {
200    const $hidden = $target.find('.mnlist_hidden');
201
202    const isEmpty = $hidden.val() == '' || $hidden.val() == '[]' || $hidden.val() == Base64.encode('[]');
203    if (isEmpty) {
204      $target.addClass('form_error');
205      $target.attr('aria-invalid', 'true');
206      return false;
207    } else {
208      $target.removeClass('form_error');
209      $target.removeAttr('aria-invalid');
210      return true;
211    }
212
213  }
214
215  return true;
216}
217
218registerNamespace('KuferTools');
219
220/**
221 * @type [{filter: (function(jQuery): bool), validate: (function(jQuery): function)}]
222 */
223KuferTools.ValidateInputs = [
224  {
225    filter: function ($target) { return $target.hasClass('val_float') || $target.hasClass('setting-inputnumeric'); },
226    validate: function ($target) { return KuferTools.Utils.Filter.IsFloatKomma; }
227  },
228  {
229    filter: function ($target) { return $target.hasClass('val_int'); },
230    validate: function ($target) { return KuferTools.Utils.Filter.IsInt; }
231  },
232  {
233    filter: function ($target) { return $target.hasClass('val_date'); },
234    validate: function ($target) { return KuferTools.Utils.Filter.IsDate; }
235  },
236  {
237    filter: function ($target) { return $target.hasClass('val_date_jahrkurz'); },
238    validate: function ($target) { return KuferTools.Utils.Filter.IsDateJahrKurz; }
239  },
240  {
241    filter: function ($target) { return $target.hasClass('val_time'); },
242    validate: function ($target) { return KuferTools.Utils.Filter.IsTime; }
243  },
244  {
245    filter: function ($target) { return $target.hasClass('val_einsnull'); },
246    validate: function ($target) { return KuferTools.Utils.Filter.IsOneOrNull; }
247  },
248  {
249    filter: function ($target) { return $target.hasClass('val_jn'); },
250    validate: function ($target) { return KuferTools.Utils.Filter.IsJOrN; }
251  },
252  {
253    filter: function ($target) { return $target.hasClass('val_image_jpeg'); },
254    validate: function ($target) { return KuferTools.Utils.Filter.IsImageJPEG; }
255  },
256  {
257    filter: function ($target) { return $target.hasClass('val_datetime'); },
258    validate: function ($target) { return KuferTools.Utils.Filter.IsDateTime; }
259  }
260];
261
262/**
263 * @type [{filter: (function(jQuery): bool), validate: (function(jQuery): function)}]
264 */
265KuferTools.ValidateInputsOptional = [
266  {
267    filter: function ($target) { return $target.hasClass('val_date_von') && $('.val_date_bis').length > 0; },
268    validate: function ($target) { return KuferTools.Utils.Filter.IsDateEarlierOrEqual($('.val_date_bis').val()); }
269  },
270  {
271    filter: function ($target) { return $target.hasClass('val_date_bis') && $('.val_date_von').length > 0; },
272    validate: function ($target) { return KuferTools.Utils.Filter.IsDateLaterOrEqual($('.val_date_von').val()); }
273  },
274  {
275    filter: function ($target) { return $target.hasClass('val_time_von') && $('.val_time_bis').length > 0; },
276    validate: function ($target) { return KuferTools.Utils.Filter.IsTimeEarlierOrEqual($('.val_time_bis').val()); }
277  },
278  {
279    filter: function ($target) { return $target.hasClass('val_time_bis') && $('.val_time_von').length > 0; },
280    validate : function ($target) { return KuferTools.Utils.Filter.IsTimeLaterOrEqual($('.val_time_von').val()); }
281  }
282];
283
284/**
285 * ACHTUNG: Gibt derzeit nicht nur zurück, ob ein Eingabefeld korrekt gefüllt ist, sondern
286 * gibt dem Eingabefeld auch die Klasse form_error.
287 * Sobald das aufgedröselt wird, muss das auch in Formulare/sightbuidler.js berücksichtigt werden.
288 *
289 * @param $target
290 * @return bool
291 */
292function validateInput($target) {
293  if ($target.prop('multiple')) {
294    return validateInputMultiSelect($target);
295  }
296
297  if ($target.hasClass('mnlist')) {
298    return validateMnList($target);
299  }
300
301  let val = '';
302  if ($target.attr('type') === 'checkbox') {
303    if ($target.prop('checked')) {
304      val = trim($target.val());
305    }
306  } else {
307    val = trim($target.val());
308  }
309
310  const wasOK = !$target.hasClass('form_error');
311
312  // Die Filterkriterien werden per bitweises ORing hinzugefügt. Dabei werden 
313  // Konstanten von KuferTools.Utils.Filter verwendet.
314  const filterFunctions = [];
315  const filter = KuferTools.Utils.Filter;
316  if ($target.hasClass('nicht_leer') || $target.hasClass('form_mandatory')) {
317    filterFunctions[filterFunctions.length] = filter.IsFilled;
318  }
319  else if ($target.hasClass('form_mandatory_no_zero')) {
320    filterFunctions[filterFunctions.length] = filter.IsFilledButNotZero;
321  }
322  else if ($target.hasClass('form_mandatory_empty_string_ok')) {
323    filterFunctions[filterFunctions.length] = filter.IsFilledEmptyStringOk;
324  }
325
326  if (val !== "") {
327    for (let i = 0; i < KuferTools.ValidateInputs.length; ++i) {
328      const obj = KuferTools.ValidateInputs[i];
329      if (obj.filter($target)) {
330        filterFunctions[filterFunctions.length] = obj.validate($target);
331        break;
332      }
333    }
334
335    KuferTools.ValidateInputsOptional.forEach(function (obj) {
336      if (obj.filter($target)) {
337        filterFunctions[filterFunctions.length] = obj.validate($target);
338      }
339    });
340  }
341
342  if (filter.FilterByArry(val, filterFunctions)) {
343
344    // Sonderfall: Es wird geprüft, ob der Radio gesetzt wurde. Sieht für mich unsauber aus, es werden 
345    // alle .check_radio über einen Kamm geschert, auch wenn diese nicht zusammenhängen
346    // Anm.: Klasse check_radio wird bei Checkboxen und Radiobuttons zum Validieren verwendet
347    if ($target.hasClass('check_radio')) {
348      if (jQuery(".check_radio:checked").length === 0) {
349        jQuery(".check_radio").each(function () {
350          jQuery(this).addClass('form_error');
351          jQuery(this).attr('aria-invalid', 'true');
352        });
353
354        return false;
355      }
356      else {
357        jQuery(".check_radio").each(function () {
358          jQuery(this).removeClass('form_error');
359          jQuery(this).removeAttr('aria-invalid');
360        });
361
362        return true;
363      }
364    }
365
366    if ($target.hasClass('val_date') || $target.hasClass('val_date_jahrkurz')) {
367      sightBuilderUpdateDate($target);
368    }
369    // Konvertiert 5:23 nach 05:23
370    if ($target.hasClass('val_time')) {
371      if (val.length === 4) {
372        $target.val("0" + val);
373      }
374    }
375    /*
376    if( $target.hasClass('val_date_von') || $target.hasClass('val_date_bis'))
377    {
378      var $valDateBis = $('.val_date_bis');
379      var $valDateVon = $('.val_date_von');
380      if(filter.FilterValue($valDateBis.val(), filter.Date) === true && $valDateBis.val().length > 0 && $valDateVon.val().length > 0) {
381        if(!KuferTools.Utils.Date.isDateBefore($valDateVon.val(), $valDateBis.val())) {
382          $valDateBis.addClass('form_error');
383          $valDateVon.addClass('form_error');
384          return false;
385        } else {
386          $valDateBis.removeClass('form_error');
387          $valDateVon.removeClass('form_error');
388        }
389      }
390    }*/
391    // Sonderfall Bankdaten. Dort wird von einer anderen Stelle aus gesetzt, ob diese korrekt oder falsch sind.
392    /*
393    if ($target.hasClass('val_bankdaten')) {
394      if ($target.hasClass('form_error'))
395        return false;
396      else
397        return true;
398    }
399    */
400    if (!wasOK) {
401      $target.removeClass('form_error');
402      $target.removeAttr('aria-invalid');
403    }
404
405    return true;
406  }
407
408  else {
409
410    if (wasOK) {
411      $target.addClass('form_error');
412      $target.attr('aria-invalid', 'true');
413    }
414
415    return false;
416  }
417}
418
419/**
420 * Wenn Datumsfelder geändert werden, müssen gleichzeitig die dazugehörigen Datumsfelder mitgeändert werden
421 * 
422 * Z. B. Wochentag muss geändert werden, wenn das Datum geändert wird.
423 * @param jQuery-Selektor $pTarget das geänderte Datumsfeld
424 * @return
425 */
426function sightBuilderUpdateDate($pTarget) {
427  var date = $pTarget.val();
428  // Wandelt jedes Datum in TT.MM.JJJJ um. Gibt false zurück, falls Leer oder kein Datum
429  date = KuferTools.Utils.Date.formatDate(date);
430  if (!date) {
431    return;
432  }
433
434  // Falls kurze Jahreszahl, wird das Jahrhuntert/tausend von anderen Feldern extrahiert.
435  //Hinweis: Im Dialogbetrieb (Tool MA Kurse) geht diese Variante nicht, da der Dialog noch nicht existiert
436  //wenn dieser Abschnitt ausgeführt wird -> kurs_ende_dat_jahrkurz und kurs_beginn_dat_jahrkurz auf read-only gesetzt
437  if ($pTarget.hasClass('val_date_jahrkurz')) {
438    if ($pTarget[0].id == 'kurs_ende_dat') {
439      var year = getIntFromDatePart($('input#kursDatumBis').val().substring(6, 8) + date.substring(8, 10));
440    }
441    else {// kurs_beginn_dat
442      var year = getIntFromDatePart($('input#kursDatumVon').val().substring(6, 8) + date.substring(8, 10));
443    }
444    var date = date.substring(0, 6) + year;
445  }
446
447  if ($pTarget[0].id == 'kurstag_datum') {
448    updateWotag($('input#kurstag_wotaglang'), date, false);
449    updateWotag($('input#kurstag_wotagkurz'), date, true);
450    updateDate($('input#kurstag_datum_kurz'), date, 1);
451  }
452  else if ($pTarget[0].id == 'kursplanung_beginn_dat') {
453    updateWotag($('#kursplanung_beginn_dat_wotaglang'), date, false);
454    updateWotag($('#kursplanung_beginn_dat_wotagkurz'), date, true);
455  }
456  else if ($pTarget[0].id == 'kursplanung_ende_dat') {
457    updateWotag($('#kursplanung_ende_dat_wotaglang'), date, false);
458    updateWotag($('#kursplanung_ende_dat_wotagkurz'), date, true);
459  }
460  else if ($pTarget[0].id == 'kurs_ende_dat' || $pTarget[0].id == 'kurs_ende_dat_jahrkurz') {
461    updateDate($('input#kurs_ende_dat_kurz'), date, 1);
462    updateDate($('input#kurs_ende_dat'), date, 0);
463    updateWotag($('input#kurs_ende_dat_wotaglang'), date, false);
464    updateWotag($('input#kurs_ende_dat_wotagkurz'), date, true);
465    updateDate($('input#kursDatumBis'), date, 0);
466    updateDate($('input#kurs_ende_dat_jahrkurz'), date, 2);
467    updateDate($('input#kurs_ende_dat_komplettlang'), date, 3);
468    updateDate($('input#kurs_ende_dat_komplettkurz'), date, 4);
469    updateDate($('input#kurs_ende_dat_komplettkurz_jahrkurz'), date, 5);
470  }
471  else if ($pTarget[0].id == 'kurs_beginn_dat' || $pTarget[0].id == 'kurs_beginn_dat_jahrkurz') {
472    updateDate($('input#kurs_beginn_dat_kurz'), date, 1);
473    updateDate($('input#kurs_beginn_dat'), date, 0);
474    updateWotag($('input#kurs_beginn_dat_wotaglang'), date, false);
475    updateWotag($('input#kurs_beginn_dat_wotagkurz'), date, true);
476    updateDate($('input#kursDatumVon'), date, 0);
477    updateDate($('input#kurs_beginn_dat_jahrkurz'), date, 2);
478    updateDate($('input#kurs_beginn_dat_komplettlang'), date, 3);
479    updateDate($('input#kurs_beginn_dat_komplettkurz'), date, 4);
480    updateDate($('input#kurs_beginn_dat_komplettkurz_jahrkurz'), date, 5);
481  }
482}
483
484/**
485 * Erwartet einen jQuery-Selektor mit Bankdaten (input Felder die auf '_blz',
486 * '_konto', '_bic', '_iban' enden), validiert diese auf PHP-Seite und ruft,
487 * je nachdem ob die Validierung erfolgreich war oder nicht, eine der
488 * Funktionen pSuccessFunc oder pErrorFunc auf.
489 * 
490 * @param jQuery-Selektor $pBankDaten
491 * @param pSuccessFunc
492 * @param pErrorFunc
493 * @param string pUrl
494 */
495function validateBankDatenPerAjax($pBankDaten, pSuccessFunc, pErrorFunc, pUrl) {
496  bankDatenSerialized = $pBankDaten.serializeArray();
497  var url;
498  if (pUrl === undefined) {
499    url = KuferTools.SelfLink.replace(/&wb__already__decoded=done/g, '').replace(/#.*/, '').replace(/145/, '434');
500    url += '&action=validate';
501  } else {
502    url = pUrl;
503  }
504  $.ajax({
505    type: "POST",
506    url: url,
507    data: bankDatenSerialized,
508    // 
509    success: function (pData) {
510
511      var bankDatenValidated = KuferTools.Utils.getObjectFromJson(pData);
512
513      // Falls kein oder ein fehlerhaftes Objekt vom Server zurückgegeben wird (z.B. wegen einer 
514      // Exception in PHP), wird eine Fehlermeldung ausgegeben.
515
516      if (KuferTools.Utils.showAjaxErrorDialog(bankDatenValidated, url))
517        return;
518
519      // Jetzt werden nur die Bankdaten auf Korrektheit überprüft
520      var fehlerhafteDaten = [];
521      var daten = [];
522
523      $.each(bankDatenValidated, function (bezeichnung, isValid) {
524        if (isValid === '0') {
525          fehlerhafteDaten[fehlerhafteDaten.length] = bezeichnung;
526        }
527        daten[daten.length] = bezeichnung;
528      });
529
530      var bankdatenAryLength = fehlerhafteDaten.length;
531      if (bankdatenAryLength === 0) {
532        pSuccessFunc(daten);
533      }
534      else {
535        pErrorFunc(fehlerhafteDaten);
536      }
537    },
538    error: function () {
539      console.log('Verbindung zum Server fehlgeschlagen. Keine Bankdaten empfangen.');
540      showMessage('Verbindung zum Server fehlerhaft. ', 'Serverfehler');
541      KuferTools.Utils.AjaxLadebildschirm.Stop();
542    }
543  });
544}
545
546/**
547 * Gibt true zurück, wenn die Eingabefelder korrekt befüllt wurden, sonst false.
548 * Erwartet einen Selector, führt für jedes Element im Selector validateInput aus.
549 * 
550 * @return bool true, falls alle Eingaben korrekt sind, sonst false.
551 */
552function validateForm($selector) {
553  var isOK = true;
554  $selector.each(function (index, element) {
555    if (!validateInput($(this)) && isOK) { //Auch wenn isOK false ist, 
556      //muss validateInput für die restlichen Felder aufgerufen werden.
557      isOK = false;
558    }
559  });
560  return isOK;
561}
562
563function validateNotenForm() {
564  if (!validateInput($(this))) {
565    //Formular sperren
566    $('#einreichenbutton').prop('disabled', true);
567    $('#eintragenbutton, #eintragenButtonTop').prop('disabled', true);
568  }
569  else {
570    if (!$('#notenform .form_error').length) {
571      $('#einreichenbutton').prop('disabled', false);
572      $('#eintragenbutton, #eintragenButtonTop').prop('disabled', false);
573    }
574  }
575}
576
577function validateUhrzeit(pUhrzeit) {
578  const regex = new RegExp("[0-1][0-9]:[0-5][0-9]|2[0-3]:[0-5][0-9]");
579  const match = regex.exec(pUhrzeit);
580
581  return match !== null;
582}
583
584//Nimmt bei den Hinterlegungen den Wert aus den Spans innerhalb der lis von $source und legt ihn in die 
585//Values von $target. Außerdem werden die angehakten Checkboxen wieder deaktiviert.
586function _restoreCheckboxToDialog($source, $target) {
587  var result = '';
588  var $lis = $source.find(':checked');
589  $lis.each(function () { result += $(this).val() + "\r\n" });
590  $lis.prop('checked', false);
591  if (result.length > 0) {
592    result = result.substring(0, result.length - 2);
593    if ($target.val() != '')
594      $target.val($target.val() + "\r\n" + result);
595    else
596      $target.val($target.val() + result);
597  }
598}
599
600/**
601 * 
602 * @param pMeldung Dialoginhalt
603 * @param pTitle Dialogtitel
604 * @param pButtons Buttons
605 * @param pWidth Breite des Fensters (optional)
606 * @param pPosition Höhe des Fensters (optional)
607 * @param pAction Action-Attribut des Formulars (optional)
608 * @param pPressEnterFunc Funktion, die aufgerufen wird, wenn die Enter-Taste gedrückt wird (optional)
609 * @return {Promise<HTMLElement>}
610 */
611function showMessage(meldung, pTitle, pButtons, pWidth, pPosition, pPressEnterFunc, pHeight) {
612  return new Promise((resolve, reject) => {
613    if (typeof pButtons == 'undefined') {
614      pButtons = {
615        "Ok": function () {
616          $(this).dialog("close");
617        }
618      };
619    }
620    if (typeof pWidth == 'undefined') {
621      pWidth = 550;
622    }
623
624    if (typeof pHeight == 'undefined') {
625      pHeight = 'auto';
626    }
627
628    if (typeof pPosition == 'undefined') {
629      pPosition = {my: "center", at: "center", of: window};
630    }
631
632    let $meldung = undefined;
633    if (typeof meldung == 'object') {
634      $meldung = meldung;
635    } else {
636      $meldung = $('<div>' + meldung + '</div>');
637    }
638
639    $meldung = $meldung.dialog({
640      modal: true,
641      autoOpen: false,
642      position: pPosition,
643      width: pWidth,
644      height: pHeight,
645      title: pTitle,
646      bgiframe: true,
647      resizable: false,
648      dialogClass: 'dialogwindow',
649      closeOnEscape: false,//ansonsten bei manchen DetailDialogen ein Problem (z.B. Unterrichtsmittellist, wenn neuer Eintrag da, und dann ESC/schließen)
650      buttons: pButtons,
651      close: function (a, b) {
652        $meldung.remove();
653        KuferTools.DialogWindows.pop();
654      },
655      open: function (event, ui) {
656        $meldung = $(this);
657
658        registerNamespace('KuferTools');
659        if (typeof (KuferTools.DialogWindows) == 'undefined') {
660          KuferTools.DialogWindows = [];
661        }
662        KuferTools.DialogWindows.push($meldung);
663        var $hasDatePicker = KuferTools.DialogWindows[KuferTools.DialogWindows.length - 1].find('.hasDatePicker');
664        KuferTools.InitDatePicker($hasDatePicker);
665
666        $hasDatePicker.on('click', function () {
667          $(this).datepicker('show');
668        });
669
670        KuferTools.DialogWindows[KuferTools.DialogWindows.length - 1].find('.hasTimePicker').timepicker({}).on('click', function () {
671          $(this).timepicker('show');
672        });
673
674        $(".ui-dialog-titlebar-close", ui.dialog).hide();
675
676        // Damit Datepicker usw. in den Dialogen wieder funktionieren.
677        KuferTools.InitAllgemeineHandler($meldung);
678
679        //Bei Drücken der Enter-Taste Formular abschicken
680        $meldung.find('input, select').on('keypress', function (event) {
681          if (event.which === 13) {
682            event.preventDefault();
683            if (typeof (pPressEnterFunc) !== "undefined") {
684              pPressEnterFunc($meldung);
685            }
686          }
687        });
688        //Bei Drücken der Esc-Taste Dialog abschließen
689        $meldung.parents('.ui-dialog').on('keydown', $(this), function (event) {
690          var key = event.which || event.keyCode;
691          if (key === 27) {
692            $meldung.dialog('close');
693          }
694        });
695
696        resolve($meldung[0]);
697      }
698    });
699
700    $meldung.dialog('open');
701  });
702}
703
704$(function () {
705
706  //Tool 13 Hervorhebung von nicht gültigen Bankdaten
707  //Wildcards: ^ = Element beginnt mit ...    $ = Element endet mit ... (id$=blz: endet mit blz)
708  $("[id$=blz]").on('keydown', function () { removeFormError('blz') });
709  $("[id$=konto]").on('keydown', function () { removeFormError('konto') });
710  $("[id$=bic]").on('keydown', function () { removeFormError('bic') });
711  $("[id$=iban]").on('keydown', function () { removeFormError('iban') });
712
713  if (typeof (KuferTools.IsValidBlz) != "undefined" && !(KuferTools.IsValidBlz == true)) {
714    $("[id$=blz]").addClass('form_error');
715  }
716  if (typeof (KuferTools.IsValidKonto) != "undefined" && !(KuferTools.IsValidKonto == true)) {
717    $("[id$=konto]").addClass('form_error');
718  }
719  if (typeof (KuferTools.IsValidBic) != "undefined" && !(KuferTools.IsValidBic == true)) {
720    $("[id$=bic]").addClass('form_error');
721  }
722  if (typeof (KuferTools.IsValidIban) != "undefined" && !(KuferTools.IsValidIban == true)) {
723    $("[id$=iban]").addClass('form_error');
724  }
725
726  function removeFormError(pArt) {
727    $("[id$=" + pArt + "]").removeClass('form_error');
728  }
729
730  //Zentrale Einstellungen von Tool 22
731  $('#semlist4Tool22').data('normalHeight', $('#semlist4Tool22').height());
732  if ($('#useSem21').prop('checked')) {
733    $('#semlist4Tool22').hide().css('height', '0px');
734  }
735  $('input[name="useTool21Semester"]').on('change', function () {
736    var $semDiv = $('#semlist4Tool22');
737    if ($(this).prop('id') == 'useSem21') {
738      $semDiv.hide().animate({ height: '0px' }, 500);
739    } else {
740      $semDiv.show().animate({ height: ($semDiv.data('normalHeight')) + 'px' }, 500);
741    }
742  })
743
744  //Zentrale Einstellungen von Tool 36; Vorgesetzten Tool
745  $('#semlist4Tool36').data('normalHeight', $('#semlist4Tool36').height());
746  if ($('#useSem20').prop('checked')) {
747    $('#semlist4Tool36').hide().css('height', '0px');
748  }
749  $('input[name="useTool20Semester"]').on('change', function () {
750    var $semDiv = $('#semlist4Tool36');
751    if ($(this).prop('id') == 'useSem20') {
752      $semDiv.hide().animate({ height: '0px' }, 500);
753    } else {
754      $semDiv.show().animate({ height: ($semDiv.data('normalHeight')) + 'px' }, 500);
755    }
756  })
757
758  KuferTools.MarkSelectedIds();//Bei Übersichten ggf. die Checkboxen markieren
759
760  //Überprüft, ob die E-Mail-Adresse im Leftmenu zu lange ist, und lässt diese ggf.
761  //in einem Dialog anzeigen.
762  $('.kontakt_email').each(function () {
763    var width = $(this).width();
764    var leftMenuWidth = $(this).parents('#leftmenu').width();
765
766    //E-Mail-Adresse ist zu lang. Ersetze die E-Mail unter Kontakt durch "anzeigen", und
767    //öffne bei einem Klick darauf ein Dialog mit der E-Mail-Adresse
768    if (width > leftMenuWidth) {
769      var $showEmail = $('<a class="show_kontakt_email">anzeigen</a>');
770      //replaceWith gibt den ersetzten part als Array von Objekten zurück.
771      var email = $(this).find('a').replaceWith($showEmail);
772
773      $($showEmail).on('click', function () {
774        //Wird email[0] als String angehängt, wird nicht <a href="mailto... sondern mailto:EMAIL angehängt
775        showMessage('Per E-Mail erreichen Sie uns unter:<br><br><span class="dialog_kontakt_email"></span>', 'E-Mail:');
776        $('.dialog_kontakt_email').append(email[0]);
777      });
778    }
779  });
780
781  /**
782   * Setzt die Button-Bilder vertikal mittig. (siehe addfunctions.php HTMLOperations::createButtonSpan())
783   * Funktioniert derzeit nicht mit nachträglich erzeugten Buttons (wie in Dialogen). Hierzu könnte evtl. das liveready-Plugin helfen.
784   * Ebenso wird eine dynamische Änderungen der Buttonhöhe nicht berücksichtigt.
785   */
786  $('.button_img').each(function () {
787    $(this).css('top', ($(this).parent().height() - $(this).height()) / 2);
788  });
789
790  $('#tipplink').on('click', function () {
791    showMessage('So können Sie die Größe der Internetseiten in Ihrem Browser ändern:\n'
792      + '<ol><li>Strg-Taste gedrückt halten und +/- Tasten drücken = Schrift vergrößern/verkleinern. Außerdem kann man in den meisten Browsern die Schriftgröße
792n mit Strg+0 wieder auf Standard zurücksetzen.</li>'
793      + '<li>Strg-Taste gedrückt halten und Mausrad drehen. InternetExplorer (IE), Chrome und Opera: Nach oben drehen = Schrift vergrößern. Firefox und Safari: Nach oben drehen = Schrift verkleinern.</li>'
794      + '<li>Über das Menü: Im IE lässt sich die Schriftgröße im Menü Ansicht/Textgröße in fünf Stufen einstellen. Beim Firefox kann man über das Menü Ansicht/Zoom die Darstellungsgröße schrittweise verändern oder zurücksetzen. Vergleichbare Funktionen sind im Chrome unter Schraubenschlüssel/Zoom verfügbar, im Opera unter Ansicht/Zoomfaktor und im Safari unter Ansicht/Schrift kleiner bzw. Schrift größer verfügbar.</li>'
795      + '<li>Sollte es beim Firefox zu Verzerrungen kommen, prüfen Sie bitte, dass im Menü unter Ansicht / Zoom die Option "Nur Text zoomen" <b>nicht</b> aktiv ist.'
796      + '</ol>'
797      + 'Die Strg-Taste (Strg = Steuerung) befindet sich jeweils ganz rechts und links in der untersten Tastenreihe von Standard-Tastaturen. Auf englischen Tastaturen heißt diese Taste Ctrl (= Control). Beim Mac muss man statt Strg die Cmd/Apfel-Taste drücken.', 'Tipp zur Auflösung');
798  });
799
800
801  //Um Darstellungsfehler von Safari und Chrome beim erstelle neuer News zu korrigieren
802  var bengruppenheight = $('#benutzergruppe').children().length * 18;
803  $('#benutzergruppe').css('height', bengruppenheight + 'px');
804  $('.newssingleselect').css('min-height', (bengruppenheight + 15) + 'px');
805
806  /*
807   * Event-Handler für den Button, welcher die Einrichtung über den Druck einer PDF-Liste informiert.
808   * Derzeit nur in den Dialogen für die PDF-Listen in Datengruppe 1 möglich.
809   */
810  $(document).on('click', '.druckliste_vhs_info', function () {
811
812    KuferTools.Utils.AjaxLadebildschirm.Start();
813
814    var url = $(this).find('.druckliste_vhs_info_link').val();
815
816    $.ajax({
817      type: 'POST',
818      url: url,
819      success: function (submsg) {
820        KuferTools.Utils.AjaxLadebildschirm.Stop();
821        showMessage(submsg, 'Info erfolgreich versendet');
822      },
823      error: function () {
824        KuferTools.Utils.AjaxLadebildschirm.Stop();
825        showMessage('Beim Versenden der Info an die Einrichtung ist ein Fehler aufgetreten. ' +
826          'Bitte versuchen Sie es später erneut.', 'Fehler beim Versenden');
827      }
828    });
829  });
830
831  //HilfeDialog
832  $('#help').dialog({
833    autoOpen: false,
834    title: 'Hilfe:',
835    width: 700,
836    buttons: { "Ok": function () { $(this).dialog("close"); } }
837  });
838
839  //ÖffnenButton für den HilfeDialog
840  $('.helpOpener').on('click', function () {
841    $('#help').dialog('open');
842    // prevent the default action, e.g., following a link
843    return false;
844  });
845
846  //Ermöglicht bei den dynamischen Sichten die Option, dass das Feld und das
847  //dazugehörige Label versteckt wird, falls der Inhalt des Feldes leer ist.
848  $('.wss_hide').each(function () {
849    //In diesem Fall wurde die Seite mit SightBuilder aufgebaut.
850    if ($(this).prop('name') == $(this).prop('id')) {
851      $('label[for = "' + $(this).prop('id') + '"]').hide();
852    }
853    //In diesem Fall wurde die Seite mit SightBuilderUebersicht aufgebaut
854    else {
855      //TODO spezialfall in den TN-Tools, wo mehrere Instanzen verschiedener
856      //Kurse auf einer Seite angezeigt werden
857      $(this).removeClass('formelement').removeClass('wss_hide');
858      $('.' + $(this).prop('class') + '.label').hide();
859    }
860    $(this).hide();
861  });
862
863  $('.nichtBenotetCheckbox').on('click', function (element) {
864    var $notenInput = $(this).closest('td').children().filter(':text, select');
865    if ($(this).is(':checked')) {
866      $notenInput.prop("disabled", true);
867    } else {
868      $notenInput.prop("disabled", false);
869    }
870  });
871
872  // Dialog mit den hinterlegten Unterrichts-Fächern
873  $('#dialog_hl_faecher').dialog({
874    autoOpen: false,
875    title: 'Unterrichts-Fächer:',
876    width: 700,
877    height: 450,
878    modal: true,
879    buttons: {
880      "Ok": function () {
881        _restoreCheckboxToDialog($(this), $('#kurstag_bemerkungen'));
882        $(this).dialog("close");
883      },
884      "Abbrechen": function () { $(this).dialog("close"); }
885    }
886  });
887
888  //ÖffnenButton für den Dialog mit den hinterlegten Unterrichts-Fächern
889  $('#button_hl_faecher, .button_hl_faecher').on('click', function () {
890    $('#dialog_hl_faecher').dialog('open');
891    // prevent the default action, e.g., following a link
892    return false;
893  });
894
895  // Dialog mit den hinterlegten Info-Feldern
896  $('#dialog_hl_info_felder').dialog({
897    autoOpen: false,
898    title: 'Info-Felder:',
899    width: 500,
900    modal: true,
901    buttons: {
902      "Ok": function () {
903        _restoreCheckboxToDialog($(this), $('#kurstag_bemerkungen'));
904        $(this).dialog("close");
905      },
906      "Abbrechen": function () { $(this).dialog("close"); }
907    }
908  });
909
910  var kurse = 'Kurse';
911  if (window.KuferTools && KuferTools.Spracheinstellungen)
912    kurse = KuferTools.Spracheinstellungen.Kurs.Plural.Nominativ;
913
914  // Dialog mit der Abfrage nach markierten Kursen
915  $('#dialog_markieren').dialog({
916    autoOpen: false,
917    title: kurse + ' markieren:',
918    width: 300,
919    modal: true,
920    buttons: {
921      "Abbrechen": function () { $(this).dialog("close"); }
922    }
923  });
924
925  // Dialog mit der Abfrage nach markierten Räumen
926  $('#dialog_markieren_hm').dialog({
927    autoOpen: false,
928    title: 'Räume markieren:',
929    width: 300,
930    modal: true,
931    buttons: {
932      "Abbrechen": function () { $(this).dialog("close"); }
933    }
934  });
935
936  // Dialog mit der Abfrage nach markierten Räumen
937  $('#dialog_markieren_termine').dialog({
938    autoOpen: false,
939    title: 'Termine markieren:',
940    width: 350,
941    modal: true,
942    buttons: {
943      "Abbrechen": function () { $(this).dialog("close"); }
944    }
945  });
946
947  //Setzt alle Felder der Erweiterten Suche auf Default
948  function filter_leeren() {
949    document.getElementsByName("search_kursbeginnzeitraum_von")[0].value = "";
950    document.getElementsByName("search_kursbeginnzeitraum_bis")[0].value = "";
951    document.getElementsByName("search_kursnummernbereich_von")[0].value = "0";
952    document.getElementsByName("search_kursnummernbereich_bis")[0].value = "ZZ";
953    $('[name="search_wochentage_suche[]"]').prop('checked', false);
954
955    var kurstitel = document.getElementsByName("search_kurstitel");
956    if (kurstitel[0].id == "ktitel")
957      kurstitel[1].value = "";
958    else
959      kurstitel[0].value = "";
960
961    document.getElementsByName("search_stichworte")[0].value = "";
962    document.getElementsByName("search_dozent")[0].value = "";
963
964    //Folgende Felder werden nicht in allen Suchformularen verwendet.
965    var searchFieldAry = Array("search_bezeichn", "search_mktext", "search_fachbereich",
966      "search_kategorie", "search_sonderkategorie");
967    var anzahlFelder = searchFieldAry.length;
968
969    for (var i = 0; i < anzahlFelder; i++) {
970      searchField = document.getElementsByName(searchFieldAry[i]);
971      if (searchField.length > 0) {
972        searchField[0].value = "-1";
973      }
974    }
975    //document.getElementsByName("search_bezeichn")[0].value = "-1";
976    //document.getElementsByName("search_mktext")[0].value = "-1";
977    //document.getElementsByName("search_fachbereich")[0].value = "-1";
978    //document.getElementsByName("search_kategorie")[0].value = "-1";
979    //document.getElementsByName("search_sonderkategorie")[0].value = "-1";
980  }
981
982  var filterInhalt = new Array();
983  //Wird beim Öffnen und Schließen des Kurssuche-Dialog aufgerufen.
984  //ist speichern true, werden die Werte der Felder in filterInhalt gespeichert,
985  //ist speichern false, so werden die zuvor gespeicherten Werte wieder in die Felder
986  //geschrieben.
987  function filter_fuellen(speichern) {
988    var feldnamen = new Array("search_kursbeginnzeitraum_von",
989      "search_kursbeginnzeitraum_bis",
990      "search_kursnummernbereich_von",
991      "search_kursnummernbereich_bis",
992      "search_kurstitel",
993      "search_stichworte",
994      "search_bezeichn",
995      "search_mktext",
996      "search_fachbereich",
997      "search_kategorie",
998      "search_sonderkategorie",
999      "search_wochentage",
1000      "search_dozent");
1001
1002    var feldnamen_length = feldnamen.length;
1003    //Die Werte aus der Suche werden im Array gespeichert
1004    if (speichern) {
1005      for (var i = 0; i < feldnamen_length; i++) {
1006        if (feldnamen[i] == "search_kurstitel") {
1007          var kurstitel = document.getElementsByName("search_kurstitel");
1008          if (kurstitel[0].id == "ktitel") {
1009            filterInhalt[i] = kurstitel[1].value;
1010          }
1011          else {
1012            filterInhalt[i] = kurstitel[0].value;
1013          }
1014        } else if (feldnamen[i] == "search_wochentage") {
1015          //Klont hier einfach die Checkboxen, um die Zustände der einzelnen Boxen später auszulesen.
1016          filterInhalt[i] = $('[name="search_wochentage_suche[]"]').clone();
1017        } else {
1018          var searchField = document.getElementsByName(feldnamen[i]);
1019          //Nicht bei allen Suchformularen werden alle Felder angezeigt.
1020          if (searchField.length > 0)
1021            filterInhalt[i] = searchField[0].value;
1022        }
1023      }
1024    }
1025    //Die vorher gespeicherten Werte werden wieder in die Felder geschrieben
1026    else {
1027      for (var i = 0; i < feldnamen_length; i++) {
1028        if (feldnamen[i] == "search_kurstitel") {
1029          var kurstitel = document.getElementsByName("search_kurstitel");
1030          if (kurstitel[0].id == "ktitel") {
1031            kurstitel[1].value = filterInhalt[i];
1032          }
1033          else {
1034            kurstitel[0].value = filterInhalt[i];
1035          }
1036        } else if (feldnamen[i] == "search_wochentage") {
1037          for (var j = 1; j <= 7; j++) {
1038            //$(filterInhalt[i]) enthält die zuvor geklonten Checkboxen
1039            $('#search_wochentage_suche_' + j).prop('checked', $(filterInhalt[i]).filter('#search_wochentage_suche_' + j).prop('checked'));
1040          }
1041        }
1042        else {
1043          var searchField = document.getElementsByName(feldnamen[i]);
1044          //Nicht bei allen Suchformularen werden alle Felder angezeigt.
1045          if (searchField.length > 0)
1046            searchField[0].value = filterInhalt[i];
1047        }
1048      }
1049    }
1050  }
1051
1052  // Dialog mit der Kurssuche
1053  // Hier wird ein Formular abgeschickt, dessen Bearbeitung  etwas länger dauern kann; daher den Dialog sofort
1054  // schließen und  mit Ajax-Loader anzeigen, dass das Formular noch geladen wird
1055
1056  var $suchDialog = $('#kurssuche');
1057  $suchDialog.dialog({
1058    autoOpen: false,
1059    title: (KuferTools && KuferTools.Spracheinstellungen) ? KuferTools.Spracheinstellungen.KursZusammengesetzt.Singular.Nominativ + 'filter' : '',
1060    width: 530,
1061    modal: true,
1062    resizable: false,
1063    buttons: {
1064      "Schließen": function () { $(this).dialog("close"); },
1065      "Filter leeren": function () {
1066        filter_leeren(); $('#suchformDiv').trigger('submit'); $(this).dialog("close");
1067
1068        KuferTools.Utils.AjaxLadebildschirm.Start();
1069      },
1070      "Filter setzen": submitKurssuche
1071    },
1072    //Beim ersten Öffnen des Dialogs sind die Felder der Kurssuche aus der
1073    //Session geladen. Dies wird nun zwischengespeichert und beim
1074    //Abbrechen werden die Felder wieder in den Ursprungszustand gesetzt
1075    open: function () {
1076      filter_fuellen(true);
1077    },
1078    close: function () {
1079      filter_fuellen(false);
1080    }
1081  });
1082
1083  function submitKurssuche() {
1084    $('#suchformDiv').trigger('submit'); $suchDialog.dialog("close");
1085
1086    KuferTools.Utils.AjaxLadebildschirm.Start();
1087  }
1088
1089  // Dialog mit der Abfrage wie bei leeren Inhalt reagiert werden soll.
1090  // Wird bei den Einstellungen der dynamischen Sichten verwendet.
1091  $('#leerer_inhalt').dialog({
1092    autoOpen: false,
1093    title: 'Vorgehensweise bei leerem Inhalt:',
1094    width: 500,
1095    modal: true,
1096    buttons: {
1097      "Ok": function () {
1098        var data_wenn_leer = '';
1099        var radioVal = $(this).find(':radio:checked').prop('value');
1100        if (radioVal == 1) {
1101          //Entspricht Label verstekcen.
1102          data_wenn_leer = '[HIDE]';
1103        }
1104        else if (radioVal == 2) {
1105          //Entspricht Alternativtest
1106          data_wenn_leer = '[TEXT]' + $('#leer_alternativtext').val();
1107        }
1108        //der else-Fall (Normales verhalten) wird durch die initialisierung
1109        //data_wenn_leer = '' bereits abgedeckt.
1110
1111        //Hängt die Information data_wenn_leer an das Feld an, von dem
1112        //der Dialog aufgerufen wurde.
1113        $(this).data('target').data('wenn_leer', data_wenn_leer);
1114
1115        $(this).dialog("close");
1116      },
1117      "Abbrechen": function () { $(this).dialog("close"); }
1118    },
1119    open: function () {
1120      //beim Öffnen werden die Einstellungen des Feldes in die Eingabefelder 
1121      //des Dialogs übernommen
1122
1123      //$(this).data('target') entspricht dem Feld, woraus der Rechtsklick gemacht wurde
1124      var wenn_leer = $(this).data('target').data('wenn_leer');
1125
1126      //hier muss auf length < 6 abgefragt werden, da sonst js weiter unten 
1127      //bei substr(0, 6) aussteigen kann.
1128      if (wenn_leer == 'undefined' || wenn_leer.length < 6) {
1129        //Entspricht dem Normalfall
1130        var check = 0;
1131        $('#leer_alternativtext').val('');
1132      }
1133      else if (wenn_leer == "[HIDE]") {
1134        //Entspricht, dass die Felder versteckt werden.
1135        var check = 1;
1136        $('#leer_alternativtext').val('');
1137      }
1138      else if (wenn_leer.substring(0, 6) == "[TEXT]") {
1139        //Entspricht einen Alternativtext.
1140        var check = 2;
1141        $('#leer_alternativtext').val(wenn_leer.substring(6));
1142      }
1143      $(this).find(':radio').each(function () {
1144        if ($(this).val() == check) {
1145          $(this).prop('checked', true);
1146        }
1147      });
1148    }
1149  });
1150
1151  // Durch Drücken des Suchenbuttons wird der Dialog für die erweiterte Suche geöffnet
1152  $('.suchen_button, #suchen_ext').on('click', function () {
1153
1154    if (KuferTools && KuferTools.Spracheinstellungen) {
1155      $('#kurssuche').dialog('option', 'title', KuferTools.Spracheinstellungen.KursZusammengesetzt.Singular.Nominativ + 'filter:');
1156
1157    }
1158    $('#kurssuche').dialog('open');
1159    //Bei Drücken der Enter-Taste Formular abschicken
1160    $('form').find('input, select').on('keypress', function (event) {
1161      if (event.which === 13) {
1162        event.preventDefault();
1163        submitKurssuche();
1164      }
1165    });
1166  });
1167
1168  //Checkboxen für die Hinterlegungen Hinzufügen
1169  var $lisFuerCheckBox = $('ul.addCheckbox li:not(.sublist)');
1170  $lisFuerCheckBox.each(function () {
1171    var $checkbox = $('<input type="checkbox" class="hlauswahl" />');
1172    $checkbox.val($(this).children('span').text());
1173    $(this).find('label').prepend($checkbox);
1174  });
1175
1176
1177  //ÖffnenButton für den Dialog mit den hinterlegten Info Feldern
1178  $('#button_hl_info_felder, .button_hl_info_felder').on('click', function () {
1179    $('#dialog_hl_info_felder').dialog('open');
1180    // prevent the default action, e.g., following a link
1181    return false;
1182  });
1183
1184  $('#einreichenbutton').on('click', function () {
1185    showMessage('Haben Sie alle Noten eingetragen und wollen Sie die Eingabe abschließen?<br>Es können dann keine Noten mehr eingetragen werden.',
1186      'Bestätigung', {
1187      "Ja": function () {
1188        $('#einreichenpressed').val('1'); $(this).dialog("close"); $('#notenform').trigger('submit');
1189      },
1190      "Nein": function () { $(this).dialog("close"); }
1191    });
1192    return false;
1193  });
1194
1195
1196  /**
1197  * Validierung aktivieren
1198  */
1199  //Hier für die Eintragung der Noten
1200  $('#notenform input[type=text]').each(function () {
1201    $(this).on('change', validateNotenForm);
1202  });
1203
1204  KuferTools.InitAllgemeineHandler($('body'));
1205
1206  /*
1207   * Vergleicht zwei HTML-Objekte aufgrund ihrer Positionierung mittels CSS-style-Tag
1208   */
1209  function compareByCssPosition(a, b) {
1210    var $a = $(a);
1211    var $b = $(b);
1212
1213    var a_left = parseInt($a.css('left'), 10);
1214    var b_left = parseInt($b.css('left'), 10);
1215    var a_top = parseInt($a.css('top'), 10);
1216    var b_top = parseInt($b.css('top'), 10);
1217    if (isNaN(a_left) || isNaN(b_left) || isNaN(a_top) || isNaN(b_top)) {
1218      return 0;
1219    }
1220    a_left = a_left.length > 2 ? a_left.substring(0, a_left.length - 2) : a_left;
1221    b_left = b_left.length > 2 ? b_left.substring(0, b_left.length - 2) : b_left;
1222    a_top = a_top.length > 2 ? a_top.substring(0, a_top.length - 2) : a_top;
1223    b_top = b_top.length > 2 ? b_top.substring(0, b_top.length - 2) : b_top;
1224
1225    // alert("atop: " + a_top + " typ:  " + (typeof a_top) + " //btop: " + b_top + " //aleft: " + a_left + " //bleft: " + b_left);
1226    if (a_top == b_top) {
1227      return a_left - b_left;
1228    }
1229    else {
1230      return a_top - b_top;
1231    }
1232  }
1233
1234  // Tab-Reihenfolge berechnen
1235  var $allTabbableFields = $('#sightbuilderform input').add('#sightbuilderform textarea').add('#sightbuilderform select').not($('[readonly]'));
1236  $allTabbableFields.sort(compareByCssPosition);
1237
1238  var $index = 1;
1239  $allTabbableFields.each(function () {
1240    $(this).prop('tabindex', $index++);
1241  });
1242
1243  /**
1244   * Hilfsfunktion für die Tooltips von Eingabefeldern
1245   */
1246  function createToolTipRow(pBeschreibung, pText) {
1247    return '<div class="toolTipRow"><span class="toolTipLbl">' + pBeschreibung + ':</span><span class="toolTipCnt">' + pText + '</span></div>';
1248  }
1249
1250  // Für die Tooltips im Veranstaltungsplanungsformular von Herne (P14297)
1251  if ($('.veranstaltungsplanung').length > 0) {
1252    $allTabbableFields = $('.veranstaltungsplanung input').not('#verAnPlan_EssenLieferZeit');
1253  }
1254
1255  /**
1256   * Tooltip für Eingabefelder im Sightbuilder.
1257   * Gibt Hinweise zum Ausfüllen der Felder an. Benutzt hierzu die Validierung der Felder val_*
1258   * und ob das Feld ein Pflichtfeld ist.
1259   * 
1260   * Neben dem Pflichtfeld wird nur eine weitere Validierung berücksichtigt!
1261   */
1262  $allTabbableFields.tooltip({
1263    position: { my: "left bottom-5", at: "left top", collision: "flipfit" },
1264    items: '*',
1265    tooltipClass: 'sightbuilderformToolTip',
1266    content: function () {
1267
1268      var result = '';
1269
1270      if ($(this).hasClass('nicht_leer') || $(this).hasClass('form_mandatory')) {
1271        result += createToolTipRow('Pflichtfeld', 'Dieses Feld muss gef&uuml;llt werden');
1272      }
1273      if ($(this).hasClass('val_float') || $(this).hasClass('setting-inputnumeric')) {
1274        result += createToolTipRow('Kommazahl', 'Zahl mit Nachkommastellen (z. B. 25,33)');
1275      }
1276      else if ($(this).hasClass('val_int')) {
1277        result += createToolTipRow('Ganzzahl', 'Zahl ohne Nachkommastellen (z. B. 25)');
1278      }
1279      else if ($(this).hasClass('val_date')) {
1280        result += createToolTipRow('Datum', 'Tag.Monat.Jahr (Tag und Monat zweistellig, Jahr vierstellig, z. B. 31.12.2055)');
1281      }
1282      else if ($(this).hasClass('val_date_jahrkurz')) {
1283        result += createToolTipRow('Datum', 'Tag.Monat.Jahr (Tag, Monat und Jahr zweistellig, z. B. 31.12.55)');
1284      }
1285      else if ($(this).hasClass('val_time')) {
1286        result += createToolTipRow('Uhrzeit', 'Stunde:Minute (Stunde und Minute zweistellig, z. B. 09:45)');
1287      }
1288      else if ($(this).hasClass('val_einsnull')) {
1289        result += createToolTipRow('1 oder 0', 'J f&uuml;r positiv, N f&uuml;r negativ');
1290      }
1291      else if ($(this).hasClass('val_jn')) {
1292        result += createToolTipRow('J oder N', 'J f&uuml;r ja, N f&uuml;r nein');
1293      }
1294      if (result != '') {
1295        var infobox = $('.hinweisbox_prototype').clone();
1296        infobox.find('.hinweisbox .hinweisbox_body li').html(result);
1297        return infobox.html();
1298      }
1299      return '';
1300    }
1301  }).off("mouseover mouseout"); // soll nur auf Focusin und -out reagieren
1302
1303  // Init für die Tooltips der WSS-Felder mit Statusfarben. In einer Funktion gewrappt und anschließend gleich
1304  // aufgerufen, damit die Tooltips beim Nachladen mit Ajax nachträglich initialisiert werden können.
1305  KuferTools.InitStatusFarbeToolTip = function () {
1306    /**
1307     * Felder, welche den Belegungs/Kurstags/Kursstatus farbig anzeigen
1308     * Legende wird als Tooltip angezeigt
1309     */
1310    window.toolTipHackVar = new Array();
1311    $('.status_farbe').tooltip({
1312      items: '*',
1313      track: true,
1314      tooltipClass: 'box',
1315      show: false,
1316      hide: false,
1317      open: function () {
1318        // hässliche notfalllösung: Im IE8 werden beim ersten Öffnen die CSS3 eingenschaften
1319        // nicht ordentlich gerendert. Deshalb wird (nicht wahrnehmbar) der Tooltip beim ersten
1320        // öffnen kurz geschlossen und erneut geöffnet (für jede verschiedene legende separat)
1321        var farbeClass = $(this).prop('class').match(/[^ ]+_status_farbe/i)[0];
1322
1323        if ($.inArray(farbeClass, window.toolTipHackVar) == -1) {
1324          window.toolTipHackVar[window.toolTipHackVar.length] = farbeClass;
1325          $(this).tooltip('close');
1326          $(this).tooltip('open');
1327        }
1328      },
1329      // Kombination aus track und position kriegt tooltip nicht gut hin (tooltip öffnet und schließt sich die ganze zeit)
1330      //position: { my: "left top-35", at: "left bottom", collision: "flipfit" },
1331      content: function () {
1332
1333        var $kurs_status_farbe = $(this);
1334        var farbeClass = $(this).prop('class').match(/[^ ]+_status_farbe/i)[0];
1335
1336        $('.status_legende ul.status_legende_list li').each(function () {
1337          var htmlClass = $(this).prop('class');
1338          // Falls mehrere Klassen wird die benötigte Klasse ermittelt.
1339          htmlClass = htmlClass.match(/status_legende_[^ ]+/i)[0];
1340          var status = htmlClass.slice(htmlClass.indexOf('_', 7) + 1);
1341
1342          if ($kurs_status_farbe.hasClass('status_' + status)) {
1343            $(this).addClass('active');
1344          }
1345          else {
1346            $(this).removeClass('active');
1347          }
1348        });
1349        var $statusLegende = $('.' + farbeClass + ' .status_legende').first().clone();
1350        $statusLegende.children().show();
1351        return $statusLegende.html();
1352      }
1353    });
1354
1355  };
1356  KuferTools.InitStatusFarbeToolTip();
1357
1358  //var classAry = new Array('formelement.dozent_name', 'formelement.kurs_kurzbez', 'formelement.kursort_bezeichnung');
1359  //var classAry = new Array('formelement.kurs_kurzbez');
1360
1361  //Klasse kurstitel_blak wird für Mitarbeiterübersicht für Firmen benötigt.
1362  //Klasse tool_21_mitarbeiterkurs wird für Kursübersicht für Firmen benötigt, damit die
1363  // weiteren Kurse des Firmenmitarbeiters nicht zweizeilig dargestellt werden.
1364  var classAry = new Array('formelement', 'kurstitel_blak', 'tool_21_mitarbeiterkurs', 'belegungsstatus_blak', 'pkt_ok_stat', 'kontakt_email');
1365  //behandelt jedes Formelement aus obiger Klasse auf der angezeigten Seite 
1366  $.each(classAry, function (index, element) {
1367    KuferTools.Utils.kuerzeInhaltAufZeile(element);
1368  });
1369
1370  //Für die Kursübersichten und Neue Anmeldungen im TN-Tool können Felder auf die Kursdetails verlinkt werden.
1371  //Ebenso kann man Felder aus den Kursübersichten von allen anderen Tools auf die Kursdetails verlinken.
1372  //KuferTools.SetLinksFromFieldsToDetails enthält den Inhalt des Selectors
1373  if (typeof (KuferTools.SetLinksFromFieldsToDetails) != 'undefined' && KuferTools.SetLinksFromFieldsToDetails != '') {
1374    $(KuferTools.SetLinksFromFieldsToDetails).each(function () {
1375      var $detaillink = $(this).parents(".content_zeile").find(".steuerelemente a.details_link");
1376      if ($detaillink.length > 0) {
1377        $(this).html("<a href=\"" + $detaillink.prop("href") + "\">" + $(this).html() + "</a>");
1378      }
1379    });//.children().css("text-decoration", "none");
1380  }
1381
1382  //Für den Browser-Replay-Schutz wird vor dem Übermitteln von Post-Formularen ein
1383  //Hidden-Feld mit der Postid mitgesendet.
1384  // Live Event verwenden, damit Replay Schutz auch bei Formularen, die via JQUERY erzeugt werden, aktiviert wird;
1385  // anstatt: $('form').on('submit', function(){
1386  $(document).on('submit', 'form', function () {
1387    //Der Attributselector form[method="post"] ist casesensitive, und kann daher nicht verwendet werden.
1388    if (typeof ($(this).prop('method')) != 'undefined' && $(this).prop('method').toLowerCase() == 'post') {
1389      if (typeof (KuferTools.ReloadSchutz) != 'undefined' && typeof (KuferTools.ReloadSchutz.PostID) != 'undefined') {
1390        $(this).append('<input type="hidden" name="postId" value="' + KuferTools.ReloadSchutz.PostID + '">');
1391      }
1392    }
1393  });
1394
1395  // In verschiedenen Browsern werden Zeilenumbrüche mit verschiedener Zeichenanzahl berechnet.
1396  // Wir benötigen 2 Zeichen in der KuferSQL-DB für Zeilenumbrüche.
1397  $(document).on('input', 'textarea', function () {
1398    KuferTools.HandleTextareaMaxLength($(this));
1399  });
1400
1401  $('.submit').on('click', function () {
1402    $(this).parents('form').trigger('submit');
1403  });
1404
1405  //$(function(){KuferTools.MarkSelectedIds();});
1406});  //end document ready
1407
1408if (typeof (KuferTools) == "undefined") {
1409  registerNamespace('KuferTools');
1410}
1411
1412/**
1413 * In verschiedenen Browsern werden Zeilenumbrüche mit verschiedener Zeichenanzahl berechnet.
1414 * Wir benötigen 2 Zeichen in der KuferSQL-DB für Zeilenumbrüche.
1415 * 
1416 * Wenn ein Browser nun ein Zeichen pro Zeilenumbruch rechnet, 
1417 * beim Einfügen in der DB jedoch zwei Zeichen berechnet werden, kann die Maximallänge
1418 * des Datenbankfeldes überschritten werden, was du DB-Fehlern führen kann.
1419 * 
1420 * Chrome rechnet zwei Zeiche, fast alle anderen Browser ein Zeichen. Der IE rechnet 
1421 * bei maxlength ein zeichen, bei manchen JS-Funktionen jedoch zwei Zeichen.
1422 */
1423KuferTools.HandleTextareaMaxLength = function ($textarea) {
1424  var maxlength = $textarea.prop('maxlength');
1425
1426  if (maxlength >= 0) {
1427    var valueOrig = $textarea.val();
1428    var valueOrigLengthNlDoppelt = getLengthCountNlAs2(valueOrig);
1429
1430    // Sollte nur hier reinfallen, falls Zeilenumbrüche in dem Browser nur als ein Zeichen gewertet werden.
1431    if (valueOrigLengthNlDoppelt > maxlength) {
1432      var caretPos = KuferTools.Utils.Focus.getCursorStartPosition($textarea);
1433      var caretPosEnd = KuferTools.Utils.Focus.getCursorEndPosition($textarea);
1434
1435      var zuVielNlDoppelt = valueOrigLengthNlDoppelt - maxlength;
1436      var toReplaceLength = zuVielNlDoppelt; // Anzahl der zu ersetzenden Zeichen (nl zählt einfach). Wird hier für den Fall vorbesetzt, dass keine NL im zu ersetzenden Bereich sind.
1437
1438      // Es werden die Zeichen vor dem Carret entfernt, daher -zuVielNlDoppelt
1439      var maxToReplace = valueOrig.slice(caretPos - zuVielNlDoppelt, caretPos);
1440      var maxToReplaceNl = countLineBreaks(maxToReplace);
1441
1442      if (maxToReplaceNl > 0) {
1443        toReplaceLength = getToReplaceLength(caretPos, maxToReplaceNl, zuVielNlDoppelt, valueOrig);
1444      }
1445
1446      kuerzeText($textarea, caretPos, toReplaceLength, valueOrig);
1447      setCaretRange($textarea, caretPos, caretPosEnd, toReplaceLength, valueOrig);
1448    }
1449  }
1450
1451  /**
1452   * Vorgehensweise bei Leerzeilen im zu ersetzenden Bereich:
1453   * Bsp: 10 Zeichen zu viel, im zu ersetzenden String 2 nl (zählen doppelt) -> es müssen je nach Verteilung der nl nur 8 oder 9 Zeichen weggeschnitten werden.
1454   * Es wird nun der mindestens zu ersetzende Teil (8 Zeichen) auf nl geprüft. Falls nicht beide nl darin enthalten sind, werden so lange 
1455   * die nächsten Zeichen hinzugefügt (nl zählen wieder doppelt) bis zuVielNlDoppelt erreicht wird.
1456   */
1457  function getToReplaceLength(caretPos, maxToReplaceNl, zuVielNlDoppelt, valueOrig) {
1458    var posMinToReplace = caretPos - zuVielNlDoppelt + maxToReplaceNl;
1459    var minToReplace = valueOrig.slice(posMinToReplace, caretPos);
1460    var countNlMinToReplace = countLineBreaks(minToReplace);
1461    var toReplaceLength = minToReplace.length;
1462
1463    var toReplaceLengthNlDoppelt = minToReplace.length + countNlMinToReplace;
1464    for (var i = 0; toReplaceLengthNlDoppelt < zuVielNlDoppelt && i < maxToReplaceNl; i++) {
1465      var char = valueOrig.charAt(posMinToReplace - 1 - i); // -1 da das Element direkt vor dem zu ersetzenden Bereich unter
1465sucht wird.
1466      if (char == '\n' || char == '\r') {
1467        toReplaceLengthNlDoppelt = toReplaceLengthNlDoppelt + 2;
1468      } else {
1469        toReplaceLengthNlDoppelt = toReplaceLengthNlDoppelt + 1;
1470      }
1471      toReplaceLength = toReplaceLength + 1;
1472    }
1473    return toReplaceLength;
1474  }
1475
1476  function kuerzeText($textarea, caretPos, toReplaceLength, valueOrig) {
1477    $textarea.val(valueOrig.substring(0, caretPos - toReplaceLength) + valueOrig.substring(caretPos));
1478  }
1479
1480  function setCaretRange($textarea, caretPos, caretPosEnd, toReplaceLength, valueOrig) {
1481    if (typeof ($textarea[0].selectionStart) != 'undefined') {
1482      $textarea[0].selectionStart = caretPos - toReplaceLength;
1483      $textarea[0].selectionEnd = caretPosEnd - toReplaceLength;
1484    } else { // Lösung für IE.
1485      range = document.selection.createRange();
1486      // Nach dem Ändern eines Textareas setzt IE automatisch die Caret-Position ans Ende.
1487      range.moveStart("character", -(getLengthCountNlAs1(valueOrig) - caretPos + toReplaceLength - 1));
1488      range.moveEnd("character", -(getLengthCountNlAs1(valueOrig) - caretPosEnd + toReplaceLength - 1));
1489      range.select();
1490    }
1491  }
1492
1493  function countLineBreaks(text) {
1494    var countRs = text.split('\r').length - 1;
1495    var countNs = text.split('\n').length - 1;
1496    return Math.max(countRs, countNs);
1497  }
1498
1499  function getLengthCountNlAs2(str) {
1500    var strOhneNl = str.replace(/\r|\n/g, '');
1501    var strAnzahlNl = countLineBreaks(str);
1502    return strOhneNl.length * 1 + 2 * strAnzahlNl;
1503  }
1504
1505  function getLengthCountNlAs1(str) {
1506    var strOhneNl = str.replace(/\r|\n/g, '');
1507    var strAnzahlNl = countLineBreaks(str);
1508    return strOhneNl.length * 1 + strAnzahlNl;
1509  }
1510}
1511
1512/**
1513 * Kennzeichnet die ausgewählten KursIds als markiert
1514 * setzt die Checkboxen der selektierten KursIds auf markiert
1515 */
1516KuferTools.MarkSelectedIds = function () {
1517  if (KuferTools.SelectedIds) {
1518    for (var i = 0; i < KuferTools.SelectedIds.length; i++) {
1519      $('input.markable[name=' + KuferTools.SelectedIds[i] + ']').prop('checked', true);
1520    }
1521  }
1522};
1523
1524/**
1525 * Liefert die beim Seitenladen selektierten Ids (KuferTools.SelectedIds) + die jetzt angehakten
1526 * berücksichtigt damit auch Ids die vor dem hin- und herblättern bereits angehakt wurden 
1527 * Achtung: kann nur auf den Übersichtsseiten für Kurse, Teilnehmer etc. verwendet werden; ist für Detailsseiten nicht spezifisch genug und
1528 * somit nicht verwendbar, da dann die angehakten Ids mehrerer Reiter selektiert werden (z.B. Ids der Reiter Termine u. Teilnehmer)   
1529 * @param {HTMLElement|undefined} container
1530 * @return {(int|string)[]}
1531 */
1532KuferTools.GetSelectedIds = function (container) {
1533  var neueIds = KuferTools.GetIdsToSelect(container);
1534  var nichtMehrAktuelleIds = KuferTools.GetIdsToUnselect(container);
1535  var aktuelleIds = KuferTools.SelectedIds;
1536  if (nichtMehrAktuelleIds.length > 0) {
1537    for (var i = 0; i < nichtMehrAktuelleIds.length; i++) {
1538      aktuelleIds = jQuery.grep(aktuelleIds, function (item, index) {
1539        return item != nichtMehrAktuelleIds[i];
1540      });
1541    }
1542  }
1543  //var  = jQuery.grep(y, function(value) { return value != removeItem; });
1544  return [... new Set($.merge(aktuelleIds, neueIds))];
1545};
1546
1547/**
1548 * Holt sich die Values der Selektierten checkboxen, die nicht schon vorher markiert waren (KuferTools.KursUebersicht.SelectedIds)
1549 * und gibt sie in einem Array zurück;
1550 * @param {HTMLElement|undefined} container
1551 * @return {number[]}
1552 */
1553KuferTools.GetIdsToSelect = function (container) {
1554  /** @type {NodeListOf<HTMLInputElement>} */
1555  const selektierteIds = (container ?? document.body)
1556    .querySelectorAll('input.markable:checked');
1557  const result = [];
1558  for (const element of selektierteIds) {
1559    if (window.getComputedStyle(element).display === 'none') {
1560      continue;
1561    }
1562
1563    if (!KuferTools.SelectedIds.includes(element.value)) {
1564      result.push(element.value);
1565    }
1566  }
1567
1568  return result;
1569};
1570
1571/**
1572 * Gibt die Ids zurück, die deselektiert werden müssen
1573 * @param {HTMLElement|undefined} container
1574 * @return {number[]}
1575 */
1576KuferTools.GetIdsToUnselect = function (container) {
1577  /** @type {NodeListOf<HTMLInputElement>} */
1578  const unselektierteIds = (container ?? document.body)
1579    .querySelectorAll('input.markable:not(:checked)');
1580  const result = [];
1581  for (const element of unselektierteIds) {
1582    //Wenn die aus der Selektion zu entfernende Id im Array der bereits Selektierten IDs vorkommt, wird sie der Rückgabemenge
1583    //hinzugefügt
1584    if (KuferTools.SelectedIds.includes(element.value)) {
1585      result.push(element.value);
1586    }
1587  }
1588
1589  return result;
1590};
1591
1592/**
1593 * @returns {FormData}
1594 */
1595KuferTools.GetUrlPartForIdSelectionFormData = function() {
1596  const result = new FormData();
1597
1598  const toUnselect = KuferTools.GetIdsToUnselect();
1599  if (toUnselect.length > 0) {
1600    result.set('idsToUnmark', toUnselect.join(':'));
1601  }
1602
1603  const toSelect = KuferTools.GetIdsToSelect();
1604  if (toSelect.length > 0) {
1605    result.set('idsToMark', toSelect.join(':'));
1606  }
1607
1608  return result;
1609}
1610
1611/**
1612 * Gibt einen Teil des Urlparameters für das Markieren zurück
1613 * 
1614 * @param {boolean} pUseAnd Gibt an ob das '&' vor die Url gestellt werden soll. Optional: falls nicht gesetzt wird es als true interpretiert
1615 * @returns {string} URL Teil z.B. idsToMark=14:17:84
1616 */
1617KuferTools.GetUrlPartForIdSelection = function (pUseAnd) {
1618  /** @type {FormData} */
1619  let formData = KuferTools.GetUrlPartForIdSelectionFormData();
1620
1621  /** @type string[] */
1622  let result = [];
1623  for (const [key, val] of formData.entries()) {
1624    result.push(encodeURIComponent(key) + "=" + encodeURIComponent(val));
1625  }
1626
1627  let strResult = result.join('&');
1628  if (strResult.length === 0) {
1629    return '';
1630  }
1631
1632  if (pUseAnd) {
1633    return '&' + strResult;
1634  }
1635
1636  return strResult;
1637}
1638
1639/**
1640 * Schließt den zuletzt per showMessage geöffneten Dialog.
1641 */
1642KuferTools.closeCurrentKuferDialog = function () {
1643  if (typeof (KuferTools.DialogWindows) != 'undefined') {
1644    if (KuferTools.DialogWindows.length > 0)
1645      KuferTools.DialogWindows[KuferTools.DialogWindows.length - 1].dialog('close');
1646  }
1647}
1648
1649/* Zentrale Einstellungen */
1650
1651/*****************************************************************************
1652 * Plus / Minus funktion für inputnumeric felder - angelehnt an die admin - settings.js 
1653 *  
1654 * Bei Feldern welche mit inputnumeric definiert sind wird ein Plus- und  
1655 * Minus-Symbol angehängt, über welches sich die Zahl erhöhen bzw. vermindern 
1656 * lässt.
1657 *****************************************************************************
1658 */
1659$(function () {
1660
1661  //Kursdetails => buttonleiste_kursdetails => Arbeitsbericht fürs BFI
1662  // wird auch im Tool Anwesenheit beim Anwesenheiten eintragen genutzt
1663  $("#dozListDruckButtonArbeitsbericht").on('click', function (event) {
1664    event.preventDefault();
1665    var msg = '<form id="dozListDruckButtonArbeitsberichtForm">';
1666    msg += '<input type="checkbox" id="zeitraumBeschraenken" name="zeitraumBeschraenken" value="1"> <label for="zeitraumBeschraenken">Nur die Tage </label>';
1667    msg += '<label for="ktvon">vom </label><input id="ktvon" name="ktvon" type="text" class="hasDatePicker date" length="12"> bis ';
1668    msg += '<label for="ktbis">zum </label><input id="ktbis" name="ktbis" type="text" class="hasDatePicker date" length="12"> berücksichtigen<br><br>';
1669    msg += '<input type="checkbox" id="nur_meine" name="nur_meine" value="1"> <label for="typ_alleDoz">nur meine Arbeitsberichte</label><br>';
1670    msg += '</form>';
1671
1672    var buttons = {
1673      "Ok": function () {
1674        var liste = 'KurstageArbeitsbericht';
1675        if (jQuery('#dozListDruckButtonArbeitsberichtForm #nur_meine').is(':checked') == 1)
1676          liste = 'KurstageArbeitsberichtAktDoz';
1677
1678        var linkDatumBereich = '';
1679        if (jQuery('#dozListDruckButtonArbeitsberichtForm #zeitraumBeschraenken').is(':checked') == 1) {
1680          var aktVal = jQuery('#dozListDruckButtonArbeitsberichtForm #ktvon').val();
1681          if (aktVal != '')
1682            linkDatumBereich += '&kt_von=' + aktVal;
1683          aktVal = jQuery('#dozListDruckButtonArbeitsberichtForm #ktbis').val();
1684          if (aktVal != '')
1685            linkDatumBereich += '&kt_bis=' + aktVal;
1686        }
1687        var newlink = '';
1688        if (typeof KuferTools.KursDetails === 'undefined') {
1689          newlink = 'printDruckListe.php?tool_id=1&fastprint=' + liste + '&selnr=' + KuferTools.Anwesenheiten.Kursnr + linkDatumBereich;
1690        }
1691        else {
1692          newlink = 'printDruckListe.php?tool_id=1&fastprint=' + liste + '&selnr=' + KuferTools.KursDetails.Kurs.Knr + linkDatumBereich;
1693        }
1694        //window.location.href = newlink;
1695        //besser:  Öffnen auf neuer Seite
1696        window.open(newlink, '_blank');
1697        $(this).dialog("close");
1698      },
1699      "Abbrechen": function () {
1700        $(this).dialog("close");
1701      }
1702    }
1703    showMessage(msg, 'Arbeitsberichte', buttons);
1704    jQuery('#dozListDruckButtonArbeitsberichtForm input.date').on('change', function () {
1705      jQuery('#dozListDruckButtonArbeitsberichtForm input#zeitraumBeschraenken').prop('checked', true);
1706    });
1707    jQuery('#dozListDruckButtonArbeitsberichtForm input#zeitraumBeschraenken').on('change', function () {
1708      if (!jQuery(this).is(':checked')) {
1709        jQuery('#dozListDruckButtonArbeitsberichtForm input.date').val('');
1710      }
1711    }
1712    );
1713  });
1714
1715  $('.inputnumeric input').each(function () {
1716    $(this).parent().children(':last')
1717      .after('<span class="count-buttons"><img class="count" src="images/plus.png" alt="+1" title="Wert um 1 erh&ouml;hen" /><img class="count" src="images/minus.png" alt="-1" title="Wert um 1 vermindern" /></span>')
1718      .parent().children('span.count-buttons').children('img.count').on('click', function () {
1719
1720        var input = $(this).parent().parent().children('input');
1721        var maxLength = parseInt(input.prop('maxlength'));
1722
1723        if (maxLength > -1 == false) {
1724          maxLength = -1; //maxlength war nicht definiert.
1725        }
1726        //Falls das input Feld disabled ist, soll +/- keine Aktion (Erhoehen, vermindern des Werts) auslösen
1727        if ($(input).prop('disabled')) {
1728          return;
1729        }
1730        if (input.val() == '')
1731          input.val(0);
1732
1733        var val = parseInt(input.val()) + parseInt($(this).prop('alt'));
1734
1735        //Validation:
1736        //Falls zuvor keine Zahl im Inputfeld stand.
1737        if (val.toString() == 'NaN') {
1738          val = 0;
1739        }
1740        //Nur Zahlen größer als 0!
1741        if (input.hasClass('bigger-null') && val <= 0) {
1742          val = 1;
1743          //Nur Zahlen größer-gleich 0
1744        } else if (input.hasClass('bigger-equal-null') && val < 0) {
1745          val = 0;
1746        }
1747
1748        if (val.toString().length <= maxLength || maxLength == -1)
1749          input.val(val);
1750      });
1751
1752  });
1753
1754  /**
1755   * Dadurch, dass "nur eigene Kurstage" der Standardwert bei "Folgende Kurstage anzeigen:" ist, 
1756   * dürfen die Plus und Minus Bilder bei dem Aufruf des Tools 18 bei "Tage, die Lehrgangsleiter in "Aktuelle Kurstage" zurückblättern können:" auch standardmäßig nicht angezeigt werden. 
1757   */
1758  if ($('#ktBackScroll4Leiter').length > 0) {
1759
1760    if ($('input[name=showKurstage]:checked').val() != "leiter") {
1761      $('#ktBackScroll4Leiter').prop('disabled', true);
1762      $('#ktBackScroll4Leiter').parent().children('.count-buttons').css('display', 'none');
1763    }
1764  }
1765
1766  // Input Feld für Leiter disablen, wenn nicht Radiobutton für Lehrgangsleiter ausgewählt wurde
1767  $('input[name="showKurstage"]').on('click', function () {
1768    var $this = $(this);
1769    if ($this.val() === "leiter") {
1770      $('#ktBackScroll4Leiter').prop('disabled', false);
1771      $('#ktBackScroll4Leiter').parent().children('.count-buttons').css('display', 'inline');
1772    }
1773    else {
1774      $('#ktBackScroll4Leiter').prop('disabled', true);
1775      $('#ktBackScroll4Leiter').parent().children('.count-buttons').css('display', 'none');
1776    }
1777  });
1778
1779
1780  $('#settingUseNoteSelect').on('change', function () {
1781    if ($(this).prop('checked')) {
1782      $('.settingNotenSelect').show();
1783    } else {
1784      $('.settingNotenSelect').hide();
1785    }
1786  });
1787
1788  $('#settingUseNoteSelect').trigger('change');
1789
1790  /**
1791   * Funktionen für die Veranstaltungsplanung von Herne im Hausmeistertool P14297
1792   */
1793
1794  if (KuferTools.isResponsive === true) {
1795    KuferTools.VeranstaltungsPlanungResponsive();
1796  }
1797
1798  /**
1799   * Wenn die Anzahl geändert wird, wird die dazugehörige Checkbox gesetzt
1800   */
1801  $('.veranstaltungsplanung input.verAnPlan_medien_anz').on('change', function () {
1802    var name = $(this).prop('name');
1803    var checkBoxVal = name.split('_')[2];
1804    $(this).parents('td').find('input[value=' + checkBoxVal + ']').prop('checked', true);
1805  });
1806  /**
1807   * Wenn die Software angegeben wird, wird die dazugehörige Checkbox gesetzt
1808   */
1809  $('.veranstaltungsplanung input.verAnArt_SoftWare').on('change', function () {
1810    $(this).parents('td').find('input[value=Software]').prop('checked', true);
1811  });
1812  /**
1813   * Wenn die Geschirrart angegeben wird, wird "Geschirr benötigt" gesetzt
1814   */
1815  $('.veranstaltungsplanung input#verAnPlan_GeschirrArt').on('change', function () {
1816    $('input[name=verAnPlan_Geschirr][value=true]').prop('checked', true);
1817  });
1818  /**
1819   * Wenn die Rechnungsanschrift geändert wird, wird die Checkbox "Fremdfinanzierung" gesetzt
1820   */
1821  $('.veranstaltungsplanung textarea#varAnPlan_FremdFinanzierung_TextArea').on('change', function () {
1822    $('input#varAnPlan_FremdFinanzierung').prop('checked', true);
1823  });
1824  /**
1825   * Wenn bei den Checkboxen "wird nicht benötigt" ausgewählt wird, so werden alle anderen
1826   * Checkboxen und eingabefelder der Zelle disabled.
1827   */
1828  $('.veranstaltungsplanung .varAnPlan_nichtBenoetigt').on('change', function () {
1829    if ($(this).is(':checked')) {
1830      $(this).parents('.hasCheckboxen').find('input').not('.varAnPlan_nichtBenoetigt').prop('disabled', true);
1831    } else {
1832      $(this).parents('.hasCheckboxen').find('input').not('.varAnPlan_nichtBenoetigt').prop('disabled', false);
1833    }
1834  });
1835  $('.veranstaltungsplanung .varAnPlan_nichtBenoetigt').trigger('change');
1836  $('.veranstaltungsplanung .val_time').timepicker({});
1837  $('.veranstaltungsplanung form input').on('change', function () {
1838    validateInput($(this));
1839  });
1840
1841  /**
1842   * Submitbutton.
1843   * Zunächst wird geprüft, ob eingabefelder falsch ausgefüllt wurden. (z. B. val_int)
1844   * Dann wird geprüft, ob alle Pflichtangaben getätigt wurden.
1845   * Zuletzt werden die bedingen Pflichtangaben geprüft (z. B. wenn Software angehakt, muss der name angegeben werden)
1846   * Wenn alles in Ordnung ist, wird das Formular abgesendet, sonst ein Hinweis ausgegeben.
1847   */
1848  $('.veranstaltungsplanung .veranstaltungsplanung_submit').on('click', function () {
1849
1850    if (!validateForm($('.veranstaltungsplanung form input').not('#verAnPlan_EssenLieferZeit'))) {
1851      showMessage('Einige Felder wurden nicht korrekt ausgefüllt. Bitte überprüfen Sie die ' +
1852        'rot markierten Felder.', 'Das Formular ist nicht korrekt ausgefüllt');
1853      return;
1854    }
1855
1856    //Array von Strings mit den Bezeichnungen der noch zu beantwortenden Formularfelder
1857    var emptyMandatory = [];
1858    // Pflichtfelder. Wird nicht über form_mandatory gemacht, da das in diesem Formular nicht so gut passt
1859    $('.pflichtfeld').each(function () {
1860      if (trim($(this).val()) === '') {
1861        emptyMandatory[emptyMandatory.length] = $('label[for=' + $(this).prop('id') + ']').text();
1862      }
1863    });
1864
1865    // Überprüfung der Checkboxfelder
1866    $('.hasCheckboxen').each(function () {
1867      if ($(this).find(':checked').length == 0) {
1868        if ($(this).parent('div').length != 0) {
1869          emptyMandatory[emptyMandatory.length] = $(this).parent('div').find('label').first().text();
1870        } else {
1871          emptyMandatory[emptyMandatory.length] = $(this).parents('tr').find('td').first().text();
1872        }
1873      }
1874    });
1875
1876    // Überprüfung, ob zu den Medien die Anzahl angegeben wurde
1877    $('.verAnPlan_medien :checked').not('[disabled=disabled]').not('#verAnPlan_MedienMaterial_nb').each(function () {
1878      var bezeichnung = $(this).val();
1879      var anzahl = $('input[name=medien_anz_' + bezeichnung + ']').val();
1880      if (!parseInt(anzahl, 10) > 0) {
1881        emptyMandatory[emptyMandatory.length] = 'Bitte die ' + bezeichnung + '-Anzahl angeben.';
1882      }
1883    });
1884
1885    // Überprüfung, ob die Software angegeben wurde, falls diese gesetzt ist.
1886    if ($('.verAnPlan_Netzwerk input[value=Software]:checked').length > 0
1887      && trim($('.verAnArt_SoftWare').val()) == '') {
1888      emptyMandatory[emptyMandatory.length] = 'Bitte den Namen der Software angeben.';
1889    }
1890    // Überprüfung, ob die Lieferuhrzeit gesetzt ist, falls der Lieferant angegeben wurde.
1891    if (trim($('#verAnPlan_LieferantNamen').val()) != ''
1892      && trim($('#verAnPlan_EssenLieferZeit').val()) == '') {
1893      emptyMandatory[emptyMandatory.length] = 'Bitte geben Sie an, wann der Lieferant das Essen liefert.';
1894    }
1895    // Überprüfung, ob die Geschirrart angegeben wurde, falls "Geschirr benötigt" angegeben ist.
1896    if ($('#verAnPlan_Geschirr_true:checked').length > 0
1897      && trim($('#verAnPlan_GeschirrArt').val()) == '') {
1898      emptyMandatory[emptyMandatory.length] = 'Bitte geben Sie die Art des Geschirrs an.';
1899    }
1900    // Überprüfung, ob die Rechnungsanschrift angegeben wurde, falls Fremdfinanzierung angegeben wurde.
1901    if ($('#varAnPlan_FremdFinanzierung:checked').length > 0
1902      && trim($('#varAnPlan_FremdFinanzierung_TextArea').val()) == '') {
1903      emptyMandatory[emptyMandatory.length] = 'Bitte geben Sie die Rechnungsanschrift mit an.';
1904    }
1905
1906    var emptyManLength = emptyMandatory.length;
1907    if (emptyManLength > 0) {
1908      var message = 'Bitte füllen Sie folgende Formularfelder:';
1909      message += '<ul>';
1910      for (var i = 0; i < emptyManLength; i++) {
1911        message += '<li>' + emptyMandatory[i] + '</li>';
1912      }
1913      message += '</ul>';
1914      showMessage(message, 'Das Formular ist nicht vollständig ausgefüllt');
1915    } else {
1916      $('.veranstaltungsplanung form').trigger('submit');
1917    }
1918  }); //end Klickhandler $('.veranstaltungsplanung .veranstaltungsplanung_submit')
1919
1920}); //end $(function() ...
1921
1922KuferTools.VeranstaltungsPlanungResponsive = function () {
1923
1924  /**
1925  * Wenn die Anzahl geändert wird, wird die dazugehörige Checkbox gesetzt
1926  */
1927  $('.veranstaltungsplanung input.verAnPlan_medien_anz').on('change', function () {
1928    var name = $(this).prop('name');
1929    var checkBoxVal = name.split('_')[2];
1930    $(this).parent('div').parent('div').find('input[value=' + checkBoxVal + ']').prop('checked', true);
1931  });
1932  /**
1933   * Wenn die Software angegeben wird, wird die dazugehörige Checkbox gesetzt
1934   */
1935  $('.veranstaltungsplanung input.verAnArt_SoftWare').on('change', function () {
1936    $(this).parent('div').parent('div').find('input[value=Software]').prop('checked', true);
1937  });
1938  /**
1939   * Wenn die Geschirrart angegeben wird, wird "Geschirr benötigt" gesetzt
1940   */
1941  $('.veranstaltungsplanung input#verAnPlan_GeschirrArt').on('change', function () {
1942    $('input[name=verAnPlan_Geschirr][value=true]').prop('checked', true);
1943  });
1944  /**
1945   * Wenn die Rechnungsanschrift geändert wird, wird die Checkbox "Fremdfinanzierung" gesetzt
1946   */
1947  $('.veranstaltungsplanung .verAnPlan_FremdFinanzierung_TextArea').on('change', function () {
1948    $('input#varAnPlan_FremdFinanzierung').prop('checked', true);
1949  });
1950
1951  if (KuferTools.FormVersendet === true) {
1952    // Besetzt die Felder erneut mit den Eingaben nach submit
1953    $("select[name='verAnPlan_RaumNr']").val(KuferTools.RaumNr);
1954    $("select[name='verAnPlan_Bestuhlung']").val(KuferTools.Bestuhlung);
1955    if (KuferTools.MedienMaterialien.length === 0) {
1956      $("input[name='verAnPlan_MedienMaterial_nb']").prop('checked', true);
1957    } else {
1958      $.each(KuferTools.MedienMaterialien, function (name, value) {
1959        $("input[value='" + name + "']").prop('checked', true);
1960        $("input[name='medien_anz_" + name + "']").val(value);
1961      });
1962    }
1963    if (KuferTools.Gedeck.length === 0) {
1964      $("input[name='verAnPlan_Gedeck_nb']").prop('checked', true);
1965    } else {
1966      $.each(KuferTools.Gedeck, function (name, value) {
1967        $("input[value='" + value + "']").prop('checked', true);
1968      });
1969    }
1970    if (KuferTools.Deko.length === 0) {
1971      $("input[name='verAnPlan_Deko_nb']").prop('checked', true);
1972    } else {
1973      $.each(KuferTools.Deko, function (name, value) {
1974        $("input[value='" + value + "']").prop('checked', true);
1975      });
1976    }
1977    if (KuferTools.Getraenke.length === 0) {
1978      $("input[name='verAnPlan_Getraenke_nb']").prop('checked', true);
1979    } else {
1980      $.each(KuferTools.Getraenke, function (name, value) {
1981        $("input[value='" + value + "']").prop('checked', true);
1982      });
1983    }
1984    if (KuferTools.EDV.length === 0) {
1985      $("input[name='verAnPlan_Netzwerk_nb']").prop('checked', true);
1986    } else {
1987      $.each(KuferTools.EDV, function (name, value) {
1988        $("input[value='" + value + "']").prop('checked', true);
1989      });
1990    }
1991    if (KuferTools.Geschirr === 'true') {
1992      $("input[id='verAnPlan_Geschirr_true']").prop('checked', true);
1993    } else {
1994      $("input[id='verAnPlan_Geschirr_false']").prop('checked', true);
1995
1996    }
1997  }
1998};
1999
2000/**
2001 * Initialisiert einen Standard-Datepicker für die übergebenen Input-Elemente
2002 * 
2003 * Es wird ein Datumsformat mit 4-Stellige Jahreszahl ausgegeben, die Jahre können via Select geändert werden
2004 * 
2005 * @param jQuery $target
2006 */
2007KuferTools.InitDatePicker = function ($pTarget) {
2008  $pTarget.datepicker({
2009    changeYear: true,
2010    constrainInput: true,
2011    dateFormat: "dd.mm.yy",
2012    yearRange: 'c-80:c+10'
2013  });
2014};
2015
2016/**
2017 * Initialisiert einen Standard-Datepicker für die übergebenen Input-Elemente
2018 * 
2019 * Es wird ein Datumsformat mit 4-Stellige Jahreszahl ausgegeben, die Jahre können via Select geändert werden
2020 * 
2021 * @param jQuery $target
2022 */
2023KuferTools.InitDateTimePicker = function ($pTarget) {
2024  $pTarget.datetimepicker({
2025    changeYear: true,
2026    constrainInput: true,
2027    dateFormat: "dd.mm.yy",
2028    yearRange: 'c-80:c+10',
2029    timeFormat: "HH:mm"
2030  });
2031};
2032
2033/**
2034 * Initialisiert allgemeine Handler, z. B. Datepicker.
2035 * 
2036 * Kann z.B. nach dem Aufruf von Dialogen aufgerufen werden, damit 
2037 * die neuen Elemente ebenfalls mit z.B. Datepicker initialisiert werden.
2038 * 
2039 * @param Selector $pContainer Selector auf das Containerelement mit den 
2040 *                             noch nicht selektierten Elementen
2041 */
2042KuferTools.InitAllgemeineHandler = function ($pContainer) {
2043  //Allgemeinen Kalender zuweisen.
2044  KuferTools.InitDatePicker($('.hasDatePicker', $pContainer));
2045
2046  //Kalender für die Anwesenheiten
2047  KuferTools.InitDatePicker($('input.date', $pContainer));
2048
2049  //Kalender für vierstellige Jahreszahl
2050  KuferTools.InitDatePicker($('input.val_date', $pContainer));
2051
2052  //Kalender mit Uhrzeit
2053  KuferTools.InitDateTimePicker($('input.val_datetime', $pContainer));
2054
2055  //Kalender für zweistellige Jahreszahl
2056  $('input.val_date_jahrkurz', $pContainer).datepicker({
2057    changeYear: true,
2058    constrainInput: true,
2059    dateFormat: "dd.mm.y",
2060    yearRange: 'c-80:c+10'
2061    //dateFormat: "D., dd.mm.y" //angezeigtes Datumsformat
2062  });
2063
2064  $('input.hasTimePicker').timepicker({});
2065  $('input.val_time').timepicker({});
2066
2067  $('textarea[maxlength]', $pContainer).on('input', function () {
2068    var max = parseInt($(this).prop('maxlength'));
2069    if ($(this).val().length > max) {
2070      $(this).val($(this).val().substring(0, $(this).prop('maxlength')));
2071    }
2072  });
2073};
2074
2075/**
2076 * Erzeugt für HtmlFreiWaehlbaresEingabefeld.php die Hinterlegungs-Dialoge für die
2077 * Hinterlegungs-Buttons
2078 * 
2079 * @param array pHinterlegung array von Objekten. [{value: X, spalte1:X1, spalte2:X2..}, {...}]
2080 *                                               value: Wert, welcher beim Klick auf die Zeile verwendet wird,
2081 *                                               der Rest sind Inhalte für die Spalten (Schlüssel wird als Überschrift verwendet).
2082 * @param string pTargetId Id des Feldes, welches durch die Hinterlegung gefüllt werden soll.
2083 */
2084KuferTools.ShowHinterlegungsDialog = function (pHinterlegung, pTargetId) {
2085
2086  var countHinterlegung = pHinterlegung.length;
2087  if (countHinterlegung === 0) {
2088    return '';
2089  }
2090
2091  var titel = $('label[for="' + pTargetId + '"]').text();
2092  var $message = $('<div><table><thead><tr></tr></thead><tbody></tbody></table></div>');
2093  var thead = '';
2094  var $tbodyTr;
2095
2096  // Pro Array-Element von pHinterlegung wird eine Zeile in der Tabelle angelegt.
2097  for (var i = 0; i < countHinterlegung; i++) {
2098    $tbodyTr = $('<tr class="hl_zeile ' + ((i % 2 === 0) ? 'farbe_sicht_erstezeile' : 'farbe_sicht_zweitezeile') + '"></tr>');
2099    // Pro Attribut (abgesehen von value) wird eine Spalte angezeigt.
2100    jQuery.each(pHinterlegung[i], function (key, val) {
2101      if (key === 'value') {
2102        // Das Clickevent muss innerhalb der Schleife gesetzt werden mit dem Parameter val.
2103        // wenn val in einer anderen Variable zwischengespeichert wird (z. B. value), und das Clickevent nach dem
2104        // each erzeugt wird, machen die Closures einen Strich durch die Rechnung, da der letzte Wert von
2105        // value für alle Click-Events verwendet.
2106        $tbodyTr.on('click', function () {
2107          $('#' + pTargetId).val(val);
2108          $($message).dialog('close');
2109        });
2110      } else {
2111        // Von der ersten Zeile werden die Spaltenüberschriften abgeleitet.
2112        if (i === 0) {
2113          thead += '<th>';
2114          thead += '<b>' + key + '</b>';
2115          thead += '</th>';
2116        }
2117        // Genau genommen ist das Unsauber, da derzeit die Attribute der Objekte immer
2118        // in der gleichen Reihenfolge erwartet werden.
2119        $tbodyTr.append('<td>' + val + '</td>');
2120      }
2121    });
2122
2123    $message.find('tbody').append($tbodyTr);
2124  }
2125  $message.find('thead tr').append(thead);
2126
2127  var buttons = { 'Abbrechen': function () { $(this).dialog('close'); } };
2128  showMessage($message, titel, buttons, 'auto');
2129};
2130
2131KuferTools.TinyMCE = function (cssSelector) {
2132  tinymce.init({
2133    selector: cssSelector,
2134    language: 'de',
2135    width: '79%',
2136    skin: 'kufer_blau',
2137    plugins: "image, link, hr",
2138    toolbar: [
2139      "undo redo  | bold italic underline strikethrough subscript superscript forecolor backcolor | fontselect fontsizeselect",
2140      "alignleft aligncenter alignright alignjustify | bullist, numlist outdent indent hr | link image | removeformat ",
2141    ],
2142    font_formats: 'Arial=arial,helvetica,sans-serif; Courier New=courier new,courier,monospace; Times New Roman=times new roman,times; Verdana=verdana,geneva;',
2143    menu: {
2144      edit: { title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall' },
2145      insert: { title: 'Insert', items: 'link image' },
2146      format: { title: 'Format', items: 'bold italic underline strikethrough superscript subscript | formats | removeformat' },
2147    }
2148  });
2149};
2150
2151KuferTools.TinyMCEResponsive = function (cssSelector, pErrorBlock) {
2152  tinymce.init({
2153    selector: cssSelector,
2154    language: 'de',
2155    width: '100%',
2156    skin: 'kufer_grau',
2157    plugins: "image, link, hr",
2158    toolbar: [
2159      "undo redo  | bold italic underline strikethrough subscript superscript | forecolor backcolor | fontselect | fontsizeselect",
2160      "alignleft aligncenter alignright alignjustify | bullist, numlist outdent indent hr | link image | removeformat ",
2161    ],
2162    font_formats: 'Arial=arial,helvetica,sans-serif; Courier New=courier new,courier,monospace; Times New Roman=times new roman,times; Verdana=verdana,geneva;',
2163    menu: {
2164      edit: { title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall' },
2165      insert: { title: 'Insert', items: 'link image' },
2166      format: { title: 'Format', items: 'bold italic underline strikethrough superscript subscript | formats | removeformat' },
2167    },
2168    setup: function (editor) {
2169      editor.on('init', function () {
2170        var input = tinyMCE.activeEditor.getContent({
2171          format: 'text'
2172        });
2173        if (input.trim() == '') {
2174          editor.getBody().style.backgroundColor = "#f7bec1";
2175          pErrorBlock.addClass('form_error');
2176        } else {
2177          editor.getBody().style.backgroundColor = "#fff";
2178          pErrorBlock.removeClass('form_error');
2179        }
2180      });
2181      editor.on('change', function () {
2182        tinyMCE.triggerSave();
2183
2184        var input = tinyMCE.activeEditor.getContent({
2185          format: 'text'
2186        });
2187        if (input.trim() == '') {
2188          editor.getBody().style.backgroundColor = "#f7bec1";
2189          pErrorBlock.addClass('form_error');
2190        } else {
2191          editor.getBody().style.backgroundColor = "#fff";
2192          pErrorBlock.removeClass('form_error');
2193        }
2194      });
2195    }
2196  });
2197};
2198
2199KuferTools.removeHinterlegungen = function () {
2200  $('#hlberuf_div').remove();
2201  $('#hlsperrvermerk_div').remove();
2202};

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.