Esri / geoform-template-js

GeoForm is a configurable template for form based data editing of a Feature Service.
http://esri.github.io/geoform-template-js/
Apache License 2.0
67 stars 83 forks source link

Fields : Concantenate Live On GeoForm? #551

Open randomblink opened 6 years ago

randomblink commented 6 years ago

So I'm using the GeoForm to allow our permitting department to INSTANTLY create new Addresses in order to assign Permits when an address isn't in our Site Address Points "Address GeoDatabase."

What this means is that I would LOVE to avoid user-input-errors by avoid duplicate entries.

We currently need users to input the following fields.

ADDRNUM (such as 175 in 175 E 2ND ST S) PREADDRNUM (such as E in 175 E 2ND ST S) STREETNAME (such as 2ND in 175 E 2ND ST S) STREETTYPE (such as ST in 175 E 2ND ST S) ADDRNUMSUF (such as S in 175 E 2ND ST S) FULLNAME (such as E 2ND ST S in 175 E 2ND ST S) FULLADDR (such as 175 E 2ND ST S in 175 E 2ND ST S)

So I'm hoping / wondering... Is there anyway to concantenate the FULLNAME and FULLADDR field based on the entries in the other fields?

randomblink commented 6 years ago

Updated GeoForm DEFAULT.JS File... Added some new attributes that are utilized in my customized MAIN.JS.

{
    "name": "FULLADDR", // field id
    "alias": "Full Address", // label   
    "fieldDescription": "The Full Address as in 175 E 2ND ST S for 175 E 2ND ST S", // Help text
    "visible": true, // show this field?
    "typeField": false, // subtype field?
    "tooltip": "175 E 2ND ST S, SUITE 3", // placeholder text
    "locked": true, // is this field editable on the main form?
    "subscription": [
        {
            "publication": "${0.value} ${1.value} ${2.value} ${3.value} ${4.value}, ${5.value} ${6.value}", 
            "editorFields": [ "ADDRNUM", "PREADDRNUM", "STREETNAME", "STREETTYPE", "ADDRNUMSUF", "UNITTYPE", "UNITID" ],
            "required": [ "UNITID", "UNITTYPE" ]
        },
        {
            "publication": "${0.value} ${1.value} ${2.value} ${3.value} ${4.value}, ${5.value}", 
            "editorFields": [ "ADDRNUM", "PREADDRNUM", "STREETNAME", "STREETTYPE", "ADDRNUMSUF", "UNITID" ],
            "required": [ "UNITID" ]
        },
        {
            "publication": "${0.value} ${1.value} ${2.value} ${3.value} ${4.value}, ${5.value}", 
            "editorFields": [ "ADDRNUM", "PREADDRNUM", "STREETNAME", "STREETTYPE", "ADDRNUMSUF", "UNITTYPE" ],
            "required": [ "UNITTYPE" ]
        },
        {
            "publication": "${0.value} ${1.value} ${2.value} ${3.value} ${4.value}",
            "editorFields": [ "ADDRNUM", "PREADDRNUM", "STREETNAME", "STREETTYPE", "ADDRNUMSUF" ],
            "required": []
        }
    ],
    "displayType": "text" // text, checkbox, radio, textarea, url, email
},

As you can see there is a new attribute "SUBSCRIPTION" that holds a new object type. The new object type holds a PUBLICATION, EDITORFIELDS (list) and a REQUIRED fields (list). The order these publications are placed in the SUBSCRIPTION list is important. The strictest REQUIRED fields need to be at the top of the list. Also the EDITORFIELDS order of entry needs to match the publication format...

randomblink commented 6 years ago

Here is the new MAIN.JS

