<% /*
     $Revision$
     $Id$

     File:          iface.inc
     Description:   generic interface functions for buttons and maybe more
                    __Logging & 64 onderdukt de suppressEmpty functionaliteit
*/ %>
<!-- #include file="../FontAwesome/icons.inc" -->
<%
if (JSON_Result)
    __SafeLog("<span style='background-color:#0ff'>JSON_Result staat aan, dan is iface.inc includen erg onlogisch.</span>");

FCLTHeader.Requires({ plugins: ["jQuery", "bootstrap", "masonry", "modernizr"], js: ["iface.js"]})
var isPrinting = getQParamInt("print", 0) == 1;

function CreateButton_HTML(tekst, onClick, btn, params)
{
  btn = btn || {};
  params = params || {}; // voor alle buttons
  if (params.showIcons == null) params.showIcons = true;
  var html = '\n';
  var hasIcon = (params.showIcons || btn.showIcon) && btn.icon; /* showIcons is de facto de default geworden eigenlijk... */
  var cls = (params.isDialog? "dialog ": "")
          + (btn.importance == 1 ? "emphasishigh " : (btn.importance == 2 ? "emphasismedium " : (btn.importance == 3 ? "emphasislow " :"emphasishigh ")))
          + (btn.xclass ? btn.xclass : "")
          + (("order" in btn) ? " ordered" : "");
  if (!params.isDialog && tekst)
  {
    if (!btn.tooltip) // Alles voor de eerste \n komt in de button, alles erna in de tooltip
    {
        var arr = tekst.split("\n");
        tekst = arr[0];
        // In de tooltip hoeven we de tekst niet (ook) nog een keer te tonen
        // Let wel: Omdat we ooit responsive op een klein scherm de teksten
        //          onderdrukken dan moet de tooltip toch blijven
        //          maar dat is alleen als er een icon bij is (anders zou je sowieso niks zien)
        if (!hasIcon)
          arr.shift(); // eerste er af
        btn.tooltip = arr.join("\n");
    }
  }
  var display = params.display || "block";
  html += '<li ' + ' class="' + cls + '"'
        + (btn.tooltip?' title="' + safe.htmlattr(btn.tooltip) + '"' : "")
        + (btn.singlepress? ' singlepress=1':'')
        + (("order" in btn) || params.vertical
          ? ' style="'
          + (btn.order ? 'order: ' + btn.order + ';' : '')
          + (params.vertical? 'display:' + display + ';' : '')
          + '"'
          : '')
        + ' onClick="iface.button.click(event, this)"'
        + ' fcltClick="' + safe.htmlattr(onClick) + '"'
        + (btn.id != null ?' id="' + btn.id + '"' : '')
        + ' tabindex="0"'
        + ' onkeypress="this.click()"'
        + '>';
  if (hasIcon)
  {
      html += I(btn.icon);
      if (params.TooltipIsText && btn.tooltip)
      {
          html += '<div class="dialogtext">' + safe.html(btn.tooltip) + '</div>';
      }
      else
      {
          if (tekst)
          {
            //Response.write("<span class='icontxt'>"+safe.html(tekst)+"</span>");
            html += '<span>' + safe.html(tekst) + '</span>';
          }
      }
  } else if (tekst) {
      html += '<span>' + safe.html(tekst) + '</span>';
  }
  html += '</li>';
  return html;
}
function CreateButton(tekst, onClick, btn, params) //akey, id, params)
{
    Response.Write(CreateButton_HTML(tekst, onClick, btn, params));
}

// Buttons is een hash
// Velden: title, action en id
// params: {    showIcons   : false    boolean om (alleen) de icons te tonen en niet de teksten
//              showText    : true     boolean om de tekst te doen
//              vertical    : false
//              autoshowOnly: false
//              autoshow    : false
//         }
var HAMBUTTONS = S("buttons_in_hamburger");
function CreateButtons_HTML(buttons, params)
{
  var html = '';
  params = params || {};
  if (typeof params.showText == "undefined") params.showText = true;

  if (buttons)
  {
    var btn_cnt = buttons.length;
    if (params.autoshowOnly) {
      btn_cnt = 0;
      for (var i = 0; i < buttons.length; i++) {
        btn_cnt += buttons[i].autoshow ? 1 : 0;
      }
    }
    html += '<div id="buttons" class="' + (params.vertical ? 'vertical ' + (btn_cnt >= 5 ? 'condensed ' : ''): '') + (params.isDialog?'dialog':'') + '">'
          + '<ul onclick="FcltMgr.stopPropagation(event);">';
    if (params.entersubmit)
    {
      html += '<li class="hiddenbutton"><input type="submit" style="height:0;width:0" tabindex="-1"' + (params.formid ? ' form="' + params.formid + '"' : '') + '></li>';
    }
    var hambuttons = [];
    var hasRefreshButton = false;
    var hasPrintButton = false;
    for (var i = 0; i < buttons.length; i++)
    {
        var btn = buttons[i];
        hasRefreshButton = hasRefreshButton || btn.icon == "fa-fclt-refresh";
        hasPrintButton = hasPrintButton || btn.icon == "fa-print";
        if (!params.autoshowOnly || btn.autoshow)
          if ((buttons.length > 2 && !params.isModal && !params.vertical && inArray(btn.icon, HAMBUTTONS)) || (params.inhamburger && !btn.showAlways) || btn.horizontalRule)
            hambuttons.push(i)
          else
            html += CreateButton_HTML(btn.title, btn.action, btn, params);
    }
    if (hasRefreshButton == false && hasPrintButton == true && !params.isModal && Request.ServerVariables("REQUEST_METHOD") == "GET")
    {
      buttons.push({ icon: "fa-fclt-refresh", title: L("lcl_refresh"), action: "FcltMgr.reload()", id: "btn_scf_refresh" });
      hambuttons.push(buttons.length - 1);
    }
    if (hambuttons.length)
    {
      params.inlineId = params.inlineId || "";
      var btn = { icon: "fa-bars", tooltip: L("lcl_more"), id: "printhamburger",
                  action: "$('li.byDropdown').toggleClass('hidden', true);$('li.byHamburger"+params.inlineId+"').toggleClass('hidden');FcltMgr.resized(null, { noMasonry: true });" }
      html += CreateButton_HTML(null, btn.action, btn, params );

      // z-index floating header = 10, so z-index hamburger = 11
      html += "<div id=\"buttons\" class=\"hambdropdown\"><ul onclick=\"FcltMgr.stopPropagation(event);\">";
      for (var x in hambuttons) {
          var btn = buttons[hambuttons[x]];
          if (btn.horizontalRule) {
            html += '<hr'
                  + (btn.order ? ' style="order: ' + btn.order + '"' : '')
                  + '>'
          } else {
            var hambAction = "$('li#printhamburger').find('> .fa-times').toggleClass('fa-bars fa-times');$('li.byHamburger"+params.inlineId+"').toggleClass('hidden');";
            btn.xclass = "hidden byHamburger" + params.inlineId;
            html += CreateButton_HTML(btn.title, hambAction + btn.action, btn, { showIcons: true, vertical: true });
          }
      }
      html += '</ul></div>';
    }
    html += '</ul>'
          + '</div><div id="layoutfixer" style="clear:right"></div>';
  }
  return html;
}
function CreateButtons(buttons, params)
{
    Response.Write(CreateButtons_HTML(buttons, params));
}

var __blockactive__ = false;

// to group fields within an edit page, returns html-string
function BLOCK_START_HTML(id, title, params) {
    // params:  ishtmlsafe
    //          icon
    //          wide
    //          flexblock
    //          extraclass
    //          hidden
    //          collapsible
    //          buttons
    //          detailToggle
    //          nopadding
    //          tableid
    params = params || {};
    var ltitle = title||"&nbsp;";
    var resultstr = "";
    var hasButtons = (params.buttons && params.buttons.length);
    id = id || "blk_" + shared.random(12, "base32"); // Als id niet is meegegeven verzinnen we zelf wel wat

    //if (!params.ishtmlsafe && title && title != "&nbsp;") var safetitle = safe.html(title);
    var safetitle = (params.ishtmlsafe || ltitle == "&nbsp;" ? ltitle : safe.html(ltitle));
    if (params.icon) safetitle = I(safe.jsstring(params.icon) + " fa-2x")+" "+safetitle;
    if (params.html) safetitle = (params.ishtmlsafe1 ? params.html : safe.html(params.html)) + " " + safetitle;

    // Bij aanpassen padding & margin, let op dat de hoogte van de block-wrapper 0px moet blijven (anders neemt een hidden block ruimte in)
    var blockwrapperclass = "block-wrapper col-12";
    if (!params.wide && S("max_horizontal_blocks") > 1) {
      blockwrapperclass += " col-lg-6";
      if (S("max_horizontal_blocks") > 2) {
        blockwrapperclass += " col-xxl-4";
      }
    }

    if ("flexblock" in params && params.flexblock) {
        blockwrapperclass += " flexblock";
        if ("labelWidth" in params) {
          var flexblockGUID = shared.random(12, "base32");
          blockwrapperclass += " flexblock_" + flexblockGUID;
          resultstr += "<style type='text/css'>"
                     + "  #" + id + " {"
                     + "    td.label {"
                     + "      width: " + params.labelWidth + "%!important;"
                     + (params.labelWidth < 50 // Alleen nodig bij verkleinen
                       ? "    max-width: calc(" + (params.wide ? "3 * " : "") + (params.labelWidth / 100) + " * 368px)!important;"
                       : "")
                     + "    }"
                     + "  }"
                     + "</style>";
        }
    }

    var blockclass = "card" + (params.extraclass ? " "+params.extraclass : "")
                            + (params.isShowExpr ? " flexlabel" : "");

    resultstr += "<div class='" + blockwrapperclass + "'>";
    resultstr += "<!-- BLOCK_START "+id+" -->";
    resultstr += "<div id='" + id + "' class='" + blockclass + "' " + (params.hidden? " style='display:none'" : "") + ">";

    if (((safetitle || title) && ((safetitle || title) !== "&nbsp;")) || params.detailToggle || hasButtons)
    { // Anders geen header, helpt ook makkelijker de vergeten block-titels te vinden
        resultstr += "<div class='card-header" + "'" + (params.collapsible ? " data-toggle='collapse' aria-expanded='" + (params.expanded ? true : false) + "' "
                                                                             + (typeof params.collapsible === "string"
                                                                                ? "data-target='" + params.collapsible + "'" // params.collapsible is hier een jQuery-selector-string
                                                                                : "data-target='#" + id + "List'")
                                                                           : "")+">";
        resultstr += "  <div class='card-header-content'>"
                   + (safetitle || title);

        if (params.treatable && params.treatable.isTreatable)
        { // De selectboxen behandelteams en behandelaar aan de bloktitiel toevoegen.
          var params_disc  = params.treatable.disc;
          var params_prs   = params.treatable.prs;
          var params_compl = params.treatable.compl;
          var urlAdd_disc  = [{ urlParam: "disc", field: "disc", init: params_disc.disc }];
          var urlAdd_prs   = [{ urlParam: "prs_key",  field: "person",           init: params_prs.melder_key },
                              { urlParam: "disc_key", field: params_prs.disc_id, init: params_prs.disc_key }];
          if (params_prs.show_alg)
            urlAdd_prs.push({   urlParam: "loc_key",  field: "locatiekey",       init: params_disc.loc_key});
          resultstr += "    <span class='span_treatable nowrap'>"
                     + "      <span class='left-treat-wrapper'>"
                     + "        <div id='span_treatable1_" + params.treatable.kkey + "'>"
                     + FCLTdisciplineselector_HTML(params_disc.id,
                                                   "sg" + params_disc.id,
                                                   { disc_key: params_disc.disc_key,
                                                     module: "MLDB",
                                                     perslidKey: params_disc.perslidKey,
                                                     autfunctionKey: -1, // Alles is toegestaan! authparams.autfunctionkey,
                                                     srtdisc_key: (S("mld_processing_group_all") == 1)? null : params_disc.srtdisc_key,
                                                     onChange: "onChange" + params_disc.id,
                                                     readonly: params_disc.reado,
                                                     urlAdd: urlAdd_disc,
                                                     noJustOne: true,
                                                     required: false,
                                                     whenEmpty: L("lcl_select_mld_process_grp_blok")
                                                   })
                     + "        </div>"
                     + "        <div id='span_treatable2_" + params.treatable.kkey + "'>"
                     + FCLTpersoonselector_HTML(params_prs.id,
                                                "sg" + params_prs.id,
                                                { perslidKey: params_prs.prs_key,
                                                  autlevel: params_prs.prsautlevel,
                                                  urlAdd: urlAdd_prs,
                                                  readonly: params_prs.reado,
                                                  filtercode: "BH2B",
                                                  whenEmpty: L("lcl_select_mld_processor_blok")
                                                })
                     + "        </div>"
                     + "      </span>";
          if (params_compl.reado && params_compl.value) { // Readonly & afgemeld
            resultstr += L("lcl_closed_at").format(toDateTimeString(params.treatable.blokafmelddatum, false, true));
          } else {
            var chb_title = L("lcl_close");
            if (params_compl.reado && !params_compl.value) {
                chb_title = L("lcl_not_closed");
            }
            resultstr += CHECKBOX_HTML("treatable_complete", params.treatable.flexid + "complete", params_compl.value, { html: "title='" + chb_title + "'", readonly: params_compl.reado });
          }
          resultstr += "    </span>"
                     + "<script type='text/javascript'>"
                     + "  function onChange" + params_disc.id + "(behandelteam_key)"
                     + "  {"
                     + "    if (typeof sg" + params_prs.id + " != 'undefined')"
                     + "    {"
                     + "      if (behandelteam_key == -1)" // Efficiënter
                     + "        sg" + params_prs.id + ".setValue(-1, '');"
                     + "      else"
                     + "        sg" + params_prs.id + ".setValue($('#" + params_prs.id + "').val(), $('#" + params_prs.id + "_show').val(), true, true);"
                     + "    }"
                     + "  }"
                     + "</script>";
        }

        if (params.detailToggle) {
            resultstr += "    <div class='btn-group' title='" + L("lcl_details") + "'></div>";
        }

        if (hasButtons) {
            resultstr += "    <div class='blockbuttoncontainer'>";
            resultstr += CreateButtons_HTML(params.buttons, { showIcons: true, isModal: params.isModal });
            resultstr += "    </div>"
        }

        resultstr += "  </div>";
        resultstr += "</div>";
    }

    resultstr += "<div id='" + id + "List' class='card-body" + (params.collapsible && typeof params.collapsible !== "string"? " collapse" : "") + (params.nopadding? " nopadding" : "") + (params.tablestyle? " table-style" : "") + "'>";
    resultstr += "<table "+ (params.tableid ? "id='" + params.tableid + "'" : "") +" class='fcltblocktab'>";
    return resultstr;
}

function BLOCK_END_HTML() {
    return "</table></div></div><!-- BLOCK_END --></div>";
}

function BLOCK_START(id, title, params) {
    if (__blockactive__)
        ERROR_NESTED_BLOCK_START_DETECTED;
    __blockactive__ = true;
    Response.Write(BLOCK_START_HTML(id, title, params));
}
function BLOCK_END() {
    if (!__blockactive__)
        ERROR_BLOCK_END_WITHOUT_BLOCK_START;
    __blockactive__ = false;
    Response.Write(BLOCK_END_HTML());
}
function MODAL_BLOCK_START(id, title, params) {
    if (__blockactive__)
        ERROR_NESTED_MODAL_BLOCK_START_DETECTED;
    __blockactive__ = true;
    params = params || {};
    params.wide = true;
    Response.Write(BLOCK_START_HTML(id, title, params));
}
function MODAL_BLOCK_END() {
    if (!__blockactive__)
        ERROR_MODAL_BLOCK_END_WITHOUT_MODAL_BLOCK_START;
    __blockactive__ = false;
    Response.Write(BLOCK_END_HTML());
}

/* optional params: { title: "Titel",        // anders L("frm_<id>")
                      refreshOnClose: true,  // zet oorspronkelijk src terug na FcltClose van child
                      FcltClose: function    // aan te roepen na FcltClose van child
                      icon: fa-icoontje      // weer te geven in de subtab voor de titel
                    }
*/
function IFRAMER(id, url, params)
{
    params = params || {};
    var lclass = "fcltframe";
    var licon = params.icon || "fa-bookmark"; // "fa-th-large"; // "fa-scrubber";
    if (params.sidebar)
    {
        if (Session("interface") == "touch")
            lclass += " col-xxl-4 col-lg-6 col-12";
        else
            lclass += " col-xxl-3 col-xl-4 col-lg-6 col-12";
    }
    else if (params.wide)
        lclass += " col-12";
    else
        lclass += " col";
%><div id="frm_<%=id%>" class="<%=lclass%><%=(params.sidebar ? " sidebar" : "")%>" data-subtab-icon="<%=licon%>" data-subtab-title="<%=safe.htmlattr((params.title || ""))%>">
<%
    if (params.buttons)
        CreateButtons(params.buttons)
%>
    <iframe id="<%=id%>" name="<%=id%>" frameborder="0"
            src="<%=url%>" height="1500"
            <%=params.refreshOnClose? " orgsrc='" + url + "'" : ""%>
            <%=params.srcparent? " srcparent='" + params.srcparent + "'" : ""%>
            <%=params.FcltClose? " FcltClose=\"" + params.FcltClose + "\"" : ""%>
            <%=params.refreshOnActivate ? " data-refresh-on-activate='1'" : ""%>
            onload="FcltMgr.iframeLoaded(this);">
    </iframe>
  </div><%
}

function PAGE_START_HTML(params)
{
    params = params || {};
    var resultstr = '';
    if ("pageHeader" in params) {
        var icon = ("icon" in params.pageHeader ? I(params.pageHeader.icon) + " " : "");
        resultstr += '<h2 class="page-header' + (params.pageHeader.animate ? ' animate-typing' : '') + '">'
                   + '  <div class="page-header-content">'
                   + '    <div class="page-header-title">'
                   + icon
                   + safe.html(params.pageHeader.title || "")
                   + (params.pageHeader.afterTitleHtml || "")
                   + '    </div>'
                   + '  </div>'
                   + '</h2>';
    }
    resultstr += '<div id="frametabs">';
    resultstr += '  <div class="container-fluid">';
    resultstr += '    <div class="row flex-center">';
    return resultstr;
}

function PAGE_END_HTML()
{
    var resultstr = '';
    resultstr += '    </div>';
    resultstr += '  </div>';
    resultstr += '</div>';
    return resultstr;
}

var __page_started__ = false;
function PAGE_START(params)
{
    if (__page_started__) ERROR_NESTED_PAGE_START;
    __page_started__ = true;
    Response.Write(PAGE_START_HTML(params));
}

function PAGE_END()
{
    if (!__page_started__) ERROR_PAGE_END_WITHOUT_PAGE_START;
    __page_started__ = false;
    Response.Write(PAGE_END_HTML());
}

function SEARCH_PAGE_START_HTML(params)
{
    params = params || {};
    var resultstr = "";
    if (S("fac_usrrap_mode") == 1)
    {

      var asWidget = getQParamInt("asWidget", 0) == 1;
      var asSavedWidget = asWidget && getQParamInt("tab_menu_key", -1) > 0;
      if (asSavedWidget)
      {
        var autosearch = getQParamInt("autosearch", 0) == 1;
        if (!autosearch)
        {
          resultstr += "<script>"
                     + "  window.afterfiltersready = function () {"
                     + "    if (typeof doSubmit === 'function')"
                     + "    {"
                     + "      doSubmit();"
                     + "    }"
                     + "    else"
                     + "    {"
                     + "      document.forms.u2.submit();"
                     + "    }"
                     + "  }"
                     + "</script>";
        }
        resultstr += "<script>"
                   + "  function toggleSearchBlock() {"
                   + "    $('.search-page-header').toggleClass('hidden');"
                   + "    $('.container-fluid').toggleClass('hidden');"
                   + "    FcltMgr.resized();"
                   + "  }"
                   + "</script>";
      }
      else if (user.has(["WEB_WGTMAN", "WEB_PRSSYS"]))
      {
          resultstr += "<script>"
                    + "  var canSaveAsWidget = true;"
                    + "</script>";
      }
    }

    var lheader = params.header || L("lcl_filterblok");  // default L("lcl_filterblok") zijn, want dat is-ie 100%?
    var safe_header = (params.ishtmlsafe ? lheader : safe.html(lheader));
    var icon = params.icon || "fa-ballot-check";

    if (params.header)
    {
      resultstr += '<nav class="search-page-header' + (asSavedWidget ? ' hidden' : '') + '">';
      resultstr += '  <span>';
      resultstr += '    ' + I(icon+" fa-2x") + ' ' + safe_header;
      resultstr += '  </span>';
      resultstr += '  <span class="scf_extrafilter">' + (params.filtercols ? params.filtercols : "");
      resultstr += '  </span>';
      resultstr += '</nav>';
    }

    resultstr += '<div class="container-fluid' + (asSavedWidget ? ' hidden' : '') + '">';
    resultstr += '  <div class="row">';
    resultstr += '    <div class="scrollTopTab" onclick="$(window).scrollTop(0);">' + I("fa-chevron-up fa-3x") + '</div>';

    return resultstr;
}

function SEARCH_PAGE_END_HTML()
{
    var resultstr = '';
    var asWidget = getQParamInt("asWidget", 0) == 1;
    if (asWidget)
        resultstr += '<input type="hidden" name="asWidget" value="1">';
    var asSavedWidget = asWidget && getQParamInt("tab_menu_key", -1) > 0;
    if (asSavedWidget)
        resultstr += '<input type="hidden" name="asSavedWidget" value="1">';
    resultstr += '  </div>';
    resultstr += '</div>';
    return resultstr;
}

var __search_page_started__ = false;
function SEARCH_PAGE_START(params)
{
    params = params || {};
    if (__search_page_started__) ERROR_NESTED_SEARCH_PAGE_START;
    __search_page_started__ = true;
    Response.Write(SEARCH_PAGE_START_HTML(params));
}

function SEARCH_PAGE_END()
{
    if (!__search_page_started__) ERROR_SEARCH_PAGE_END_WITHOUT_SEARCH_PAGE_START;
    __search_page_started__ = false;
    Response.Write(SEARCH_PAGE_END_HTML());
}

// ! Wordt ook in sommige niet-search schermen gebruikt (bijv. /CNT/cnt_edit_scope.asp)
function SEARCH_BLOCK_START_HTML(params)
{
    params = params || {};
    var resultstr = "";
    var searchblockclass = "search-block-wrapper col-12";
    if (!params.wide) // Default 2 responsive kolommen
        searchblockclass += " col-lg-6";
    resultstr += '<div class="' + searchblockclass + '">';
    resultstr += '  <table id="searchblock_' + (params.volgnr ? params.volgnr : 0) + '">';
    return resultstr;
}

function SEARCH_BLOCK_END_HTML()
{
    var resultstr = "";
    resultstr += '  </table>';
    resultstr += '</div>';
    return resultstr;
}

function SEARCH_BLOCK_START(params)
{
    params = params || {};
    if (__blockactive__)
        ERROR_NESTED_SEARCH_BLOCK_START;
    __blockactive__ = true;
    Response.Write(SEARCH_BLOCK_START_HTML(params));
}

function SEARCH_BLOCK_END()
{
    if (!__blockactive__)
        ERROR_SEARCH_BLOCK_END_WITHOUT_SEARCH_BLOCK_START;
    __blockactive__ = false;
    Response.Write(SEARCH_BLOCK_END_HTML());
}

function SIMPLE_BLOCK_START_HTML(params)
{
    params = params || {};
    var simpleblockclass = "simple-block-wrapper col-12";
    simpleblockclass += params.extraclass ? " " + params.extraclass : "";
    if ("wide" in params && !params.wide) // Default 1 kolom met 100% width
      simpleblockclass += " col-lg-6";
    return '<div class="' + simpleblockclass + '"' + (params.hidden ? ' style="display: none"' : '') + '>';
}

function SIMPLE_BLOCK_END_HTML()
{
    return '</div>';
}

function SIMPLE_BLOCK_START(params)
{
    params = params || {};
    if (__blockactive__)
        ERROR_NESTED_SIMPLE_BLOCK_START;
    __blockactive__ = true;
    Response.Write(SIMPLE_BLOCK_START_HTML(params));
}

function SIMPLE_BLOCK_END()
{
    if (!__blockactive__)
        ERROR_SIMPLE_BLOCK_END_WITHOUT_SIMPLE_BLOCK_START;
    __blockactive__ = false;
    Response.Write(SIMPLE_BLOCK_END_HTML());
}

function IFRAMER_HEADER(titel, buttons, params, checkBoxes)
{
    params = params || {};
    var collapsed = getQParamInt("collapsed", 0) == 1;
    params.collapsible = params.collapsible || hasQParam("collapsed");
    var safetitle = params.ishtmlsafe ? titel : safe.html(titel || "");
    if (!("icon" in params) || !params.icon)
        params.icon = "fa-bookmark"; /* Deze default dan maar */
%>
    <script>
      function moveHeaderToFooter()
      {
        headertofooter();
        <% if (collapsed) { %>
          $(".fcltframeheader").next().toggle();
          FcltMgr.resized(window);
        <% } %>
      }

      $(function()
      {
        if (window.FcltMgr)
        {
            FcltMgr.setFrameTitle("<%=safe.jsstring(safetitle)%>", { icon: "<%=params.icon%>"<%=("id" in params ? ', id: "' + params.id + '"' : '')%> });
            if (typeof buttons_hit_test === "function")
                buttons_hit_test();
        }
        if ($.active > 0) // Has active ajax calls?
        {
          // Then await those calls first (UWVA#51618)
          $(document).on("ajaxStop", function()
          {
            $(this).off("ajaxStop");
            moveHeaderToFooter();
          });
        }
        else
          moveHeaderToFooter();
      });
    </script>
      <div <%=("id" in params ? 'id="fcltframeheader' + params.id + '" ' : '')%>class="fcltframeheader<%=(params.collapsible ? ' collapsible' : '')%> block-buttons order-first col-12<%=collapsed ? ' collapsed' : ''%>"<%=params.collapsible? " onclick=\"$('#collapseblock, div.fcltblock, div.fcltblockhead, div.buttoncontainer, div.fcltframefooter div#buttons', $(this).parent()).toggle();$(this).toggleClass('collapsed');FcltMgr.resized(window);updateTableHeaders()\"" : ""%>>
          <span id="iframerextratitle"></span>
        <% // checkboxes: Array of objects containing data to create extra checkboxes to filter table: { lcl, checked, param, transitParams }
        if (checkBoxes) {
            var i = 0;
            while(i < checkBoxes.length) {
              var checkboxId = "toggle-"+ i;
              var isChecked = checkBoxes[i].checked;
              var qParams = "?" + checkBoxes[i].param + "="
                          + (isChecked ? "0" : "1")
                          + "&rst_filters=1"
                          + checkBoxes[i].transitParams;
              %>
              <span class="iframe-chb-toggle">
                <%CHECKBOX("", checkboxId, isChecked);%>
                <label for="<%=checkboxId%>"><%=checkBoxes[i].lcl%></label>
              </span>
              <script>
                $("#" + '<%=checkboxId%>').on("click", function(e) {
                    window.location.href = '<%=qParams%>';
                });
              </script>
        <%    i++;
            }
          }   %>

<%      if (buttons) {
            %><div class="buttoncontainer" style="float:right;"><%
            CreateButtons(buttons, { showIcons: true, inlineId: params.inlineId, isModal: params.noHamburger, inhamburger: params.inhamburger || false });
            %></div><%
        }
        if (params.hints) { %>
            <span class='hints default-clickable-icon' onclick='scf_enablehint();FcltMgr.stopPropagation(event);' title='<%=L("lcl_hint")%>'>
              <%=I("fa-headset fa-xl")%>
              <%=I("fa-question fa-sm tinyhint")%>
            </span>
<%      }
%>    </div>
<%
}

function SUBFRAME_START_HTML(params)
{
    params = params||{};
    var resultstr = '';
    resultstr += '<div class="subframe container-fluid' + ("containerClass" in params ? ' ' + params.containerClass : '') + '">';
    resultstr += '  <div class="row content-wrapper' + ("rowClass" in params ? ' ' + params.rowClass : '') + '">';
    var blockSizerCls = "block-sizer col-12";
    if (S("max_horizontal_blocks") > 1) {
      blockSizerCls += " col-lg-6";
      if (S("max_horizontal_blocks") > 2) {
        blockSizerCls += " col-xxl-4";
      }
    }
    resultstr += '    <div class="' + blockSizerCls + '"></div>'; // for masonry
    return resultstr;
}

function SUBFRAME_END_HTML()
{
    var resultstr = '';
    resultstr += '  </div>';
    resultstr += '</div>';
    return resultstr;
}

var __subframe_started__ = 0;
function SUBFRAME_START(params)
{
    params = params||{};
    if (__subframe_started__) ERROR_NESTED_SUBFRAME_START;
    __subframe_started__ = 1;
    Response.Write(SUBFRAME_START_HTML(params));
}

function SUBFRAME_END()
{
    if (!__subframe_started__) ERROR_SUBFRAME_END_WITHOUT_SUBFRAME_START;
    __subframe_started__ = 0;
    Response.Write(SUBFRAME_END_HTML());
}

function MODAL_START_HTML()
{
    var resultstr = '';
    resultstr += '<div class="container-fluid">';
    resultstr += '  <div class="row content-wrapper">';
    resultstr += '    <div class="block-sizer col-12"></div>'; // for masonry
    return resultstr;
}

function MODAL_END_HTML()
{
    var resultstr = '';
    resultstr += '  </div>';
    resultstr += '</div>';
    return resultstr;
}

var __modal_started__ = 0;
function MODAL_START()
{
    if (__modal_started__) ERROR_NESTED_MODAL_START;
    __modal_started__ = 1;
    Response.Write(MODAL_START_HTML());
}

function MODAL_END()
{
    if (!__modal_started__) ERROR_MODAL_END_WITHOUT_MODAL_START;
    __modal_started__ = 0;
    Response.Write(MODAL_END_HTML());
}

// Bij leeg label krijg je helemaal geen <td>'s
function AFIELD(pclass, plabel, phref, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar

  if (plabel) {
      %><td class="label"><label <%=params && params.id? ' for=\"' + params.id + '\"' : ''%>><%=plabel? plabel : ""%></label></td>
        <td><%
  }
%>
  <a class="<%=pclass%>" <%=params && params.id? ' id=\"' + params.id + '\"' + ' name=\"' + params.id + '\"' : ''%> href="<%=safe.htmlattr(phref)%>" <%=params && params.onclick? ' onclick=\"' + safe.jsstring(params.onclick) + '\"' : ''%>
  <%=(params.html? " " + params.html + " " : "")%>><%=safe.html(pvalue)%></a>
  <%=((params.rating && params.rating.score) ? rating.stars(params.rating.score, params) : "")%>
<%
  if (plabel) { %>
    </td><%
  }
}

function AFIELDTR(pclass, plabel, phref, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar

  %><tr <%=params.trclass?"class='"+params.trclass+"'":""%>>
      <% if (!plabel && params.emptylabel) { %><td class="label"></td><% } %>
      <% if (!plabel) { %><td><% } %>
      <%AFIELD(pclass, plabel, phref, pvalue, params)%>
      <% if (!plabel) { %></td><% } %>
  </tr><%
}

function ROFIELD(pclass, plabel, pvalue, params)
{
  Response.Write(ROFIELD_HTML(pclass, plabel, pvalue, params));
}

// Bij leeg label krijg je helemaal geen <td>'s
function ROFIELD_HTML(pclass, plabel, pvalue, params)
{
  var resultstr = "";
  params = params || {};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar

  // Vanuit API2 model
  if (pvalue != null && typeof pvalue == "object" && "name" in pvalue)
    pvalue = pvalue["name"];

  if (plabel || params.labelbutton) {
    resultstr +=
      "<td class='label" + (params.hint_tz ? " hashint" : "") + "'>"
    + "  <label" + (params && params.id? " for='" + params.id + "'" : "") + ">"
    + (plabel ? plabel : "")
    + "  </label>"
    + (params.labelbutton
      ? "  <span class='labelextra'>"
      + "    <span title='" + safe.htmlattr(params.labelbutton.title) + "' onclick='" + safe.htmlattr(params.labelbutton.action) + "'>"
      +        I(params.labelbutton.icon)
      + "    </span>"
      + "  </span>"
      : "")
    + (params.hint_tz
      ? "  <span class='labelextra'>"
      + "    <span class='hint_tz' data-title='" + safe.htmlattr(L("lcl_timezone_is_local")) + "'>"
      +        I("fa-earth-americas")
      + "    </span>"
      + "  </span>"
      : "")
    + "</td>"
    + "<td>"
  }
  var input = "";
  if ("icon" in params)
  {
    resultstr += '<span' + (params.iconclass ? ' class="' + safe.htmlattr(params.iconclass) + '"' : '') + '>' + I(params.icon) + '</span>';
  }
  else if (params.datatype == "color" && pvalue)
  {
    resultstr += "<span class='color-preview' style='color: " + safe.htmlattr(pvalue) + "'>" + I("fa-square fa-2x", { fastyle: "fas" }) + "</span>";
  }
  resultstr += "<span";

  var safe_value;
  switch(params.datatype)
  {
      case "currency":
          pvalue = (params.prefix ? S("currency_pref") + " " : "") + safe.curr(pvalue||0) + (params.suffix ? S("currency_suff") : "");
          pclass += " currency";
          break;
      case "percentage":
      case "hours":
          params.trimZeros = true;
      case "float":
          pvalue = safe.showFloat(pvalue, params.decimals, params.trimZeros);
          pclass += " float";
          break;
      default:
          break;
  }
  // De classes
  if (params.selector) pclass += " flduo"; /* Maak dan beiden 50% breed zodat ze naast elkaar passen */
    resultstr += " class='" + pclass;

  // TODO; icm met width in px zorgt deze class ervoor dat een tooltip multi-line mag zijn
  // maar width in px wordt deprecated, dus deze ook (?)
  if (params.infoPointer)
    resultstr += " details";
  if (params.type == 'button')
    resultstr += " button";
  resultstr += "'"; // Einde class

  if (params.type == 'button') /* volgens mij is een readonly button vrij zeldzaam */
    resultstr += " type='button'";
  if (params.id)
    resultstr += " id='" + params.id + "' name='" + params.id + "'";
  if (params.title)
    resultstr += " title='" + safe.htmlattr(params.title) + "'";

  if (params.html)
    resultstr += " " + params.html + " ";

  if (params.infoPointer)
  {
    var url = params.infoPointer.Url;
    if (params.infoPointer.NewWindow)
    {
        var fnclick = "FcltMgr.windowopen(\"" + safe.jsstring(url) + "\")";
    }
    else if (params.infoPointer.Modal)
    {
      fnclick = "FcltMgr.openModalDetail(\"" + safe.jsstring(url) + "\""
                      + ", { titel: \"" + safe.jsstring(params.infoPointer.Title || "") + "\" })";
    }
    else
    {
      fnclick = "FcltMgr.openDetail(\"" + safe.jsstring(url) + "\""
                      + ", { reuse: true, titel: \"" + safe.jsstring(params.infoPointer.Title || "") + "\" })";
    }
    resultstr += " onclick='" + safe.htmlattr(fnclick) + "'";
  }
  if (params.secret)
    resultstr += " title='{0}' onclick='this.innerText=this.title;this.onclick=null'>".format(safe.htmlattr(pvalue)) + I("fa-eye fa-lg") + "</span>";
  else {
    var safe_value = (params.ishtmlsafe ? pvalue : safe.html(pvalue));
    resultstr += ">" + safe_value + "</span>";
  }

  if (params.tooltip)
    resultstr += " <span class=\"fclt-tooltip\">" + safe.html(params.tooltip) + "</span>";

  if (params.selector) {
    resultstr += FCLTselector_HTML(params.selector.fieldName, params.selector.sql, params.selector.params);
  }
  if (plabel)
    resultstr += "</td>";

  return resultstr;
}

function ROFIELDTR(pclass, plabel, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar

  var linkType;
  switch(params.type)
  {
    case "mail":
    case "email":
    case "e-mail":
    case "mailto":
      linkType = "mailto";
      break;
    case "tel":
    case "phone":
    case "callto":
    case "telefoon":
      linkType = S("fac_phone_protocol");
      break;
  }

  if (plabel && params.translate && S("multi_language_option"))
  {
    var fn = "iface.translate('"+params.translate.fld+"', "+params.translate.key+", this.innerText, '"+safe.jsstring(pvalue)+"', 'input')"
    if (params.org_lcl)
        var fn = "iface.overrule('"+safe.jsstring(params.org_lcl)+"')"
    plabel = "<span class='facmgtmultilang' onclick='"+safe.htmlattr(fn)+"'>" + plabel + "</span>";
  }

  if (linkType)
  {
      pclass += linkType + " details";
      var phref = linkType + ":" + pvalue;
  }

  %><tr<%=params.trid?" id='"+params.trid+"'":""%><%=params.trclass?" class='"+params.trclass+"'":""%><%=params.trhidden ? " style='display:none'" : ""%>>
      <% if (!plabel) { %><td class="label"></td><td><% }
  if (linkType)
      AFIELD(pclass, plabel, phref, pvalue, params);
  else
      ROFIELD(pclass, plabel, pvalue, params);
        if (!plabel) { %></td><% } %>
  </tr><%
}

// Kort een string in tot maximaal len tekens inclusief ellipsis indien nodig
// met {middle: true} wordt inwendig afgekort, beter voor bv filenamen of secrets
function shorten (fld, len, params)
{
  params = params||{};

  if (fld && fld.length > len) {
    if (params.middle)
    {
      var half = Math.floor((len - 3) / 2);
      return fld.slice(0, half) + "..." + fld.slice(fld.length - half);
    }
    else
      return fld.substring(0, len-3) + "...";
  }
  else
  {
    return fld;
  }
}

function ROTEXTAREATR(pclass, plabel, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar

  if (plabel && params.translate && S("multi_language_option"))
  {
    var fn = "iface.translate('"+params.translate.fld+"', "+params.translate.key+", this.innerText, '"+safe.jsstring(shorten(pvalue, 300))+"', 'textarea')"
    if (params.org_lcl)
        var fn = "iface.overrule('"+safe.jsstring(params.org_lcl)+"')"
    plabel = "<span class='facmgtmultilang' onclick='"+safe.htmlattr(fn)+"'>" + plabel + "</span>";
  }

  if (params && params.id && params.markup)
  {
    %>
        <input type="hidden" id="<%=params.id%>_safe" name="<%=params.id%>_safe" value="<%=safe.htmlattr(pvalue)%>"<%=(params.formid ? ' form="' + params.formid + '"' : '')%>>

        <script>
            $(function()
                {
                    $("#<%=params.id%>").html($("#<%=params.id%>_safe").val());
                }
            );
        </script>
    <%
  }

%>
    <tr <%=params.trclass?"class='"+params.trclass+"'":""%>>
<%  if (plabel) {%>
      <td class="label"><label><%=plabel? plabel : ""%></label></td>
<%  }

    var params_html = (params.html? " " + params.html + " " : "");
    var params_id = (params.id ? ' id=\"' + params.id + '\"' : '');
    var params_safe = (params.ishtmlsafe ? pvalue : safe.fclthtml(pvalue, params));
%>
      <td <%=(params.tdhtml_ta? " " + params.tdhtml_ta : "")%>>
        <div class="readonly fclthtml <%=pclass%>"<%=params_html%><%=params_id%>><%=params_safe%></div>
      </td>
    </tr>
<%
}

function RWFIELD(pname, pclass, plabel, pvalue, params)
{
  Response.Write(RWFIELD_HTML(pname, pclass, plabel, pvalue, params));
}

// params.html wordt er ook tussen geplakt (onclick bijvoorbeeld)
function RWFIELD_HTML(pname, pclass, plabel, pvalue, params)
{
  var resultstr = "";
  pvalue = safe.nvl(pvalue);
  params = params||{};
  if (plabel) {
    resultstr += "<td class='label'><label for='" + pname + "'>" + plabel + "</label></td><td>";
  }
  if (params.fronttext) {
    resultstr += params.fronttext
  }
  var lclass = (pclass ? pclass : "fld");
  if (params.infoPointer) lclass += " details";
  if (params.selector) lclass += " flduo"; /* Maak dan beiden 50% breed zodat ze naast elkaar passen */
  if (params.extraclass)  lclass += " " + params.extraclass;
  if (!params.readonly && params.required) lclass += " required";
  if (!params.readonly && params.requiredor0) lclass += " required required0isoke";
  var inputtype = (isBadInput()? " type='text'" : " type='number'");
  var lstep = "";
  switch (params.datatype) {
    case "number":         lclass += " number"; break;
    case "float":          lclass += " float"; break;
    case "processingtime": lclass += " float"; break;
    case "currency":       lclass += " currency"; lstep= " step='0.01'"; break;
    case "text":           inputtype = " type='text'"; break;
    case "color":          inputtype = (pvalue ? " type='color'" : " type='text'"); break;
    case "button":         inputtype = " type='button'"; break;
    default:               inputtype = ""; break;
  }
  if (params.endicon)
  {
    resultstr += "<span class='button-icon-wrapper'>";
  }
  else if (params.datatype == "color")
  {
    resultstr += "<span class='input-icon-wrapper'>";
  }
  resultstr += "<input class='" + lclass + "'" + inputtype + lstep + " name='" + pname + "' id='" + pname + "' value='" + safe.htmlattr(pvalue) + "'"
             + (params.placeholder? " placeholder='" + params.placeholder + "'": "")
             + (params.maxlength? " maxlength=" + params.maxlength : "")
             + (params.readonly? " readonly tabindex='-1'" : "")
             + (params.html? " " + params.html + " " : "")
             + (params.formid? " form='" + params.formid + "'" : "");

  if (params.infoPointer)
  { // Hebben we anno 2015.1 nog wel ergens een RWFIELD met infopointer?
    resultstr += "onclick=\"FcltMgr.openDetail('" + safe.jsstring(params.infoPointer.Url) + "', { reuse: true, titel: '" + safe.jsstring(params.infoPointer.Title || "") + "' })\"";
  }
  resultstr += ">";
  if (params.datatype == "color")
  {
    resultstr += "<span class='default-clickable-icon' onclick='iface.toggleColorPicker(this)'>" + I(pvalue? "fa-trash-alt" : "fa-paint-brush") + "</span>";
  }
  if (params.selector) {
    resultstr += FCLTselector_HTML(params.selector.fieldName, params.selector.sql, params.selector.params);
  }
  if (params.reartext) {
    resultstr += params.reartext;
  }
  if (params.endicon)
  {
    resultstr += "<span class='endicon'>"
               + I(params.endicon)
               + "</span>"
               + "</span>";
  }
  else if (params.datatype == "color")
  {
    resultstr += "</span>";
  }
  if (plabel) {
    resultstr += "</td>";
  }
  return resultstr;
}

// Sommige browsers ondersteunen het input type='number' en dan gaat het fout als wij
// er iets met een komma instoppen.
function isBadInput()
{
    var agent = "" + Request.ServerVariables("HTTP_USER_AGENT");
    if (agent.indexOf("Chrome")>=0)
        return true;
    if (agent.indexOf("Firefox")>=0)
        return true;
    if (agent.indexOf("Safari")>=0)
        return true;

    return false;
}

function RWFIELDTR(pname, pclass, plabel, pvalue, params)
{
  Response.Write(RWFIELDTR_HTML(pname, pclass, plabel, pvalue, params));
}

function RWFIELDTR_HTML(pname, pclass, plabel, pvalue, params)
{
  var resultstr = "";
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)) && params.readonly)
    return; // snel klaar

  resultstr += "<tr " + (params.trid?"id='"+params.trid+"'":"") + (params.trclass?"class='"+params.trclass+"'":"") + (params.trhidden ? " style='display:none'" : "") + ">"
             + (!plabel? "<td class='label'></td><td>" : "")
             + RWFIELD_HTML(pname, pclass, plabel, pvalue, params)
             + (!plabel? "</td>" : "")
             + "</tr>"
  return resultstr;
}

