<%@language = "javascript"%>
<% /*
     $Revision$
     $Id$
*/ %>

<%
var ANONYMOUS_Allowed = 1;
var DOCTYPE_Disable = 1;
var FCLTEXPIRES = 8*60; // geen database interactie tenslotte
%>

<!-- #include file="../Shared/common.inc" -->

<%
Response.ContentType = "text/javascript";
%>

/*
i volgnr
ktype 'D', 'C', 'N' etc.
klen lengte
kdec decimalen
kmin kmax
*/

function checkRequiredGroup(group, params)
{
  params = params || {};
  var has_emptyvalue = typeof(params.emptyvalue) != "undefined"; // Er kan een empty waarde meegegeven zijn die als lege waarde opgevat moet worden, bijvoorbeeld als aantal 0 is.
  var requiredgroup = "required" + group;
  var groupisrequired = false;
  var rgroup = $("." + requiredgroup);

  for (var i = 0; i < rgroup.length; i++)
  {
    var rgvalue   = rgroup[i].value;
    var tagName   = rgroup[i].tagName;
    var tagType   = rgroup[i].type;
    var isbijlage = rgroup[i].getAttribute("isBijlage")==1;
    var bijlage   = rgroup[i].getAttribute("nBijlagen");
    var ischecked = rgroup[i].checked;

    var hasInput    = false;
    var hasSelect   = (tagName == "SELECT" && rgvalue > 0);
    var hasBijlage  = (tagName == "INPUT" && isbijlage && bijlage > 0);
    var hasCheckbox = false;
    if (tagType == "checkbox")
      hasCheckbox = (tagName == "INPUT" && tagType == "checkbox" && ischecked);
    else
      hasInput = (((tagName == "INPUT" || tagName == "TEXTAREA") &&
                   ((!has_emptyvalue && rgvalue != "") || (has_emptyvalue && rgvalue != 0))) &&
                  !isbijlage);

    if (hasInput || hasSelect || hasBijlage || hasCheckbox)
    {
      groupisrequired = true;
      break;
    }
  }

  if (groupisrequired)
  {
    $("." + requiredgroup).addClass("required")
                          .attr("required", "required");
    for (var i = 0; i < rgroup.length; i++)
    { // Als checkbox dan toch verplicht is, vink maar aan.
      if (rgroup[i].type == "checkbox" && !rgroup[i].checked)
      {
        rgroup[i].checked = true;
        $(rgroup[i]).change();
      }
    }
  }
  else
  {
    $("." + requiredgroup).removeClass("required")
                          .removeAttr("required");
  }
}

