import { Resources } from '../../resources/resources';
import { checkBrowserCompatibility } from '../../view/helpers';
import { Events, ApiMethods, parseJson, callApiMethod } from './components';
function arrayContains(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
/**
* Represents a component that provides both UI and programmatic interaction with PMA.core forms and data.
* @param {PMA.UI.Components.Context} context
* @param {Object} options - Reserved for future use
* @tutorial 06-forms
*/
export class Forms {
constructor(context, options) {
if (!checkBrowserCompatibility()) {
return;
}
this.listeners = {};
this.listeners[Events.FormSaved] = [];
this.listeners[Events.FormEditClick] = [];
this.context = context;
}
/**
* Renders a form field in read-only form
* @param {Object} field - A PMA.core form field structure
* @param {Object} record - A PMA.core form field value structure
* @param {string} cssClass - Extra CSS class to add to the container element
* @returns {string} The HTML output
*/
renderReadOnlyField(field, record, cssClass) {
var strVal = (record && record.FormValue ? record.FormValue : '').replace(/"/g, """);
if (strVal.length !== 0 && record && field.FieldType != Forms.FieldType.CheckBox && field.FormList && field.FormList.FormListValues && !record.IsOtherValue && !record.IsBelowDetectableLimit) {
strVal = field.FormList.FormListValues[strVal].Value;
}
if (record && record.IsBelowDetectableLimit) {
strVal = Resources.translate("Below detectable limit");
}
var html = "";
switch (field.FieldType) {
case Forms.FieldType.Paragraph:
html += '<p class="' + cssClass + '">' + strVal + '</p>';
break;
case Forms.FieldType.CheckBox:
if (field.FormList && field.FormList.FormListValues && record && !record.IsOtherValue && strVal.length !== 0 && !record.IsBelowDetectableLimit) {
var chkValues = strVal.split("|");
html += '<ul class="' + cssClass + '">';
for (let k = 0; k < chkValues.length; k++) {
html += "<li>" + field.FormList.FormListValues[chkValues[k]].Value + "</li>";
}
html += '</ul>';
}
else {
html += '<div class="' + cssClass + '">' + strVal + '</div>';
}
break;
case Forms.FieldType.Percentage:
html += '<div class="' + cssClass + '">' + strVal + '%</div>';
break;
case Forms.FieldType.HyperLink:
html += '<a class="link-field" title="' + field.Tooltip + '" href="' + field.Url + '" ' + (field.NewWindow === true ? ' target="_blank" ' : '') + '>' + field.Label + '</a>';
break;
case Forms.FieldType.Label:
break;
default:
html += '<div class="' + cssClass + '">' + strVal + '</div>';
break;
}
return html;
}
/**
* Passes a form definition and optionally form data back to the caller
* @callback Forms~getFormCallback
* @param {Object} form - The requested form definition
* @param {Object} [data] - The submitted form data
*/
/**
* A callback to filter the data retrieved from the server
* @callback Forms~filterDataCallback
* @param {Object} [data] - The retrieved form data
* @returns {Object} The filtered data
*/
/**
* Loads a form definition and optionally the available submitted data
* @param {String} serverUrl
* @param {Number} formId
* @param {Object} [dataOptions] - Used when it is desired to load submitted data as well
* @param {string} dataOptions.path - The path to load form submitted data for
* @param {boolean} [dataOptions.currentUserOnly=false] - True to load only the current user's data. The user is determined by the server's URL and the authentication providers available in the context.
* @param {string | Forms~filterDataCallback} [dataOptions.dataFilter=""] - Optional parameter to filter data results with. If the parameter is a string it is considered a username and data from this user are kept. This is useful when a particular user's data is desired, but not the currently logged on one's. If a callback function is provided it should return the filtered data
* @param {Forms~getFormCallback} [success]
* @param {function} [failure]
*/
getForm(serverUrl, formId, dataOptions, success, failure) {
var _this = this;
_this.context.getSession(serverUrl, function (sessionId) {
callApiMethod({
serverUrl: serverUrl,
method: ApiMethods.GetForm,
data: { sessionID: sessionId, id: formId },
success: function (http) {
var response = parseJson(http.responseText);
if (response) {
if (dataOptions !== null && dataOptions !== undefined && typeof dataOptions === "object") {
loadFormData.call(_this, serverUrl, sessionId, response, dataOptions.path, dataOptions.currentUserOnly === true, dataOptions.dataFilter,
function (data) {
response.FormData = data;
if (typeof success === "function") {
success.call(_this, response, data);
}
}, failure);
}
else if (typeof success === "function") {
success.call(_this, response, null);
}
}
else if (typeof failure === "function") {
failure();
}
},
failure: failure
});
}, failure);
}
/**
* Passes form definitions back to the caller
* @callback Forms~getFormsCallback
* @param {Object[]} forms - Form definition objects fetched from PMA.core
*/
/**
* Loads all the available form definitions from a PMA.core server
* @param {String} serverUrl - The PMA.core server URL
* @param {Forms~getFormsCallback} success - Called upon successful completion of the data request.
* @param {function} [failure]
*/
getForms(serverUrl, success, failure) {
var _this = this;
_this.context.getSession(serverUrl, function (sessionId) {
callApiMethod({
serverUrl: serverUrl,
method: ApiMethods.GetForms,
data: { sessionID: sessionId },
success: function (http) {
var response = parseJson(http.responseText);
if (response && typeof success === "function") {
success(response);
}
else if (typeof failure === "function") {
failure(response);
}
},
failure: failure
});
}, failure);
}
/**
* Called while rendering each field. This function gives the opportunity to the caller to make modifications per element, or return false to prevent rendering of specific fields.
* @callback Forms~renderFieldCallback
* @param {Object} form - The definition of the form that is being rendered
* @param {Object} field - The definition of the field that is being rendered
* @param {Object} field.fieldGroupClass - The CSS class to assign to the fields group element
* @param {Object} field.fieldContainerClass - The CSS class to assign to the field's container
* @param {Object} [record] - The data that will be displayed by the field. Can be null if no data is available or loaded.
* @returns {boolean} True to render this field, otherwise false
*/
/**
* Renders a form and optionally loads the available user submitted data
* @param {string} serverUrl
* @param {Number} formId
* @param {string|HTMLElement} element - The element that hosts the form. It can be either a valid CSS selector or an HTMLElement instance.
* @param {Object} [dataOptions] - Supplied only when it is desired to load form submitted data as well
* @param {string} dataOptions.path - The path to load form submitted data for
* @param {boolean} [dataOptions.currentUserOnly=false] - True to load only the current user's data. The user is determined by the server's URL and the authentication providers available in the context.
* @param {string | Forms~filterDataCallback} [dataOptions.dataFilter=""] - Optional parameter to filter data results with. If the parameter is a string it is considered a username and data from this user are kept. This is useful when a particular user's data is desired, but not the currently logged on one's. If a callback function is provided it should return the filtered data
* @param {string} [dataOptions.btnContainerClass] - CSS class to assign the to element that contains the save and reset buttons
* @param {string} [dataOptions.btnResetClass] - CSS class to assign the reset button
* @param {string} [dataOptions.btnSaveClass] - CSS class to assign the save button
* @param {Forms~renderFieldCallback} [dataOptions.fieldCb] - Called when rendering each field.
* @param {string} [dataOptions.fieldContainerClass] - CSS class to assign the to element that contains field controls
* @param {string} [dataOptions.fieldValidationClass] - CSS class to assign to error labels that are displayed upon validating the form
* @param {string} [dataOptions.formClass] - CSS class to assign to the rendered form element
* @param {string} [dataOptions.inputClass] - CSS class to assign the to input elements
* @param {boolean} [dataOptions.readOnly=false] - True to render the form in read only mode
* @param {boolean} [dataOptions.editButton=false] - True to render an edit button next to the form's name. Only applicable in read only mode
* @param {string} [dataOptions.validationClass] - CSS class to assign to generic validation messages (e.g. "The form could not be saved")
* @param {function} [success]
* @param {function} [failure]
*/
displayForm(serverUrl, formId, element, dataOptions, success, failure) {
var _this = this;
this.getForm(serverUrl, formId, dataOptions,
function (form, data) {
_this.serverUrl = serverUrl;
if (form) {
_this.form = form;
_this.form.enabled = true;
if (form.ReadOnly === true) {
dataOptions.readOnly = true;
}
}
_this.path = dataOptions.path;
_this.originalData = data;
renderForm.call(_this, element, form, dataOptions, data, success, failure);
},
failure);
}
/**
* Renders a form and optionally loads the available user submitted data without loading from the server
* @param {string|HTMLElement} element - The element that hosts the form. It can be either a valid CSS selector or an HTMLElement instance.
* @param {Object} form - The form definition object
* @param {Object} [dataOptions] - Supplied only when it is desired to load form submitted data as well
* @param {string} dataOptions.path - The path to load form submitted data for
* @param {boolean} [dataOptions.currentUserOnly=false] - True to load only the current user's data. The user is determined by the server's URL and the authentication providers available in the context.
* @param {string | Forms~filterDataCallback} [dataOptions.dataFilter=""] - Optional parameter to filter data results with. If the parameter is a string it is considered a username and data from this user are kept. This is useful when a particular user's data is desired, but not the currently logged on one's. If a callback function is provided it should return the filtered data
* @param {string} [dataOptions.btnContainerClass] - CSS class to assign the to element that contains the save and reset buttons
* @param {string} [dataOptions.btnResetClass] - CSS class to assign the reset button
* @param {string} [dataOptions.btnSaveClass] - CSS class to assign the save button
* @param {Forms~renderFieldCallback} [dataOptions.fieldCb] - Called when rendering each field.
* @param {string} [dataOptions.fieldContainerClass] - CSS class to assign the to element that contains field controls
* @param {string} [dataOptions.fieldValidationClass] - CSS class to assign to error labels that are displayed upon validating the form
* @param {string} [dataOptions.formClass] - CSS class to assign to the rendered form element
* @param {string} [dataOptions.inputClass] - CSS class to assign the to input elements
* @param {boolean} [dataOptions.readOnly=false] - True to render the form in read only mode
* @param {boolean} [dataOptions.editButton=false] - True to render an edit button next to the form's name. Only applicable in read only mode
* @param {string} [dataOptions.validationClass] - CSS class to assign to generic validation messages (e.g. "The form could not be saved")
* @param {Object} [data] - The data to load to the form displayed
* @param {function} [success]
* @param {function} [failure]
*/
renderForm(element, form, dataOptions, data, success, failure) {
if (form) {
this.form = form;
this.form.enabled = true;
if (form.ReadOnly === true) {
dataOptions.readOnly = true;
}
}
this.path = dataOptions.path;
this.originalData = data;
renderForm.call(this, element, form, dataOptions, data, success, failure);
}
/**
* Saves the currently rendered form to PMA.core
* @param {function} [success]
* @param {function} [failure]
* @fires PMA.UI.Components.Events#FormSaved
*/
saveForm(success, failure) {
var _this = this;
_this.setEnabled(false);
$("#" + _this.form.ClientID + " button[type='submit']").html(Resources.translate("Saving..."));
submitForm.call(this, function (args) {
$("#" + _this.form.ClientID + " button[type='submit']").html(Resources.translate("Save"));
_this.setEnabled(true);
_this.fireEvent(Events.FormSaved, args);
if (typeof success === "function") {
success(args);
}
},
function (args) {
$("#" + _this.form.ClientID + " button[type='submit']").html(Resources.translate("Save"));
_this.setEnabled(true);
_this.fireEvent(Events.FormSaved, args);
if (typeof failure === "function") {
failure(args);
}
});
}
/**
* Enables or disables the currently rendered form
* @param {boolean} enabled
*/
setEnabled(enabled) {
if (this.form) {
this.form.enabled = !!enabled;
$("#" + this.form.ClientID + " > fieldset").prop("disabled", !this.form.enabled);
}
else {
console.error("No form");
}
}
/**
* Gets the state of the currently rendered form
* @return {boolean}
*/
getEnabled() {
if (this.form) {
return this.form.enabled;
}
else {
console.error("No form");
}
}
/**
* Attaches an event listener
* @param {PMA.UI.Components.Events} eventName - The name of the event to listen to
* @param {function} callback - The function to call when the event occurs
*/
listen(eventName, callback) {
if (!this.listeners.hasOwnProperty(eventName)) {
console.error(eventName + " is not a valid event");
}
this.listeners[eventName].push(callback);
}
// fires an event
fireEvent(eventName, eventArgs) {
if (!this.listeners.hasOwnProperty(eventName)) {
console.error(eventName + " does not exist");
return;
}
for (var i = 0, max = this.listeners[eventName].length; i < max; i++) {
this.listeners[eventName][i].call(this, eventArgs);
}
}
/**
* Checks if the currently loaded form has any changes that have not been saved yet.
* @return {boolean}
*/
hasChanges() {
if (!this.form) {
return false;
}
return this.hasChangesProperty;
}
/**
* Resets the currently loaded form to it's initial state
*/
reset() {
if (!this.form) {
return false;
}
$("#" + this.form.ClientID + " [type='reset']").click();
}
}
/**
* Available form field types
* @readonly
* @enum {number}
*/
Forms.FieldType = {
/**
* Simple text (input)
*/
Text: 0,
/**
* Simple paragraph (label)
*/
Paragraph: 1,
/**
* Dropdown
*/
ListBox: 2,
/**
* Checkbox list
*/
CheckBox: 3,
/**
* Radio button list
*/
RadioButton: 4,
/**
* Integer input
*/
Integer: 5,
/**
* Decimal input
*/
Double: 6,
/**
* Datetime input
*/
DateTime: 7,
/**
* Percentage input
*/
Percentage: 8,
/**
* Section separator - label
*/
Label: 9,
/**
* HyperLink
*/
HyperLink: 10
};
function getCheckboxesValue(el) {
var value = "";
el.each(function () {
if (value.length > 0) {
value += "|";
}
value += this.value;
});
return value;
}
function createPostData(sessionId) {
var values = [];
var form = this.form;
for (var i = 0; i < this.form.FormFields.length; i++) {
var field = form.FormFields[i];
var fieldId = getFieldId(this.form, i);
var value = null,
below = false,
other = false,
el, otherElVal;
switch (field.FieldType) {
case Forms.FieldType.Text:
case Forms.FieldType.Paragraph:
case Forms.FieldType.DateTime:
el = $("#" + fieldId);
if (el.val() !== "") {
value = el.val();
}
break;
case Forms.FieldType.Integer:
case Forms.FieldType.Double:
case Forms.FieldType.Percentage:
el = $("#" + fieldId);
if (el.val() !== "") {
value = el.val();
}
else if (field.AllowBelowDetectableLimit === true && $("#" + fieldId + "_below:checked").length === 1) {
below = true;
}
break;
case Forms.FieldType.ListBox:
el = $("#" + fieldId);
if (el.val() !== "") {
value = el.val();
}
else if (field.AllowOther && $("#" + fieldId + "_other").val() !== "") {
value = $("#" + fieldId + "_other").val();
other = true;
}
break;
case Forms.FieldType.CheckBox:
otherElVal = $("#" + fieldId + "_other").val();
el = $("input[name='" + fieldId + "']:checked");
if (el.length !== 0) {
value = getCheckboxesValue(el);
}
else if (field.AllowOther === true && otherElVal !== "") {
value = otherElVal;
other = true;
}
break;
case Forms.FieldType.RadioButton:
otherElVal = $("#" + fieldId + "_other").val();
el = $("input[name='" + fieldId + "']:not([id$='_other_indicator']):checked");
if (el.length !== 0) {
value = el.val();
}
else if (field.AllowOther === true && otherElVal !== "") {
value = otherElVal;
other = true;
}
break;
}
values.push({
FieldId: field.FieldID,
FormValue: value,
IsBelowDetectableLimit: below,
IsOtherValue: other
});
}
return {
sessionID: sessionId,
pathOrUid: this.path,
formId: this.form.FormID,
fieldValues: values
};
}
function submitForm(success, failure) {
if (!validateForm.call(this)) {
if (typeof failure === "function") {
failure({ success: false, message: Resources.translate("Form validation error") });
}
return;
}
var _this = this;
_this.context.getSession(_this.serverUrl, function (sessionId) {
var postData = createPostData.call(_this, sessionId);
callApiMethod({
serverUrl: _this.serverUrl,
method: ApiMethods.SaveFormData,
httpMethod: "POST",
contentType: 'application/json',
data: postData,
success: function (http) {
_this.hasChangesProperty = false;
if (typeof success === "function") {
success({ success: true, message: '' });
}
},
failure: function (http) {
var errorMsg = Resources.translate("Save failed. Check the form values and try again.");
if (http && http.responseText) {
var errorObj = JSON.parse(http.responseText);
if (errorObj && errorObj.Message) {
errorMsg = errorObj.Message;
}
}
$("#" + _this.form.ClientID + "_validation").html(errorMsg);
if (typeof failure === "function") {
failure({ success: false, message: errorMsg });
}
}
});
}, function (args) {
if (typeof failure === "function") {
failure({ success: false, message: ((args && args.Message) ? args.Message : Resources.translate("Authentication error")) });
}
});
}
function clearValidationErrors() {
if (!this.form) {
return;
}
$("#" + this.form.ClientID + " [id$='_validation']").html("");
$("#" + this.form.ClientID + " *").removeClass("invalid");
}
function validateForm() {
if (!this.form) {
return false;
}
clearValidationErrors.call(this);
var form = this.form;
$("#" + form.ClientID + "_validation").html("");
var el, otherEl, isValid;
for (var i = 0; i < this.form.FormFields.length; i++) {
var field = form.FormFields[i];
var fieldId = getFieldId(this.form, i);
var validationSpan = $("#" + fieldId + "_validation");
validationSpan.html("");
switch (field.FieldType) {
case Forms.FieldType.Text:
case Forms.FieldType.Paragraph:
case Forms.FieldType.DateTime:
el = $("#" + fieldId);
if (field.Required === true && el.val() === "") {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please enter a value"));
return false;
}
el.removeClass("invalid");
break;
case Forms.FieldType.Integer:
case Forms.FieldType.Double:
case Forms.FieldType.Percentage:
el = $("#" + fieldId);
if (field.Required === true && el.val() === "") {
isValid = false;
if (field.AllowBelowDetectableLimit === true && $("#" + fieldId + "_below:checked").length === 1) {
isValid = true;
}
if (!isValid) {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please enter a value"));
return false;
}
}
var numVal = el.val();
if (isNaN(numVal)) {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please enter a valid value"));
return false;
}
if (typeof numVal !== "number") {
numVal = parseFloat(numVal);
}
if (typeof field.LowerBound === "number" && numVal < field.LowerBound) {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please enter a value larger than or equal to {LowerBound}", { LowerBound: field.LowerBound }));
return false;
}
if (typeof field.UpperBound === "number" && numVal > field.UpperBound) {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please enter a value less than or equal to {UpperBound}", { UpperBound: field.UpperBound }));
return false;
}
el.removeClass("invalid");
break;
case Forms.FieldType.ListBox:
el = $("#" + fieldId);
if (field.Required === true && el.val() === "") {
isValid = false;
if (field.AllowOther && $("#" + fieldId + "_other").val() !== "") {
isValid = true;
}
if (!isValid) {
el.addClass("invalid");
el.focus();
validationSpan.html(Resources.translate("Please select a value"));
return false;
}
}
el.removeClass("invalid");
break;
case Forms.FieldType.CheckBox:
case Forms.FieldType.RadioButton:
// if the field is required and not option is select apart from the "other value" indicator
if (field.Required === true && $("input[name='" + fieldId + "']:not([id$='_other_indicator']):checked").length === 0) {
if (field.AllowOther !== true || $("#" + fieldId + "_other").val() === "") {
$("input[name='" + fieldId + "']").first().focus();
validationSpan.html(Resources.translate("Please select a value"));
return false;
}
}
break;
case Forms.FieldType.Label:
case Forms.FieldType.HyperLink:
break;
default:
console.error("Unknown field type " + field.FieldType);
return false;
}
}
return true;
}
function bindClearFieldValueWhenBelowCheckedEvent(field, fieldId) {
$("#" + fieldId + "_below").change(function () {
if (this.checked) {
$("#" + fieldId).val("");
}
});
}
function bindUncheckBelowEvent(field, fieldId) {
$("#" + fieldId).change(function () {
if ($(this).val() !== "") {
$("#" + fieldId + "_below").prop("checked", false);
}
});
}
function bindClearFieldValueWhenOtherChangedEvent(field, fieldId) {
$("#" + fieldId + "_other").change(function () {
if ($(this).val() !== "") {
$("#" + fieldId).val("");
$("input[name='" + fieldId + "'").prop("checked", false);
$("#" + fieldId + "_other_indicator").prop("checked", true);
}
});
}
function bindClearOtherWhenValueSelectedEvent(field, fieldId) {
$("input[name='" + fieldId + "'], #" + fieldId).change(function () {
if (this.checked || (this.tagName === "SELECT" && this.value !== "")) {
$("#" + fieldId + "_other").val("");
}
});
}
function bindFormElementEvents() {
var _this = this;
$("#" + this.form.ClientID).submit(function (evt) {
evt.preventDefault();
_this.saveForm();
}).change(function () {
_this.hasChangesProperty = true;
});
$("#" + this.form.ClientID + " legend .edit-button").click(function (evt) {
evt.preventDefault();
_this.fireEvent(Events.FormEditClick);
});
$("#" + this.form.ClientID + " [type='reset']").click(function (evt) {
clearValidationErrors.call(_this);
_this.hasChangesProperty = false;
$("#" + _this.form.ClientID + " select").val('');
$("#" + _this.form.ClientID + " input[type='text']").val('');
$("#" + _this.form.ClientID + " input[type='number']").val('');
$("#" + _this.form.ClientID + " textarea").val('');
$("#" + _this.form.ClientID + " input[type='checkbox'], #" + _this.form.ClientID + " input[type='radio']").prop('checked', false);
evt.preventDefault();
});
for (var i = 0; i < this.form.FormFields.length; i++) {
var fieldId = getFieldId(this.form, i);
var field = this.form.FormFields[i];
if (field.AllowBelowDetectableLimit) {
bindClearFieldValueWhenBelowCheckedEvent.call(_this, field, fieldId);
bindUncheckBelowEvent.call(_this, field, fieldId);
}
if (field.AllowOther) {
bindClearFieldValueWhenOtherChangedEvent.call(_this, field, fieldId);
bindClearOtherWhenValueSelectedEvent.call(_this, field, fieldId);
//bindUncheckBelowEvent.call(_this, field, fieldId);
}
}
}
function getFieldId(form, fieldIndex) {
return form.ClientID + "_field_" + form.FormFields[fieldIndex].FieldID;
}
function getDataRecord(fieldId) {
if (!this.originalData) {
return;
}
for (var i = 0; i < this.originalData.length; i++) {
var dataSet = this.originalData[i];
if (!dataSet.FieldValues || !dataSet.FieldValues.length) {
continue;
}
for (var j = 0; j < dataSet.FieldValues.length; j++) {
var f = dataSet.FieldValues[j];
if (f.FieldId === fieldId) {
return f;
}
}
}
return null;
}
function renderField(form, fieldIndex, dataOptions) {
var field = form.FormFields[fieldIndex];
var list, k;
field.Tooltip = field.Tooltip || "";
var fieldId = getFieldId(form, fieldIndex);
var record = getDataRecord.call(this, field.FieldID);
if (!record) {
record = {
IsOtherValue: false,
IsBelowDetectableLimit: false,
FormValue: null
};
}
if (typeof dataOptions.fieldCb === "function") {
if (dataOptions.fieldCb(form, field, record) === false) {
return '';
}
}
var fieldGroupClass = '';
if (field.ExtraStyle) {
fieldGroupClass += " " + field.ExtraStyle + " ";
}
if (field.fieldGroupClass) {
fieldGroupClass += " " + field.fieldGroupClass + " ";
}
var strVal = record && record.FormValue ? record.FormValue : '';
var html = '<div class="form-group ' + (field.Required === true ? "required" : "") + " " + fieldGroupClass + '" title="' + field.Tooltip + '">';
if (field.FieldType !== Forms.FieldType.HyperLink) {
html += '<label for="' + fieldId + '">' + field.Label + '</label>';
}
html += "<div class='field-container " + (dataOptions.fieldContainerClass ? dataOptions.fieldContainerClass : "") + " " + (field.fieldContainerClass ? field.fieldContainerClass : "") + " '>";
var requiredStr = "";
if (field.Required === true) {
requiredStr = ' required="required" ';
}
var inputClassStr = '';
if (dataOptions.inputClass) {
inputClassStr += " " + dataOptions.inputClass + " ";
}
if (field.fieldClass) {
inputClassStr += " " + field.fieldClass + " ";
}
if (field.FieldType === Forms.FieldType.DateTime) {
console.warn("PMA.UI.Components.Forms: No proper date time field support yet.");
}
if (dataOptions.readOnly === true) {
html += this.renderReadOnlyField(field, record, inputClassStr);
}
else {
switch (field.FieldType) {
case Forms.FieldType.Text:
html += '<input id="' + fieldId + '" name="' + fieldId + '" value="' + strVal + '" type="text" placeholder="' + field.Tooltip + '" ' + requiredStr + ' class="' + inputClassStr + '" />';
break;
case Forms.FieldType.DateTime: // no proper date time support yet
html += '<input id="' + fieldId + '" name="' + fieldId + '" value="' + strVal + '" type="text" placeholder="yyyy-MM-dd HH:mm:ss" ' + requiredStr + ' class="' + inputClassStr + '" />';
break;
case Forms.FieldType.Paragraph:
html += '<textarea id="' + fieldId + '" name="' + fieldId + '" placeholder="' + field.Tooltip + '"' + requiredStr + ' class="' + inputClassStr + '">' + strVal + '</textarea>';
break;
case Forms.FieldType.ListBox:
html += '<select id="' + fieldId + '" name="' + fieldId + '" ' + ' class="' + inputClassStr + '">';
if (field.FormList && field.FormList.FormListValues) {
html += '<option value="" ' + (strVal.length === 0 ? 'selected="selected"' : "") + '>' + field.Tooltip + '</option>';
list = field.FormList.FormListValues;
for (let k = 0; k < list.length; k++) {
html += '<option value="' + list[k].ValueID + '" ' + (strVal.length !== 0 && list[k].ValueID == strVal ? 'selected="selected"' : "") + '>' + list[k].Value + '</option>';
}
}
html += '</select>';
break;
case Forms.FieldType.CheckBox:
html += '<ul class="checkboxlist">';
var strValues = strVal.split("|");
if (field.FormList && field.FormList.FormListValues) {
list = field.FormList.FormListValues;
for (let k = 0; k < list.length; k++) {
html += '<li>';
html += '<input type="checkbox" class="' + inputClassStr + '" id="' + fieldId + '_' + list[k].ValueID + '" name="' + fieldId + '" value="' + list[k].ValueID + '" ' + (arrayContains(strValues, "" + list[k].ValueID) ? 'checked="checked"' : "") + '/>';
html += '<label for="' + fieldId + '_' + list[k].ValueID + '">' + list[k].Value + '</label>';
html += "</li>";
}
}
html += '</ul>';
break;
case Forms.FieldType.RadioButton:
html += '<ul class="radiobuttonlist">';
if (field.FormList && field.FormList.FormListValues) {
list = field.FormList.FormListValues;
/*
if (field.Required === false) {
html += '<li>';
html += '<input type="radio" id="' + fieldId + '_novalue" name="' + fieldId + '" value="" />';
html += '<label for="' + fieldId + '_novalue">' + Resources.translate("(No selection)") + '</label>';
html += "</li>";
}
*/
for (let k = 0; k < list.length; k++) {
html += '<li>';
html += '<input type="radio" class="' + inputClassStr + '" id="' + fieldId + '_' + list[k].ValueID + '" name="' + fieldId + '" value="' + list[k].ValueID + '" ' + (strVal !== "" && list[k].ValueID == strVal ? 'checked="checked"' : "") + ' />';
html += '<label for="' + fieldId + '_' + list[k].ValueID + '">' + list[k].Value + '</label>';
html += "</li>";
}
if (field.AllowOther === true) {
html += '<li>';
html += '<input type="radio" class="' + inputClassStr + '" id="' + fieldId + '_other_indicator" name="' + fieldId + '" ' + (record && record.IsOtherValue ? 'checked="checked"' : "") + ' value="other" />';
html += '<label for="' + fieldId + '_other_indicator">' + Resources.translate("Other value") + '</label>';
html += "</li>";
}
}
html += '</ul>';
break;
case Forms.FieldType.Integer:
var step = 1;
if (field.Interval) {
step = field.Interval | 0;
}
html += '<input id="' + fieldId + '" name="' + fieldId + '"' + requiredStr + ' ' + (field.LowerBound !== null ? 'min="' + field.LowerBound + '"' : "") + ' ' + (field.UpperBound !== null ? 'max="' + field.UpperBound + '"' : "") + ' type="number" step="' + step + '" value="' + strVal + '" placeholder="' + field.Tooltip + '" class="' + inputClassStr + '"/>';
break;
case Forms.FieldType.Double:
html += '<input id="' + fieldId + '" name="' + fieldId + '"' + requiredStr + ' ' + (field.LowerBound !== null ? 'min="' + field.LowerBound + '"' : "") + ' ' + (field.UpperBound !== null ? 'max="' + field.UpperBound + '"' : "") + ' type="number" step="' + (field.Interval ? field.Interval : 'any') + '" value="' + strVal + '" placeholder="' + field.Tooltip + '" class="' + inputClassStr + '" />';
break;
case Forms.FieldType.Percentage:
var minv = 0,
maxv = 100;
if (field.LowerBound !== null && (field.LowerBound | 0) >= 0) {
minv = field.LowerBound | 0;
}
if (field.UpperBound !== null && (field.UpperBound | 0) <= 0) {
maxv = field.UpperBound | 0;
}
html += '<input id="' + fieldId + '" name="' + fieldId + '"' + requiredStr + ' min="' + minv + '" max="' + maxv + '" type="number" step="' + (field.Interval ? field.Interval : 'any') + '" value="' + strVal + '" placeholder="' + field.Tooltip + '" class="' + inputClassStr + '" />';
break;
case Forms.FieldType.Label:
////html += '<div class="labelfield" id="' + fieldId + '">' + field.Label + '</div>';
break;
case Forms.FieldType.HyperLink:
html += '<a class="link-field" id="' + fieldId + '" title="' + field.Tooltip + '" href="' + field.Url + '" ' + (field.NewWindow === true ? ' target="_blank" ' : '') + '>' + field.Label + '</a>';
break;
}
if (field.AllowBelowDetectableLimit === true) {
html += '<div class="below-container">';
html += '<input id="' + fieldId + '_below" name="' + fieldId + '_below" type="checkbox" ' + (record && record.IsBelowDetectableLimit === true ? 'checked="checked"' : "") + ' value="below" />';
html += '<label for="' + fieldId + '_below">' + Resources.translate("Below detectable limit") + '</label>';
html += '<div>';
}
if (field.AllowOther === true) {
html += '<input id="' + fieldId + '_other" class="other ' + (dataOptions.inputClass ? dataOptions.inputClass : "") + '" name="' + fieldId + '_other" type="text" value="' + (strVal !== "" && record && record.IsOtherValue === true ? strVal : "") + '" placeholder="' + Resources.translate("Other value") + '" />';
}
}
html += '<span id="' + fieldId + '_validation" class="field-validation ' + (dataOptions.fieldValidationClass ? dataOptions.fieldValidationClass : "") + '"></span>';
if (field.additionalHtml) {
html += field.additionalHtml;
}
html += "</div></div>";
return html;
}
function renderForm(element, form, dataOptions, data, success, failure) {
var _this = this;
_this.form.ClientID = "frm" + ((Math.random() * 10000000) | 0);
_this.hasChangesProperty = false;
var html = "<form class='pma-ui-form " + (dataOptions.formClass ? dataOptions.formClass : "") + "' name='" + form.ClientID + "' id='" + form.ClientID + "' autocomplete='off' novalidate><fieldset>";
if (form.FormName) {
html += "<legend class='form-name'>" + form.FormName + (dataOptions.editButton === true && dataOptions.readOnly === true ? "<span class=\"edit-button\">" + Resources.translate("[Edit]") + "</span>" : "") + "</legend>";
}
/*
if (form.Description) {
html += "<div class='form-description'>" + form.Description + "</div>";
}
*/
if (form.Instructions) {
html += "<div class='form-instructions'>" + form.Instructions + "</div>";
}
form.FormFields.sort(function (a, b) {
return a.DisplayOrder - b.DisplayOrder;
});
for (var i = 0; i < form.FormFields.length; i++) {
html += renderField.call(_this, form, i, dataOptions);
}
html += "<div id='" + form.ClientID + "_validation' class='form-validation " + (dataOptions.validationClass ? dataOptions.validationClass : "") + "'></div>";
if (dataOptions.readOnly !== true) {
html += "<div class='input-container " + (dataOptions.btnContainerClass ? dataOptions.btnContainerClass : "") + "'>";
html += "<button type='submit' value='" + Resources.translate("Save") + "' class='" + (dataOptions.btnSaveClass ? dataOptions.btnSaveClass : "") + "' >" + Resources.translate("Save") + "</button>";
html += "<button type='reset' value='" + Resources.translate("Reset") + "' class='" + (dataOptions.btnResetClass ? dataOptions.btnResetClass : "") + "' >" + Resources.translate("Reset") + "</button>";
}
html += "</div>";
html += "</fieldset></form>";
$(element).html(html);
bindFormElementEvents.call(_this);
if (typeof success === "function") {
success.call(_this, _this.form, null);
}
}
function loadFormData(serverUrl, sessionId, form, path, currentUserOnly, dataFilter, success, failure) {
var _this = this;
callApiMethod({
serverUrl: serverUrl,
method: ApiMethods.GetFormData,
data: { sessionID: sessionId, pathOrUid: path, formId: form.FormID, currentUserOnly: currentUserOnly },
success: function (http) {
var response = parseJson(http.responseText);
if (typeof success === "function") {
var data = null;
if (typeof dataFilter === "string") {
for (var i = 0; i < response.length; i++) {
if (response[i].Login == dataFilter) {
data = [response[i]];
break;
}
}
}
else if (typeof dataFilter === "function") {
data = dataFilter.call(_this, response);
}
else {
data = response;
}
success.call(_this, data);
}
},
failure: failure
});
}