gd-sprest-bs
Version:
SharePoint JavaScript, TypeScript and Web Components designed using the Bootstrap framework.
1,042 lines (1,041 loc) • 60.9 kB
JavaScript
import { Helper, SPTypes } from "gd-sprest";
import { Components } from "../core";
import { DateTimeControlType } from "../datetime";
import { PeoplePickerControlType } from "../peoplePicker";
import { RichTextBoxControlType, RichTextBoxTypes } from "../richTextBox";
/**
* Field
*/
export const Field = (props) => {
let control;
let lookupFieldInfo = null;
let mmsFieldInfo = null;
// Method to get the choice options
let getChoiceItems = (isCheckbox, field, selectedValues) => {
let items = [];
// Update the selected values
selectedValues = selectedValues && selectedValues.results ? selectedValues.results : [selectedValues];
// Parse the choices
for (let i = 0; i < field.Choices.results.length; i++) {
let choice = field.Choices.results[i];
let isSelected = false;
// Determine if this choice is selected
for (let j = 0; j < selectedValues.length; j++) {
// See if this choice is selected
if (choice == selectedValues[j]) {
// Set the flag and break from the loop
isSelected = true;
break;
}
}
// See if this is a checkbox
if (isCheckbox) {
// Add the item
items.push({
isSelected,
label: choice
});
}
else {
// Add the item
items.push({
isSelected,
label: choice,
text: choice,
value: choice
});
}
}
// Parse the selected values
for (let i = 0; i < selectedValues.length; i++) {
let existsFl = false;
let selectedValue = selectedValues[i];
// Parse the items
for (let j = 0; j < items.length; j++) {
let itemValue = isCheckbox ? items[j]["label"] : items[j]["value"];
// See if the value exists
if (selectedValue == itemValue) {
// Set the flag
existsFl = true;
break;
}
}
// Ensure a value exists and see if this was a fill-in choice
if (!existsFl && selectedValue) {
// See if this is a checkbox
if (isCheckbox) {
// Add the item
items.push({
isSelected: true,
label: selectedValue
});
}
else {
// Add the item
items.push({
isSelected: true,
label: selectedValue,
text: selectedValue,
value: selectedValue
});
}
}
}
// See if this is a dropdown and no selected values exists, and this is a required field
if (!isCheckbox && items.length > 0 && selectedValues.length == 0 && field.Required) {
// Select the first item
items[0].isSelected = true;
}
// Return the items
return items;
};
// Method to get the file extension
let getFileExtension = (fileName = "") => {
let extension = fileName.split('.');
return extension[extension.length - 1].toLowerCase();
};
// Method to generate the lookup dropdown items
let getLookupItems = (field, lookupItems, selectedValues) => {
let items = [];
// Update the selected values
selectedValues = selectedValues && selectedValues.results ? selectedValues.results : [selectedValues];
// Parse the lookup items
for (let i = 0; i < lookupItems.length; i++) {
let item = lookupItems[i];
let isSelected = false;
// Determine if this lookup is selected
for (let j = 0; j < selectedValues.length; j++) {
let id = selectedValues[j] && selectedValues[j].Id ? selectedValues[j].Id : selectedValues[j];
// See if this choice is selected
if (item.Id == id) {
// Set the flag and break from the loop
isSelected = true;
break;
}
}
// Add the item
items.push({
data: item,
isSelected,
text: item[field.LookupField],
value: item.Id.toString()
});
}
// See if no selected values exists, and this is a required field
if (items.length > 0 && selectedValues.length == 0 && field.Required) {
// Select the first item
items[0].isSelected = true;
}
// Return the items
return items;
};
// Method to get the mms dropdown items
let getMMSItems = (term, selectedValues = [], isRoot = true) => {
let items = [];
// See if information exists
if (term.info && !isRoot) {
let isSelected = false;
// Parse the selected values
for (let i = 0; i < selectedValues.length; i++) {
// See if this item is selected
if (selectedValues[i] == term.info.id) {
isSelected = true;
break;
}
}
// Add the heading
items.push({
data: term,
isSelected,
text: term.info.name,
value: term.info.id
});
}
// Parse the terms
for (let termName in term) {
let child = term[termName];
// Skip the info and parent properties
if (termName == "info" || termName == "parent") {
continue;
}
// Get the child items
let childItems = getMMSItems(child, selectedValues, false);
// Add the item
items = items.concat(childItems);
}
// See if no selected values exists, and this is a required field
if (items.length > 0 && selectedValues.length == 0 && isRequired) {
// Select the first item
items[0].isSelected = true;
}
// Return the items
return items;
};
// Set the properties based on the field link
let fieldLink = props.listInfo.fieldLinks ? props.listInfo.fieldLinks[props.field.InternalName] : null;
let isReadonly = fieldLink && typeof (fieldLink.ReadOnly) === "boolean" ? fieldLink.ReadOnly : props.field.ReadOnlyField;
let isRequired = fieldLink && typeof (fieldLink.Required) === "boolean" ? fieldLink.Required : props.field.Required;
// See if this is an internal field
if (props.field.CanBeDeleted == false) {
// Override the property based on the field property
isReadonly = isReadonly || props.field.ReadOnlyField;
}
// Set the default properties for the control
let controlProps = {
description: props.field.Description,
errorMessage: props.errorMessage,
id: props.field.InternalName,
isReadonly,
label: (isRequired ? "* " : "") + props.field.Title,
name: props.field.InternalName,
onControlRendering: control => {
// Execute the event
return props.onControlRendering ? props.onControlRendering(control, props.field) : null;
},
onControlRendered: formControl => {
// Save the control
control = formControl;
// Execute the event
return props.onControlRendered ? props.onControlRendered(control, props.field) : null;
},
required: isRequired,
type: Components.FormControlTypes.TextField,
value: props.value
};
// Define a base validation method
let baseValidation = null;
// See if this is a new form, a default value exists and no value has been defined
if (props.controlMode == SPTypes.ControlMode.New && props.field.DefaultValue && props.value == null) {
// Set the default value
controlProps.value = props.field.DefaultValue;
}
// Set the type
let onControlRendered = null;
let onControlRendering = null;
switch (props.field.FieldTypeKind) {
// Boolean
case SPTypes.FieldType.Boolean:
// Set the type
controlProps.type = Components.FormControlTypes.Checkbox;
// Create the item
controlProps.items = [{ label: controlProps.label }];
// Clear the label
controlProps.label = "";
break;
// Choice
case SPTypes.FieldType.Choice:
let allowFillIn = props.field.FillInChoice;
let displayRadioButtons = props.field.SchemaXml.indexOf('Format="RadioButtons"') > 0 ? true : false;
// See if we are displaying radio buttons
if (displayRadioButtons) {
// Set the type
controlProps.type = Components.FormControlTypes.Switch;
}
else {
// Set the type
controlProps.type = Components.FormControlTypes.Dropdown;
}
// Get the items
let items = getChoiceItems(displayRadioButtons, props.field, props.value);
// Add a blank entry if this is a dropdown
if (!displayRadioButtons) {
items = [{
text: "",
value: null
}].concat(items);
}
// See if we are allowing custom values
if (allowFillIn) {
// Set the base validation
baseValidation = (ctrl, result) => {
// Update the value
result.value = result.value && typeof (result.value.text) === "string" ? result.value.value : result.value;
// See if a fill-in choice exists
let fillInChoice = tbFillIn.getValue();
if (fillInChoice) {
// Override the value
result.value = fillInChoice;
}
// See if this control is required
if (ctrl.props.required) {
// Update the flag
result.isValid = result.value ? true : false;
}
// Return the result
return result;
};
// Set the rendered event
let tbFillIn = null;
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Append a textbox
tbFillIn = Components.InputGroup({
el: formControl.el,
className: "choice-fill-in",
placeholder: "Fill In Choice"
});
// Call the event
onControlRendered ? onControlRendered(formControl) : null;
};
}
// Set the items
controlProps.items = items;
// Set the base validation
baseValidation = (ctrl, result) => {
// See if a selected item exists and the field is required
if (result.value && ctrl.props.required) {
// See if this is a dropdown
if (ctrl.props.type == Components.FormControlTypes.Dropdown) {
let ddlItem = result.value;
// See if the text and value don't exist
if (ddlItem.value || ddlItem.text ? false : true) {
// Set the flag
result.isValid = false;
}
}
// Else, it's a switch
else {
let cbItem = result.value;
// See if a value doesn't exist
if (cbItem.label ? false : true) {
// Set the flag
result.isValid = false;
}
}
}
// Return the result
return result;
};
break;
// Currency Field
case SPTypes.FieldType.Currency:
// Set the type
controlProps.type = Components.FormControlTypes.TextField;
// Set the rendered event
onControlRendering = controlProps.onControlRendering;
controlProps.onControlRendering = (tbProps) => {
// See if the currency exists in the field
let shortName = props.field.TypeShortDescription;
let matches = /\(([^)]+)\)/.exec(shortName);
let symbol = matches.length > 0 ? matches[1] : "$";
// Set the text
tbProps.prependedLabel = symbol;
// Call the event
onControlRendering ? onControlRendering(tbProps) : null;
// Set the validation event
// Validate the extension
baseValidation = (ctrl, results) => {
// Ensure a value exists
if (results.value) {
// Ensure it's a valid currency value
results.isValid = /(?=.*?\d)^\$?(([1-9]\d{0,2}(,\d{3})*)|\d+)?(\.\d{1,2})?$/.test(results.value);
results.invalidMessage = "The currency format is not a valid.";
}
// Return the results
return results;
};
};
break;
// Date/Time
case SPTypes.FieldType.DateTime:
// Set the time flag
let showTime = props.field.DisplayFormat == SPTypes.DateFormat.DateTime;
controlProps.showTime = showTime;
// Set the type
controlProps.type = DateTimeControlType;
// See if there is a formula and this is a new form
let dtValue = (props.field.DefaultFormula || props.field.DefaultValue || "").toLowerCase();
if (dtValue && props.controlMode == SPTypes.ControlMode.New) {
let idx = dtValue.indexOf("today");
// See if the date is a formula
if (idx >= 0) {
let dtNow = new Date(Date.now());
// See if we are adding days
let daysIdx = dtValue.indexOf("+", idx);
if (daysIdx > 0) {
// Get the number of days to add
let days = parseInt(dtValue.substr(daysIdx + 1));
if (days > 0) {
// Add the days
dtNow.setDate(dtNow.getDate() + days);
}
}
// See if we are subtracting days
daysIdx = dtValue.indexOf("-", idx);
if (daysIdx > 0) {
// Get the number of days to add
let days = parseInt(dtValue.substr(daysIdx + 1));
if (days > 0) {
// Add the days
dtNow.setDate(dtNow.getDate() - days);
}
}
// Set the value
controlProps.value = dtNow;
}
else {
// Set the value
controlProps.value = new Date(dtValue);
}
}
break;
// Image
case SPTypes.FieldType.Image:
let fileInfo = null;
let imageValue = controlProps.value;
// Set the type
controlProps.type = Components.FormControlTypes.TextField;
controlProps.placeholder = "Add an image";
controlProps.isDisabled = true;
// Update the value
if (controlProps.value) {
// Update the value to only display the file name
try {
let imageProps = JSON.parse(controlProps.value);
controlProps.value = imageProps.fileName;
}
catch (_a) { }
}
// Validate the extension
baseValidation = (ctrl, results) => {
// See if we are uploading a new file
if (fileInfo) {
// Ensure it's an image
let info = fileInfo.name.split('.');
let fileExt = info[info.length - 1].toLowerCase();
if (["tiff", "pjp", "jfif", "bmp", "gif", "svg", "png", "xbm", "dib", "jxl",
"jpeg", "svgz", "jpg", "webp", "ico", "tif", "pjpeg", "avif"].indexOf(fileExt) < 0) {
// Set the flag
results.isValid = false;
results.invalidMessage = "The file must be an image.";
}
}
// Else, see if a value doesn't exist
else if (results.value == null) {
// Set the flag based on if it's required
results.isValid = ctrl.props.required ? false : results.isValid;
}
// Return the results
return results;
};
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (ctrl) => {
// Append the edit button
Components.Button({
el: ctrl.textbox.el,
type: Components.ButtonTypes.OutlineSecondary,
text: "Edit",
onClick: () => {
// Show a file loader
Helper.ListForm.showFileDialog().then(file => {
// Save the file info
fileInfo = file;
fileInfo.fieldId = props.field.Id;
fileInfo.fieldName = props.field.InternalName;
// Set the value to the file name
ctrl.textbox.setValue(file.name);
});
}
});
// Append the clear button
Components.Button({
el: ctrl.textbox.el,
type: Components.ButtonTypes.OutlineSecondary,
text: "Clear",
onClick: () => {
// Clear the value
ctrl.textbox.setValue("");
fileInfo = null;
imageValue = null;
}
});
// Call the rendered event
onControlRendered ? onControlRendered(ctrl) : null;
};
// Set the get value event
controlProps.onGetValue = () => {
// Return the file information
return fileInfo || imageValue;
};
break;
// Lookup
case SPTypes.FieldType.Lookup:
// Default the lookup field props will determine the default type
controlProps.type = props.field.AllowMultipleValues ? Components.FormControlTypes.MultiDropdown : Components.FormControlTypes.Dropdown;
// See if this field is readonly and a value exists
if (isReadonly) {
// Update the value
controlProps.type = Components.FormControlTypes.Readonly;
// Ensure a value exists
if (props.value) {
// Set the rendered event
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Set the class name
control.el.classList.add("form-control");
control.el.style.backgroundColor = "#e9ecef";
// Override the html rendered
control.el.innerHTML = props.listInfo.fieldValuesAsHtml[props.field.InternalName];
};
}
}
else {
// Set the rendering event
onControlRendering = controlProps.onControlRendering;
controlProps.onControlRendering = newProps => {
// Update the control properties
controlProps = newProps;
// Display a loading message
controlProps.loadingMessage = "Loading the Lookup Data";
// Return a promise
return new Promise((resolve, reject) => {
// Load the field information
Helper.ListFormField.create({
field: props.field,
listName: props.listInfo.list.Title,
name: props.field.InternalName,
webUrl: props.listInfo.webUrl
}).then(
// Success
(fieldInfo) => {
// Save the field information
lookupFieldInfo = fieldInfo;
// Set the lookup filter
lookupFieldInfo.lookupFilter = props.lookupFilter;
// Update the multi property
controlProps.multi = lookupFieldInfo.multi;
// Get the drop down information
Helper.ListFormField.loadLookupData(lookupFieldInfo, 500).then(
// Success
items => {
// Get the dropdown items
let ddlItems = getLookupItems(props.field, items, props.value);
// See if this is not a required field and not a multi-select
if (!isRequired && !lookupFieldInfo.multi) {
// Add a blank entry
ddlItems = [{
text: "",
value: null
}].concat(ddlItems);
}
// Set the items
controlProps.items = ddlItems;
// Clear the element
controlProps.el ? controlProps.el.innerHTML = "" : null;
// Clear the value, since the getLookupItems method takes care of this for us
controlProps.value = null;
// Call the event
let returnVal = onControlRendering ? onControlRendering(controlProps) : null;
if (returnVal && returnVal.then) {
// Wait for the promise to complete
returnVal.then(props => {
// Resolve the promise
resolve(props || controlProps);
});
}
else {
// Resolve the promise
resolve(controlProps);
}
},
// Error
msg => {
// Set the error message
let errorMessage = "Error loading the lookup field values for '" + props.field.InternalName + "'.";
// Display an error message
Components.Alert({
el: controlProps.el,
content: errorMessage,
type: Components.AlertTypes.Danger
});
// Call the error event
props.onError ? props.onError(errorMessage) : null;
});
},
// Error
msg => {
// Set the error message
let errorMessage = "Error loading the field information for field '" + props.field.InternalName + "'.";
// Display an error message
controlProps.el.innerHTML = "";
Components.Alert({
el: controlProps.el,
content: "Error loading the lookup field information.",
type: Components.AlertTypes.Danger
});
// Call the error event
props.onError ? props.onError(errorMessage) : null;
// Reject the request
reject(msg);
});
});
};
}
break;
// Multi-Choice
case SPTypes.FieldType.MultiChoice:
let allowFillInMulti = props.field.FillInChoice;
let isChoice = props.field.SchemaXml.indexOf('Format="RadioButtons"') > 0 ? true : false;
// Set the type
controlProps.type = isChoice ? Components.FormControlTypes.MultiSwitch : Components.FormControlTypes.MultiDropdown;
// Update the value
controlProps.value = (props.value ? props.value.results : null) || props.value;
// Set the items
controlProps.items = getChoiceItems(isChoice, props.field, props.value);
// See if we are allowing custom values
if (allowFillInMulti) {
// Set the base validation
baseValidation = (ctrl, result) => {
// See if a fill-in choice exists
let fillInChoice = tbFillIn.getValue();
if (fillInChoice) {
// Append the value
result.value.push({
isSelected: true,
label: fillInChoice,
text: fillInChoice,
value: fillInChoice
});
}
// See if this control is required
if (ctrl.props.required) {
// Update the flag
result.isValid = result.value.length ? true : false;
}
// Return the result
return result;
};
// Set the rendered event
let tbFillIn = null;
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Append a textbox
tbFillIn = Components.InputGroup({
el: formControl.el,
className: "choice-fill-in",
placeholder: "Fill In Choice"
});
// Call the event
onControlRendered ? onControlRendered(formControl) : null;
};
}
break;
// Note
case SPTypes.FieldType.Note:
let noteField = props.field;
// See if this is plain text
if (noteField.RichText) {
let rtbProps = controlProps;
let fullToolbar = noteField.SchemaXml.match(/RichTextMode="FullHtml"/i) ? true : false;
// Set the properties
rtbProps.type = RichTextBoxControlType;
rtbProps.toolbarType = fullToolbar ? RichTextBoxTypes.Full : RichTextBoxTypes.Basic;
}
else {
// Set the properties
controlProps.type = Components.FormControlTypes.TextArea;
controlProps.rows = props.field.NumberOfLines;
}
break;
// Number Field
case SPTypes.FieldType.Number:
let numberField = props.field;
let numberProps = controlProps;
// Set the default value
numberProps.value = numberProps.value == null ? numberField.DefaultValue : numberProps.value;
// See if this is a percentage
let isPercent = numberField.ShowAsPercentage;
if (isPercent == null) {
// Set the value from the schema (2013 environments)
isPercent = numberField.SchemaXml.toLowerCase().indexOf('percentage="true"') > 0;
}
if (isPercent) {
// Set the type
numberProps.type = Components.FormControlTypes.Range;
// Default the max
numberProps.max = numberField.MaximumValue == 1 || numberField.MaximumValue == Number.MAX_VALUE ? 100 : numberField.MaximumValue;
// Set the min value
numberProps.min = numberField.MinimumValue == -1.7976931348623157e+308 ? 0 : numberField.MinimumValue;
// Set the value
numberProps.value = numberProps.value == null || numberProps.value == Number.MIN_VALUE ? 0 : numberProps.value;
numberProps.value = numberProps.value * (numberProps.max == 100 && numberProps.value <= 1 ? 100 : 1);
}
// Else, see if the min/max values are defined
else if ((typeof (numberField.MaximumValue) == "number" && numberField.MaximumValue != Number.MAX_VALUE) && (typeof (numberField.MinimumValue) == "number" && numberField.MinimumValue != Number.MIN_VALUE)) {
// Update the properties to display a range
numberProps.type = Components.FormControlTypes.Range;
numberProps.max = numberField.MaximumValue;
numberProps.min = numberField.MinimumValue;
numberProps.value = typeof (numberProps.value) == "number" ? numberProps.value : numberProps.min;
// Set validation
if (numberField.MinimumValue || numberField.MaximumValue) {
// Add validation
baseValidation = (control, result) => {
// Ensure the value is a number
if (/^[0-9]*$/.test(result.value) == false) {
// Update the validation and return it
result.isValid = false;
result.invalidMessage = "The value must be a number.";
return result;
}
// Validate the min value
if (numberField.MinimumValue && result.value < numberField.MinimumValue) {
// Update the validation and return it
result.isValid = false;
result.invalidMessage = "The value must be greater than or equal to " + numberField.MinimumValue;
return result;
}
// Validate the max value
if (numberField.MaximumValue && result.value > numberField.MaximumValue) {
// Update the validation and return it
result.isValid = false;
result.invalidMessage = "The value must be less than or equal to " + numberField.MaximumValue;
return result;
}
// Valid
result.isValid = true;
// Return the result
return result;
};
}
}
else {
// Set the type
numberProps.type = Components.FormControlTypes.TextField;
// Set the render event
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Set the type to be a number
formControl.textbox.elTextbox.setAttribute("type", "number");
};
}
break;
// URL
case SPTypes.FieldType.URL:
let desc = null;
let url = null;
let value = props.value;
// See if a value exists
if (props.value) {
// Update the value
controlProps.value = props.value.Url;
}
// Set the render event
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Save the control
control = formControl;
// Clear the element
control.el.innerHTML = "";
// See if we are rendering the description
let showDesc = controlProps.showDescription;
showDesc = typeof (showDesc) === "boolean" ? showDesc : true;
if (showDesc) {
// Render the description
desc = Components.FormControl({
className: "mb-1",
el: control.el,
placeholder: "Description",
type: Components.FormControlTypes.TextField,
value: value ? value.Description : null
});
}
// Render the url
url = Components.FormControl({
el: control.el,
placeholder: "Url",
type: Components.FormControlTypes.TextField,
value: value ? value.Url : null
});
// Set the get value event
control.props.onGetValue = () => {
// Return the value
return {
Description: desc ? desc.getValue() : url.getValue(),
Url: url.getValue()
};
};
// Call the event
onControlRendered ? onControlRendered(formControl) : null;
};
// Set the validate event
baseValidation = (control, result) => {
let descValid, urlValid = false;
// Get the form control elements
let elFormControl = control.el.querySelectorAll(".form-control");
// See if both the description and url are displayed
let elDesc = null;
let elUrl = null;
if (elFormControl.length > 1) {
// Set the elements
elDesc = elFormControl[0];
elUrl = elFormControl[1];
}
else {
// Set the elements
elUrl = elFormControl[0];
// Set the flag
descValid = true;
}
// See if the description exists
if (elDesc) {
// Clear the classes
elDesc.classList.remove("is-invalid");
elDesc.classList.remove("is-valid");
// Set the flag
descValid = control.props.required ? (desc.getValue() ? true : false) : true;
// Set the class
elDesc.classList.add(descValid ? "is-valid" : "is-invalid");
}
// See if the url exists
if (elUrl) {
// Clear the classes
elUrl.classList.remove("is-invalid");
elUrl.classList.remove("is-valid");
// Set the flag
urlValid = control.props.required ? (url.getValue() ? true : false) : true;
// Set the class
elUrl.classList.add(urlValid ? "is-valid" : "is-invalid");
}
// Set the validation falg
result.isValid = descValid && urlValid;
// Return the result
return result;
};
break;
// User
case SPTypes.FieldType.User:
// Set the type
controlProps.type = isReadonly ? Components.FormControlTypes.Readonly : PeoplePickerControlType;
// Update the properties, based on the field settings
controlProps.allowGroups = props.field.SelectionGroup == SPTypes.FieldUserSelectionType.PeopleAndGroups;
controlProps.groupId = props.field.SelectionGroup;
controlProps.multi = props.field.AllowMultipleValues;
// Set the rendered event
onControlRendered = controlProps.onControlRendered;
controlProps.onControlRendered = (formControl) => {
// Save the control
control = formControl;
// See if this field is readonly and a value exists
if (props.value && isReadonly) {
// Set the class name
control.el.classList.add("form-control");
control.el.style.backgroundColor = "#e9ecef";
// Override the html rendered
control.el.innerHTML = props.listInfo.fieldValuesAsHtml[props.field.InternalName];
}
// Call the event
onControlRendered ? onControlRendered(formControl) : null;
};
break;
}
// See if this is the document name field
if (props.field.InternalName == "FileLeafRef") {
// Set base validation
baseValidation = (control, result) => {
let value = result.value;
// Ensure the value exists
result.isValid = value ? true : false;
if (result.isValid) {
// See if it ends w/ a .
if (value[value.length - 1] == '.') {
// Update the validation
result.isValid = false;
result.invalidMessage = "The value cannot end with a '.' character.";
}
// Else, see if it contains invalid characters
else if (/[~"\#\%\&\*\:\<\>\?\/\\\{\|\}"]/.test(value) || value.indexOf('\\') >= 0) {
// Update the validation
result.isValid = false;
result.invalidMessage = "The value cannot contain the following characters: ~ \" # % & * : < > ? / \\ { | }";
}
// Else, see if we are changing the extension
else if (control.props.value) {
// Get the file extensions
let origExtension = getFileExtension(control.props.value);
let newExtension = getFileExtension(value);
// Update the validation
result.isValid = origExtension == newExtension;
result.invalidMessage = "The file extension cannot be changed. It must end with '." + origExtension + "'";
}
}
// Return the validation result
return result;
};
}
// See if this is a taxonomy field
if (/^TaxonomyFieldType/.test(props.field.TypeAsString)) {
// Set the type
controlProps.type = Components.FormControlTypes.Dropdown;
// Set a render event
onControlRendering = controlProps.onControlRendering;
controlProps.onControlRendering = newProps => {
// Update the control properties
controlProps = newProps;
// Return a promise
return new Promise((resolve, reject) => {
// Display a loading message
controlProps.loadingMessage = "Loading the MMS Data";
// Load the field information
Helper.ListFormField.create({
field: props.field,
listName: props.listInfo.list.Title,
name: props.field.InternalName,
webUrl: props.listInfo.webUrl
}).then(
// Success
(fieldInfo) => {
// Save the field information
mmsFieldInfo = fieldInfo;
// Set the type
controlProps.type = mmsFieldInfo.multi ? Components.FormControlTypes.MultiDropdown : Components.FormControlTypes.Dropdown;
// Load the value field
Helper.ListFormField.loadMMSValueField(mmsFieldInfo).then(
// Success
valueField => {
// Set the value field
mmsFieldInfo.valueField = valueField;
// See if this is a new form
if (props.controlMode == SPTypes.ControlMode.New) {
let fieldValue = [];
// Get the default values
let values = (props.field.DefaultValue || "").split(";#");
for (let i = 0; i < values.length; i++) {
let value = values[i].split("|");
if (value.length == 2) {
// Add the term id
fieldValue.push(value[1]);
}
}
// Update the field value
controlProps.value = fieldValue;
}
else {
let fieldValue = props.value;
// Get the field value
let values = fieldValue && fieldValue.results ? fieldValue.results : [fieldValue];
// Clear the field values
fieldValue = [];
// Parse the values
for (let i = 0; i < values.length; i++) {
// Ensure the value exists
if (values[i] && values[i].TermGuid) {
// Add the value
fieldValue.push(values[i].TermGuid);
}
}
// Update the field value
controlProps.value = fieldValue;
}
// Load the terms
Helper.ListFormField.loadMMSData(mmsFieldInfo).then(
// Success
terms => {
// Get the items
let items = getMMSItems(Helper.Taxonomy.toObject(terms), controlProps.value);
// See if this is not a required field and not a multi-select
if (!isRequired && !mmsFieldInfo.multi) {
// Add a blank entry
items = [{
text: "",
value: null
}].concat(items);
}
// Set the items
controlProps.items = items;
// Clear the element
controlProps.el ? controlProps.el.innerHTML = "" : null;
// Call the event
let returnVal = onControlRendering ? onControlRendering(controlProps) : null;
if (returnVal && returnVal.then) {
// Wait for the promise to complete
returnVal.then(props => {
// Resolve the promise
resolve(props || controlProps);
});
}
else {
// Resolve the promise
resolve(controlProps);
}
},
// Error
msg => {
// Set the error message
let errorMessage = "Error loading the mms terms for '" + props.field.InternalName + "'.";
// Display an error message
Components.Alert({
el: controlProps.el,
content: errorMessage,
type: Components.AlertTypes.Danger
});
// Call the error event
props.onError ? props.onError(errorMessage) : null;
});
},
// Error
msg => {
// Set the error message
let errorMessage = "Error loading the mms value field for '" + props.field.InternalName + "'.";
// Display an error message
Components.Alert({
el: controlProps.el,
content: errorMessage,
type: Components.AlertTypes.Danger
});
// Call the error event
props.onError ? props.onError(errorMessage) : null;
// Reject the request
reject(msg);
});
}, msg => {
// Display an error message
Components.Alert({
el: controlProps.el,
content: msg,
type: Components.AlertTypes.Danger
});
// Call the error event
props.onError ? props.onError(msg) : null;
});
});
};
}
// Create the field
let field = {
control,
controlProps,
setControl: ctrl => { control = ctrl; field.control = ctrl; },
getValue: () => {
let fieldValue = {
name: props.field.InternalName,
value: control ? control.getValue() : null
};
// Ensure the control exists
if (control == null) {
return fieldValue;
}
// Get the checkbox and dropdown value(s)
let cbValues = control.checkbox ? control.checkbox.getValue().selectedItems : null;
let ddlValues = control.dropdown ? control.dropdown.getValue() : null;
// See if there is a custom value
if (controlProps && controlProps.onGetValue) {
// Update the value
fieldValue.value = controlProps.onGetValue(controlProps);
}
// Update the field name/value, based on the type
switch (props.field.FieldTypeKind) {
// Boolean
case SPTypes.FieldType.Boolean:
// Update the value
fieldValue.value = cbValues ? true : false;
break;
// Choice
case SPTypes.FieldType.Choice:
// See if this is a dropdown
if (ddlValues) {
// See if there is a value
let ddlValue = ddlValues;
if (ddlValue) {
if (ddlValue.value || ddlValue.text) {
// Update the field value