function BB_BUTTONS_HTML(uid, show, upload_params)
{
  var cls  = "text-style-button default-clickable-icon";
  if (upload_params) {
    var props = flexProps(upload_params.module);
    var extFilter = props.extFilter || S("flexAllowedExt");
    var extension_list = ["*"];
    // Komt het extension-filter in het formaat 'jpg|png|bmp'? Dan sta ik alleen dat clientside toe, regexp gaan we niet clientside valideren
    if (extFilter == extFilter.match(/[a-z\d\|]*/)[0]) {
      extension_list = extFilter.split(/\|/);
      for (var i = 0; i < extension_list.length; i++) {
        extension_list[i] = "." + extension_list[i];
      }
    }
    var transitParams = buildTransitParam(["mld_key", "opdr_key"]);
  }
  var result = '<div class="text-styles' + (show ? "" : " closed") + '" aria-controls="' + uid + '">'
             + '    <span class="' + cls                                                                    + '" title="' + safe.htmlattr(L("lcl_text_style_hint_bold"))          + '" data-style="b">'       + I("fa-bold",          { "fastyle": "far" }) + '</span>'
             + '    <span class="' + cls                                                                    + '" title="' + safe.htmlattr(L("lcl_text_style_hint_italic"))        + '" data-style="i">'       + I("fa-italic",        { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls                                                                    + '" title="' + safe.htmlattr(L("lcl_text_style_hint_underline"))     + '" data-style="u">'       + I("fa-underline",     { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-md-initial d-lg-none d-3xl-initial')  + '" title="' + safe.htmlattr(L("lcl_text_style_hint_strikethrough")) + '" data-style="s">'       + I("fa-strikethrough", { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial')                          + '" title="' + safe.htmlattr(L("lcl_text_style_hint_header1"))       + '" data-style="h1">'      + I("fa-h1",            { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial')                          + '" title="' + safe.htmlattr(L("lcl_text_style_hint_header2"))       + '" data-style="h2">'      + I("fa-h2",            { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial d-lg-none d-xl-initial')   + '" title="' + safe.htmlattr(L("lcl_text_style_hint_header3"))       + '" data-style="h3">'      + I("fa-h3",            { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial')                          + '" title="' + safe.htmlattr(L("lcl_text_style_hint_url"))           + '" data-style="url">'     + I("fa-link",          { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial')                          + '" title="' + safe.htmlattr(L("lcl_text_style_hint_code"))          + '" data-style="code">'    + I("fa-code",          { "fastyle": "fal" }) + '</span>'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-md-initial d-lg-none d-3xl-initial')  + '" title="' + safe.htmlattr(L("lcl_text_style_hint_table"))         + '" data-style="table">'   + I("fa-table",         { "fastyle": "fal" }) + '</span>'
             + '    <input type="color" class="hidden" onchange="iface._insert_bb_code.call(this, null, \'color\')">'
             + '    <span class="' + cls + (show ? '' : ' d-xs-none d-md-initial d-lg-none d-3xl-initial')  + '" title="' + safe.htmlattr(L("lcl_text_style_hint_color"))         + '" data-style="color">'   + I("fa-paintbrush",    { "fastyle": "fal" }) + '</span>'
             + (upload_params
               ? '<input type="file" accept="' + extension_list.join(",") + '" id="' + upload_params.module + '_bijlagen" name="' + upload_params.module + '_bijlagen"'
               + (upload_params.bb_files_nr? ' bb_files_nr="' + upload_params.bb_files_nr + '"' : '')
               + ' onchange="iface.bb_upload(this)" multiple="multiple" data-new="' + (upload_params.refkey > 0 ? 0 : 1) + '"'
               + (upload_params.formid ? ' form="' + upload_params.formid + '"' : '')
               + ' data-upload-url="' + protectQS.create("../Shared/UploadForm_save.asp?action=insert&module=" + upload_params.module + "&key=" + upload_params.refkey + transitParams) + '">'
               + '<span class="' + cls + (show ? '' : ' d-xs-none d-sm-initial') + '" title="' + safe.htmlattr(L("lcl_text_style_hint_attach")) + '" data-style="file">' + I("fa-paperclip", { "fastyle": "fal" }) + '</span>'
               : '')
             + '    <span class="text-style-toggle default-clickable-icon'                                  + '" title="' + safe.htmlattr(L("lcl_text_style_toggle"))             + '" data-style="toggle">'  + I("fa-font",          { "fastyle": "fas" }) + '</span>'
             + '</div>';
  return result;
}

function BB_ATTACHMENTS_HTML(pmodule, pkey, prefix, mode) {
  var props = flexProps(pmodule, pkey, undefined, undefined, { cacheablehmac: true });
  var prefix = (prefix ? prefix + "-" : ""); // bijv. "note-"
  var mode = mode || "show";
  var result = "";
  for (var i = 0; i < props.files.length; i++) {
      var ext = props.files[i].name.split(".").pop().toLowerCase();
      var isImage = inArray(ext, ["bmp", "gif", "png", "jpg", "jpeg"]);
      if (mode == "show" && isImage) {
        continue; // Geen download box nodig
      }
      result += '<div class="' + prefix + 'attachment"';
      if (mode == "show") { // Download on click
        result += ' onclick="FcltMgr.windowopen(\'' + safe.jsstring(props.files[i].deepurl) + '\', \'' + prefix + 'file\')'
      }
      result += '">';
      if (mode == "show") {
        switch (ext.toLowerCase()) {
          case "pdf": result += I("fa-file-pdf"); break;
          case "rft":
          case "txt": result += I("fa-file-lines"); break;
          case "xml": result += I("fa-file-code"); break;
          case "dot":
          case "mcw":
          case "doc":
          case "docx": result += I("fa-file-word"); break;
          case "csv": result += I("fa-file-csv"); break;
          case "xsl":
          case "xlsx": result += I("fa-file-spreadsheet"); break;
          case "eml":
          case "msg": result += I("fa-envelope"); break;
          case "zip":
          case "7z":
          case "rar":
          case "gzip":
          case "gz": result += I("fa-file-zip"); break;
          case "tif":
          case "tiff":
          case "vsd": result += I("fa-file-image"); break;
          case "ppt":
          case "pptx": result += I("fa-file-powerpoint"); break;
          case "oft": result += I("fa-envelope-circle-check"); break;
          case "encrypted": result += I("fa-file-shield"); break;
          case "mp4":
          case "mov":
          case "m4v":
          case "3gp":
          case "avi": result += I("fa-file-video"); break;
          case "dwg":
          case "dwf": result += I("fa-layer-group"); break;
          default: result += I("fa-paperclip");
        }
      }
      result += '<span class="' + prefix + 'attachment-name';
      if (mode == "edit" && isImage) {
        result += ' note-attachment-image'; // Deze zorgt dat een bb-code wordt ingevoegd onclick (iface.js)
      }
      result += '">' + safe.html(props.files[i].name) + '</span>'
      if (mode == "edit") { // In edit mode ook een delete kruisje rechts naast de filename
        result += '  <span class="note-attachment-delete default-clickable-icon"'
               + ' data-delete-url="'+ safe.htmlattr(protectQS.create(rooturl + "/appl/Shared/Bijlagenform_delete.asp?DoDelete=" + safe.htmlattr(Server.URLEncode(props.files[i].name)) + "&key=" + pkey + "&module=" + pmodule)) + '">'
               +      I("fa-lg fa-xmark")
               + '  </span>'
      }
      result += '</div>';
  }
  return '<div class="' + prefix + 'attachments">' + result + '</div>';
}

function BB_BUTTONS(uid, show, upload_params)
{
  Response.Write(BB_BUTTONS_HTML(uid, show, upload_params));
}

function RWTEXTAREATR(pname, pclass, plabel, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)) && params.readonly)
    return; // snel klaar
  var lclass = (pclass ? pclass : "fldtxt");
  if (lclass.indexOf("fldtxt") === -1)
      lclass += " fldtxt";

  %><tr <%=params.trclass?"class='"+params.trclass+"'":""%>>
<%  if (plabel)
    {
        var label_txt = "<label for='"+pname+"'>" + (plabel? plabel : "") +"</label>";
        if (params.labelaction)
        {
            label_txt = label_txt
                      + "<span class='labelextra' id='" + pname + "_action' onclick='"+params.labelaction.action+"'>"
                      + "<span class='hint' title='" + params.labelaction.hint + "'>"
                      + "<div class='labelaction'>" + I(params.labelaction.icon) + "</div>"
                      + "</span></span>";
        }
    %><td class="label textarea"><%=label_txt%></td><%
    }
%>
      <td <%=(params.tdhtml_ta? " " + params.tdhtml_ta : "")%>><%
  if (!params.readonly && !params.no_bb_codes)
  {
    BB_BUTTONS(pname, params.bb_codes, params.upload_params);
    lclass += " bb_enabled";
    if ("upload_params" in params) {
      lclass += " bb_upload_enabled";
    }
  } %>
        <textarea class="<%=lclass%>"
            <%=(params.html? " " + params.html + " " : "")%>
            <%=' id=\"' + pname + '\"' + ' name=\"' + pname + '\"'%>
            <%=" maxlength="+(params.maxlength||4000)%>
            <%=(params.readonly ? " readonly " : "")%>
            <%=(params.formid? " form='" + params.formid + "'" : "")%>
            <%=(params.upload_params? " aria-controls='" + params.upload_params.module + "_bijlagen'" : "")%>
            <%=(params.placeholder ? " placeholder='" + params.placeholder + "'" : "")%>><%=safe.textarea(pvalue)%></textarea>
      </td>
    </tr><%
}

// Zie save2db.inc type "check": we voegen een hidden field has_xxxx toe
// params.html wordt er ook tussen geplakt (onclick bijvoorbeeld)
// EXTERNALLY DEPRECATED; gebruik CHECKBOX()
function CHECKBOX_HTML(pclass, pid, pvalue, params)
{
    params = params || {};
    var keyvalue = (params.keyvalue ? params.keyvalue : 1);
    var result = '';
    result += '<input type="hidden" id="has_' + pid + '" name="has_' + pid + '" value="'+keyvalue+'" '
            + (params.readonly? " disabled" : "")
            + (params.formid ? ' form="' + params.formid + '"' : '') + '>';
    result += '<input type="checkbox" id="' + pid + '" name="' + pid + '"'
            + ' class="' + pclass + '" ' + (pvalue? "checked " : "") + (params.hidden ? "style=\"visibility: hidden\"" : "")
            + (params.readonly ? " disabled" : "")
            + (params.html ? " " + params.html : "")
            + (params.formid ? ' form="' + params.formid + '"' : '')
            + ("value" in params? " value='" + safe.htmlattr(params.value) + "'":"") + '>';
    return result;
}
function CHECKBOX(pclass, pid, pvalue, params)
{
    params = params || {};
    Response.Write(CHECKBOX_HTML(pclass, pid, pvalue, params));
}

function ICONPICKER_HTML(pname, plabel, pvalue, params) {
    params = params || {};
    var result = "";
    var hasIcon = pvalue && pvalue.indexOf("fa-") > -1 && pvalue.indexOf(".") === -1;
    // De TR functies die deze aanroepen moeten het hidden fld maar aanmaken die deze picker dan vult
    result += "<span class='button-icon-wrapper fa-picker'>"
            + "    <span class='starticon'>" + (hasIcon ? I(pvalue) : I("fa-flag")) + "</span>"
            + "    <input type='button' class='button symbol-iconpicker' title='" + safe.htmlattr(plabel) + "' value='" + safe.htmlattr(pvalue || L("mgt_kenmerk_icon")) + "'"
            +     " data-default-title='" + safe.htmlattr(plabel) + "' aria-controls='" + pname + "'" + (params.formid ? " form='" + params.formid + "'" : "") + ">"
            + "</span>";
    return result;
}

function FILEPICKER_HTML(pname, plabel, pvalue, params) {
    var result = "";
    // De TR functies die deze aanroepen moeten het hidden fld maar aanmaken die deze picker dan vult
    result += "<span class='button-icon-wrapper file-picker'>"
            + "    <span class='starticon'>" + I(params.icon || "fa-file-image") + "</span>"
            + "    <input type='button' class='button symbol-upload' title='" + safe.htmlattr(params.defaultValue || L("lcl_image")) + "' value='" + safe.htmlattr(pvalue || params.defaultValue || L("lcl_image")) + "'"
            +     " aria-controls='" + pname + "'"
            +     " data-default-value='" + safe.htmlattr(params.defaultValue || L("lcl_image")) + "'"
            +     " data-default-title='" + safe.htmlattr(plabel) + "'"
            +     " data-new='" + (params.key > 0 ? 0 : 1) + "'"
            +     " data-module='" + params.module + "'"
            + (params.formid ? " form='" + params.formid + "'" : "")
            + (params.reloadOnCallback ? " data-reload-on-callback='1'" : "")
            +     " data-upload-url='" + protectQS.create("../shared/BijlagenForm.asp?key=" + (params.key || -1) + "&module=" + params.module) + "'>"
            + "</span>";
    return result;
}

function ICONPICKERTR_HTML(pname, plabel, pvalue, params) {
    var result = "<tr>"
               + "    <td class='label'>"
               + "        <label>" + safe.html(plabel) + "</label>"
               + "    </td>"
    if (params.readonly) {
      result += "    <td>"
              + I(pvalue + " fa-lg")
              + "    </td>";
    } else {
      result += "    <td class='iconpicker'>"
              + "        <input type='hidden' id='" + pname + "' name='" + pname + "' value='" + safe.htmlattr(pvalue) + "'"
              +         (params.callback ? " data-callback='" + params.callback + "'" : "")
              +         (params.formid ? " form='" + params.formid + "'" : "") + ">"
              + ICONPICKER_HTML(pname, plabel, pvalue, params)
              + "        <span class='default-clickable-icon symbol-delete' aria-controls='" + pname + "' title='" + L("lcl_delete") + "'>"
              + I("fa-trash-alt")
              + "        </span>"
              + "    </td>";
    }
    result += "</tr>";
    return result;
}

function FILEPICKERTR_HTML(pname, plabel, pvalue, params) {
    var fileProps = flexProps(params.module);
    if (pvalue !== null || // -> Vind 0 of 1 bestand
        !fileProps.multi && !fileProps.pickfile) { // (Deprecated) Soms zit hier toch een bestand bij, bijv. in de SML/MRK module
        fileProps = flexProps(params.module, params.key, null, null, { getFiles: true, getFile: pvalue });
        if (pvalue === null && fileProps.files.length > 0) { // Geen waarde, wel files gevonden; 1 map per 'key' -> pak de eerste (normaal is dit er ook max. 1)
            pvalue = fileProps.files[0].name;
            params.addDeleteUrl = "&DoDelete=" + Server.URLEncode(pvalue);
        }
    }
    if (params.readonly) {
        if (fileProps.files.length == 0 && (params.suppressEmpty && !(__Logging & 64))) {
            return; // Early exit
        }
        var regex = new RegExp(S("flexPreviewExt"), "i");
        var anyPreview = false;
        if (!fileProps.pickfile) {
          for (var i = 0; !anyPreview && i < fileProps.files.length; i++) {
              anyPreview |= regex.test(fileProps.files[i].name);
          }
        }

        var result = "<tr>"
                   + "    <td class='label'>"
                   + "        <label>" + safe.html(plabel) + "</label>"
                   + (anyPreview
                       ? "<span class='labelextra details preview'"
                       + " data-preview-url='" + safe.htmlattr(protectQS.create("../Shared/BijlagenPreview.asp?key=" + params.key + "&module=" + params.module))
                       + "' title='" + safe.htmlattr(L("lcl_flex_preview")) + "'>" + I("fa-image fa-lg") + "</span>"
                       : "")
                   + "    </td>"
                   + "    <td>"
                   + (fileProps.files.length && (!fileProps.multi || fileProps.pickfile) // => Max. 1 bestand
                       ? "<span class='details' onclick='FcltMgr.windowopen(\"" + safe.htmlattr(safe.jsstring(fileProps.files[0].deepurl)) + "\", \"" + safe.htmlattr(plabel) + "\")'>" + safe.html(pvalue || fileProps.files[0].name) + "</span>"
                       : "")
                   + "    </td>"
                   + "</tr>";
    } else {
        var result = "<tr>"
                   + "    <td class='label'>"
                   + "        <label>" + safe.html(plabel) + "</label>"
                   + "    </td>"
                   + "    <td class='filepicker'>"
                   + "        <input type='hidden' id='" + pname + "' name='" + pname + "' value='" + safe.htmlattr(pvalue) + "'"
                   +          (params.callback ? " data-callback='" + params.callback + "'" : "")
                   +          (params.formid ? " form='" + params.formid + "'" : "") + ">"
                   + FILEPICKER_HTML(pname, plabel, pvalue, params)
                   + "        <span class='default-clickable-icon symbol-delete' aria-controls='" + pname + "' title='" + L("lcl_delete") + "'"
                   + (fileProps.linkImmediate || !(fileProps.multi && fileProps.pickfile) // Bij multi = true && pickfile = true wordt er met deze knop niets gedelete
                      ? " data-delete-url='" + safe.htmlattr(protectQS.create(rooturl + "/appl/Shared/Bijlagenform_delete.asp?key=" + (params.key || -1) + "&module=" + params.module + (params.addDeleteUrl || ""))) + "'"
                      : "")
                   +          ">"
                   + I("fa-trash-alt")
                   + "        </span>"
                   + "    </td>"
                   + "</tr>";
    }
    return result;
}

function ROSYMBOLTR_HTML(pname, plabel, pvalue, params)
{
    var valType = 0;
    if (pvalue) {
      if (pvalue.indexOf("fa-") === 0) {
        valType = 1; // Icon
      } else {
        valType = 2; // Image
      }
    }

    if (valType == 0 && (params.suppressEmpty && !(__Logging & 64)))
      return; // Early exit

    params.readonly = true;
    return valType == 2 ? FILEPICKERTR_HTML(pname, plabel, pvalue, params)
                        : ICONPICKERTR_HTML(pname, plabel, pvalue, params);
}

function ROSYMBOLTR(pname, plabel, pvalue, params)
{
    params = params || {};
    params.suppressEmpty = params.suppressEmpty || true; // Default true
    Response.Write(ROSYMBOLTR_HTML(pname, plabel, pvalue, params));
}

// Laat 2 knoppen zien, 1 voor de iconpicker en 1 voor de filepicker.
function RWSYMBOLTR_HTML(pname, plabel, pvalue, params)
{
    var valType = 0; // Geen waarde
    if (pvalue) {
        valType = pvalue.indexOf("fa-") === 0 ? 1 : 2; // 0=Geen waard, 1=Icon, 2=Image
    }
    var result = "<tr>"
               + "    <td class='label'>"
               + "        <label>" + safe.html(plabel) + "</label>"
               + "    </td>"
               + "    <td data-type='" + valType + "'>"
               + "        <input type='hidden' id='" + pname + "' name='" + pname + "' value='" + safe.htmlattr(pvalue) + "'"
               +          (params.callback ? " data-callback='" + params.callback + "'" : "")
               +          (params.formid ? " form='" + params.formid + "'" : "") + ">"
               + ICONPICKER_HTML(pname, plabel, pvalue, params)
               + FILEPICKER_HTML(pname, plabel, pvalue, params)
               + "        <span class='default-clickable-icon symbol-delete' aria-controls='" + pname + "' title='" + L("lcl_delete") + "'"
               + (valType == 2 ? " data-delete-url='" + safe.htmlattr(protectQS.create(rooturl + "/appl/Shared/Bijlagenform_delete.asp?DoDelete=" + Server.URLEncode(pvalue) + "&key=" + (params.key || -1) + "&module=" + params.module)) + "'"
                               : "")
               +          ">"
               + I("fa-trash-alt")
               + "        </span>"
               + "    </td>"
               + "</tr>";
    return result;
}

function ICONPICKERTR(pname, plabel, pvalue, params) {
    params = params || {};
    params.suppressEmpty = params.suppressEmpty || params.readonly; // Default true bij readonly
    Response.Write(ICONPICKERTR_HTML(pname, plabel, pvalue, params));
}

function FILEPICKERTR(pname, plabel, pvalue, params) {
    params = params || {};
    params.suppressEmpty = params.suppressEmpty || params.readonly; // Default true bij readonly
    Response.Write(FILEPICKERTR_HTML(pname, plabel, pvalue, params));
}

function RWSYMBOLTR(pname, plabel, pvalue, params)
{
    params = params || {};
    Response.Write(RWSYMBOLTR_HTML(pname, plabel, pvalue, params));
}

function RWCHECKBOXTR(pname, pclass, plabel, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)) && params.readonly)
    return; // snel klaar
%>
  <tr <%=params.trclass?"class='"+params.trclass+"'":""%>>
<%
  if (!params.boxfirst) {
    if (plabel) {
        %><td class="label" <%=params.hidden?"style=\"visibility:hidden\"" : ""%>><label for="<%=pname %>"><%=plabel?plabel:""%></label></td><td><%
      } else {
        %><td class="label"></td><td><%
      }
      CHECKBOX(pclass, pname, pvalue, params)
      if (params.posthtml)
        Response.Write(params.posthtml);
      if (plabel) { %></td><% }
    } else {
        if (params.twocols) {
          %><td class="label"><span class="labelextra"><% CHECKBOX(pclass, pname, pvalue, params)
          %></span></td><td><%
        } else {
          %><td colspan="2"><% CHECKBOX(pclass, pname, pvalue, params)
        }
        if (plabel) {
          %><label for="<%=pname %>"><%=plabel?plabel:""%></label></td><%
        } else {
          %></td><%
        }
    }
    %></tr><%
}

function CHECKBOXTR(plabel, pclass, pid, pvalue, params) // DEPCRECATED, backward compatible
{
    RWCHECKBOXTR(pid, pclass, plabel, pvalue, params);
};

function ROCHECKBOXTR(pclass, plabel, pvalue, params)
{
  params = params||{};
  if ((pvalue == null || pvalue == "") && (params.suppressEmpty && !(__Logging & 64)))
    return; // snel klaar
  if ((pvalue == 0) && params.suppressNo)
    return; // snel klaar
  if ((pvalue) && params.suppressYes)
    return; // snel klaar

  pvalue = (pvalue?L("lcl_Yes"):L("lcl_No"));
  ROFIELDTR(pclass, plabel, pvalue, params)
}

