private void buildHiddenSelectorWidget(
      SerialisationContext pSerialisationContext,
      HTMLSerialiser pSerialiser,
      EvaluatedNodeInfoItem pEvalNode,
      List<FieldSelectOption> pSelectOptions) {
    Map<String, Object> lTemplateVars =
        super.getGenericTemplateVars(pSerialisationContext, pSerialiser, pEvalNode);

    // Force the style to be off screen
    lTemplateVars.put("Style", "position: absolute; left: -999em;");

    if (pEvalNode.getSelectorMaxCardinality() > 1) {
      lTemplateVars.put("Multiple", true);
    }

    // Always set size greater than 2, otherwise all fields post back with first value
    lTemplateVars.put("Size", Math.max(2, pSelectOptions.size()));

    List<Map<String, Object>> lOptions = new ArrayList<>();
    OPTION_LOOP:
    for (FieldSelectOption lOption : pSelectOptions) {
      if (lOption.isHistorical() && !lOption.isSelected()) {
        // Skip un-selected historical items
        continue OPTION_LOOP;
      }
      Map<String, Object> lOptionVars = new HashMap<>(3);
      lOptionVars.put("Key", lOption.getDisplayKey());
      lOptionVars.put("Value", lOption.getExternalFieldValue());
      if (lOption.isSelected()) {
        lOptionVars.put("Selected", true);
      }
      if (lOption.isDisabled()) {
        lOptionVars.put("Disabled", true);
      }
      lOptions.add(lOptionVars);
    }
    lTemplateVars.put("Options", lOptions);

    MustacheFragmentBuilder.applyMapToTemplate(
        SELECTOR_MUSTACHE_TEMPLATE, lTemplateVars, pSerialiser.getWriter());
  }
  /**
   * Take in all the lists from the mapset and generate a JSON object array for each entry, to be
   * used by the search-selector widget
   *
   * @param pEvalNode Current ENI to get options from
   * @param pBaseURL Base URL of static servlet to replace %IMAGE_BASE% with in suggestion text
   * @return String of the JSON array to be set at the top of the page
   */
  private String mapsetToJSON(EvaluatedNodeInfoItem pEvalNode, String pBaseURL) {
    JSONArray lMapsetJSON = new JSONArray();
    JSONObject lMapsetObject = new JSONObject();
    JSONObject lJSONEntry;

    int i = 1;
    for (FieldSelectOption lItem : filteredOptionList(pEvalNode)) {
      FieldSelectOption lSearchableItem = lItem;

      String lHiddenSearchable = lItem.getAdditionalProperty(HIDDEN_SEARCHABLE_MS_PROPERTY);
      String lSuggestion = lItem.getAdditionalProperty(SUGGESTION_DISPLAY_MS_PROPERTY);
      String lLevel = lItem.getAdditionalProperty(LEVEL_MS_PROPERTY);

      if ((pEvalNode.getFieldMgr().getVisibility() == NodeVisibility.VIEW && !lItem.isSelected())) {
        // Skip putting it in the JSON if it's got null entries or in read only mode and not
        // selected
        continue;
      }

      lJSONEntry = new JSONObject();

      lJSONEntry.put("id", lSearchableItem.getExternalFieldValue());
      lJSONEntry.put(KEY_JSON_PROPERTY, lSearchableItem.getDisplayKey());
      lJSONEntry.put(SORT_JSON_PROPERTY, i++);

      // Add suggestion text (if none in mapset the JS will use the key safely escaped)
      if (!XFUtil.isNull(lSuggestion)) {
        lJSONEntry.put(
            SUGGESTION_DISPLAY_JSON_PROPERTY,
            StringEscapeUtils.escapeHtml4(lSuggestion.replaceAll("%IMAGE_BASE%", pBaseURL)));
      }

      lJSONEntry.put(HIDDEN_SEARCHABLE_JSON_PROPERTY, XFUtil.nvl(lHiddenSearchable, ""));

      // Add entry for hierarchical data
      if (lLevel != null) {
        lJSONEntry.put(LEVEL_JSON_PROPERTY, lLevel);
      }

      // If it was selected add that entry
      if (lSearchableItem.isSelected()) {
        lJSONEntry.put(SELECTED_JSON_PROPERTY, true);
      }

      // If it's a historical entry add that entry
      if (lSearchableItem.isHistorical()) {
        lJSONEntry.put(HISTORICAL_JSON_PROPERTY, true);
        lJSONEntry.put(SUGGESTABLE_JSON_PROPERTY, false);
      } else {
        lJSONEntry.put(SUGGESTABLE_JSON_PROPERTY, true);
      }

      if (lSearchableItem.getAdditionalProperty(OptionFieldMgr.FREE_TEXT_ADDITIONAL_PROPERTY)
          != null) {
        lJSONEntry.put(FREE_TEXT_JSON_PROPERTY, true);
      }

      lJSONEntry.put(DISABLED_JSON_PROPERTY, lSearchableItem.isDisabled());

      lMapsetJSON.add(lJSONEntry);
      lMapsetObject.put(lSearchableItem.getExternalFieldValue(), lJSONEntry);
    }
    return lMapsetObject.toJSONString();
  }