` /global $,define,document,require,moment / /jslint sloppy:true,nomen:true / define([ "dojo/_base/declare", "dojo/_base/kernel", "dojo/_base/lang", "dojo/topic", "dojo/string", "esri/dijit/BasemapToggle", "esri/arcgis/utils", "esri/config", "dojo/dom", "dojo/dom-class", "dojo/dom-style", "dojo/on", "dojo/Deferred", "dojo/promise/all", "dojo/query", "dojo/io-query", "dojo/_base/array", "dojo/dom-construct", "dojo/dom-attr", "esri/dijit/LocateButton", "esri/dijit/Search", "dojo/text!views/modal.html", "dojo/text!views/user.html", "dojo/i18n!application/nls/resources", "esri/tasks/ProjectParameters", "esri/geometry/webMercatorUtils", "esri/geometry/Point", "esri/layers/GraphicsLayer", "application/ShareModal", "application/localStorageHelper", "esri/graphic", "esri/symbols/PictureMarkerSymbol", "esri/toolbars/edit", "esri/InfoTemplate", "esri/dijit/Popup", "application/themes", "application/pushpins", "application/SearchSources", "vendor/usng", "dijit/a11yclick", "dojo/NodeList-traverse", "application/wrapper/main-jquery-deps", "dojo/domReady!" ], function ( declare, kernel, lang, topic, string, basemapToggle, arcgisUtils, esriConfig, dom, domClass, domStyle, on, Deferred, all, query, ioQuery, array, domConstruct, domAttr, LocateButton, Search, modalTemplate, userTemplate, nls, ProjectParameters, webMercatorUtils, Point, GraphicsLayer, ShareModal, localStorageHelper, Graphic, PictureMarkerSymbol, editToolbar, InfoTemplate, Popup, theme, pushpins, SearchSources, usng, a11yclick) {

var NORTHING_OFFSET = 10000000.0; // (meters)

return declare([], { arrPendingAttachments: [], objFailedAttachments: {}, arrRetryAttachments: [], flagAttachingPrevFile: true, nls: nls, config: {}, map: null, addressGeometry: null, editToolbar: null, themes: theme, pins: pushpins, localStorageSupport: null, defaultValueAttributes: null, sortedFields: [], isHumanEntry: null, currentLocation: null, dateFormat: "LLL", subscriptions: [],

startup: function (config, appResponse, isPreview, node) {

  document.documentElement.lang = kernel.locale;

  this._appResponse = appResponse;
  var localStorageSupport = new localStorageHelper();
  if (localStorageSupport.supportsStorage() && localStorage.getItem("geoform_config")) {
    config = JSON.parse(localStorage.getItem("geoform_config"));
    localStorage.clear();
  }
  // config will contain application and user defined info for the template such as i18n strings, the web map id
  // and application id
  // any url parameters and any application specific configuration information.
  if (config) {
    this.config = config;
    // create localstorage helper
    this.localStorageSupport = new localStorageHelper();
    // modal i18n
    var modalTemplateSub = string.substitute(modalTemplate, {
      id: "myModal",
      title: "",
      labelId: "myModalLabel",
      close: nls.user.close
    });
    // place modal code
    domConstruct.place(modalTemplateSub, document.body, 'last');
    //supply either the webmap id or, if available, the item info
    if (isPreview) {
      this._initPreview(node);
    } else {
      this._init();
    }
  } else {
    var error = new Error("Main:: Config is not defined");
    this.reportError(error);
  }
},

_loadCSS: function () {
  var cssStyle;
  cssStyle = dom.byId("rtlCSS");
  cssStyle.href = "js/vendor/bootstrap-rtl.min.css";
},

_init: function () {
  var userHTML, itemInfo;
  // no theme set
  if (!this.config.theme) {
    // lets use bootstrap theme!
    this.config.theme = "basic";
  }
  // set theme
  this._switchStyle(this.config.theme);
  if (this.config && this.config.i18n && this.config.i18n.direction == "rtl") {
    this._loadCSS();
  }
  userHTML = string.substitute(userTemplate, nls);
  dom.byId("parentContainter").innerHTML = userHTML;
  // get item info from template
  itemInfo = this.config.itemInfo || this.config.webmap;
  // create map
  this._createWebMap(itemInfo);
  // if small header is set
  if (this.config.useSmallHeader) {
    // remove class
    domClass.remove(dom.byId('jumbotronNode'), "jumbotron");
  }
},
_initPreview: function (node) {
  var cssStyle;
  // if local storage supported
  if (this.localStorageSupport.supportsStorage()) {
    localStorage.setItem("geoform_config", JSON.stringify(this.config));
  }
  // set theme to selected
  array.forEach(this.themes, lang.hitch(this, function (currentTheme) {
    if (this.config.theme == currentTheme.id && currentTheme.url) {
      cssStyle = domConstruct.create('link', {
        rel: 'stylesheet',
        type: 'text/css',
        href: currentTheme.url
      });
    }
  }));
  //Handle case where edit is first url parameter we'll use the same logic we used in ShareModal.js
  var url = 'https://' + window.location.host + window.location.pathname;
  if (window.location.href.indexOf("?") > -1) {
    var queryUrl = window.location.href;
    var urlParams = ioQuery.queryToObject(window.location.search.substring(1)),
      newParams = lang.clone(urlParams);
    delete newParams.edit; //Remove edit parameter
    delete newParams.folderid; //Remove folderid parameter
    url = queryUrl.substring(0, queryUrl.indexOf("?") + 1) + ioQuery.objectToQuery(newParams);
  }
  node.src = url;
  // on iframe load
  node.onload = function () {
    var frame = document.getElementById("iframeContainer").contentWindow.document;
    var h = frame.getElementsByTagName('head')[0];
    if (h && cssStyle) {
      domConstruct.place(cssStyle, h, "last");
    }
  };
},
_submitForm: function () {
  var btn = $('#submitButton');
  btn.button('loading');
  var erroneousFields = [];
  array.forEach(query(".geoFormQuestionare"), lang.hitch(this, function (currentField) {
    if (domClass.contains(currentField, "hasAttachment")) {
      if (domClass.contains(currentField, "mandatory") && query(".alert-dismissable", dom.byId("divColumn2")).length === 0) {
        this._validateUserInput(nls.user.requiredFields, currentField, query(".hideFileInputUI")[0].value, true);
        erroneousFields.push(currentField);
      }
      return true;
    }
    //to check for errors in form before submitting.
    //condition check to filter out radio fields
    if (query(".form-control", currentField)[0]) {
      //if condition to check for conditions where the entered values are erroneous.
      if (domClass.contains(currentField, "has-error") && query("select", currentField).length === 0) {
        erroneousFields.push(currentField);
      }
      //if condition to check for conditions where mandatory fields are kept empty.
      if ((query(".form-control", currentField)[0] && (query(".form-control", currentField)[0].value === "") && domClass.contains(currentField, "mandatory")) || (query(".filterSelect", currentField)[0] && (query(".filterSelect", currentField)[0].value === "") && domClass.contains(currentField, "mandatory"))) {
        var selectValue = query(".form-control", currentField)[0] ? query(".form-control", currentField)[0].value : query(".filterSelect", currentField)[1].value;
        this._validateUserInput(nls.user.requiredFields, currentField, query(".form-control", selectValue, true));
        erroneousFields.push(currentField);
      } else {
        if (domClass.contains(currentField, "mandatory")) {
          var mandatoryValue = query(".form-control", currentField)[0] ? query(".form-control", currentField)[0].value : query(".filterSelect", currentField)[1].value;
          this._validateUserInput(false, currentField, mandatoryValue, true);
        }
      }
    }
    //handle errors in radio and checkbox fields here.
    else {
      if (!query(".filterSelect", currentField)[0]) {
        if (domClass.contains(currentField, "mandatory") && query(".radioInput:checked", currentField).length === 0 && query(".checkboxContainer", currentField).length === 0) {
          this._validateUserInput(nls.user.requiredFields, currentField, query(".radioInput:checked", currentField), true);
          erroneousFields.push(currentField);
        } else {
          if (domClass.contains(currentField, "mandatory")) {
            this._validateUserInput(false, currentField, query(".radioInput:checked", currentField), true);
          }
        }
      }
    }
  }));
  array.forEach(query(".filterSelect"), lang.hitch(this, function (currentField) {
    if (currentField.value === "" && domClass.contains(currentField.parentElement, "mandatory")) {
      this._validateUserInput(nls.user.requiredFields, currentField, currentField.value, true);
      erroneousFields.push(currentField);
    }
  }));
  //this statement will remove the error message div at first and then will be applied if a valid location is not selected
  this._removeErrorNode(dom.byId("select_location").nextSibling);
  //conditional blocks to check and validate the form and show appropriate error messages.
  var errorMessage;
  if (erroneousFields.length !== 0) {
    if (!this.addressGeometry) {
      // reset submit button
      this._resetButton();
      // error message
      errorMessage = '';
      errorMessage += nls.user.selectLocation;
      this._showErrorMessageDiv(errorMessage, dom.byId("select_location"));
    }
    var elementId;
    if (!erroneousFields[0].children[0].id) {
      elementId = erroneousFields[0].parentElement.children[0].id;
      domClass.remove(elementId, "has-success");
    } else {
      elementId = erroneousFields[0].children[0].id;
    }
    $('html, body').animate({
      scrollTop: $("#" + elementId).offset().top
    }, 500);
    btn.button('reset');
  } else {
    if (this.addressGeometry) {
      this._addFeatureToLayer();
    } else {
      // reset submit button
      this._resetButton();
      // error message
      errorMessage = '';
      errorMessage += nls.user.selectLocation;
      this._showErrorMessageDiv(errorMessage, dom.byId("select_location"));
      $('html, body').animate({
        scrollTop: $("#select_location").offset().top
      }, 500);
    }
  }
},
reportError: function (error) {
  // remove loading class from body
  domClass.remove(document.body, "app-loading");
  domClass.add(document.body, "app-error");
  // an error occurred - notify the user. In this example we pull the string from the
  // resource.js file located in the nls folder because we've set the application up
  // for localization. If you don't need to support multiple languages you can hardcode the
  // strings here and comment out the call in index.html to get the localization strings.
  // set message
  var node = dom.byId("loading_message");
  if (node) {
    if (this.config && this.config.i18n) {
      node.innerHTML = this.config.i18n.map.error + ": " + error.message;
    } else {
      node.innerHTML = "Unable to create map: " + error.message;
    }
  }
},
_centerPopup: function () {
  if (this.map.infoWindow && this.map.infoWindow.isShowing) {
    var location = this.map.infoWindow.location;
    if (location) {
      this.map.centerAt(location);
    }
  }
},
_resizeInfoWin: function () {
  if (this.map.infoWindow) {
    var iw, ih;
    var h = this.map.height;
    var w = this.map.width;
    // width
    if (w < 300) {
      iw = 125;
    } else if (w < 600) {
      iw = 200;
    } else {
      iw = 300;
    }
    // height
    if (h < 300) {
      ih = 75;
    } else if (h < 600) {
      ih = 100;
    } else {
      ih = 200;
    }
    this.map.infoWindow.resize(iw, ih);
  }
},
// set symbol for submitting location
_setSymbol: function (point, isMapClicked) {
  if (this.map.infoWindow) {
    var symbolUrl, pictureMarkerSymbol, graphic, it;
    // use appropriate symbol pin image
    array.some(this.pins, lang.hitch(this, function (currentPin) {
      if (this.config.pushpinColor == currentPin.id) {
        symbolUrl = currentPin.url;
        // create symbol and offset 10 to the left and 17 to the bottom so it points correctly
        pictureMarkerSymbol = new PictureMarkerSymbol(symbolUrl, currentPin.width, currentPin.height).setOffset(currentPin.offset.x, currentPin.offset.y);
        // text info template
        it = new InfoTemplate(nls.user.locationPopupTitle, "${text}");
        // graphic for point
        graphic = new Graphic(point, pictureMarkerSymbol, {
          text: nls.user.addressSearchText
        }, it);
        // private geoform graphic identifier
        graphic._geoformGraphic = true;
        // add to graphics layer
        this._gl.add(graphic);
        // get current features
        var features = isMapClicked ? this.map.infoWindow.features : [];
        // remove existing geoform graphic(s)
        var filtered = array.filter(features, function (item) {
          return !item._geoformGraphic;
        });
        // add feature
        filtered.splice(0, 0, graphic);
        // set popup features
        this.map.infoWindow.setFeatures(filtered);
        // show popup
        this.map.infoWindow.show(graphic.geometry);
        // edit movable
        this.editToolbar.activate(editToolbar.MOVE, graphic, null);
        return true;
      }
    }));
  }
},
_setCoordInputs: function (pt) {
  // get lat/lng
  var lat = pt.getLatitude();
  var lng = pt.getLongitude();
  // if valid lat/lng
  if (typeof lat !== "undefined" && typeof lng !== "undefined") {
    dom.byId('lat_coord').value = lat.toFixed(5);
    dom.byId('lng_coord').value = lng.toFixed(5);
    // try to convert LL to other coordinates
    try {
      // set USNG
      var usngResult = usng.LLtoUSNG(lat, lng, 5);
      if (usngResult) {
        dom.byId('usng_coord').value = usngResult;
      }
      // set MGRS
      var mgrsResult = usng.LLtoMGRS(lat, lng, 5);
      if (mgrsResult) {
        dom.byId('mgrs_coord').value = mgrsResult;
      }
      // set UTM
      var utmResults = [];
      usng.LLtoUTM(lat, lng, utmResults);
      if (utmResults && utmResults.length === 3) {
        var northing = parseFloat(utmResults[1]);
        var easting = parseFloat(utmResults[0]);
        var zone = parseInt(utmResults[2], 10);
        if(northing < 0){
          zone += "S";
          northing = northing + NORTHING_OFFSET;
        }
        else{
          zone += "N";
        }
        dom.byId('utm_easting').value = parseInt(easting, 10);
        dom.byId('utm_northing').value = parseInt(northing, 10);
        dom.byId('utm_zone_number').value = zone;
      }
    } catch (e) {
      console.log(e);
    }
  }
  this._checkUTM();
  this._checkMGRS();
  this._checkLatLng();
  this._checkUSNG();
},
// create lat lon point
_calculateLatLong: function (pt) {
  // return string
  var str = '';
  // if spatial ref is web mercator
  if (pt) {
    // get lat/lng
    var lat = pt.getLatitude();
    var lng = pt.getLongitude();
    if (lat && lng) {
      // create string
      str = nls.user.latitude + ': ' + lat.toFixed(5) + ', ' + '&nbsp;' + nls.user.longitude + ': ' + lng.toFixed(5);
    }
  }
  return str;
},
//function to set the logo-path, application title and details
_setAppConfigurations: function (appConfigurations) {
  var appLogoNode, appTitleNode, appDescNode;
  // get all nodes
  appLogoNode = dom.byId('appLogo');
  appTitleNode = dom.byId('appTitle');
  appDescNode = dom.byId('appDescription');
  // set logo
  if (appConfigurations.Logo && !this.config.disableLogo) {
    appLogoNode.src = appConfigurations.Logo;
  } else {
    domClass.add(appLogoNode, "hide");
  }
  // set title
  if (appConfigurations.Title) {
    appTitleNode.innerHTML = appConfigurations.Title;
  } else {
    domClass.add(appTitleNode, "hide");
  }
  // set description
  if (appConfigurations.Description) {
    appDescNode.innerHTML = appConfigurations.Description;
  } else {
    domClass.add(appDescNode, "hide");
  }
  // remove jumbotron style option
  if (domClass.contains(appLogoNode, "hide") && domClass.contains(appTitleNode, "hide") && domClass.contains(appDescNode, "hide")) {
    domClass.add(dom.byId('jumbotronNode'), "hide");
  }
},
//function to set the theme for application
_switchStyle: function (themeName) {
  array.forEach(this.themes, lang.hitch(this, function (currentTheme) {
    if (themeName == currentTheme.id && currentTheme.url) {
      var themeNode = domConstruct.create("link", {
        rel: "stylesheet",
        type: "text/css",
        href: currentTheme.url
      });
      domConstruct.place(themeNode, query("head")[0]);
      // add identifying theme class to the body
      domClass.add(document.body, "geoform-" + currentTheme.id);
    }
  }));
},
//function to validate and create the form
_createForm: function (fields) {
  // editable layer
  if (this._formLayer) {
    // if indexedDB is supported
    if (window.indexedDB && this.config.enableOfflineSupport) {
      // get offline support
      require(["application/OfflineSupport"], lang.hitch(this, function (OfflineSupport) {
        // support basic offline editing
        this._offlineSupport = new OfflineSupport({
          map: this.map,
          proxy: this.config.proxyurl,
          layer: this._formLayer
        });
      }));
    }
  }
  domConstruct.empty(dom.byId('userForm'));
  this.sortedFields = [];
  var formContent, labelContent, matchingField, newAddedFields = [],
    userFormNode;
  if (!this._formLayer) {
    this._showErrorMessageDiv(nls.user.noLayerConfiguredMessage, dom.byId("errorMessageDiv"));
    array.some(query(".row"), lang.hitch(this, function (currentNode) {
      if (currentNode.children) {
        if (domClass.contains(currentNode.children[0], "errorMessageDiv")) {
          array.forEach(query(currentNode).nextAll(), lang.hitch(this, function (currentNode) {
            domStyle.set(currentNode, "display", "none");
          }));
          return true;
        }
      }
    }));
    return;
  }
  array.forEach(this._formLayer.fields, lang.hitch(this, function (field) {
    var layerField = lang.clone(field);
    matchingField = false;
    array.forEach(fields, lang.hitch(this, function (currentField) {
      if (layerField.name == currentField.name && currentField.visible) {
        if (layerField.name === this._formLayer.typeIdField) {
          layerField.subTypes = this._formLayer.types;
          layerField.typeField = true;
        } else {
          layerField.typeField = false;
        }
        newAddedFields.push(lang.mixin(layerField, currentField));
        matchingField = true;
      } else if (layerField.name == currentField.name && currentField.hasOwnProperty("visible") && !currentField.visible) {
        matchingField = true;
      }
    }));
    if (!matchingField) {
      if ((layerField.editable && !(layerField.type === "esriFieldTypeOID" || layerField.type === "esriFieldTypeGeometry" || layerField.type === "esriFieldTypeBlob" || layerField.type === "esriFieldTypeRaster" || layerField.type === "esriFieldTypeGUID" || layerField.type === "esriFieldTypeGlobalID" || layerField.type === "esriFieldTypeXML"))) {
        if (layerField.name === this._formLayer.typeIdField) {
          layerField.subTypes = this._formLayer.types;
          layerField.typeField = true;
        } else {
          layerField.typeField = false;
        }
        layerField.isNewField = true;
        newAddedFields.push(layerField);
      }
    }
  }));
  array.forEach(fields, lang.hitch(this, function (sortedElement) {
    array.some(newAddedFields, lang.hitch(this, function (newElement) {
      var fName = newElement.name;
      if (this.config.appid) {
        if (sortedElement.name == fName) {
          this.sortedFields.push(newElement);
          return true;
        }
      } else {
        if (sortedElement.name == fName) {
          this.sortedFields.push(newElement);
          return true;
        }
      }
    }));
  }));
  array.forEach(this.sortedFields, lang.hitch(this, function (currentField, index) {
    //code to set true/false value to property 'isTypeDependent' of the field.
    currentField.isTypeDependent = false;
    array.forEach(this._formLayer.types, function (type) {
      var currentType = lang.clone(type);
      var hasDomainValue = null,
        hasDefaultValue = null;
      hasDomainValue = currentType.domains[currentField.name];
      hasDefaultValue = currentType.templates[0].prototype.attributes[currentField.name];
      //if hasDefaultValue is 0 then we need to set isTypeDependent property to true
      if (hasDefaultValue === 0) {
        hasDefaultValue = true;
      }
      if ((hasDomainValue && hasDomainValue.type !== "inherited") || (hasDefaultValue && !currentField.typeField)) {
        currentField.isTypeDependent = true;
      }
    });
    if (currentField.isTypeDependent) {
      return true;
    }
    //function to create form elements(referenceNode is passed null)
    this._createFormElements(currentField, index, null);
  }));
  // if form has attachments
  if (this._formLayer.hasAttachments && this.config.attachmentInfo[this._formLayer.id] && this.config.attachmentInfo[this._formLayer.id].enableAttachments) {
    var requireField = null,
      helpBlock, labelHTML = "",
      divRow, divColumn1, fileBtnSpan, fileInput, fileChange, divColumn2, fileForm;
    userFormNode = dom.byId('userForm');
    formContent = domConstruct.create("div", {
      className: "form-group hasAttachment geoFormQuestionare"
    }, userFormNode);
    //code to make the attachment input mandatory
    if (this.config.attachmentInfo[this._formLayer.id].attachmentIsRequired) {
      domClass.add(formContent, "mandatory");
      requireField = domConstruct.create("small", {
        className: 'requireFieldStyle',
        innerHTML: nls.user.requiredField
      }, formContent);
    }
    // attachment label html
    labelHTML += "<span class=\"glyphicon glyphicon-paperclip\"></span> ";
    labelHTML += (this.config.attachmentInfo[this._formLayer.id].attachmentLabel || nls.user.attachment);
    // attachment label
    labelContent = domConstruct.create("label", {
      innerHTML: labelHTML,
      id: "geoFormAttachmentLabel",
      "for": "geoFormAttachment"
    }, formContent);
    if (requireField && labelContent) {
      domConstruct.place(requireField, labelContent, "last");
    }
    divRow = domConstruct.create("div", {
      "class": "row"
    }, formContent);
    divColumn1 = domConstruct.create("div", {
      "class": "col-sm-2 form-group"
    }, divRow);
    fileBtnSpan = domConstruct.create("span", {
      "class": "btn btn-default btn-file",
      "innerHTML": nls.user.btnSelectFileText
    }, divColumn1);
    fileForm = domConstruct.create("form", {
      "class": "selectFileForm"
    }, fileBtnSpan);
    fileInput = domConstruct.create("input", {
      "type": "file",
      "class": "hideFileInputUI",
      "title": nls.user.selectFileTitle,
      "name": "attachment"
    }, fileForm);
    fileChange = on(fileInput, "change", lang.hitch(this, function (evt) {
      this._validateSelectedFile(evt, fileInput, fileBtnSpan, formContent, fileChange);
    }));
    if (this.config.attachmentInfo[this._formLayer.id].attachmentIsRequired) {
      fileInput.setAttribute("aria-required", true);
      fileInput.setAttribute("required", "");
    }
    if (this.config.attachmentInfo[this._formLayer.id].attachmentHelpText) {
      helpBlock = domConstruct.create("p", {
        className: "help-block",
        innerHTML: this.config.attachmentInfo[this._formLayer.id].attachmentHelpText
      }, formContent);
    }
    //prepare domnode to show the selected file list
    divColumn2 = domConstruct.create("div", {
      "class": "col-sm-10",
      "id": "divColumn2"
    }, divRow);
  }
  // randomblink : add in piece that creates the events and listeners
  // make sure this is performed at end of all Form Element creation
  this._createSubscribersList();
  this._verifyHumanEntry();
},
// BLINKS CODE: Create the list of Subscribers.
_createSubscribersList: function(){
    this.subscriptions = array.map( this.subscriptions, lang.hitch( this, function( currSubscriber ){
        var currPublishers = array.map( currSubscriber.subscription, lang.hitch( this, function( currPublisher ){
            array.forEach( currPublisher.editorFields, lang.hitch( this, function( editorField ){
                this._createTopicPublisher( editorField );
            }) );
            return {
                "publication": currPublisher.publication,
                "editorFields": currPublisher.editorFields,
                "requiredFields": currPublisher.required
            };
        }));
        this. _createTopicSubscriber( currSubscriber.name );
        return { "subscriber": currSubscriber.name, "subscription": currPublishers };
    }));
},  
// BLINKS CODE: Let's consume the publication as it's published.
_consumePublication: function( nameOfSubscriber ){
    var targetSubscriber;
    array.forEach( this.subscriptions, lang.hitch( this, function( currSubscriber ){
        if( currSubscriber.subscriber === nameOfSubscriber ){
            targetSubscriber = currSubscriber;
        }
    }) );
    var targetSubscription;
    if( array.some( targetSubscriber.subscription, lang.hitch( this, function( currSubscription )
    {
        var AllReqsMet = this._isRequirementsMet( currSubscription.requiredFields );
        targetSubscription = currSubscription;
        return AllReqsMet;
    }))){
        // If AllReqsMet returns TRUE then do this
        var listOfFields = targetSubscription.editorFields;
        var targetPublication = targetSubscription.publication;
        listOfFields = array.map( listOfFields, lang.hitch( this, function( currField ){
            var currTargetField = dom.byId( currField );
            var currTargetFieldValue;
            switch( currTargetField.nodeName )
            {
                case "INPUT": currTargetFieldValue = currTargetField.value; break;
                case "SELECT": 
                    if( currTargetField.selectedOptions[0].value !== "" ){
                        currTargetFieldValue = currTargetField.selectedOptions[0].text;
                    }else{
                        currTargetFieldValue = currTargetField.selectedOptions[0].value;
                    }
                    break;
            }
            return { "value": currTargetFieldValue };
        }) );
        var testPublish = string.substitute( targetPublication, listOfFields );
        dom.byId( nameOfSubscriber ).value = testPublish;
    }
},
// BLINKS CODE: Let's check if the Requirements are met.
_isRequirementsMet: function( requirementsArray ){
    if( requirementsArray.length === 0 ){
        return true;
    }

    if( array.every( requirementsArray, lang.hitch( this, function( requiredFieldName ){
        var targetField = dom.byId( requiredFieldName ), valueToTest = "";

        switch( targetField.nodeName ){
            case "INPUT": valueToTest = targetField.value; break;
            case "SELECT": 
                if( targetField.selectedOptions[0].value !== "" ){
                    valueToTest = targetField.selectedOptions[0].text;
                }else{
                    valueToTest = targetField.selectedOptions[0].value;
                }
                break;
            default: break;
        }
        return valueToTest !== "";

    }))){
        return true;
    }else{
        return false;
    }

},
// BLINKS CODE: This takes the name of the field that is subscribing to the publication and sets up the Subscribe command
_createTopicSubscriber: function( subscriberName ){

        topic.subscribe( "publishTopic", lang.hitch( this, function( ){
        this._consumePublication( subscriberName, arguments[0].publisherName, arguments[0].publishedValue );

        } ) );
},
// BLINKS CODE: This takes the name of the field that will be publishing it's data and sets up the Publish command
_createTopicPublisher: function( publisherName ){
    var newPublisherField = dom.byId( publisherName ), publisherFieldType = newPublisherField.nodeName, fieldEvent = "N/A", publisherValue;
    switch( publisherFieldType )
    {
        case "INPUT": fieldEvent = "keyup"; publisherValue = newPublisherField.value; break;
        case "SELECT": fieldEvent = "change"; publisherValue = newPublisherField.selectedOptions[0].text; break;
    }
    on( newPublisherField, fieldEvent, function(){
        switch( publisherFieldType )
        {
            case "INPUT": publisherValue = newPublisherField.value; break;
            case "SELECT": 
                if( newPublisherField.selectedOptions[0].value !== "" ){
                    publisherValue = newPublisherField.selectedOptions[0].text;
                }else{
                    publisherValue = newPublisherField.selectedOptions[0].value;
                }
                break;
        }
        topic.publish( "publishTopic", { "publisherName": publisherName, "publishedValue": publisherValue } );
    });
},
_addToFileList: function (fileInput, fileBtnSpan, formContent, fileDetails) {
  var unit, fileSize = "",
    alertHtml, fileChange, fileForm, formsToSubmit, formId;
  formsToSubmit = query(".formToSubmit", dom.byId('userForm'));
  //Toggle class and give unique id to the form selected for attachment
  domClass.replace(fileInput.parentNode, "formToSubmit", "selectFileForm");
  if (formsToSubmit.length === 0) {
    formId = 0;
  } else {
    formId = parseInt(formsToSubmit[formsToSubmit.length - 1].id.split("formToSubmit")[1]) + 1;
  }
  fileInput.parentNode.id = "formToSubmit" + formId;
  //Toggle class and give unique id to the form selected for attachment
  domClass.replace(fileInput, "fileToSubmit", "hideFileInputUI");
  fileInput.id = "geoformAttachment" + formId;
  //disabling and hiding the selected file so that it is neither clickable nor visible
  //need to re-enable the file before submitting
  domAttr.set(fileInput, "disabled", "disabled");
  domStyle.set(fileInput, "opacity", "0");
  domStyle.set(fileInput, "position", "absolute");
  //check for availability of HTML-5 file handling properties and then display the file size on domNode
  if (fileDetails.files && fileDetails.files[0]) {
    fileSize = parseFloat(fileDetails.files[0].size / 1024);
    unit = "kb";
    if (fileSize > 999) {
      unit = "mb";
      fileSize = parseFloat(fileSize / 1024);
    }
    fileSize = fileSize.toFixed(2) + unit;
  }
  //Preparing the domNode for selected file
  alertHtml = "<div class=\"alert alert-dismissable alert-success\">";
  alertHtml += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">" + "&times" + "</button>";
  alertHtml += "<strong class=\"fileInputUI\">" + fileDetails.value.split('\\').pop() + "<br/>" + fileSize + "</strong>";
  alertHtml += "</div>";
  alertHtml = domConstruct.place(alertHtml, dom.byId("divColumn2"), "last");
  domConstruct.place(fileInput.parentNode, alertHtml, "last");
  //binding event to perform activities on removal of a selected file from the file list
  on(query(".close", alertHtml)[0], a11yclick, function () {
    if (query(".alert-dismissable").length === 1) {
      domClass.remove(formContent, ".has-success");
    }
  });
  fileInput = "";
  fileForm = domConstruct.create("form", {
    "class": "selectFileForm"
  }, fileBtnSpan);
  fileInput = domConstruct.create("input", {
    "type": "file",
    "class": "hideFileInputUI",
    "title": nls.user.selectFileTitle,
    "name": "attachment"
  }, fileForm);
  domConstruct.place(fileForm, fileBtnSpan, "first");
  fileChange = on(fileInput, "change", lang.hitch(this, function (evt) {
    this._validateSelectedFile(evt, fileInput, fileBtnSpan, formContent, fileChange);
  }));
},
_validateSelectedFile: function (evt, fileInput, fileBtnSpan, formContent, fileChange) {
  fileChange.remove();
  if (evt.currentTarget.files && evt.currentTarget.files[0] && evt.currentTarget.files[0].size > 26214400) {
    $(fileBtnSpan).popover({
      content: nls.user.fileTooLargeError,
      container: 'body',
      trigger: 'manual',
      placement: 'bottom'
    });
    $(fileBtnSpan).popover('show');
    setTimeout(function () {
      $(fileBtnSpan).popover('hide');
    }, 3000);
    //this line to change the value of fileinput so that on-change event fires
    $(evt.currentTarget).replaceWith($(evt.currentTarget).val('').clone(true));
    fileChange = on(query(".hideFileInputUI")[0], "change", lang.hitch(this, function (evt) {
      this._validateSelectedFile(evt, fileInput, fileBtnSpan, formContent, fileChange);
    }));
    return true;
  }
  if (query(".alert-dismissable", dom.byId("divColumn2")).length > 19) {
    $(fileBtnSpan).popover({
      content: nls.user.exceededFileCountError,
      container: 'body',
      trigger: 'manual',
      placement: 'bottom'
    });
    $(fileBtnSpan).popover('show');
    setTimeout(function () {
      $(fileBtnSpan).popover('hide');
    }, 3000);
    //this line to change the value of fileinput so that on-change event fires
    $(evt.currentTarget).replaceWith($(evt.currentTarget).val('').clone(true));
    fileChange = on(query(".hideFileInputUI")[0], "change", lang.hitch(this, function (evt) {
      this._validateSelectedFile(evt, fileInput, fileBtnSpan, formContent, fileChange);
    }));
    return true;
  }
  //block to remove error message after selection of file and to replace error class with success class.
  if (query(".errorMessage", formContent)[0]) {
    this._removeErrorNode(query(".errorMessage", formContent)[0]);
    domClass.replace(formContent, "has-success", "has-error");
  }
  this._addToFileList(query(".hideFileInputUI")[0], fileBtnSpan, formContent, evt.currentTarget);
},
//function to create elements of form.
_createFormElements: function (field, index, referenceNode) {
  var currentField = lang.clone(field);
  var radioContainer, fieldname, radioContent, inputContent, labelContent, fieldLabelText, selectOptions, inputLabel, radioInput, formContent, requireField, userFormNode,
    checkboxContainer, checkboxContent, checkBoxCounter = 0,
    helpBlock, rangeHelpText, inputGroupContainer;
  userFormNode = dom.byId('userForm');
  formContent = domConstruct.create("div", {}, userFormNode);
  if (!!currentField.locked) {
    domClass.add(formContent, "disabled");
  }

  // randomblink : Beginning of code for concantenated field
  if (!!currentField.subscription) 
  {
    domClass.add(formContent, "subscriber");
    this.subscriptions.push(currentField);
  }
  // randomblink : End of code for concantenated field

    //code block to fade in the sub-types dependent fields
  if (referenceNode) {
    domConstruct.place(formContent, referenceNode, "after");
    domClass.add(formContent, "fade");
    setTimeout(function () {
      domClass.add(formContent, "in");
    }, 100);
  }
  if ((!currentField.nullable || currentField.typeField) && currentField.displayType !== "checkbox") {
    domClass.add(formContent, "form-group geoFormQuestionare mandatory");
    requireField = domConstruct.create("small", {
      className: 'requireFieldStyle',
      innerHTML: nls.user.requiredField
    }, formContent);
  } else {
    domClass.add(formContent, "form-group geoFormQuestionare");
  }
  if (currentField.alias) {
    fieldLabelText = currentField.alias;
  } else {
    fieldLabelText = currentField.name;
  }
  fieldname = currentField.name;
  if (currentField.displayType !== "checkbox" || currentField.domain) {
    labelContent = domConstruct.create("label", {
      "for": fieldname,
      className: "control-label",
      innerHTML: fieldLabelText,
      id: fieldname + "_label_" + index
    }, formContent);
  }
  if (requireField && labelContent) {
    domConstruct.place(requireField, labelContent, "last");
  }
  if (this._formLayer.templates[0] && !currentField.defaultValue) {
    for (var fieldAttribute in this._formLayer.templates[0].prototype.attributes) {
      if (fieldAttribute.toLowerCase() == fieldname.toLowerCase()) {
        currentField.defaultValue = this._formLayer.templates[0].prototype.attributes[fieldAttribute];
      }
    }
  }
  //code to make select boxes in case of a coded value
  if (currentField.domain || currentField.typeField) {
    if ((currentField.domain && (typeof currentField.domain.type === 'undefined' || currentField.domain.type === 'codedValue')) || currentField.typeField) {
      radioInput = false;
      if (currentField.displayType && currentField.displayType === "radio") {
        radioInput = true;
      }
      //check for fieldType: if not present create dropdown
      //If present check for fieldType value and accordingly populate the control
      if (!radioInput) {
        inputContent = domConstruct.create("select", {
          className: "selectDomain",
          disabled: !!currentField.locked,
          "id": fieldname
        }, formContent);
        if (currentField.domain && !currentField.typeField) {
          if (currentField.displayType == "Filter Select") {
            this._createFilterSelectInput(inputContent, fieldname);
          } else {
            selectOptions = domConstruct.create("option", {
              innerHTML: nls.user.domainDefaultText,
              value: ""
            }, inputContent);
            domClass.add(inputContent, "form-control");
          }
          array.forEach(currentField.domain.codedValues, lang.hitch(this, function (currentOption) {
            selectOptions = domConstruct.create("option", {
              innerHTML: currentOption.name,
              value: currentOption.code
            }, inputContent);
            //if field contain default value, make that option selected
            if (currentField.defaultValue === currentOption.code) {
              domAttr.set(selectOptions, "selected", true);
              domClass.add(inputContent.parentNode, "has-success");
              if (domClass.contains(inputContent, "filterSelect")) {
                $(inputContent).val(currentOption.code).trigger("change");
              }
            }
          }));
        } else {
          if (currentField.displayType == "Filter Select") {
            this._createFilterSelectInput(inputContent, fieldname);
          } else {
            selectOptions = domConstruct.create("option", {
              innerHTML: nls.user.domainDefaultText,
              value: ""
            }, inputContent);
            domClass.add(inputContent, "form-control");
          }
          if(currentField.domain){
            array.forEach(currentField.domain.codedValues, lang.hitch(this, function (currentOption) {
              selectOptions = domConstruct.create("option", {}, inputContent);
              selectOptions.text = currentOption.name;
              selectOptions.value = currentOption.code;
              //default values for subtypes(if any) has to be handled here
            }));
          }
          else if(currentField.subTypes){
            array.forEach(currentField.subTypes, lang.hitch(this, function (currentOption) {
              selectOptions = domConstruct.create("option", {}, inputContent);
              selectOptions.text = currentOption.name;
              selectOptions.value = currentOption.id;
              //default values for subtypes(if any) has to be handled here
            }));
          }
        }
        on($("#" + fieldname), "change", lang.hitch(this, function (evt) {
          //function call to take appropriate actions on selection of a subtypes
          if (currentField.typeField) {
            this._validateTypeFields(evt.currentTarget, currentField);
          }
          //To apply has-success class on selection of a valid option
          if (evt.target.value !== "") {
            if (query(".errorMessage", evt.currentTarget.parentNode).length !== 0) {
              domConstruct.destroy(query(".errorMessage", evt.currentTarget.parentNode)[0]);
              domClass.remove($(evt.target.parentNode)[0], "has-error");
            }
            domClass.add($(evt.target.parentNode)[0], "has-success");
          } else {
            domClass.remove($(evt.target.parentNode)[0], "has-success");
          }
        }));
      } else {
        radioContainer = domConstruct.create("div", {
          className: "radioContainer",
          id: fieldname
        }, formContent);
        if (currentField.domain && !currentField.typeField) {
          array.forEach(currentField.domain.codedValues, lang.hitch(this, function (currentOption) {
            radioContent = domConstruct.create("div", {
              className: "radio"
            }, radioContainer);
            inputLabel = domConstruct.create("label", {
              "for": fieldname + currentOption.code
            }, radioContent);
            inputContent = domConstruct.create("input", {
              "id": fieldname + currentOption.code,
              disabled: !!currentField.locked,
              className: "radioInput",
              type: "radio",
              name: fieldname,
              value: currentOption.code
            }, inputLabel);
            //if field has default value,set radio button checked by default
            if (currentOption.code === currentField.defaultValue) {
              domAttr.set(inputContent, "checked", "checked");
              domClass.add(radioContainer.parentNode, "has-success");
            }
            // add text after input
            inputLabel.innerHTML += currentOption.name;
            //code to assign has-success class on click of a radio button
            on(inputContent, a11yclick, function (evt) {
              if (evt.target.checked) {
                if (query(".errorMessage", formContent).length !== 0) {
                  domConstruct.destroy(query(".errorMessage", formContent)[0]);
                  domClass.remove(formContent, "has-error");
                }
                domClass.add(formContent, "has-success");
              } else {
                domClass.remove(formContent, "has-success");
              }
            });
          }));
        } else {
          array.forEach(currentField.subTypes, lang.hitch(this, function (currentOption) {
            //Code to validate for applying has-success class
            radioContent = domConstruct.create("div", {
              className: "radio"
            }, radioContainer);
            inputLabel = domConstruct.create("label", {
              "for": fieldname + currentOption.id
            }, radioContent);
            inputContent = domConstruct.create("input", {
              "id": fieldname + currentOption.id,
              disabled: !!currentField.locked,
              className: "radioInput",
              type: "radio",
              name: fieldname,
              value: currentOption.id
            }, inputLabel);
            //if field has default value,set radio button checked by default
            if (currentOption.id === currentField.defaultValue) {
              domAttr.set(inputContent, "checked", "checked");
              domClass.add(radioContainer.parentNode, "has-success");
            }
            // add text after input
            inputLabel.innerHTML += currentOption.name;
            on(dom.byId(fieldname + currentOption.id), a11yclick, lang.hitch(this, function (evt) {
              //function call to take appropriate actions on selection of a subtypes
              if (currentField.typeField) {
                this._validateTypeFields(evt.currentTarget, currentField);
              }
              if (evt.target.checked) {
                if (query(".errorMessage", formContent).length !== 0) {
                  domClass.remove(formContent, "has-error");
                  domConstruct.destroy(query(".errorMessage", formContent)[0]);
                }
                domClass.add(formContent, "has-success");
              } else {
                domClass.remove(formContent, "has-success");
              }
            }));
          }));
        }
      }
    } else {
      //if field type is date
      if (currentField.type == "esriFieldTypeDate") {
        var inputRangeDateGroupContainer = this._addNotationIcon(formContent, "glyphicon-calendar");
        inputContent = this._createDateField(inputRangeDateGroupContainer, true, fieldname, currentField, currentField.defaultValue);
        if(currentField.domain.minValue !== currentField.domain.maxValue && currentField.domain.minValue > -2147483648 && currentField.domain.maxValue > -2147483648){
          rangeHelpText = string.substitute(nls.user.dateRangeHintMessage, {
            minValue: moment(currentField.domain.minValue).format(this.dateFormat),
            maxValue: moment(currentField.domain.maxValue).format(this.dateFormat),
            openStrong: "<strong>",
            closeStrong: "</strong>"
          });
        }
      } else {
        //if field type is integer
        rangeHelpText = this._setRangeForm(currentField, formContent, fieldname);
      }
    }
  } else {
    //Condition to check if a checkbox is required for integer fields in user form
    if (currentField.displayType && currentField.displayType === "checkbox") {
      currentField.type = "binaryInteger";
    }
    switch (currentField.type) {
    case "esriFieldTypeString":
      if (currentField.displayType && currentField.displayType === "textarea") {
        inputContent = domConstruct.create("textarea", {
          disabled: !!currentField.locked,
          className: "form-control",
          "data-input-type": "String",
          "rows": 4,
          "maxLength": currentField.length,
          "id": fieldname
        }, formContent);
      } else {
        if (currentField.displayType && currentField.displayType === "email") {
          inputGroupContainer = this._addNotationIcon(formContent, "glyphicon-envelope");
        } else if (currentField.displayType && currentField.displayType === "url") {
          inputGroupContainer = this._addNotationIcon(formContent, "glyphicon-link");
        }
        inputContent = domConstruct.create("input", {
          type: "text",
          disabled: !!currentField.locked,
          className: "form-control",
          "data-input-type": "String",
          "maxLength": currentField.length,
          "id": fieldname
        }, inputGroupContainer ? inputGroupContainer : formContent);
      }
      break;
    case "binaryInteger":
      checkboxContainer = domConstruct.create("div", {
        className: "checkboxContainer"
      }, formContent);

      checkboxContent = domConstruct.create("div", {
        className: "checkbox"
      }, checkboxContainer);
      inputLabel = domConstruct.create("label", {
        "for": fieldname
      }, checkboxContent);
      inputContent = domConstruct.create("input", {
        className: "checkboxInput",
        disabled: !!currentField.locked,
        type: "checkbox",
        "data-input-type": "binaryInteger",
        "id": fieldname
      }, inputLabel);
      domAttr.set(inputContent, "data-checkbox-index", checkBoxCounter);
      inputLabel.innerHTML += fieldLabelText;
      checkBoxCounter++;
      break;
    case "esriFieldTypeSmallInteger":
      inputContent = domConstruct.create("input", {
        disabled: !!currentField.locked,
        type: "text",
        className: "form-control",
        "data-input-type": "SmallInteger",
        "id": fieldname,
        "pattern": "[0-9]*"
      }, formContent);
      break;
    case "esriFieldTypeInteger":
      inputContent = domConstruct.create("input", {
        disabled: !!currentField.locked,
        type: "text",
        className: "form-control",
        "data-input-type": "Integer",
        "id": fieldname,
        "pattern": "[0-9]*"
      }, formContent);
      break;
    case "esriFieldTypeSingle":
      inputContent = domConstruct.create("input", {
        disabled: !!currentField.locked,
        type: "text",
        className: "form-control",
        "data-input-type": "Single",
        "id": fieldname
      }, formContent);
      break;
    case "esriFieldTypeDouble":
      inputContent = domConstruct.create("input", {
        disabled: !!currentField.locked,
        type: "text",
        className: "form-control",
        "data-input-type": "Double",
        "id": fieldname,
        step: ".1"
      }, formContent);
      break;
    case "esriFieldTypeDate":
      var inputDateGroupContainer = this._addNotationIcon(formContent, "glyphicon-calendar");
      if (currentField.hiddenDate) {
        domClass.add(formContent, "hidden");
      }
      inputContent = this._createDateField(inputDateGroupContainer, false, fieldname, currentField, currentField.defaultValue);
      break;
    }
    //Add Placeholder if present
    if (currentField.tooltip) {
      domAttr.set(inputContent, "placeholder", currentField.tooltip);
    }
    //If present fetch default values
    if (currentField.defaultValue) {
      if (currentField.type == "esriFieldTypeString" && lang.trim(currentField.defaultValue) !== "") {
        domAttr.set(inputContent, "value", currentField.defaultValue);
        domClass.add(formContent, "has-success");
      }
    }
    //Add specific display type if present
    if (currentField.displayType && currentField.displayType !== "") {
      domAttr.set(inputContent, "data-display-type", currentField.displayType);
    }
    var helpHTML = "";
    if (currentField.type !== "esriFieldTypeDate") {
      on(inputContent, "focusout", lang.hitch(this, function (evt) {
        this._validateField(evt, true);
      }));
      on(inputContent, "keyup", lang.hitch(this, function () {
        if (currentField.displayType === "textarea") {
          var availableLength;
          if (inputContent.value.length > currentField.length) {
            //Work around to make textarea work in IE8
            //Truncate the text if necessary
            $(inputContent).val(inputContent.value.substr(0, currentField.length));
          } else {
            availableLength = string.substitute(nls.user.remainingCharactersHintMessage, {
              value: (currentField.length - inputContent.value.length).toString()
            });
            helpBlock.innerHTML = lang.trim(helpHTML + " " + availableLength);
          }
        }
      }));
    }
  }
  // if field is required and field exists
  if (!currentField.nullable && inputContent) {
    inputContent.setAttribute("aria-required", true);
    inputContent.setAttribute("required", "");
  }
  if(currentField.defaultValue){
    // store default value
    domAttr.set(inputContent, "data-default-value", currentField.defaultValue);
  }
  if (currentField.isNewField) {
    // make sure popup info and fields are defined
    if (this._formLayer && this._formLayer.infoTemplate && this._formLayer.infoTemplate.info && this._formLayer.infoTemplate.info.fieldInfos) {
      array.forEach(this._formLayer.infoTemplate.info.fieldInfos, function (currentFieldPopupInfo) {
        if (currentFieldPopupInfo.fieldName == currentField.name) {
          if (currentFieldPopupInfo.tooltip) {
            helpHTML = currentFieldPopupInfo.tooltip;
          }
        }
      });
    }
  } else {
    helpHTML = currentField.fieldDescription;
  }
  if (helpHTML || currentField.displayType === "textarea") {
    var availableLength = "";
    if (currentField.displayType === "textarea") {
      availableLength = string.substitute(nls.user.remainingCharactersHintMessage, {
        value: currentField.length.toString()
      });
    }
    helpBlock = domConstruct.create("p", {
      className: "help-block",
      innerHTML: lang.trim(helpHTML + " " + availableLength)
    }, formContent);
  }
  if (rangeHelpText) {
    var options = {
      trigger: 'focus',
      placement: 'top',
      container: 'body',
      content: rangeHelpText,
      html: true
    };
    $('#' + fieldname).popover(options);
  }
},
// date range field
_setRangeForm: function (currentField, formContent, fieldname) {
  var inputContent, setStep, setDefault = "",
    stepDivisibility = 'none',
    decimalPoints = 0,
    inputcontentSpinner, rangeHelpText;
  inputContent = domConstruct.create("input", {
    disabled: !!currentField.locked,
    id: fieldname,
    type: "text",
    className: "form-control",
    min: currentField.domain.minValue.toString(),
    max: currentField.domain.maxValue.toString()
  }, formContent);
  domAttr.set(inputContent, "data-input-type", currentField.type.replace("esriFieldType", ""));
  if (currentField.defaultValue) {
    setDefault = currentField.defaultValue;
    domClass.add(inputContent.parentNode, "has-success");
  }
  if (domAttr.get(inputContent, "data-input-type") === "Double" || domAttr.get(inputContent, "data-input-type") === "Single") {
    decimalPoints = 2;
    if (currentField.domain.minValue - Math.floor(currentField.domain.minValue) === 0.5) {
      setStep = 0.5;
    } else {
      setStep = 0.1;
    }
  } else {
    setStep = 1;
    stepDivisibility = 'round';
  }
  inputcontentSpinner = $(inputContent).TouchSpin({
    initval: setDefault,
    min: currentField.domain.minValue.toString(),
    max: currentField.domain.maxValue.toString(),
    forcestepdivisibility: stepDivisibility,
    step: setStep,
    boostat: 5,
    decimals: decimalPoints,
    maxboostedstep: 10
  });
  //Event to address validations for manual entry in the touch-spinner input.
  on(inputContent, "keyup", function () {
    if (inputContent.value === "") {
      domClass.remove(inputContent.parentNode.parentNode, "has-success");
    } else {
      domClass.add(inputContent.parentNode.parentNode, "has-success");
    }
  });
  on(inputcontentSpinner, "touchspin.on.startspin", lang.hitch(this, function (evt) {
    inputcontentSpinner.trigger("touchspin.updatesettings", {});
    domClass.add(evt.currentTarget.parentNode.parentNode, "has-success");
  }));
  if (!currentField.nullable) {
    inputContent.setAttribute("aria-required", true);
    inputContent.setAttribute("required", "");
  }
  rangeHelpText = string.substitute(nls.user.textRangeHintMessage, {
    minValue: currentField.domain.minValue.toString(),
    maxValue: currentField.domain.maxValue.toString(),
    openStrong: "<strong>",
    closeStrong: "</strong>"
  });
  return rangeHelpText;
},
_createFilterSelectInput: function (inputContent, fieldname) {
  domClass.add(inputContent, "filterSelect");
  domStyle.set(inputContent, "width", "100%");
  var options = domConstruct.create("option", {}, inputContent);
  options.text = "";
  options.value = "";
  $("#" + fieldname).select2({
    placeholder: nls.user.filterSelectEmptyText,
    allowClear: true
  });
},
//function to validate the fields defined within subtypes
_validateTypeFields: function (currentTarget, currentField) {
  var selectedType, defaultValue, switchDomainType, referenceNode;
  if (currentTarget.value === "") {
    //no type is selected, so the code to remove the type dependent fields will come here
    array.forEach(this.sortedFields, lang.hitch(this, function (currentInput) {
      if (!currentInput.isTypeDependent) {
        return true;
      }
      if (dom.byId(currentInput.name)) {
        var domToDestroy = this._getFormElement(dom.byId(currentInput.name));
        domConstruct.destroy(domToDestroy);
      }
      this._resizeMap();
    }));
    return true;
  } else {
    //code to get all the domains and default values of the selected subtype
    array.some(currentField.subTypes, function (currentSelection) {
      if (currentTarget.value === currentSelection.id.toString()) {
        selectedType = currentSelection;
        return true;
      }
    });
  }
  //initial point of reference to put elements
  referenceNode = dom.byId(this._formLayer.typeIdField).parentNode;
  //code to populate type dependent fields
  array.forEach(this.sortedFields, lang.hitch(this, function (currentInput, index) {
    var field = null,
      domain, minValue, maxValue;
    //condition to filter out fields independent of subtypes
    if (!currentInput.isTypeDependent) {
      return true;
    }
    array.some(this._formLayer.fields, function (layerField) {
      var lyrField = lang.clone(layerField);
      if (lyrField.name === currentInput.name) {
        field = lang.clone(lang.mixin(lyrField, currentInput));
        return true;
      }
    });
    //code to fetch the default value of a field for selected subtype.
    if (selectedType.templates[0]) {
      for (var fieldAttribute in selectedType.templates[0].prototype.attributes) {
        if (fieldAttribute.toLowerCase() === field.name.toLowerCase()) {
          defaultValue = selectedType.templates[0].prototype.attributes[fieldAttribute];
          field.defaultValue = defaultValue;
          domAttr.set(currentTarget, "data-default-value", defaultValue);
          break;
        }
      }
    }
    for (var i in selectedType.domains) {
      //condition to find the domain properties for current field
      if (i === field.name) {
        switchDomainType = selectedType.domains[i].type || "codedValue";
        switch (switchDomainType) {
        case "inherited":
          //for inherited domains we need to populate the domains from the layer.
          if (field.domain.type === "range") {
            minValue = field.domain.minValue;
            maxValue = field.domain.maxValue;
          } else {
            domain = field.domain.codedValues;
          }
          break;
        case "codedValue":
          if (!field.domain) {
            field.domain = {};
          }
          field.domain.codedValues = selectedType.domains[i].codedValues;
          domain = selectedType.domains[i].codedValues;
          break;
        case "range":
          //Condition to change the range domain values of field already having domain.
          if (!field.domain) {
            field.domain = {};
          }
          field.domain.minValue = selectedType.domains[i].minValue;
          field.domain.maxValue = selectedType.domains[i].maxValue;
          minValue = selectedType.domains[i].minValue;
          maxValue = selectedType.domains[i].maxValue;
          break;
        }
      }
    }
    //code to be executed when the input is already present
    if (dom.byId(field.name)) {
      var domToDestroy;
      domToDestroy = this._getFormElement(dom.byId(field.name));
      domConstruct.destroy(domToDestroy);
    }
    this._createFormElements(field, index, referenceNode);
    referenceNode = this._getFormElement(dom.byId(field.name));
  }));
  this._resizeMap();
},
// validate form field
_validateField: function (currentNode, iskeyPress) {
  var inputType, inputValue, displayType = null,
    node, typeCastedInputValue, decimal = /^[-+]?[0-9]+$/,
    float = /^[-+]?[0-9]+\.[0-9]+$/,
    email = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/,
    url = /^(http[s]?:\/\/){0,1}(www\.){0,1}[a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,5}[\.]{0,1}/,
    error;
  //To remove extra spaces
  currentNode.currentTarget.value = lang.trim(currentNode.currentTarget.value);
  if (iskeyPress) {
    inputValue = currentNode.currentTarget.value;
    inputType = domAttr.get(currentNode.currentTarget, "data-input-type");
    if (domAttr.get(currentNode.currentTarget, "data-display-type") !== null) {
      displayType = domAttr.get(currentNode.currentTarget, "data-display-type");
    }
    //Since we are adding a new div inside formContent in case of email and url
    //We need to traverse one step more
    if (displayType === "email" || displayType === "url") {
      node = $(currentNode.target.parentNode.parentNode)[0];
    } else {
      if ($(currentNode.target)) {
        node = $(currentNode.target.parentNode)[0];
      } else {
        node = $(currentNode.srcElement.parentNode)[0];
      }
    }
  } else {
    inputValue = query(".form-control", currentNode)[0].value;
    inputType = domAttr.get(query(".form-control", currentNode)[0], "data-input-type");
    if (domAttr.get(query(".form-control", currentNode)[0], "data-display-type") !== null) {
      displayType = domAttr.get(query(".form-control", currentNode)[0], "data-display-type");
    }
    node = query(".form-control", currentNode)[0].parentElement;
  }
  switch (inputType) {
  case "String":
    if (inputValue.length !== 0 && ((displayType === "email" && inputValue.match(email)) || (displayType === "url" && inputValue.match(url)) || displayType === null) || displayType === "text" || displayType === "textarea") {
      this._validateUserInput(false, node, inputValue, iskeyPress);
    } else {
      error = string.substitute(nls.user.invalidString, {
        openStrong: "<strong>",
        closeStrong: "</strong>"
      });
      this._validateUserInput(error, node, inputValue, iskeyPress);
    }
    break;
  case "SmallInteger":
    typeCastedInputValue = parseInt(inputValue);
    if ((inputValue.match(decimal) && typeCastedInputValue >= -32768 && typeCastedInputValue <= 32767) && inputValue.length !== 0) {
      this._validateUserInput(false, node, inputValue);
    } else {
      error = string.substitute(nls.user.invalidSmallNumber, {
        openStrong: "<strong>",
        closeStrong: "</strong>"
      });
      this._validateUserInput(error, node, inputValue, iskeyPress);
    }
    break;
  case "Integer":
    typeCastedInputValue = parseInt(inputValue);
    if ((inputValue.match(decimal) && typeCastedInputValue >= -2147483648 && typeCastedInputValue <= 2147483647) && inputValue.length !== 0) {
      this._validateUserInput(false, node, inputValue, iskeyPress);
    } else {
      error = string.substitute(nls.user.invalidNumber, {
        openStrong: "<strong>",
        closeStrong: "</strong>"
      });
      this._validateUserInput(error, node, inputValue, iskeyPress);
    }
    break;
  case "Single":
    //zero or more occurrence of (+-) at the start of expression
    //at least one occurrence of digits between o-9
    //occurrence of .
    //at least one occurrence of digits between o-9 in the end
    typeCastedInputValue = parseFloat(inputValue);
    if (((inputValue.match(decimal) || inputValue.match(float)) && typeCastedInputValue >= -3.4 * Math.pow(10, 38) && typeCastedInputValue <= 1.2 * Math.pow(10, 38)) && inputValue.length !== 0) {
      this._validateUserInput(false, node, inputValue, iskeyPress);
    } else {
      error = string.substitute(nls.user.invalidFloat, {
        openStrong: "<strong>",
        closeStrong: "</strong>"
      });
      this._validateUserInput(error, node, inputValue, iskeyPress);
    }
    break;
  case "Double":
    typeCastedInputValue = parseFloat(inputValue);
    if (((inputValue.match(decimal) || inputValue.match(float)) && typeCastedInputValue >= -2.2 * Math.pow(10, 308) && typeCastedInputValue <= 1.8 * Math.pow(10, 38)) && inputValue.length !== 0) {
      this._validateUserInput(false, node, inputValue, iskeyPress);
    } else {
      error = string.substitute(nls.user.invalidDouble, {
        openStrong: "<strong>",
        closeStrong: "</strong>"
      });
      this._validateUserInput(error, node, inputValue, iskeyPress);
    }
    break;
  }
},
// reset form fields
_clearFormFields: function () {
  this._createForm(this._savedFields);
},
// validate form input
_validateUserInput: function (error, node, inputValue, iskeyPress) {
  if (domClass.contains(node, "filterSelect") && inputValue === "" && domClass.contains(node.parentElement, "mandatory")) {
    this._showErrorMessageDiv(error, node.parentElement.children[0]);
    domClass.add(node.parentElement, "has-error");
    domClass.remove(node, "has-success");
    return;
  }
  if (query(".errorMessage", node)[0]) {
    domConstruct.destroy(query(".errorMessage", node)[0]);
  }
  if (!error || (inputValue.length === 0 && !domClass.contains(node, "mandatory"))) {
    domClass.add(node, "has-success");
    domClass.remove(node, "has-error");
  } else {
    this._showErrorMessageDiv(error, node.children[0]);
    domClass.add(node, "has-error");
    domClass.remove(node, "has-success");
  }
  if (iskeyPress && inputValue.length === 0 && !domClass.contains(node, "mandatory")) {
    domClass.remove(node, "has-error");
    domClass.remove(node, "has-success");
  }
},
// create a map based on the input web map id
_createWebMap: function (itemInfo) {
  var mouseWheel; //To capture the mouse-wheel scroll event and then later deactivate it
  var popup = new Popup({
    highlight: false
  }, domConstruct.create("div"));
  domClass.add(popup.domNode, 'light');
  var mapDiv = dom.byId('mapDiv');
  // fullscreen button HTML
  if (this.config.enableBasemapToggle) {
    var fsHTML = '';
    fsHTML = '<div class="basemapToggle-button"><div class="basemapToggle-button" id="BasemapToggle"></div></div>';
    fsHTML += '</div>';
    mapDiv.innerHTML = fsHTML;
  }
  arcgisUtils.createMap(itemInfo, mapDiv, {
    mapOptions: {
      infoWindow: popup
        // Optionally define additional map config here for example you can
        // turn the slider off, display info windows, disable wraparound 180, slider position and more.
    },
    editable: true,
    usePopupManager: false,
    layerMixins: this.config.layerMixins || [],
    bingMapsKey: this.config.bingKey
  }).then(lang.hitch(this, function (response) {
    // Once the map is created we get access to the response which provides important info
    // such as the map, operational layers, popup info and more. This object will also contain
    // any custom options you defined for the template. In this example that is the 'theme' property.
    // Here' we'll use it to update the application to match the specified color theme.
    // console.log(this.config);
    this._createGeoformSections();
    this.map = response.map;
    // Disable scroll zoom handler
    if (this.config.enableBasemapToggle) {
      var toggle = new basemapToggle({
        map: this.map,
        basemap: this.config.defaultBasemap,
        defaultBasemap: this.config.nextBasemap
      }, "BasemapToggle");
      toggle.startup();

      var layers = this.map.getLayersVisibleAtScale(this.map.getScale());
      on.once(this.map, 'basemap-change', lang.hitch(this, function () {
        for (var i = 0; i < layers.length; i++) {
          if (layers[i]._basemapGalleryLayerType) {
            var layer = this.map.getLayer(layers[i].id);
            this.map.removeLayer(layer);
          }
        }
      }));
    }
    this.map.disableScrollWheelZoom();
    this.defaultExtent = this.map.extent;
    // webmap defaults
    this._setWebmapDefaults();
    // default layer
    this._setLayerDefaults();
    // set configuration
    this._setAppConfigurations(this.config.details);
    domAttr.set(dom.byId('submitButton'), "innerHTML", this.config.submitButtonText ? this.config.submitButtonText : nls.user.submitButtonText);
    domAttr.set(dom.byId('viewSubmissionsButton'), "innerHTML", this.config.viewSubmissionsText ? this.config.viewSubmissionsText : nls.user.btnViewSubmissions);
    // window title
    if (this.config.details && this.config.details.Title) {
      window.document.title = this.config.details.Title;
    }
    if (this.config.form_layer.id == "all") {
      var webmapLayers, deferredListArray = [];
      this.layerCollection = {};
      webmapLayers = domConstruct.create("select", {
        "class": "form-control selectDomain allLayerList"
      }, dom.byId("multipleLayers"));
      for (var key in this.config.fields) {
        if (this.config.fields.hasOwnProperty(key) && key !== "length") {
          deferredListArray.push(this._loadNewLayer(webmapLayers, key));
        }
      }
      //run this block after all the layers are loaded and are correspondingly pushed in the layer-select-box
      all(deferredListArray).then(lang.hitch(this, function () {
        //if at-least one editable point layer is found then create the form or else show error message
        if (webmapLayers.options[0]) {
          webmapLayers.options[0].selected = true;
          this._formLayer = this.layerCollection[webmapLayers.options[0].value];
          this._savedFields = this.config.fields[webmapLayers.options[0].value];
          this._createForm(this._savedFields);
          on(webmapLayers, "change", lang.hitch(this, function (evt) {
            this._savedFields = this.config.fields[evt.currentTarget.value];
            this._formLayer = this.layerCollection[evt.currentTarget.value];
            this._createForm(this._savedFields);
            this._resizeMap();
          }));
        } else {
          var error = new Error(nls.user.invalidLayerMessage);
          this.reportError(error);
        }
      }));
    } else {
      if (this._formLayer) {
        this._savedFields = this.config.fields[this._formLayer.id];
        // create form fields
        this._createForm(this._savedFields);
      }
    }
    // create locate button
    this._createLocateButton();
    // create geocoder button
    this._createGeocoderButton();
    // make graphics layer
    this._gl = new GraphicsLayer();
    this.map.addLayer(this._gl);
    // add border radius to map
    domClass.add(this.map.root, 'panel');
    // remove loading class from body
    domClass.remove(document.body, "app-loading");
    // drag point edit toolbar
    this.editToolbar = new editToolbar(this.map);
    // start moving
    on(this.editToolbar, "graphic-move-start", lang.hitch(this, function () {
      if (this.map.infoWindow) {
        this.map.infoWindow.hide();
      }
    }));
    // stop moving
    on(this.editToolbar, "graphic-move-stop", lang.hitch(this, function (evt) {
      var locationCoords = this._calculateLatLong(evt.graphic.geometry);
      domAttr.set(dom.byId("coordinatesValue"), "innerHTML", locationCoords);
      this.addressGeometry = evt.graphic.geometry;
      this._setCoordInputs(evt.graphic.geometry);
    }));
    // show info window on graphic click
    on(this.editToolbar, "graphic-click", lang.hitch(this, function (evt) {
      var graphic = evt.graphic;
      if (graphic && this.map.infoWindow) {
        this.map.infoWindow.setFeatures([graphic]);
        this.map.infoWindow.show(graphic.geometry);
      }
    }));
    // map click
    on(this.map, 'click', lang.hitch(this, function (evt) {
      //remove the location-error message as soon as the point on the map is selected.
      this._removeErrorNode(dom.byId("select_location").nextSibling);
      this._clearSubmissionGraphic();
      this.addressGeometry = evt.mapPoint;
      this._setSymbol(this.addressGeometry, true);
      // get coords string
      var coords = this._calculateLatLong(evt.mapPoint);
      domAttr.set(dom.byId("coordinatesValue"), "innerHTML", coords);
      this._setCoordInputs(evt.mapPoint);
    }));
    //on mouse move show lat lon
    on(this.map, 'mouse-move', lang.hitch(this, function (evt) {
      // get coords string
      var coords = this._calculateLatLong(evt.mapPoint);
      domAttr.set(dom.byId("coordinatesValue"), "innerHTML", coords);
    }));
    mouseWheel = on(this.map, 'mouse-wheel', lang.hitch(this, function () {
      //Enables scrollwheel zoom 3 seconds after a user hovers over the map
      setTimeout(lang.hitch(this, function () {
        this.map.enableScrollWheelZoom();
      }), 3000);
      mouseWheel.remove();
    }));
    // Add desirable touch behaviors here
    if (this.map.hasOwnProperty("isScrollWheelZoom")) {
      if (this.map.isScrollWheelZoom) {
        this.map.enableScrollWheelZoom();
      } else {
        this.map.disableScrollWheelZoom();
      }
    } else {
      // Default
      this.map.disableScrollWheelZoom();
    }
    // FeatureLayers
    if (this.map.infoWindow) {
      // resize popup
      on(this.map.infoWindow, "selection-change, set-features, show", lang.hitch(this, function () {
        this._resizeInfoWin();
      }));
    }
    // When window resizes
    on(window, 'resize', lang.hitch(this, function () {
      this._resizeMap(true);
      this._resizeInfoWin();
      this._centerPopup();
    }));
    // Lat/Lng coordinate events
    var latNode = dom.byId('lat_coord');
    var lngNode = dom.byId('lng_coord');
    on(latNode, "keyup", lang.hitch(this, function () {
      this._validateLocationInputs('lat');
    }));
    on(latNode, "keypress", lang.hitch(this, function (evt) {
      this._findLocation(evt);
      this._checkLatLng();
    }));
    on(lngNode, "keypress", lang.hitch(this, function (evt) {
      this._findLocation(evt);
      this._checkLatLng();
    }));
    on(lngNode, "keyup", lang.hitch(this, function () {
      this._validateLocationInputs('lng');
    }));
    // lat/lng changed
    on(latNode, "change", lang.hitch(this, function () {
      this._checkLatLng();
    }));
    on(lngNode, "change", lang.hitch(this, function () {
      this._checkLatLng();
    }));
    on(dom.byId('cordsSubmit'), a11yclick, lang.hitch(this, function (evt) {
      this._evaluateCoordinates(evt);
    }));
    // USNG
    on(dom.byId('usng_submit'), a11yclick, lang.hitch(this, function () {
      this._convertUSNG();
    }));
    var usngInput = dom.byId('usng_coord');
    on(usngInput, "change", lang.hitch(this, function () {
      this._checkUSNG();
    }));
    on(usngInput, "keypress", lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 13) {
        this._convertUSNG();
      }
      this._checkUSNG();
    }));
    // MGRS
    on(dom.byId('mgrs_submit'), a11yclick, lang.hitch(this, function () {
      this._convertMGRS();
    }));
    var mgrsInput = dom.byId('mgrs_coord');
    on(mgrsInput, "change", lang.hitch(this, function () {
      this._checkMGRS();
    }));
    on(mgrsInput, "keypress", lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 13) {
        this._convertMGRS();
      }
      this._checkMGRS();
    }));
    // UTM
    var northNode = dom.byId('utm_northing');
    var eastNode = dom.byId('utm_easting');
    var zoneNode = dom.byId('utm_zone_number');
    on(dom.byId('utm_submit'), a11yclick, lang.hitch(this, function () {
      this._convertUTM();
    }));
    on(northNode, "keypress", lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 13) {
        this._convertUTM();
      }
      this._checkUTM();
    }));
    on(northNode, "change", lang.hitch(this, function () {
      this._checkUTM();
    }));
    on(eastNode, "keypress", lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 13) {
        this._convertUTM();
      }
      this._checkUTM();
    }));
    on(eastNode, "change", lang.hitch(this, function () {
      this._checkUTM();
    }));
    on(zoneNode, "keypress", lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 13) {
        this._convertUTM();
      }
      this._checkUTM();
    }));
    on(zoneNode, "change", lang.hitch(this, function () {
      this._checkUTM();
    }));
    // fullscreen
    var fsButton = domConstruct.create("div", {
      tabindex: "0",
      "class": "fullScreenButtonContainer"
    }, mapDiv);
    domConstruct.create("span", {
      id: "fullscreen_icon",
      title: "Full Screen",
      "class": "glyphicon glyphicon-fullscreen fullScreenImage"
    }, fsButton);
    if (fsButton) {
      on(fsButton, a11yclick, lang.hitch(this, function () {
        this._toggleFullscreen();
      }));
    }
    // fullscreen esc key
    on(document.body, 'keyup', lang.hitch(this, function (evt) {
      var keyCode = evt.charCode || evt.keyCode;
      if (keyCode === 27) {
        this._toggleFullscreen(false);
      }
    }));
    // finished button
    var submitButtonNode = dom.byId('submitButton');
    if (submitButtonNode) {
      on(submitButtonNode, a11yclick, lang.hitch(this, function () {
        this._submitForm();
      }));
    }
    //disable viewSubmissionsButton
    if (this.config.disableViewer) {
      domClass.add(dom.byId("viewSubmissionsButton"), 'hidden');
    }
    domAttr.set(dom.byId("viewSubmissionsButton"), "href", this._viewSubmissions());
    // set location options
    this._populateLocationsOptions();
    // resize map
    this._resizeMap();
    // load map
    if (this.map.loaded) {
      this._mapLoaded();
    } else {
      // map loaded
      on(this.map, 'load', lang.hitch(this, function () {
        this._mapLoaded();
      }));
    }
    //Check location parameters in url
    if (this.config.locate) {
      this._setLocation("locate", this.config.locate);
    } else if (this.config.search) {
      this._setLocation("search", this.config.search);
    } else if (this.config.latlon) {
      this._setLocation("latlon", this.config.latlon);
    }
  }), this.reportError);
},

//this function opens viewer page
_viewSubmissions: function () {
  var urlString = "viewer.html";
  if (this.config.appid) {
    urlString += "?appid=" + this.config.appid;
  } else if (this.config.webmap) {
    urlString += "?webmap=" + this.config.webmap;
  }
  return urlString;
},

//this function ensures that the layer is either loaded or throws an error in console naming the layer that did not load successfully
_loadNewLayer: function (webmapLayers, key) {
  var layerLoadedEvent, errorLoadEvent, def, layer;
  //Fetch all the layers at once
  def = new Deferred();
  layer = this.map.getLayer(key);
  //this block will be called if the layer is already loaded
  if (layer && layer.url) {
    if (layer.loaded) {
      if (layer.isEditable() && layer.geometryType === 'esriGeometryPoint') {
        this._pushToLayerDrpDwn(webmapLayers, key, layer);
      }
      def.resolve();
    } else {
      //this block will be called if there is some error in layer load
      if (layer.loadError) {
        console.log(nls.user.error + ": " + layer.name);
        def.resolve();
      }
      //this block attaches 'load' and 'loadError' events respectively
      else {
        layerLoadedEvent = on.once(layer, "load", lang.hitch(this, function () {
          errorLoadEvent.remove();
          if (layer.isEditable() && layer.geometryType === 'esriGeometryPoint') {
            this._pushToLayerDrpDwn(webmapLayers, key, layer);
          }
          def.resolve();
        }));
        errorLoadEvent = on.once(layer, "error", lang.hitch(this, function () {
          layerLoadedEvent.remove();
          console.log(nls.user.error + ": " + layer.name);
          def.resolve();
        }));
      }
    }
  } else {
    //This error will be logged in case the layer is undefined
    //this will happen in case where the key from this.config.fields supplies a layer id not present in the map
    console.log(nls.user.invalidLayerMessage + ": " + key);
    def.resolve();
  }
  return def.promise;
},
//function to push the layer name to layer drop down
_pushToLayerDrpDwn: function (webmapLayers, key, layer) {
  this.layerCollection[key] = layer;
  var option = domConstruct.create("option", {}, webmapLayers);
  option.text = this.layerCollection[key].name;
  option.value = key;
},
_createGeoformSections: function () {
  array.forEach(query(".geoformSection"), lang.hitch(this, function (currentSection, index) {
    if (this.config.form_layer.id === "all") {
      currentSection.innerHTML = string.substitute(currentSection.innerHTML, {
        formSection: ++index + "."
      });
    } else {
      if (index !== 0) {
        currentSection.innerHTML = string.substitute(currentSection.innerHTML, {
          formSection: index + "."
        });
      } else {
        domStyle.set(dom.byId("selectLayer"), "display", "none");
      }
    }
  }));
},

_mapLoaded: function () {
  // center coords
  setTimeout(lang.hitch(this, function () {
    var mapCenter = this.map.extent.getCenter();
    if (mapCenter) {
      this._setCoordInputs(mapCenter);
      var locationCoords = this._calculateLatLong(mapCenter);
      domAttr.set(dom.byId("coordinatesValue"), "innerHTML", locationCoords);
    }
    this._resizeMap();
  }), 500);
  // resize map
  setTimeout(lang.hitch(this, function () {
    this._resizeMap();
  }), 1000);
},

_setLocation: function (urlParameter, value) {
  switch (urlParameter) {
  case "locate":
    this.currentLocation.locate();
    break;
  case "search":
    this.geocodeAddress.set("value", value);
    this.geocodeAddress.search();
    break;
  case "latlon":
    var latlonValue = value.split(",");
    this._locatePointOnMap(latlonValue[0], latlonValue[1], 'latlon');
    domAttr.set(dom.byId('lat_coord'), "value", latlonValue[0]);
    domAttr.set(dom.byId('lng_coord'), "value", latlonValue[1]);
    break;
  default:
    //Code for default value
    break;
  }
},
_fullscreenState: function () {
  // get all nodes
  var mapNode, fsContainerNode, btnNode, mapContainerNode;
  mapNode = dom.byId('mapDiv');
  fsContainerNode = dom.byId('fullscreen_container');
  mapContainerNode = dom.byId('map_container');
  btnNode = dom.byId('fullscreen_icon');
  if (domClass.contains(document.body, 'fullscreen')) {
    domClass.remove(this.map.root, 'panel');
    domConstruct.place(mapNode, fsContainerNode);
    domClass.replace(btnNode, "glyphicon glyphicon-remove", "glyphicon glyphicon-fullscreen");
    // move map node and clear hash
    window.location.hash = "";
    btnNode.title = nls.user.mapRestore;
  } else {
    domClass.add(this.map.root, 'panel');
    domConstruct.place(mapNode, mapContainerNode);
    domClass.replace(btnNode, "glyphicon glyphicon-fullscreen", "glyphicon glyphicon-remove");
    window.location.hash = "#mapDiv";
    btnNode.title = nls.user.mapFullScreen;
  }
  this._resizeMap();
  // if current selected location
  if (this.addressGeometry) {
    setTimeout(lang.hitch(this, function () {
      this.map.centerAt(this.addressGeometry);
    }), 500);
  }
},
_toggleFullscreen: function (condition) {
  // swap classes
  domClass.toggle(document.body, 'fullscreen', condition);
  // update state
  this._fullscreenState();
},
_validateLocationInputs: function (mode) {
  switch (mode) {
  case 'lat':
    var lat = lang.trim(dom.byId('lat_coord').value);
    if (lat === '') {
      domClass.remove(dom.byId('lat_coord').parentNode, 'has-error');
      domClass.remove(dom.byId('lat_coord').parentNode, 'has-success');
      return;
    }
    if (lat >= -90 && lat <= 90) {
      domClass.replace(dom.byId('lat_coord').parentNode, 'has-success', 'has-error');
    } else {
      domClass.replace(dom.byId('lat_coord').parentNode, 'has-error', 'has-success');
    }
    break;
  case 'lng':
    var lng = lang.trim(dom.byId('lng_coord').value);
    if (lng === '') {
      domClass.remove(dom.byId('lng_coord').parentNode, 'has-error');
      domClass.remove(dom.byId('lng_coord').parentNode, 'has-success');
      return;
    }
    if (lng >= -180 && lng <= 180) {
      domClass.replace(dom.byId('lng_coord').parentNode, 'has-success', 'has-error');
    } else {
      domClass.replace(dom.byId('lng_coord').parentNode, 'has-error', 'has-success');
    }
    break;
  }
},
// utm to lat lon
_convertUTM: function () {
  this._clearSubmissionGraphic();
  var northing = parseFloat(dom.byId('utm_northing').value);
  var easting = parseFloat(dom.byId('utm_easting').value);

  var zoneNode = dom.byId('utm_zone_number');
  var zoneString = zoneNode.value;

  var zoneLastChar = zoneString.substr(zoneString.length-1);

  var zone = parseInt(zoneString, 10);

  if(isNaN(zoneLastChar)){
    if(zoneLastChar.toLowerCase() === "s"){
      northing = Math.abs(northing) - NORTHING_OFFSET;
    }
  }
  else{
    northing = Math.abs(northing);
  }

  var converted = {};
  try {
    usng.UTMtoLL(northing, easting, zone, converted);
  } catch (e) {
    this._coordinatesError('utm');
  }
  if (converted) {
    this._locatePointOnMap(converted.lat, converted.lon, 'utm');
  }
},
// usng to lat lon
_convertUSNG: function () {
  this._clearSubmissionGraphic();
  var value = dom.byId('usng_coord').value;
  var converted = [];
  try {
    usng.USNGtoLL(value, converted);
  } catch (e) {
    this._coordinatesError('usng');
  }
  if (converted.length === 2) {
    this._locatePointOnMap(converted[0], converted[1], 'usng');
  }
},
// convert mgrs to lat lon
_convertMGRS: function () {
  this._clearSubmissionGraphic();
  var value = dom.byId('mgrs_coord').value;
  var converted = [];
  try {
    usng.USNGtoLL(value, converted);
  } catch (e) {
    this._coordinatesError('mgrs');
  }
  if (converted.length === 2) {
    this._locatePointOnMap(converted[0], converted[1], 'mgrs');
  }
},
// make sure valid coordinates
_evaluateCoordinates: function () {
  var latNode = dom.byId('lat_coord');
  var lngNode = dom.byId('lng_coord');
  this._clearSubmissionGraphic();
  if (latNode.value === "") {
    this._showErrorMessageDiv(nls.user.emptylatitudeAlertMessage, dom.byId("select_location"));
    return;
  } else if (lngNode.value === "") {
    this._showErrorMessageDiv(nls.user.emptylongitudeAlertMessage, dom.byId("select_location"));
    return;
  }
  // place on map
  this._locatePointOnMap(latNode.value, lngNode.value, 'latlon');
},
_checkLatLng: function () {
  // make sure lat and lon are both filled out to show button
  var lat = lang.trim(dom.byId('lat_coord').value);
  var lng = lang.trim(dom.byId('lng_coord').value);
  var coord = dom.byId('cordsSubmit');
  if (lat && lng) {
    domAttr.remove(coord, 'disabled');
  } else {
    domAttr.set(coord, 'disabled', 'disabled');
  }
},
_checkUTM: function () {
  // make sure lat and lon are both filled out to show button
  var e = dom.byId('utm_northing').value;
  var n = dom.byId('utm_easting').value;
  var z = dom.byId('utm_zone_number').value;
  var s = dom.byId('utm_submit');
  if (e && n && z) {
    domAttr.remove(s, 'disabled');
  } else {
    domAttr.set(s, 'disabled', 'disabled');
  }
},
_checkUSNG: function () {
  // make value(s) are set
  var inputVal = dom.byId('usng_coord').value;
  var btn = dom.byId('usng_submit');
  if (inputVal) {
    domAttr.remove(btn, 'disabled');
  } else {
    domAttr.set(btn, 'disabled', 'disabled');
  }
},
_checkMGRS: function () {
  // make value(s) are set
  var inputVal = dom.byId('mgrs_coord').value;
  var btn = dom.byId('mgrs_submit');
  if (inputVal) {
    domAttr.remove(btn, 'disabled');
  } else {
    domAttr.set(btn, 'disabled', 'disabled');
  }
},
// find location for coordinates
_findLocation: function (evt) {
  var keyCode = evt.charCode || evt.keyCode;
  if (keyCode === 13) {
    // check coordinates
    this._evaluateCoordinates();
  }
},
// my location button
_createLocateButton: function () {
  // create widget
  this.currentLocation = new LocateButton({
    map: this.map,
    highlightLocation: false,
    theme: "btn btn-default"
  }, domConstruct.create('div'));
  this.currentLocation.startup();
  if(this.currentLocation.visible){
    // on current location submit
    on(this.currentLocation, "locate", lang.hitch(this, function (evt) {
      // remove error
      var errorMessageNode = dom.byId('errorMessageDiv');
      domConstruct.empty(errorMessageNode);
      // if error
      if (evt.error) {
        alert(nls.user.locationNotFound);
      } else {
        this.addressGeometry = evt.graphic.geometry;
        this._setSymbol(evt.graphic.geometry);
        this._resizeMap();
        //If the location is found we will remove the location-error message if it exists
        this._removeErrorNode(dom.byId("select_location").nextSibling);
      }
      // reset button
      $('#geolocate_button').button('reset');
    }));
    // event for clicking node
    on(dom.byId('geolocate_button'), a11yclick, lang.hitch(this, function (evt) {
      // remove graphic
      this._clearSubmissionGraphic();
      // set loading button
      $('#geolocate_button').button('loading');
      // widget locate
      this.currentLocation.locate();
      evt.stopPropagation();
      evt.preventDefault();
    }));
  }
  else{
    $('#geolocate_button').addClass('hidden');
  }
},

// geocoder with bootstrap
_createGeocoderButton: function () {
  var searchOptions = {
    map: this.map,
    geocoders: this.config.helperServices.geocode || [],
    itemData: this.config.itemInfo.itemData
  };
  if (this.config.searchConfig) {
    searchOptions.enableSearchingAll = this.config.searchConfig.enableSearchingAll;
    searchOptions.activeSourceIndex = this.config.searchConfig.activeSourceIndex;
    searchOptions.applicationConfiguredSources = this.config.searchConfig.sources || [];
  } else {
    var configuredSearchLayers = (this.config.searchLayers instanceof Array) ? this.config.searchLayers : JSON.parse(this.config.searchLayers);
    searchOptions.configuredSearchLayers = configuredSearchLayers;
    searchOptions.geocoders = this.config.locationSearch ? this.config.helperServices.geocode : [];
  }
  var searchSources = new SearchSources(searchOptions);
  // get options
  var createdOptions = searchSources.createOptions();
  createdOptions.enableHighlight = false;
  createdOptions.enableInfoWindow = false;
  // create geocoder
  this.geocodeAddress = new Search(createdOptions, "search-widget");
  this.geocodeAddress.startup();
  // on find
  on(this.geocodeAddress, "select-result", lang.hitch(this, function (evt) {
    var coords = this._calculateLatLong(evt.result.feature.geometry);
    domAttr.set(dom.byId("coordinatesValue"), "innerHTML", coords);
    //this will remove the error message if it exists
    this._removeErrorNode(dom.byId("select_location").nextSibling);
    this.addressGeometry = evt.result.feature.geometry;
    this._setSymbol(evt.result.feature.geometry);
    this.map.centerAt(evt.result.feature.geometry).then(lang.hitch(this, function () {
      this._resizeMap();
    }));
  }));
},

// submit form with applyedits
_addFeatureToLayer: function () {
  var userFormNode, featureData, key, value, defaultValue;
  userFormNode = dom.byId('userForm');
  //To populate data for apply edits
  featureData = new Graphic();
  featureData.attributes = {};
  // start with layer defaults
  if (this._formLayer.templates[0] && this._formLayer.templates[0].prototype.attributes) {
    featureData.attributes = lang.clone(this._formLayer.templates[0].prototype.attributes);
  }
  //condition to filter out radio inputs
  array.forEach(query(".geoFormQuestionare .form-control"), function (currentField) {
    key = domAttr.get(currentField, "id");
    if (currentField.value !== "") {
      if (domClass.contains(currentField, "hasDatetimepicker")) {
        var picker = $(currentField.parentNode).data('DateTimePicker');
        var d = picker.date();
        // need to get time of date in ms for service
        value = d.valueOf();
      } else {
        value = lang.trim(currentField.value);
      }
      featureData.attributes[key] = value;
    }
    else if(domAttr.has(currentField, "data-default-value")){
      defaultValue = domAttr.get(currentField, "data-default-value");
      value = defaultValue;
      featureData.attributes[key] = value;
    }
  });
  array.forEach(query(".filterSelect"), function (currentField) {
    key = domAttr.get(currentField, "id");
    if (currentField.value) {
      value = lang.trim(currentField.value);
      featureData.attributes[key] = value;
    }
    else if(domAttr.has(currentField, "data-default-value")){
      defaultValue = domAttr.get(currentField, "data-default-value");
      value = defaultValue;
      featureData.attributes[key] = value;
    }
  });
  // each radio button
  array.forEach(query(".geoFormQuestionare .radioContainer"), function (currentField) {
    var radioFields = query(".radioInput:checked", currentField);
    if (radioFields.length) {
      var selectedField = radioFields[0];
      key = selectedField.name;
      value = lang.trim(selectedField.value);
      featureData.attributes[key] = value;
    }
  });
  // each checkbox
  array.forEach(query(".geoFormQuestionare .checkboxContainer"), function (currentField) {
    key = query(".checkboxInput", currentField)[0].id;
    value = query(".checkboxInput:checked", currentField).length;
    featureData.attributes[key] = value;
  });
  featureData.geometry = {};
  featureData.geometry = new Point(Number(this.addressGeometry.x), Number(this.addressGeometry.y), this.map.spatialReference);
  //code for apply-edits
  this._formLayer.applyEdits([featureData], null, null, lang.hitch(this, function (addResults) {
    // Add attachment on success
    if (addResults[0].success && this.isHumanEntry) {
      if (query(".fileToSubmit", userFormNode).length === 0) {
        this._resetAndShare();
      } else {
        this._openFileUploadStatusModal(query(".fileToSubmit", userFormNode));
        var fileObjArray = [];
        for (var i = 0; i < query(".formToSubmit", userFormNode).length; i++) {
          fileObjArray.push(query(".formToSubmit", userFormNode)[i].id);
        }
        this.arrPendingAttachments = fileObjArray.reverse();
        this._addAttachment(addResults[0].objectId, dom.byId(this.arrPendingAttachments.pop()));
      }
      return true;
    }
    domConstruct.destroy(query(".errorMessage")[0]);
    // open error modal if unsuccessful
    if (!addResults[0].success || (!this.isHumanEntry && addResults[0].success)) {
      var error;
      if(!addResults[0].success){
        error = addResults[0].error || new Error("");
      }
      else {
        error = new Error(nls.user.applyEditsFailedRobot);
      }
      this._openErrorModal(error);
      this._verifyHumanEntry();
      return;
    }
  }), lang.hitch(this, function (error) {
    // no longer editable
    this._formLayer.setEditable(false);
    // remove error
    domConstruct.destroy(query(".errorMessage")[0]);
    // open error
    this._openErrorModal(error);
    // log for development
    console.log(nls.user.addFeatureFailedMessage);
  }));
},
_resetAndShare: function () {
  // remove graphic
  this._clearSubmissionGraphic();
  // reset form
  this._clearFormFields();
  // reset to default extent
  if (this.config.defaultMapExtent) {
    this.map.setExtent(this.defaultExtent);
  }
  this._verifyHumanEntry();
  this._openShareModal();

  // reset submit button
  this._resetButton();
  window.location.href = '#top';
  // After moving geoform to top, map was not getting resized properly.
  // And pushpin was not getting placed correctly.
  this._resizeMap();
},
_addAttachment: function (recordId, currentElement) {
  var currentBadge;
  this.flagAttachingPrevFile = true;
  currentBadge = query(".file-upload-status-badge[data-badge=" + currentElement[0].id + "]")[0];
  //re-enabling the file i/p field before sending to attach
  domAttr.set(currentElement[0], "disabled", false);
  this._formLayer.addAttachment(recordId, currentElement, lang.hitch(this, function () {
    if (dom.byId("fileUploadStatusMsgContainer")) {
      this.flagAttachingPrevFile = false;
      //adding/removing attributes to keep the user updated on current state of file attachment
      domClass.replace(currentBadge.parentNode, "alert-success", "alert-info");
      domClass.replace(currentBadge, "glyphicon-ok", "glyphicon-upload");
      domStyle.set(currentBadge, "cursor", "auto");
      currentBadge.innerHTML = nls.user.successBadge;
      if (this.arrRetryAttachments.length !== 0) {
        this._addAttachment(recordId, dom.byId(this.arrRetryAttachments.pop()));
        return true;
      }
      if (this.arrPendingAttachments.length !== 0) {
        this._addAttachment(recordId, dom.byId(this.arrPendingAttachments.pop()));
        return true;
      }
    }
  }), lang.hitch(this, function () {
    //condition to check whether file upload status modal is open or not
    if (dom.byId("fileUploadStatusMsgContainer")) {
      this.flagAttachingPrevFile = false;
      //Keep a copy of ids that failed to upload to pick them back while retrying to upload the failed file
      this.objFailedAttachments[currentElement[0].id] = currentElement.id;

      //adding/removing attributes to keep the user updated on current state of file attachment
      domClass.replace(currentBadge.parentNode, "alert-warning", "alert-info");
      domClass.remove(query(".attachment-error-message", currentBadge.parentNode)[0], "hide");
      domClass.replace(currentBadge, "btn btn-danger btn-xs", "glyphicon-upload");
      currentBadge.innerHTML = nls.user.retryBadge;
      domStyle.set(currentBadge, "cursor", "pointer");
      //This click event will work on retry button in case of failure in attachment
      //and process to re-upload the file will start
      on.once(currentBadge, a11yclick, lang.hitch(this, function (evt) {
        //adding/removing attributes to keep the user updated on current state of file attachment
        domClass.replace(currentBadge.parentNode, "alert-info", "alert-warning");
        domClass.add(query(".attachment-error-message", currentBadge.parentNode)[0], "hide");
        domClass.replace(currentBadge, "glyphicon-upload", "btn btn-danger btn-xs glyphicon-repeat");
        evt.currentTarget.innerHTML = nls.user.uploadingBadge;
        domStyle.set(evt.currentTarget, "cursor", "auto");
        this.arrRetryAttachments.push(this.objFailedAttachments[domAttr.get(evt.currentTarget, "data-badge")]);
        delete this.objFailedAttachments[domAttr.get(evt.currentTarget, "data-badge")];
        if (this.flagAttachingPrevFile === false) {
          this._addAttachment(recordId, dom.byId(this.arrRetryAttachments.pop()));
        }
        return true;
      }));
      console.log(nls.user.addAttachmentFailedMessage);
      if (this.arrRetryAttachments.length !== 0) {
        this._addAttachment(recordId, dom.byId(this.arrRetryAttachments.pop()));
        return true;
      }
      if (this.arrPendingAttachments.length !== 0) {
        this._addAttachment(recordId, dom.byId(this.arrPendingAttachments.pop()));
        return true;
      }
    }
  }));
},
// remove point graphic
_clearSubmissionGraphic: function () {
  this.addressGeometry = null;
  this._gl.clear();
  if (this.map.infoWindow && this.map.infoWindow.isShowing) {
    this.map.infoWindow.hide();
  }
},
// display coordinates error
_coordinatesError: function (type) {
  switch (type) {
  case "utm":
    this._showErrorMessageDiv(nls.user.invalidUTM, dom.byId("select_location"));
    break;
  case "usng":
    this._showErrorMessageDiv(nls.user.invalidUSNG, dom.byId("select_location"));
    break;
  case "mgrs":
    this._showErrorMessageDiv(nls.user.invalidMGRS, dom.byId("select_location"));
    break;
  default:
    this._showErrorMessageDiv(nls.user.invalidLatLong, dom.byId("select_location"));
  }
},
_projectPoint: function (geometry) {
  // this function takes a lat/lon (4326) point and converts it to map's spatial reference.
  var def = new Deferred();
  // maps spatial ref
  var sr = this.map.spatialReference;
  // map and point are both lat/lon
  if (sr.wkid === 4326) {
    def.resolve(geometry);
  }
  // map is mercator
  else if (sr.isWebMercator()) {
    // convert lat lon to mercator. No network request.
    var pt = webMercatorUtils.geographicToWebMercator(geometry);
    def.resolve(pt);
  }
  // map is something else & has geometry service
  else if (esriConfig.defaults.geometryService) {
    // project params
    var params = new ProjectParameters();
    params.geometries = [geometry];
    params.outSR = this.map.spatialReference;
    // use geometry service to convert lat lon to map format (network request)
    esriConfig.defaults.geometryService.project(params).then(function (projectedPoints) {
      if (projectedPoints && projectedPoints.length) {
        def.resolve(projectedPoints[0]);
      } else {
        def.reject(new Error("GeoForm::Point was not projected."));
      }
    }, function (error) {
      def.reject(error);
    });
  }
  // cant do anything, leave lat/lon
  else {
    def.resolve(geometry);
  }
  return def;
},
// put x,y point on map in mercator
_locatePointOnMap: function (x, y, type) {
  if (x >= -90 && x <= 90 && y >= -180 && y <= 180) {
    var mapLocation = new Point(y, x);
    // convert point
    this._projectPoint(mapLocation).then(lang.hitch(this, function (pt) {
      if (pt) {
        this._removeErrorNode(dom.byId("select_location").nextSibling);
        this.addressGeometry = pt;
        // set point symbol
        this._setSymbol(pt);
        // center map at point and resize
        this.map.centerAt(pt).then(lang.hitch(this, function () {
          this._resizeMap();
        }));
        var errorMessageNode = dom.byId('errorMessageDiv');
        domConstruct.empty(errorMessageNode);
      }
    }), lang.hitch(this, function (error) {
      console.log(error);
      this._coordinatesError(type);
    }));
  } else {
    // display coordinates error
    this._coordinatesError(type);
  }
},
// open modal
_openShareModal: function () {
  // destroy modal if it exists
  if (this._ShareModal) {
    this._ShareModal.destroy();
  }
  // create modal content
  this._createShareDlgContent();
  // create modal
  this._ShareModal = new ShareModal({
    image: this.config.sharinghost + '/sharing/rest/content/items/' + this.config.itemInfo.item.id + '/info/' + this.config.itemInfo.item.thumbnail,
    title: this.config.details.Title || nls.user.geoformTitleText || '',
    summary: this.config.itemInfo.item.snippet || '',
    hashtags: 'esriGeoForm',
    shareOption: this.config.enableSharing
  });
  this._ShareModal.startup();
  // show modal
  $("#myModal").modal('show');
  domAttr.set(dom.byId("viewSubmissionsOption"), "href", this._viewSubmissions());
},
// error modal content
_openErrorModal: function (error) {
  var errorMsgContainer;
  domConstruct.empty(query(".modal-body")[0]);
  domAttr.set(dom.byId('myModalLabel'), "innerHTML", nls.user.error);
  errorMsgContainer = domConstruct.create("div", {}, query(".modal-body")[0]);
  var errorMessage = (error && error.message) || nls.user.applyEditsFailedMessage;

  if(error && error.code === "IdentityManagerBase.1"){
    errorMessage = nls.user.applyEditsAuthError;
  }

  domConstruct.create("div", {
    className: "alert alert-danger errorMessage",
    innerHTML: errorMessage
  }, errorMsgContainer);
  $("#myModal").modal('show');
  this._resetButton();
},
_openFileUploadStatusModal: function (fileList) {
  var fileUploadStatusMsgContainer, fileUploadStatusMsgUl, fileUploadStatusMsgLi, fileUploadStatusMsgBadge;
  domConstruct.empty(query(".modal-body")[0]);
  if (dom.byId("viewSubmissionsOption")) {
    domConstruct.destroy(query(".modal-footer")[0].children[1]);
  }
  domAttr.set(dom.byId('myModalLabel'), "innerHTML", nls.user.fileUploadStatus);
  fileUploadStatusMsgContainer = domConstruct.create("div", {
    "id": "fileUploadStatusMsgContainer"
  }, query(".modal-body")[0]);
  fileUploadStatusMsgUl = domConstruct.create("ul", {
    "class": "list-group"
  }, fileUploadStatusMsgContainer);

  for (var i = 0; i < fileList.length; i++) {
    fileUploadStatusMsgLi = domConstruct.create("li", {
      "class": "message alert alert-info fileInputUI"
    }, fileUploadStatusMsgUl);
    fileUploadStatusMsgBadge = domConstruct.create("span", {
      "class": "pull-right file-upload-status-badge glyphicon glyphicon-upload",
      "innerHTML": nls.user.uploadingBadge,
      "id": "badge" + i
    }, fileUploadStatusMsgLi);
    fileUploadStatusMsgBadge = domConstruct.create("span", {
      "class": "pull-right hide attachment-error-message",
      "innerHTML": nls.user.errorBadge
    }, fileUploadStatusMsgLi);
    fileUploadStatusMsgLi.innerHTML += fileList[i].value.split('\\').pop();
    domAttr.set(dom.byId("badge" + i), "data-badge", fileList[i].id);
  }
  $('#myModal').on('hidden.bs.modal', lang.hitch(this, function () {
    if (dom.byId("fileUploadStatusMsgContainer")) {
      this._resetAndShare();
    }
  }));

  $("#myModal").modal('show');
},
// share modal content
_createShareDlgContent: function () {
  var iconContainer, group;
  // empty modal node
  domConstruct.empty(query(".modal-body")[0]);
  if (dom.byId("viewSubmissionsOption")) {
    domConstruct.destroy(query(".modal-footer")[0].children[1]);
  }
  // set modal title
  domAttr.set(dom.byId('myModalLabel'), "innerHTML", nls.user.shareUserTitleMessage);
  // create nodes for modal
  iconContainer = domConstruct.create("div", {
    className: "iconContainer"
  }, query(".modal-body")[0]);
  domConstruct.create("div", {
    className: "alert alert-success",
    role: "alert",
    innerHTML: nls.user.entrySubmitted
  }, iconContainer);
  if (this.config.enableSharing) {
    domConstruct.create("h3", {
      innerHTML: nls.user.shareThisForm
    }, iconContainer);
    domConstruct.create("p", {
      innerHTML: nls.user.shareUserTextMessage
    }, iconContainer);
    domConstruct.create("a", {
      "tabindex": "0",
      className: "fa fa-facebook-square iconClass text-primary",
      id: "facebookIcon"
    }, iconContainer);
    domConstruct.create("a", {
      "tabindex": "0",
      className: "fa fa-twitter-square iconClass text-primary",
      id: "twitterIcon"
    }, iconContainer);
    domConstruct.create("a", {
      "tabindex": "0",
      className: "fa fa-google-plus-square iconClass text-primary",
      id: "google-plusIcon"
    }, iconContainer);
  }
  domConstruct.create("a", {
    "tabindex": "0",
    className: "fa fa-envelope iconClass text-primary",
    id: "mailIcon"
  }, iconContainer);
  domConstruct.create("div", {
    className: "clearfix"
  }, iconContainer);
  domConstruct.create("h3", {
    innerHTML: nls.user.shareModalFormText
  }, iconContainer);
  group = domConstruct.create("div", {
    className: "input-group"
  }, iconContainer);
  domConstruct.create("span", {
    className: "input-group-addon",
    innerHTML: "<span class=\"glyphicon glyphicon-link\"></span>"
  }, group);
  domConstruct.create("input", {
    type: "text",
    className: "form-control",
    id: "shareMapUrlText"
  }, group);
  domConstruct.create("a", {
    className: "btn btn-default pull-left",
    href: "#",
    id: "viewSubmissionsOption",
    innerHTML: this.config.viewSubmissionsText ? this.config.viewSubmissionsText : nls.user.btnViewSubmissions
  }, query(".modal-footer")[0]);
  if (this.config.disableViewer) {
    domClass.add(dom.byId("viewSubmissionsOption"), "hidden");
  }
},
// display error message
_showErrorMessageDiv: function (errorMessage, errorMessageNode) {
  // clear node
  var errorNode, place = "after";
  if (errorMessageNode.id === "errorMessageDiv") {
    place = "only";
  }
  if (errorMessageNode) {
    this._removeErrorNode(errorMessageNode.nextSibling);
  }
  // create node
  errorNode = domConstruct.create("div", {
    className: "alert alert-danger errorMessage",
    id: "errorMessage" + errorMessageNode.id,
    innerHTML: errorMessage
  }, null);
  domConstruct.place(errorNode, errorMessageNode, place);
  // resize map
  this._resizeMap();
},
// reset submit button
_resetButton: function () {
  var btn = $(dom.byId('submitButton'));
  btn.button('reset');
},
// set defaults for layer
_setLayerDefaults: function () {
  var error, flagPointFeatureLayer;
  // if no layer id is set, try to use first feature layer
  if (!this.config.form_layer || !this.config.form_layer.id) {
    flagPointFeatureLayer = false;
    array.some(this.config.itemInfo.itemData.operationalLayers, lang.hitch(this, function (currentLayer) {
      if (currentLayer.layerType && currentLayer.layerType === "ArcGISFeatureLayer") {
        if (currentLayer.resourceInfo.geometryType === 'esriGeometryPoint') {
          flagPointFeatureLayer = true;
          // if no object present
          if (!this.config.form_layer) {
            this.config.form_layer = {};
          }
          // set id
          this.config.form_layer.id = currentLayer.id;
          //Add the default fields in the fields object
          //This case will work when application is running without app id
          if(!this.config.fields.hasOwnProperty(this.config.form_layer.id)){
            this.config.fields[this.config.form_layer.id] = this.map.getLayer(this.config.form_layer.id).fields;
          }
          return true;
        } else {
          flagPointFeatureLayer = false;
        }
      }
    }));
    if (!flagPointFeatureLayer) {
      error = new Error(nls.user.invalidLayerMessage);
      this.reportError(error);
    }
  }
  // get editable layer
  this._formLayer = this.map.getLayer(this.config.form_layer.id);
  // if we have a layer
  if (this._formLayer) {
    // if fields not set or empty
    var isFieldsEmpty = this._isFieldsEmpty(this.config.fields);
    if (!this.config.fields || (this.config.fields && isFieldsEmpty)) {
      array.some(this.config.itemInfo.itemData.operationalLayers, lang.hitch(this, function (operationalLayer, index) {
        //condition to catch the right layer from webmap
        if (operationalLayer.id === this._formLayer.id) {
          //This loop runs through all the fields configured in the popup
          array.forEach(this.config.itemInfo.itemData.operationalLayers[index].popupInfo.fieldInfos, lang.hitch(this, function (popupField) {
            //This loop will run through all the fields in the formLayer and will break when the field matches with currently selected field of pop
            array.some(this._formLayer.fields, lang.hitch(this, function (formLayerField) {
              //condition to match the popup field with the formLayer field to mixin the properties of object.
              if (formLayerField.name === popupField.fieldName) {
                //condition to show a type field irrespective of it's configured edit property.
                if (formLayerField.name === this._formLayer.typeIdField) {
                  popupField.isEditable = true;
                }
                formLayerField.alias = popupField.label;
                formLayerField.editable = popupField.isEditable;
                formLayerField.visible = popupField.isEditable;
                formLayerField.tooltip = popupField.tooltip;
                formLayerField.locked = popupField.locked;
                this.config.fields[this._formLayer.id].push(formLayerField);
                return true;
              }
            }));
          }));
          return true;
        }
      }));
    }
    if (this.config.showLayer) {
      this._formLayer.setVisibility(true);
    } else {
      this._formLayer.setVisibility(false);
    }
    //This logic will convert the old array structure to equivalent object
    if (this.config.fields.length) {
      var fieldsArray = lang.clone(this.config.fields);
      this.config.fields = {};
      this.config.fields[this._formLayer.id] = fieldsArray;
    }
  } else {
    if (this.config.form_layer.id !== "all") {
      error = new Error(nls.user.invalidLayerMessage);
      this.reportError(error);
      return;
    }
  }
},
_isFieldsEmpty: function (object) {
  for (var key in object) {
    if (object[key]) {
      return false;
    }
    return true;
  }
},
// set defaults for app settings
_setWebmapDefaults: function () {
  // if details not defined
  if (!this.config.details) {
    this.config.details = {};
  }
  // if no app title
  if (!this.config.details.Title) {
    if (this._appResponse && this._appResponse.item) {
      // use app title
      this.config.details.Title = this._appResponse.item.title;
    }
    // if item
    if (this.config.itemInfo && this.config.itemInfo.item) {
      // use webmap title
      this.config.details.Title = this.config.itemInfo.item.title;
    }
  }
  // if no app description
  if (!this.config.details.Description) {
    // if item
    if (this.config.itemInfo && this.config.itemInfo.item) {
      // use webmap snippet
      this.config.details.Description = this.config.itemInfo.item.snippet;
    }
  }
  // if no app logo
  if (!this.config.details.Logo) {
    // if item and thumb
    if (this.config.itemInfo && this.config.itemInfo.item && this.config.itemInfo.item.thumbnail) {
      // use webmap logo
      this.config.details.Logo = this.config.sharinghost + "/sharing/rest/content/items/" + this.config.webmap + '/info/' + this.config.itemInfo.item.thumbnail;
    }
  }
},
// resize map
_resizeMap: function (force) {
  if (this.map) {
    this.map.reposition();
    this.map.resize(force);
  }
},
// set visible location options
_populateLocationsOptions: function () {
  var count = 0,
    total = 0,
    locationTabs, tabContents;
  locationTabs = query("#location_pills li");
  tabContents = query("#location_tabs .tab-pane");
  if (!this.config.locationSearchOptions) {
    this.config.locationSearchOptions = {
      "enableMyLocation": true,
      "enableSearch": true,
      "enableLatLng": true,
      "enableUSNG": false,
      "enableMGRS": false,
      "enableUTM": false
    };
  }
  for (var key in this.config.locationSearchOptions) {
    if (this.config.locationSearchOptions.hasOwnProperty(key) && key !== "enableMyLocation") {
      for(var i = 0; i < locationTabs.length; i++){
        var tab = locationTabs[i];
        var tabId = domAttr.get(tab, "data-tab-id");
        if(tabId === key){
          domStyle.set(tab, 'display', this.config.locationSearchOptions[key] ? "block" : "none");
        }
        on(tab, a11yclick, lang.hitch(this, this._resizeMap));
        total++;
      }
    }
  }
  if (!this.config.locationSearchOptions.enableMyLocation) {
    domStyle.set(dom.byId("geolocate_button"), 'display', 'none');
  }
  if (!this.config.locationSearchOptions.enableSearch) {
    domStyle.set(dom.byId("search-widget"), 'display', 'none');
  }
  //add 'active' class to first tab and its content
  array.some(locationTabs, lang.hitch(this, function (tab, idx) {
    if (domStyle.get(tab, 'display') == 'block') {
      domClass.add(tab, 'active');
      domClass.add(tabContents[idx], 'active');
      return true;
    }
  }));
  if (total > 1) {
    dom.byId("locationOptionDescriptor").innerHTML = nls.user.locationDescriptionForMoreThanOneOption;
  } else {
    // hide tab nav if zero or one tabs
    var node = dom.byId('location_nav');
    if (node) {
      domStyle.set(node, 'display', 'none');
    }
    var panelNode = dom.byId('location_panel');
    if (panelNode) {
      domClass.remove(panelNode, 'panel panel-default');
    }
    var panelBodyNode = dom.byId('location_panel_body');
    if (panelBodyNode) {
      domClass.remove(panelBodyNode, 'panel-body');
    }
    if (total === 1) {
      dom.byId("locationOptionDescriptor").innerHTML = nls.user.locationDescriptionForOneOption;
    } else {
      dom.byId("locationOptionDescriptor").innerHTML = nls.user.locationDescriptionForNoOption;
    }
  }
  // resize map
  this._resizeMap();
},
_addNotationIcon: function (formContent, imageIconClass) {
  var inputIconGroupContainer, inputIconGroupAddOn;
  inputIconGroupContainer = domConstruct.create("div", {
    className: "input-group"
  }, formContent);
  inputIconGroupAddOn = domConstruct.create("span", {
    className: "input-group-addon"
  }, inputIconGroupContainer);
  domConstruct.create("span", {
    className: "glyphicon " + imageIconClass
  }, inputIconGroupAddOn);
  return inputIconGroupContainer;
},
_getFormElement: function (currentDom) {
  var formElement = currentDom;
  while (!domClass.contains(formElement, "geoFormQuestionare")) {
    formElement = formElement.parentNode;
  }
  return formElement;
},
_createDateField: function (parentNode, isRangeField, fieldname, currentField, defaultValue) {
  domClass.add(parentNode, "date");
  var minDate, maxDate, defaultDate;
  if (currentField && currentField.preventPast) {
    minDate = new Date();
  }
  if (currentField && currentField.preventFuture) {
    maxDate = new Date();
  }
  if (currentField && currentField.setCurrentDate) {
    defaultDate = new Date();
  }
  else if (defaultValue) {
    defaultDate = moment(defaultValue).format(this.dateFormat);
  }
  var dateInputField = domConstruct.create("input", {
    disabled: !!currentField.locked,
    type: "text",
    value: "",
    className: "form-control hasDatetimepicker",
    "data-input-type": "Date",
    "id": fieldname
  }, parentNode);
  on(dateInputField, "focus", function (e) {
    $(this.parentElement).data("DateTimePicker").show(e);
  });
  on(dateInputField, "blur", function () {
    $(this.parentElement).data("DateTimePicker").hide();
  });
  var dpOptions = {
    useStrict: false,
    locale: kernel.locale,
    minDate: minDate,
    maxDate: maxDate,
    format: this.dateFormat,
    defaultDate: defaultDate,
    useCurrent: true
  };
  if (kernel.locale === "en" || kernel.locale === "en-us") {
    dpOptions.extraFormats = ["M/D/YYYY", "M-D-YYYY", "M.D.YYYY", "M D YYYY"];
  }
  if (isRangeField && currentField.domain.minValue !== currentField.domain.maxValue && currentField.domain.minValue > -2147483648 && currentField.domain.maxValue > -2147483648) {
    dpOptions.minDate = moment(currentField.domain.minValue);
    dpOptions.maxDate = moment(currentField.domain.maxValue);
  }
  $(parentNode).datetimepicker(dpOptions).on('dp.show', function (evt) {
    var picker = $(this).data('DateTimePicker');
    var selectedDate = picker.date();
    if (selectedDate === null) {
      query("input", this)[0].value = "";
    }
    domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-error");
    domClass.add(query(evt.target).parents(".geoFormQuestionare")[0], "has-success");
    if (query("input", this)[0].value === "") {
      domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-success");
    }
  }).on('dp.error', function (evt) {
    evt.target.value = '';
    domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-success");
    domClass.add(query(evt.target).parents(".geoFormQuestionare")[0], "has-error");
    $(this).data("DateTimePicker").hide();
  }).on("dp.hide", function (evt) {
    if (query("input", this)[0].value === "") {
      domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-success");
      domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-error");
    }
  }).on('dp.change', function (evt) {
    domClass.add(query(evt.target).parents(".geoFormQuestionare")[0], "has-success");
    domClass.remove(query(evt.target).parents(".geoFormQuestionare")[0], "has-error");
  });
  return dateInputField;
},
_verifyHumanEntry: function () {
  this.isHumanEntry = false;
  setTimeout(lang.hitch(this, function () {
    this.isHumanEntry = true;
  }), 2000);
},
//This function will remove the error message div.
_removeErrorNode: function (node) {
  if (domClass.contains(node, "errorMessage")) {
    domConstruct.destroy(node);
  }
}

}); }); `

apena12 commented 5 years ago

Hello,

Is this to store address into attribute from search location map? Please kindly confirm. Thank you for your assistance.

Alex