function RWRADIOTR(pname, params)
{
    var params = params || {};
    var result = "<tr" + (params.trclass ? " class='" + params.trclass + "'" : "" ) + ">";
    if (params.label != null)
    {
        result += "<td>";
        if (params.label != "")
        {
            result += "<label>" + safe.html(params.label) + "</label>";
        }
        result += "</td>";
    }
    result += "<td>";
    for (var i=0; i<params.radios.length; i++)
    {
        var radio = params.radios[i];
        result += (params.horizontal ? "" : "<div>")
                + "<label for='" + radio.id + "'>"
                + "<input type='radio' name='" + pname + "' id='" + radio.id + "' value='" + radio.rval + "'"
                  + (params.onchange ? " onChange='" + params.onchange + "'" : "")
                  + (params.formid ? " form='" + params.formid + "'" : "")
                  + (params.initval && params.initval == radio.rval ? " checked" : "")
                + ">"
                + safe.html(radio.label)
                + "</label>"
                + (params.horizontal ? "" : "</div>");
    }
    result += "</td></tr>";
    Response.Write(result);
}

function GROUP_CHECK(pgroup, pclass, pvalue, params, pkey)
{
    var params = params || {};
    var group_val = pvalue & pgroup.mask;
    var isallreadonly = params.readonly;

    Response.Write("<tr " + (params.trclass ? "class=\"" + params.trclass + "\"" : "") + ">");
    if (pgroup.label) {
      Response.Write("<td class=\"label " + pclass + "\">");
      Response.Write("<label>" + (pgroup.label?safe.html(pgroup.label):"") + "</label>");
      Response.Write("</td>");
    }

    Response.Write("<td>");
    for (var i=0; i<pgroup.bits.length; i++)
    {
        var chk = pgroup.bits[i];
        var bit = 1 << i;

        var defaultchecked = pkey < 0 && (pgroup.defaultmask & bit);
        var ischecked = (chk.mask == 0
                        ? (group_val == chk.mask)
                        : ((group_val & chk.mask) == chk.mask)
                        );
        var isreadonly = isallreadonly || chk.readonly;

        Response.Write("\n<input type=\"hidden\" id=\"has_" + pgroup.name + "_" + bit + "\" name=\"has_" + pgroup.name + "_" + bit + "\" value=\"1\""
                      + (params.formid ? " form='" + params.formid + "'" : "")
                      + (params.readonly ? " disabled" : "")
                      +">");

        if (isreadonly)
        {   // LET OP: Bij readonly wordt dit veld altijd aan de form-parameters meegegeven met waarde "on" of leeg.
            //         Dit is nodig om een aangevinkt bitje ook aangevinkt te laten bij het bewaren.
            Response.Write("<input type=\"hidden\" id=\"" + pgroup.name + "_" + bit + "\" name=\"" + pgroup.name + "_" + bit + "\""
                          + " value=\"" + (ischecked?"on":"") + "\""
                          + (params.formid ? " form='" + params.formid + "'" : "")
                          + ">");
            Response.Write("<input type=\"checkbox\" id=\"lbl_" + pgroup.name + "_" + bit + "\" name=\"lbl_" + pgroup.name + "_" + bit + "\""
                          +" class=\"fldcheck\""
                          + (ischecked || defaultchecked ? " CHECKED" : "")
                          + (params.formid ? " form='" + params.formid + "'" : "")
                          + " disabled"
                          + (params.html ? params.html : "")
                          +">");
            if (chk.label)
            {
                Response.Write("<label for=\"lbl_" + pgroup.name + "_" + bit + "\">" + (chk.label ? chk.label :"") + "</label>");
            }
        }
        else
        {   // LET OP: Bij editable wordt dit veld alleen aan de form-parameter meegegeven als het veld aangevinkt is (en waarde "on" heeft).
            Response.Write("<input type=\"checkbox\" id=\"" + pgroup.name + "_" + bit + "\" name=\"" + pgroup.name + "_" + bit + "\""
                          +" class=\"fldcheck\" data-name=\"" + pgroup.name + "\""
                          +" mask=\"" + chk.mask + "\""
                          + (ischecked || defaultchecked ? " CHECKED" : "")
                          + (params.hidden ? " style=\"visibility:hidden\"" : "")
                          + (params.formid ? " form='" + params.formid + "'" : "")
                          + (params.html ? params.html : "")
                          +">");
            if (chk.label)
            {
                Response.Write("<label for=\"" + pgroup.name + "_" + bit + "\">" + (chk.label ? chk.label :"") + "</label>");
            }
        }
        Response.Write("<br>");
    }
    Response.Write("</td>");
    Response.Write("</tr>");
}

// Functie t.b.v. tijd velden
// altijd :-syntax
// serverside versie
function decimalToHour(val)
{
    if (!val || val == 0)
        return "";
    var mintime = Math.abs(val) != val; // is tijd negatief of positief
    var hh = Math.floor(Math.abs(val) + 0.5 / 60); // reken met positief tijd
    var mm = Math.floor((Math.abs(val) - hh) * 60 + 0.5);

    var timestr = String(hh) + ":" + String((mm < 10? "0" : "") + mm);
    return (mintime ? "-" + timestr : timestr); // voeg eventueel weer min-teken toe
}

// Kopie in ../shared/iface.inc
IFACE =
{
    FORM_END: function(params)
    {
        protectRequest.inputToken(params || {});
    }
}

function SYMBOL(name, params) {
    params = params || {};
    var symbol = name || params.defVal;
    if (symbol && symbol.match(/^fa-/) !== null) {
        return I(symbol, params);
    } else {
        return IMG(symbol, params);
    }
}

function IMG(fileName, params) {
    if ("module" in params) {
        var fso = Server.CreateObject("Scripting.FileSystemObject");
        var flexParams = {};
        if ("key" in params) {
            flexParams.getFiles = true;
        } else if (fileName) {
            flexParams.getFile = fileName;
        }
        flexParams.cacheablehmac = true;
        var fileProps = flexProps(params.module, params.key || null, null, null, flexParams);
        if (fileProps.files.length && fso.FileExists(fileProps.AttachPath + fileProps.files[0].name)) {
            return "<img loading='lazy' src='" + safe.htmlattr(fileProps.files[0].deepurl) + "' alt='" + safe.htmlattr(params.alt || L("lcl_photos")) + "'>";
        } else if (fileName) {
            return "<span title='{0}'>".format(safe.htmlattr(fileName || "")) + I("fa-question") + "</span>";
        }
    }
    return "";
}

// Returns a Font Awesome icon to be displayed (e.g. "fa-user")
// fa-qualifiers (e.g. "fa-2x fa-rotate-180") are preserved
// icons may be defined in icons.inc by Facilitor with a fa-fclt- prefix
// The optional params provides some options
//    params.fastyle: overrule global fastyle
//    params.fa_fw:   overrule fa-fw class (by default this class is added)
function I(icon, params)
{
    if (!icon)
        return "";
    var params = params || {};

    if (icon.match(/^fa-/))
    {
        var lstyle = params.fastyle == null ? S("fontawesomestyle") : params.fastyle;
        var fa_fw = !("fa_fw" in params) || params.fa_fw ? " fa-fw" : ""; /* Default met fa-fw maar je kunt het er afhalen met { fa-fw: false } */
        var icon_arr = icon.split(/\s/);
        for (var i = 0; i < icon_arr.length; i++)
            icon_arr[i] = ICONS.placeholder(icon_arr[i]); /* Vervang door placeholder icon indien aanwezig */
        icon = icon_arr.join(" ");

        /* Geef ik een style mee in de icoon naam, bijv: I("fa-image fas"), dan is die leidend, nuttig voor placeholder-overrules */
        var styles = ["fal", "far", "fas"];
        for (style in styles)
            if (inArray(styles[style], icon.split(/\s/)))
            {
                lstyle = styles[style];
                icon = icon.replace(new RegExp("\\s?" + lstyle), "");
            }
        return "<i class='{0}{1} {2}'></i>".format(lstyle, fa_fw, safe.htmlattr(icon));
    }
    return "";
}

// Aanroep te plaatsen zo laat mogelijk in <head><script>
function OVERRULELAYOUT(screenname, params)
{
    params = params || {};
    var sql = "SELECT fac_layout_options"
            + "     , fac_layout_version" // ignored for now
            + "  FROM fac_layout"
            + " WHERE fac_layout_screen = " + safe.quoted_sql(screenname);
    var oRs =Oracle.Execute(sql);
    if (oRs.EOF)
    {
        oRs.Close()
        return;
    }
    var layoutfields = oRs("fac_layout_options").Value;
    oRs.Close();
    /*
    var layoutfields = [{ "action": "move", "from": "#disc_show", "closest": "tr", "to": "#account_show", "where": "insertAfter" }
                       ,{ "action": "move", "from": "#verdieping", "closest": "tr", "to": "#person_show", "where": "insertBefore"}
                       ,{ "action": "move", "from": "#flx1", "to": "#mldCaller", "where": "insertAfter"}
                       ,{ "action": "hide", "from": "#gebouw", "closest": "tr", "newonly":false}
                       ];
    */
%>
    $(function ()
    {
        var layoutfields = JSON.parse("<%=safe.jsstring(layoutfields)%>");
        var params = JSON.parse("<%=safe.jsstring(JSON.stringify(params))%>");
        iface.overrulelayout(layoutfields, params );
    });
<%
}
%>