var in_use = false; // Semaphore(Seinvlag) om nested loop van de alerts van twee velden met te lange invoer te vermijden.
function checkKenmerk(field, show, ktype, klen, kdec, kmin, kmax, params)
{
  params = params || {};
  var valid = true;
  if (!in_use)
  {
    in_use = true;
    var value = field.value;
    var error = L("lcl_mld_invalid_kenmerk_format");

    if (value != '')
    {
      if (ktype == 'D')
      {
        $(field).change(cal_show_onChange);

        // Native datepicker of jQuery datepicker?
        // Kopie uit kenmerk_common.inc
        var touchdevice = (typeof window.orientation !== "undefined") || (typeof window.ontouchstart !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
        var native = !(typeof Modernizr == "undefined" || !Modernizr.inputtypes.date || !touchdevice);

        // Test of er nu een geldig datumformaat staat.
        // [YYYY-MM-DD] for native pickers,
        // [DD-MM-YYYY] voor jQuery datepicker
        var regex = native ? /^(\d{1,4})[-](\d{1,2})[-](\d{1,2})$/
                           : /^(\d{1,2})[-](\d{1,2})[-](\d{1,4})$/;
        var arr = regex.exec(value);
        if (arr)
        {
          var date = native ? arr[3] : arr[1];
          var month = arr[2];
          var year = native ? arr[1] : arr[3];
          var dt = new Date(year, month-1, date);

          if (date != dt.getDate() || month != dt.getMonth() + 1 || (year != dt.getYear() && year != dt.getFullYear()))
          {
            valid = false;
          }
        }
        else valid = false;
      }
      else if (ktype == 'T')
      {
        // sta toe 14 -> 14:00h
        // sta toe 930 -> 9:30h
        // sta ook allerlei separators toe.
        var TIME_RE = /^(\d*)[\/\.\-\: ]?(\d\d?)?$/;
        posstime = value.match(TIME_RE);
        if (posstime && posstime.length && !isNaN(parseInt(posstime, 10)))  // er moet minstens iets goed zijn
        {
          var hh = parseInt(posstime, 10);
          mm = 0;
          if (posstime.length > 1 && posstime[2])
          {
            var mm = parseInt(posstime[2],10);
          }
          else // 930 voor 9:30h
            if (hh > 100)
            {
                mm = hh % 100;
                hh = Math.floor(hh / 100);
            }
          hh = hh % 24;
          mm = mm % 60;
          // Opgeschoonde waarde opslaan
           $(field).val(String((hh<10?"0":"")+hh) + ":" + String((mm<10?"0":"")+mm), true);

          if (kmin || kmax)
          {
              var kval = parseFloat(hh + "." + mm);
              kmin = kmin ? parseFloat(kmin.split(":").join(".")) : 0;
              kmax = kmax ? parseFloat(kmax.split(":").join(".")) : 24;
              if (kmin > kval || kval > kmax)
              {
                  valid = false;
                  error = L("lcl_mld_kenmerk_out_range");
              }
          }
        }
        else
            valid = false;
      }
      else if (ktype == 'C' || ktype == 'L' || ktype == 'Q')
      { // newlines verdubbelen naar %0D%0A dus aantal regels bijtellen
        if (value.length + (value.split("\n").length-1) > klen) valid = false;
      }
      // new fieldtype "checkbox"
      else if (ktype == 'V')
      {
      }
      else if (ktype == 'N')
      {
        allowInputExpression(field);
        value = field.value; // mogelijk gewijzigd
        var arrValue = [value];
        var check_minmax;
        for (var i = 0; i < arrValue.length; i++)
        {
          if (kdec)
          {
            var l1 = klen-kdec;
            var l2 = kdec;
            // Als een punt én een komma in een getal behouden we alleen de laatste
            if (arrValue[i].lastIndexOf(".") > arrValue[i].lastIndexOf(","))
            {
                value.replace(arrValue[i], arrValue[i].replace(/\,/ig, ""));
                field.value = value;
            }
            if (arrValue[i].lastIndexOf(",") > arrValue[i].lastIndexOf("."))
            {
                value.replace(arrValue[i], arrValue[i].replace(/\./ig, ""));
                field.value = value;
            }

            // Als er een relatieve waarde is ingevuld, dan kan de uiteindelijke waarde niet clientside berekend worden bij multi wijzigen.
            // Controle moet dan plaats vinden bij het opslaan.
            check_minmax = false;
            if (params.relativeValuesAllowed && arrValue[i].match("%"))
              var s = '^[-\\+]?(\\d{1,'+Math.max(1, l1)+'}[.,]?|\\d{0,'+l1+'}[.,]\\d{1,'+l2+'})[%]$';    // RegExpr for currency field with % sign and with mandatory + or -
            else if (params.relativeValuesAllowed && arrValue[i].match(/^\+{2}|-{2}/))
              var s = '^(\\+{2}|-{2})(\\d{1,'+Math.max(1, l1)+'}[.,]?|\\d{0,'+l1+'}[.,]\\d{1,'+l2+'})$'; // RegExpr for currency field with ++ (add) or -- (sub) without % sign
            else
            {
              var s = '^[-\\+]?(\\d{1,'+Math.max(1, l1)+'}[.,]?|\\d{0,'+l1+'}[.,]\\d{1,'+l2+'})$';       // RegExpr for currency field without % sign
              check_minmax = true;
            }

            valid = arrValue[i].match(new RegExp(s)) && valid;

            if (check_minmax)
              if (valid) { var t = parseFloat(arrValue[i].replace(',','.'));}
          }
          else
          {
            check_minmax = true;
            var s = '^[-\\+]?\\d{1,'+klen+'}[.,]?$';
            valid = arrValue[i].match(new RegExp(s)) && valid;
            if (valid) { var t = parseInt(arrValue[i]);}
          }
        }
        if (check_minmax && valid && ktype != 'T') // Time wordt hierboven al gecontroleerd
        {
          if ((kmin !== null) && (t < kmin)) { valid = false; error = L("lcl_mld_kenmerk_out_range"); }
          if ((kmax !== null) && (t > kmax)) { valid = false; error = L("lcl_mld_kenmerk_out_range"); }
        }
      }
    }
    validateField(field, valid, error);
    if (!show && valid && field.className.match(/required\d*S\d*/g) && field.className.match(/required\d*S\d*/g).length > 0)
    { // Er is een required groep aanwezig.
      var requiredgroup = field.className.match(/required\d*S\d*/g)[0];
      var group = requiredgroup.substr(8);
      checkRequiredGroup(group, params);
    }

    in_use = false;
    return valid;
  }
  return false; // inuse
}

// Op een generieke manier documenten openen
// DWF bestanden worden eventueel met de SLNKDWF viewer geopend
// Poweruser IE feature: Ctrl ingedrukt opent DWF bestanden toch 'gewoon'
function openDoc(filepath)
{
<%if (S("view_dwf_with_slnkdwf"))
  { %>
    if (!(window.event && event.ctrlKey) && filepath.toUpperCase().match('.DWF'))
      FcltMgr.windowopen("../SLNKDwf/ShowDWF.asp?relfile=" + filepath,'facDoc',"");
    else
<%} %>
      FcltMgr.windowopen(filepath);
      // Unsafe:
      // FcltMgr.windowopen(filepath, 'facDoc', "");
}

// Data komt terug van de closeModal
function bijlagen_callback(data, orgParams)
{
  var btn = orgParams.params.objButton;
  if (btn)
  {
    btn.setAttribute("nBijlagen", data.cnt);
    if (orgParams.params.multi) // ktype == "M"
    {
      btn.value = L("lcl_appendixes_teller").format(data.cnt);
    }
    else
    {
      // Sla de naam op in het hidden field met het name attribuut zodat we de naam ook in de kenmerk-tabel opslaan
      $(btn).parent(".button-icon-wrapper").siblings("[name=" + btn.id + "]").val(data.fileName || "");

      if ($(btn).hasClass("signature")) { // Handtekening
        var $img = $(btn).parent(".button-icon-wrapper").siblings("img.kenmerk");
        if (data.fullPath) {
          $img.one("load", function () { FcltMgr.resized(); });
          $img.attr("src", data.fullPath);
        } else {
          $img.attr("src", "");
          FcltMgr.resized();
        }
      } else {
        btn.value = data.fileName || L("lcl_add");
      }
    }
    if (btn.onchange)
      btn.onchange(); // Omdat input veld readonly is wordt de onchange niet automatisch uitgevoerd.
  }

  if (orgParams.params.saveUrl)
  {
      $.post(orgParams.params.saveUrl, { flexVal: data.fileName }); // DIRECT opslaan in de database
  }
}
// encrypt geeft aan of bestand encrypted moet worden.
function onBijlagen(formurl, // protected
                    saveUrl, // protected
                    multi,
                    objButton)
{
  var params = { multi: multi, objButton: objButton};
  // Voor de zekerheid slaan we wijziging van de bestandsnaam direct op.
  // op het filesysteem is het namelijk ook al 'gecommit'

  params.saveUrl = saveUrl;
  allparams = {params: params,
               callback: bijlagen_callback,
               XXXXalwaysCallback: true,
               noClose: true  // Voor bijlagenscherm dus geen close-knopje (kruisje) in rechter bovenhoek.
              };
  FcltMgr.openModalDetail(formurl, L("lcl_appendixes"), allparams );
}

function xmlNodeDetails(key, xmlnode)
{
  var url = "";
  switch (xmlnode.toLowerCase())
  {
    case "afdeling"     :   url = "appl/prs/prs_afdeling.asp?key=" + key; break;
    case "afspraak"     :   url = "appl/bez/bez_afspraak.asp?afspr_key=" + key + "&urole=fo"; break;
    case "bedrijf"      :   url = "appl/prs/prs_bedrijf.asp?bedrijf_key=" + key; break;
    case "bestelling"   :   url = "appl/bes/bes_bestelling.asp?bes_key=" + key + "&urole=fo"; break;
    case "bestelopdr"   :   url = "appl/bes/bes_opdr.asp?ordernr=" + key + "&urole=fo"; break;
    case "contract"     :   url = "appl/cnt/cnt_contract.asp?cnt_key=" + key + "&urole=bo"; break;
    case "deel"         :   url = "appl/ins/ins_deel.asp?ins_key=" + key + "&urole=bo"; break;
    case "factuur"      :   url = "appl/fin/fin_factuur.asp?fin_key=" + key; break;
    case "gebouw"       :   url = "appl/alg/alg_gebouw.asp?key=" + key; break;
    case "locatie"      :   url = "appl/alg/alg_locatie.asp?key=" + key; break;
    case "melding"      :   url = "appl/mld/mld_melding.asp?mld_key=" + key + "&urole=fo"; break;
    case "message"      :   url = "appl/msg/msg_message.asp?message_key=" + key + "&urole=bo"; break;
    case "opdracht"     :   url = "appl/mld/mld_opdr.asp?opdr_key=" + key + "&urole=bo"; break;
    case "perslid"      :   url = "appl/fac/fac_user.asp?prs_key=" + key; break;
    case "reservering"  :   url = "appl/res/res_reservering.asp?rsv_ruimte_key=" + key + "&urole=fo"; break;
    case "xreservering" :   url = "appl/res/res_reservering.asp?reservering_key=" + key + "&urole=fo"; break;
    case "ruimte"       :   url = "appl/alg/alg_ruimte.asp?key=" + key; break;
    case "scenario"     :   url = "appl/prj/prj_scenario.asp?prj_key=" + key; break;
    case "verdieping"   :   url = "appl/alg/alg_verdieping.asp?key=" + key; break;
    default             :   break;
  }
  if (url != "")
    FcltMgr.openDetail(url, L("lcl_job_product"), {callback: FcltMgr.reload});
}

// Argumenten, als niet expliciet gedefinieerd;
//  data, textStatus, jqXHR (de default $.ajax callback argumenten)
// Als wel expliciet gedefinieerd
//  data, mobile (boolean), context (jQuery-selector-string voor als er meerdere flex-marker's op de pagina staan, bijv. bij artikel-kenmerken)
async function flexReloaded(data, mobile, context) {
  if (typeof mobile === "boolean" && mobile === true) {
    $("[id^=flx_]").remove();
  } else {
    $(".flexblock").remove();
  }
  const $getFlexMarker = _ => {
    if (typeof context === "string") {
      return $(context).find("flex-marker");
    } else {
      return $("flex-marker");
    }
  }
  $getFlexMarker().replaceWith(data);
  let $fld = $getFlexMarker().parent().find("[id$=_data][data-module]"); // #k_data
  const calculateFlexExpressionPromises = [];
  $fld.each((i, elem) => {
    calculateFlexExpressionPromises.push(calculateFlexExpressions(elem));
  });
  await Promise.all(calculateFlexExpressionPromises);
  FcltMgr.resized();
}

var fvalid; // definition of fvalid in case a HTML element uses its value without declaring first
$(function() {
  $(function() { // Truukje zodat deze pas als laatste 'onReady' wordt uitgevoerd, zodat de suggests in ieder geval gedefinieerd zijn (of ze klaar zijn is nog niet zeker)
    calculateFlexExpressions(undefined, true);
  });
});

// Processes any evaluated ##EXPR## and ##SHOW## expressions
function callback_flex_expr_info(json)
{
  for (var kenmerk=0; kenmerk < json.length; kenmerk++)
  {
    // save  initial visibility state of field
    var $visibleElem;
    switch (json[kenmerk].kenmerktype) {
      case "S": $visibleElem = $("#Suggest" + json[kenmerk].kfieldid + "_show"); break;
      case "r": $visibleElem = $("[name=" + json[kenmerk].kfieldid + "val").eq(0); break;
      default: $visibleElem = $("#" + json[kenmerk].kfieldid + "val"); break;
    }
    var initialVisible = $visibleElem.is(":visible");

    // Fill the attribute "default" if it isn't defined yet. The parameter "json[kenmerk].waarde" contains the current/correct value for new and existing calls.
    if (!$visibleElem.attr("default"))
      $visibleElem.attr("default", json[kenmerk].waarde);

    if ($visibleElem.hasClass("flexshow") ||
        (["L", "X"].indexOf(json[kenmerk].kenmerktype) > -1 && $("label[for=" + json[kenmerk].kfieldid + "val]").hasClass("flexshow")) ||
        (["L"].indexOf(json[kenmerk].kenmerktype) > -1 && $("label[for=" + json[kenmerk].kfieldid + "val]").closest("tr").hasClass("flexlabel")) ||
        (["l"].indexOf(json[kenmerk].kenmerktype) > -1 && $("#" + json[kenmerk].kfieldid + "val").closest("div.card").hasClass("flexlabel")) ||
        ($(".flexshow", $("#" + json[kenmerk].kfieldid + "val").closest("tr")).length > 0)
      )
    {
      if (typeof mobile == "object") // PDA has in mobile.inc an object "mobile" while the desktop has not
      {
        if (json[kenmerk].kenmerktype == "L")
        {
          var $fld = $("#" + json[kenmerk].kfieldid + "val");
          $fld = $fld.add($("label[for=" + json[kenmerk].kfieldid + "val]"));
        }
        else if (json[kenmerk].kenmerktype == "S")
        {
          var $fld = $("#Suggest" + json[kenmerk].kfieldid + "_show").closest("div").not('[data-role=content]').not('div.ui-collapsible-content');
          $fld = $fld.add($("label[for=" + json[kenmerk].kfieldid + "val]"));
        }
        else if (json[kenmerk].kenmerktype == "r")
        {
          var $fld = $("[name=" + json[kenmerk].kfieldid + "val").closest(".ui-radio");
          $fld = $fld.add($("label[for=" + json[kenmerk].kfieldid + "val]"));
        }
        else if (json[kenmerk].kenmerktype == "D" || json[kenmerk].kenmerktype == "T")
        {
          var $fld = $("#" + json[kenmerk].kfieldid + "val").closest(".input-icon-wrapper");
          $fld = $fld.add($("label[for=" + json[kenmerk].kfieldid + "val]"));
        }
        else
        {
          var $fld = $("#" + json[kenmerk].kfieldid + "val:not(textarea)").closest("div").not('[data-role=content]').not('div.ui-collapsible-content');
          if ($fld.length == 0) {
            $fld = $("textarea#" + json[kenmerk].kfieldid + "val"); // textarea has no parent div
          }
          if (json[kenmerk].kenmerktype == "F") {
            $fld = $fld.add($fld.next(".button-icon-wrapper"));
          }
          $fld = $fld.add($("label[for=" + json[kenmerk].kfieldid + "val]"));
        }
        $fld.toggle(json[kenmerk].exprwaarde != 0 && json[kenmerk].exprwaarde != null);
      }
      else
      {
        if (json[kenmerk].kenmerktype == "L")
        {
          var $td = $("label[for=" + json[kenmerk].kfieldid + "val]").closest("td");
          $td.add($td.next(".lhint")).toggle(json[kenmerk].exprwaarde != 0 && json[kenmerk].exprwaarde != null);
        }
        else if (json[kenmerk].kenmerktype == "l")
        {
            var $div = $("#" + json[kenmerk].kfieldid + "val").closest("div.card");
            if (json[kenmerk].exprwaarde != 0 && json[kenmerk].exprwaarde != null)
                $div.show();
            else
                $div.hide();
        }
        else
        {
          // hide table row when characteristic is invisible
          $visibleElem.closest("tr").toggle(json[kenmerk].exprwaarde != 0 && json[kenmerk].exprwaarde != null);
        }
      }

      var $fld = $("#" + json[kenmerk].kfieldid + "val");
      var $fld_show = $("#Suggest" + json[kenmerk].kfieldid + "_show");

      var listboxOrSuggest = json[kenmerk].kenmerktype == "R" || json[kenmerk].kenmerktype == "r" || json[kenmerk].kenmerktype == "S";
      var valueIsEmpty = $fld.val() === undefined ||
                          listboxOrSuggest
                            ? $fld.val() === null || $fld.val() == -1
                            : $fld.val() == "";

      if (json[kenmerk].exprwaarde == 0 || json[kenmerk].exprwaarde == null)
      {
        // Save default value in flex field
        if (initialVisible) // We hebben een zichtbaar veld nu conditioneel onzichtbaar gemaakt
        {
          if ($fld.length && $fld.attr("type") == "checkbox") { $fld.attr("default", $fld.prop("checked") ? "1" : "0"); }
          $("#" + json[kenmerk].kfieldid + "val").attr("default", json[kenmerk].waarde);
          var $fld = $("#" + json[kenmerk].kfieldid + "val");
          if ($fld.length && $fld.attr("type") == "checkbox" && !$fld.prop("checked")) { $fld.prop("checked", $fld.attr("default") == "1"); }
        }
        // erase the value when the field is hidden and the field has a value
        if ($fld.length && $fld.attr("type") == "checkbox") { if ($fld.prop("checked")) $fld.prop("checked", false); }   // uncheck checkbox
        else if ($fld_show.length) { // Suggest
          if ($fld_show.attr("sgcurrentvalue")) {
            $fld_show.attr("sgcurrentvalue", "").val(""); // empty suggest
          }
        }
        else if (!$fld.attr("nBijlagen") && !valueIsEmpty) { $fld.attr("disabled", "disabled"); }                        // disable the field so the value doesn't get submitted
      }
      // Restore the fields value when the field changes from invisible to visible
      else if (!initialVisible) // We hebben een onzichtbaar veld nu conditioneel zichtbaar gemaakt
      {
        if ($fld.length && $fld.attr("type") == "checkbox") { if (!$fld.prop("checked")) $fld.prop("checked", $fld.attr("default") == "1"); } // default check/uncheck checkbox
        else if ($fld_show.length) { // Suggest
          if (!$fld_show.attr("sgcurrentvalue")) {
            $fld_show.attr("sgcurrentvalue", $fld.attr("default")); // defaultvalue for suggest
          }
        }
        else if (!$fld.attr("nBijlagen") && !valueIsEmpty) { $fld.removeAttr("disabled"); }                                                   // reinstate the previously filled out value
        else if (!$fld.attr("nBijlagen") && valueIsEmpty) {  $fld.val($fld.attr("default")); }                                                // default value for field
      }
    }
    else
    {
      // Indien het een expressie kenmerk veld is zoals bij objecten, met een volgnummer 900 of hoger, dan wordt het kenmerk readonly weergegeven voor BO.
      // De functie isReadonly in de bestanden xxx_flexkenmerk.inc regelen die readonly status.
      // De waarde van het kenmerk komt dan tussen een <div> of <span> tag te staan.
      // Mocht de functie isReadonly false opleveren en dus niet readonly, dan zorg de EXPRESSIE er wel voor dat het kenmerk readonly wordt weergegeven.
      // De waarde komt dan echter wel in een <input> of <textarea> veld te staan.
      // Staat de waarden in een input of textarea veld, dan moet de waarde met een ".val()" aangepast worden.
      // Staat de waarde tussen een div of span, dan moet de waarde op een iets andere manier worden aangepast.
      if (!$("#" + json[kenmerk].kfieldid + "val").is(":hidden"))
        $("#" + json[kenmerk].kfieldid + "val").val(json[kenmerk].waarde);
      else if ($("#" + json[kenmerk].kfieldid + "val").closest("td").find("div").length)              // Betreft readonly 900+ karakterveld met 50 tekens of meer (Tussen <div>).
        $("#" + json[kenmerk].kfieldid + "val").closest("td").find("div").text(json[kenmerk].waarde)
      else if ($("#" + json[kenmerk].kfieldid + "val").closest("td").find("span").length)             // Betreft readonly 900+ karakterveld met minder dan 50 tekens (Tussen <span>).
        $("#" + json[kenmerk].kfieldid + "val").closest("td").find("span").text(json[kenmerk].waarde)
    }
  }
  $("div.time-holder").each(function() { $(this).css('top', "").css('left', ""); });
  FcltMgr.resized();

  // Resolve value
  return true;
}

// Evaluates the values of any ##EXPR## and ##SHOW## expressions
function calculateFlexExpressions(field, showOnly)
{
  let $forms,
      promises = [];
  if (typeof field === "undefined") {
    $forms = $("form");
  } else {
    $forms = $(field.form);
    var nameprefix = field.id.replace(/^Suggest/, '').replace(/(_data|\d+(_show|val|(_\d{1,2})?))$/, '');
  }

  $forms.each(async (index, form) => { // Dit moet toch per formulier gebeuren, ook al is het er maar 1, nu zijn we future-proof
    let nameprefixes = [];
    if (typeof field === "undefined") { // Vind dan eerst alle nameprefixes
      $(form).find("[name=nameprefix]").each((index, elem) => nameprefixes.push(elem.value));
    } else {
      nameprefixes = [nameprefix];
    }
    for (let i = 0; i < nameprefixes.length; i++) {
      let $data = $("#" + nameprefixes[i] + "_data"); // Dit veld is er alleen als er ook expressies zijn
      let $flds = $(form).find("[name^=" + nameprefixes[i] + "], [name^=has_" + nameprefixes[i] + "]");
      if (showOnly) {
        var awaitPromises = [];
        $flds.filter("[name$=t]").each(async (i, elem) => {
          if ($(elem).val() === "S" &&
              window["Suggest" + elem.name.slice(0, -1)] instanceof Suggest)
          {
            awaitPromises.push(window["Suggest" + elem.name.slice(0, -1)].sgReadyState)
          }
        });
        await Promise.all(awaitPromises);
      }

      if ($data.length && (!showOnly || $data.data("any-show") == 1) && $flds.has("div.bad").length == 0) {
        let params = $flds.serialize()
                   + "&module=" + $data.data("module")
                   + "&refkey=" + $data.data("refkey")
                   + "&niveau=" + $data.data("niveau")
                   + "&nameprefix=" + nameprefixes[i]
                   + "&extraserie=" + ($data.data("extraserie") ? 1 : 0)
                   + "&RVT_token=" + encodeURIComponent(window.RVT_token);
        promises.push(
          new Promise((resolve, reject) => {
            $.when($.post(rooturl+"/appl/Shared/calculate_flex_expr.asp",
                          params,
                          null,
                          "json")).then((data, textStatus, jqXHR) => {
              let success = jqXHR.status == 200 && callback_flex_expr_info(data);
              resolve(success);
            }).fail((response) => {
              reject("Failed $.post to 'calculate_flex_expr.asp' => " + response.statusText + " (" + response.status + ")");
            });
          }).catch((errmsg) => {
            console.error(errmsg);
          })
        );
      }
    }
  });

  return Promise.all(promises);
}

function multi_fld_change(pfld, ptxt, pparams)
{   // Wordt gebruikt in xxx_edit_kenmerk_multi om het checkveld vooraan aan te vinken als er een waarde in het dataveld wordt ingevuld.
    //
    var fld = (pparams ? $("#"+pparams.suggestid)[0] : pfld);
    // Zetten vinkje als je waarde invult
    if ($(fld).is(":checkbox"))
    {
        var isgevuld = $(fld).is(":checked")
    }
    else if ($(fld).is("select"))
    {   // Als er een tekst is ingevuld is er ook een waarde ingevuld. De value kan dan null of "" zijn.
        // Bijvoorbeeld bij alg_ruimte heeft het veld "Alleen op werkdagen" een lege waarde voor de selectie "Volgens gebouw".
        var selected_val = $(fld).val() > 0;
        var selected_txt = ($(fld).find(":selected").attr("selected") ? false : true);
        var isgevuld = (selected_val || selected_txt) ;
    }
    else if ($(fld).hasClass("suggest"))
    {   // Suggest veld: In kenmerk_common wordt de functie multi_fld_change aan sgOnchange gekoppeld.
        // Deze krijgt 3 parameters terug: geselecteerde_key, geselecteerde_tekst, object met suggestid.
        var isgevuld = $(fld).attr("sgcurrentvalue") != "";
    }
    else
    {   // De overige veldtypen
        var isgevuld = ($(fld).val() != "");
    }

    var fldcheck = "mcb_" + $(fld).attr("name").replace("Suggest","").replace("_show","val");
    $("#" + fldcheck).prop("checked", (isgevuld));

    multi_cb_change();
}

function multi_change(fldcheck)
{   // Wordt gebruikt in xxx_edit_kenmerk_multi om het dataveld leeg te maken als het vinkje vooraan wordt weggehaald.
    //
    var deze = $("#"+$(fldcheck).attr("data-name"))[0];
    if (!$(fldcheck).is(":checked"))
    {   // Vinkje verwijderen
        if (deze.tagName === "SELECT")
        {
            deze.selectedIndex = 0;
        }
        else if ($(deze).hasClass("suggest"))
        {
            $("#" + deze.id.substr(0, deze.id.length-5)).val(-1);
            $("#" + deze.id).attr("sgkey", "");
            $("#" + deze.id).attr("sgcurrentvalue", "");
            $(deze).val("");
        }
        else if (deze.type === "checkbox")
        {
            deze.checked = false;
        }
        else
        {
            $(deze).val("");
        }
    }
    else
    {   // Vinkje zetten.
        if ($(this).attr("req_" + $(this).attr("name")) == "true")
        {
            $(deze).addClass("required");
        }
    }

    multi_cb_change();
}

function multi_cb_change()
{
    var has_changes = false;
    var km_list = $("#multikenmerkList").find("tbody");
    $(km_list).find("tr td.multi_cb input").each(function()
        { // Kijk of er tenminste 1 van de kenmerken is aangevinkt om te worden gewijzigd.
            has_changes |=  $("#" + this.id).prop("checked");
        });

    var km_body = $("#multikenmerkList").closest("body")[0];
    var km_submit = $(km_body).attr("kenmerk_submit");
    if (has_changes)
        $("#"+km_submit).show();
    else
        $("#"+km_submit).hide();
}

<% ASPPAGE_END(); %>
