Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

default.js : locked attribute doesn't work #550

Closed
randomblink opened this issue Apr 4, 2018 · 8 comments
Closed

default.js : locked attribute doesn't work #550

randomblink opened this issue Apr 4, 2018 · 8 comments

Comments

@randomblink
Copy link
Contributor

This attribute is not stopping end users from changing the contents of the field.

@clm42
Copy link

clm42 commented Apr 4, 2018

How I accomplished this was to edit the GeoForm code to look for the locked attribute of a field in the config and then add the disabled class to the form field. It will grey out the field in the form so a user can’t edit it but you can programmatically edit it and the user will see that value.

@driskull
Copy link
Member

driskull commented Apr 4, 2018

How I accomplished this was to edit the GeoForm code to look for the locked attribute of a field in the config and then add the disabled class to the form field. It will grey out the field in the form so a user can’t edit it but you can programmatically edit it and the user will see that value.

👍

Where is the 'locked' property coming from? Is that a non standard property on a fieldInfo?

@randomblink
Copy link
Contributor Author

The locked attribute doesn't work.

"name": "SITEADDID", // field id
"alias": "Site Address ID", // label
"defaultValue": "GF" + new Date().getTime(),
"locked": true,
"fieldDescription": "The ID of the address point", // Help text
"visible": true, // show this field?
"typeField": false, // subtype field?
"tooltip": "", // placeholder text
"displayType": "text", // text, checkbox, radio, textarea, url, email

Form doesn't grey it out : https://youtu.be/7kR-792vTzA
Changed SITEADDID evidence : https://youtu.be/S6x_A62wDrg

@randomblink
Copy link
Contributor Author

You can see that the custom SITEADDID is working... I get the customized field entry that I want. But... the end user can tank the whole process which is not acceptable. Endusers are notorious for editing stuff they are specifically trained not to. I have to make that field UNTOUCHABLE.

@driskull
Copy link
Member

driskull commented Apr 4, 2018

@randomblink can you try using this and let me know if it's what you're looking for:

main.js

/*global $,define,document,require,moment */
/*jslint sloppy:true,nomen:true */
define([
    "dojo/_base/declare",
    "dojo/_base/kernel",
    "dojo/_base/lang",
    "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,
  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",

    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);
      }
      this._verifyHumanEntry();
    },
    _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");
      }
      //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);
      }
    }
  });
});

@clm42
Copy link

clm42 commented Apr 5, 2018

I added a locked property the same way he did. That way the field name isn’t hard coded into the app and I can use that tweaked geoform base for multiple projects. I’d post my tweaks but I’m out on paternity leave and my code is all at work. It might be in an old fork I did if I didn’t delete it. Editing existing feature attributes (not geometry) is also in that fork if I remember.

@randomblink
Copy link
Contributor Author

@driskull that is EXACTLY what I needed. Oh my goodness... that just fixed so many things.

Thank you so much... This should "seriously" be in the main code.

@driskull
Copy link
Member

driskull commented Apr 5, 2018

Ok cool. I'll check it into the main code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants