gd-sprest-bs
Version:
SharePoint JavaScript, TypeScript and Web Components designed using the Bootstrap framework.
1,091 lines • 56.8 kB
JavaScript
import { Helper, SPTypes } from "gd-sprest";
import { Components } from "../core";
import { DateTimeControlType } from "../datetime";
import { Field } from "../field";
import { RichTextBoxControlType, RichTextBoxTypes } from "../richTextBox";
// Extend the list form
export const ListForm = Helper.ListForm;
// Method to get the fields to render
let getFieldsToRender = (props) => {
let fieldNames = [];
// See if the "include" fields property is defined
if (props.includeFields) {
// Set the field names
fieldNames = props.includeFields;
}
else {
// Parse the fields
for (let fieldName in props.info.fields) {
// See if the "exclude" property is set
if (props.excludeFields) {
let renderFl = true;
// Parse the fields
for (let i = 0; i < props.excludeFields.length; i++) {
// See if we are excluding this field
if (props.excludeFields[i] == fieldName) {
// Set the flag
renderFl = false;
break;
}
}
// Skip this field, if we are not rendering it
if (!renderFl) {
continue;
}
}
// Add the field name
fieldNames.push(fieldName);
}
}
// See if an event exists
if (props.onGetFields) {
// Call the event
fieldNames = props.onGetFields(fieldNames);
}
// Return the field names
return fieldNames;
};
// Method to render the display control
let renderDisplay = (fieldName, props) => {
let control = null;
let field = props.info.fields[fieldName];
let isRichText = field ? field.RichText : false;
let value = props.info.fieldValuesAsText ? props.info.fieldValuesAsText[fieldName] || "" : "";
let html = props.info.fieldValuesAsHtml ? props.info.fieldValuesAsHtml[fieldName] || props.info.fieldValuesAsHtml[fieldName.replace(/\_/g, "_x005f_")] || "" : "";
// Ensure the field exists
if (field == null) {
// See if a value was found
if (value || html) {
// Return a read-only control
return {
data: value || html,
isDisabled: true,
label: fieldName,
name: fieldName,
type: Components.FormControlTypes.TextField,
value: value || html
};
}
// Log
console.warn("[List Form] Field '" + fieldName + "' does not exist. Check the list or query.");
return control;
}
// See if we are hiding the field
if (field.SchemaXml.indexOf('ShowInDisplayForm="FALSE"') > 0) {
return control;
}
// See if this is an image field
if (field.FieldTypeKind == SPTypes.FieldType.Image) {
// Ensure a value exists
if (value) {
// Update the html
try {
let imgInfo = JSON.parse(value);
html = "<img style='height: 64px; width: 64px;' src='" + imgInfo.serverRelativeUrl + "' alt='" + imgInfo.fileName + "' />";
}
catch (_a) { }
}
}
// Else, see if this is a note field
else if (field.FieldTypeKind == SPTypes.FieldType.Note) {
// Update the html
html = html.replace(/\r?\n/g, '<br />')
.replace(/"/g, '"');
}
// Else, see if this is a user field
else if (field.FieldTypeKind == SPTypes.FieldType.User) {
// See if this is a multi-user selection
if (field.AllowMultipleValues) {
let userNames = [];
// Parse the users
let users = (props.info.item[fieldName] ? props.info.item[fieldName].results : null) || [];
for (let j = 0; j < users.length; j++) {
// Append the user name
userNames.push(users[j].Title);
}
// Set the html value
html = userNames.join('<br />\n');
}
else {
// Extract the text only for single selections
let elUser = document.createElement("div");
elUser.innerHTML = html;
html = elUser.innerText;
}
}
// Else, see if this is a choice field
else if (field.FieldTypeKind == SPTypes.FieldType.Choice || field.FieldTypeKind == SPTypes.FieldType.MultiChoice) {
// Update the html
html = value;
}
// Set the control
control = {
data: html,
description: field.Description,
isDisabled: true,
label: field.Title,
name: field.InternalName,
type: Components.FormControlTypes.TextField,
value: html
};
// Update the type, based on the field
switch (field.FieldTypeKind) {
case SPTypes.FieldType.DateTime:
// Set the time flag
control.showTime = field.DisplayFormat == SPTypes.DateFormat.DateTime ? true : false;
// Set the type
control.type = DateTimeControlType;
break;
case SPTypes.FieldType.Lookup:
// Ensure a value exists
if (html) {
// Create an element to store the html
let elLookup = document.createElement("div");
elLookup.innerHTML = html;
// Update the value to be text
html = elLookup.innerText;
control.data = html;
control.value = html;
}
break;
case SPTypes.FieldType.Note:
// See if this is a rich text field
if (isRichText) {
// Set the properties
control.toolbarType = RichTextBoxTypes.None;
control.type = RichTextBoxControlType;
}
else {
// Set the type
control.type = Components.FormControlTypes.TextArea;
}
break;
case SPTypes.FieldType.URL:
// Set the value
let urlValue = props.info.item[fieldName];
html = urlValue ? urlValue.Url : html;
control.value = html;
break;
case SPTypes.FieldType.User:
// Set the type
control.type = field.AllowMultipleValues ? Components.FormControlTypes.TextArea : control.type;
break;
}
// Detect html
if (/<*>/g.test(html)) {
let isMultiLine = html.indexOf("<br />") >= 0 ? true : false;
// See if it's an image
if (field.FieldTypeKind == SPTypes.FieldType.Image) {
// Set the rendered event
control.onControlRendered = control => {
// Override the html rendered
control.el.innerHTML = html;
};
}
// Else, ensure this isn't a rich text field or multi-line
else if (!isRichText && !isMultiLine) {
// Update the control to be read-only
control.type = Components.FormControlTypes.Readonly;
// Set the rendered event
control.onControlRendered = control => {
// Get the target element
let elTarget = control.el.querySelector("input") || control.el;
// Override the html rendered
elTarget.innerHTML = control.props.data;
};
}
else {
// Update the html break line
html = html.replace(/<br \/>/g, '\n');
control.data = html;
control.value = html;
}
}
// Else, detect xml
else if (/<|>|&|"/i.test(html)) {
// Update the value
control.value = html.replace(/</ig, '<')
.replace(/>/ig, '>')
.replace(/&/ig, '&')
.replace(/"/ig, '"');
}
// Return the control
return control;
};
// Method to generate the attachments row
let generateAttachmentsControl = (props) => {
// See if we are rendering attachments
let displayAttachments = typeof (props.displayAttachments) === "boolean" ? props.displayAttachments : true;
if (props.info.attachments && displayAttachments) {
// Render the attachments
return {
id: "ListFormAttachments",
label: "Attachments",
name: "Attachments",
onControlRendered: control => {
let items = [];
// Parse the attachments
for (let i = 0; i < props.info.attachments.length; i++) {
let attachment = props.info.attachments[i];
// Add the item
items.push({
buttons: [{
className: "me-1",
data: attachment.ServerRelativeUrl,
isSmall: true,
text: attachment.FileName,
onClick: (btn) => {
// Open the attachment in a new tab
window.open(btn.data, "_blank");
}
}]
});
}
// Render a toolbar
Components.Toolbar({
el: control.el,
items
});
}
};
}
};
// Method to render a display form for an item
ListForm.renderDisplayForm = (props) => {
let form = null;
let totalControls = 0;
// Render a loading message
let progress = Components.Progress({
el: props.el,
isAnimated: true,
isStriped: true,
label: "Loading the Form",
size: 100
});
let mapper = {};
let rows = [];
// Get the fields to render
let fieldNames = getFieldsToRender(props);
// Parse the fields to render
for (let i = 0; i < fieldNames.length; i++) {
let fieldName = fieldNames[i];
// See if this is the attachment field
if (fieldName == "Attachments") {
// Generate the attachments control
let ctrlAttachments = generateAttachmentsControl(props);
if (ctrlAttachments) {
rows.push({
columns: [{
control: ctrlAttachments
}]
});
}
// Increment the total controls
totalControls++;
// Continue the loop
continue;
}
// Generate the control
let control = renderDisplay(fieldName, props);
if (control) {
// Update the mapper
mapper[fieldName] = control;
// Add the row
rows.push({
columns: [{ control }]
});
// Increment the total controls
totalControls++;
}
}
// See if there is a template
if (props.template) {
// Reset the total controls
totalControls = 0;
// Updates the control
let updateControl = (refControl) => {
// Get the control from the mapper
let control = refControl ? mapper[refControl.name] : null;
// Ensure the controls exists
if (control && refControl) {
// Parse the control keys
for (let key in control) {
// Skip if a value is already defined
if (refControl[key]) {
continue;
}
// Update the property
refControl[key] = control[key];
}
// Update the mapper
mapper[refControl.name] = refControl;
}
};
// Parse the template
for (let i = 0; i < props.template.length; i++) {
let row = props.template[i];
// Parse the columns if there are columns
let columns = row.columns || [];
for (let j = 0; j < columns.length; j++) {
let column = columns[j];
// Update the control
updateControl(column.control);
// Increment the total controls
totalControls++;
}
}
}
// Remove the progress bar
progress.el.parentElement ? progress.el.parentElement.removeChild(progress.el) : null;
// Counter for each control
let ctrlCounter = 0;
// Render the form
form = Components.Form({
el: props.el,
className: props.className,
groupClassName: props.groupClassName,
rowClassName: props.rowClassName,
onControlRendered: control => {
// See if all of the controls have been rendered
if (++ctrlCounter == totalControls) {
// See if an event exists
if (props.onFormRendered) {
// Execute the form rendered event in another thread
setTimeout(() => { props.onFormRendered(form); }, 10);
}
}
// Return the control rendered event
return props.onControlRendered ? props.onControlRendered(control, props.info.fields[control.props.name]) : null;
},
onControlRendering: control => { return props.onControlRendering ? props.onControlRendering(control, props.info.fields[control.name]) : null; },
rows: props.template || rows
});
// Execute the assign to event
props.assignTo ? props.assignTo(form) : null;
// Return the form informaiton
return {
get el() { return form ? form.el : null; },
getControl(fieldName) { return form ? form.getControl(fieldName) : null; }
};
};
// Render the edit form
ListForm.renderEditForm = (props) => {
let customControls = [];
let mapper = {};
let rows = [];
let totalControls = 0;
let value = {};
let attachments = {
delete: [],
new: []
};
// Method to add a refresh alert
let addRefreshLink = () => {
// Ensure the link doesn't already exist
if (props.el.querySelector(".refresh-btn")) {
return;
}
// Create the refresh button
let alert = Components.ButtonGroup({
className: "refresh-btn",
buttonType: Components.ButtonTypes.Danger,
buttons: [
{
text: "Refresh Form",
onClick: () => {
// Clear the element and reload the form
props.el.innerHTML = "";
// Render the form
ListForm.renderEditForm(props);
}
},
{
text: "Refresh Page",
onClick: () => {
// Refresh the page
document.location.href = document.location.href;
}
}
]
});
// Add the element at the top
props.el.insertBefore(alert.el, props.el.children[0]);
};
// Method to remove the attachments
let removeAttachments = (info) => {
// Return a promise
return new Promise((resolve, reject) => {
// Ensure attachments exists
if (attachments.delete.length == 0) {
resolve();
return;
}
// Get the web
props.info.list.ParentWeb().execute(web => {
// Parse the attachments
Helper.Executor(attachments.delete, attachment => {
// Get the attachment file
web.getFileByServerRelativeUrl(attachment.ServerRelativeUrl).delete().execute();
// Parse the attachments
for (let i = 0; i < props.info.attachments.length; i++) {
// See if this is the target attachment
if (props.info.attachments[i].ServerRelativeUrl == attachment.ServerRelativeUrl) {
// Remove this item
props.info.attachments.splice(i, 1);
break;
}
}
}).then(() => {
// Wait for the files to be deleted
web.done(() => {
// Clear the attachments
attachments.delete = [];
// Resolve the promise
resolve();
});
});
});
});
};
// Method to save the attachments
let saveAttachments = (info) => {
// Return a promise
return new Promise((resolve, reject) => {
// Ensure attachments exists
if (attachments.new.length == 0) {
resolve();
return;
}
// Parse the attachments
Helper.Executor(attachments.new, attachment => {
// Get the item's attachments
props.info.list.Items(info.item.Id).AttachmentFiles()
// Add the file
.add(attachment.name, attachment.data)
// Execute the request
.execute(attachment => {
// Ensure attachments exist
info.attachments = info.attachments || [];
// Append the attachment
info.attachments.push(attachment);
});
}).then(() => {
// Wait for the files to upload
props.info.list.done(() => {
// Clear the attachments
attachments.new = [];
// Resolve the promise
resolve();
});
});
});
};
// Method to upload the images
let images = [];
let uploadImages = (info) => {
// Return a promise
return new Promise((resolve) => {
let values = {};
// Ensure we have images
if (images.length == 0) {
// Do nothing
resolve(values);
return;
}
// Get the list folder
Helper.ListFormField.getOrCreateImageFolder(info).then(fld => {
// Removes the existing image
let removeExisting = (value) => {
// Return a promise
return new Promise(resolve => {
// Try to get the image info
let imageInfo = null;
try {
imageInfo = JSON.parse(value);
}
catch (_a) { }
// Ensure the info exists
if (imageInfo) {
// See if the file exists
fld.Files(imageInfo.fileName).execute(
// Exists
file => {
// Delete the file
file.delete().execute(() => {
// Resolve the request
resolve(null);
});
},
// Doesn't exist
() => {
// Resolve the request
resolve(null);
});
}
else {
// Resolve the request
resolve(null);
}
});
};
// Validates the list name
let validateFileName = (fileName) => {
// Return a promise
return new Promise(resolve => {
// Get the file name w/out the extension
let info = fileName.toLowerCase().split('.');
let fileExt = info[info.length - 1];
let fileNameNoExt = "";
for (let i = 0; i < info.length - 1; i++) {
fileNameNoExt += info[i];
}
// Get the files with a similar name
fld.Files().query({
Filter: "startswith(Name, '" + fileNameNoExt + "')",
Top: 5000
}).execute(files => {
let isValid = true;
let counter = -1;
let validFileName = null;
// See if no files were found
if (files.results.length == 0) {
// Resolve the request
resolve(fileName);
return;
}
// Loop until it's valid
do {
// Reset the flag and file name
validFileName = fileNameNoExt + (++counter == 0 ? "" : counter) + "." + fileExt;
isValid = true;
// Parse the files
for (let i = 0; i < files.results.length; i++) {
let file = files.results[i];
// See if there is a match
if (file.Name.toLowerCase() == validFileName) {
// Set the flag
isValid = false;
break;
}
}
} while (!isValid);
// Resolve the request
resolve(validFileName);
});
});
};
// Parse the images
Helper.Executor(images, imageInfo => {
// See if this is a file that needs to be uploaded
if (imageInfo.name && imageInfo.data && imageInfo.fieldName) {
// Return a promise
return new Promise(resolve => {
// Remove the existing image
removeExisting(info.item ? info.item[imageInfo.fieldName] : null).then(() => {
// Validate the name
validateFileName(imageInfo.name).then(fileName => {
// Upload the file
fld.Files().add(fileName, true, imageInfo.data).execute(file => {
// Update the field value
values[imageInfo.fieldName] = JSON.stringify({
fieldId: imageInfo.fieldId,
fieldName: imageInfo.fieldName,
fileName: file.Name,
id: file.UniqueId,
nativeFile: {},
serverRelativeUrl: file.ServerRelativeUrl,
type: "thumbnail"
});
// Resolve the request
resolve(null);
});
});
});
});
}
}).then(() => {
// Resolve the request
resolve(values);
});
});
});
};
// Render a loading message
let progress = Components.Progress({
el: props.el,
isAnimated: true,
isStriped: true,
label: "Loading the Form",
size: 100
});
// Generates the attachments row
let controlAttachments = null;
let generateAttachmentsRow = () => {
// See if we are rendering attachments
let displayAttachments = typeof (props.displayAttachments) === "boolean" ? props.displayAttachments : true;
let attachmentsExist = props.info.item == null ? true : (props.info.attachments ? true : false);
if (attachmentsExist && displayAttachments) {
// Set a default field
// This will help w/ the onControlRendering/ed events to not have a null value for this parameter
props.info.fields["Attachments"] = {};
// Create the attachments control
controlAttachments = {
id: "ListFormAttachments",
label: "Attachments",
name: "Attachments",
onControlRendered: control => {
// Render a toolbar
let toolbar = Components.Toolbar({
el: control.el,
items: [{
buttons: [{
className: "upload-btn me-1",
isSmall: true,
text: "Upload",
type: Components.ButtonTypes.Secondary,
onClick: (btn, ev) => {
let elUpload = ev.currentTarget;
// Display an upload dialog
Helper.ListForm.showFileDialog().then(fileInfo => {
// Get the buttons and remove any duplicates
let buttons = elUpload.parentElement.querySelectorAll(".btn");
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i];
// See if this is the associated button
if (button.innerText.replace(/X$/, '') == fileInfo.name) {
// Get the badge
let badge = button.querySelector(".badge");
if (badge) {
// Remove the button
badge.click();
}
break;
}
}
// Save the file information
attachments.new.push(fileInfo);
// Append the attachment
elUpload.parentElement.appendChild(Components.Popover({
isDismissible: true,
type: Components.PopoverPlacements.Bottom,
btnProps: {
className: "me-1 file-attachment",
isSmall: true,
text: fileInfo.name
},
options: {
content: Components.Button({
data: fileInfo,
isSmall: true,
text: "Remove",
type: Components.ButtonTypes.Danger,
onClick: (btn, ev) => {
let fileName = btn.data.name;
// Parse the array
for (let i = 0; i < attachments.new.length; i++) {
// See if this is the target attachment
if (attachments.new[i].name == fileName) {
// Remove this attachment
attachments.new.splice(i, 1);
break;
}
}
// Get the files
let files = btnGroup.querySelectorAll(".btn.file-attachment");
for (let i = 0; i < files.length; i++) {
let file = files[i];
// See if this is the target button
if (file.innerText == fileName) {
// Remove this popover
file.parentElement.removeChild(file);
break;
}
}
}
}).el
}
}).el);
});
}
}]
}]
});
// Get the button group
let btnGroup = toolbar.el.querySelector(".btn-group");
if (btnGroup) {
// Parse the attachments
let itemAttachments = props.info.attachments || [];
for (let i = 0; i < itemAttachments.length; i++) {
let attachment = itemAttachments[i];
// Add the attachment
btnGroup.appendChild(Components.Popover({
isDismissible: true,
type: Components.PopoverPlacements.Bottom,
btnProps: {
className: "me-1 file-attachment",
isSmall: true,
text: attachment.FileName,
},
options: {
content: Components.ButtonGroup({
buttons: [
{
data: attachment,
isSmall: true,
text: "Remove",
type: Components.ButtonTypes.Danger,
onClick: (btn, ev) => {
let attachment = btn.data;
// Add this file for deletion
attachments.delete.push(attachment);
// Get the files
let files = btnGroup.querySelectorAll(".btn.file-attachment");
for (let i = 0; i < files.length; i++) {
let file = files[i];
// See if this is the target button
if (file.innerText == attachment.FileName) {
// Remove this popover
file.parentElement.removeChild(file);
break;
}
}
}
},
{
data: attachment,
isDisabled: attachment.ServerRelativeUrl ? false : true,
isSmall: true,
text: "View",
type: Components.ButtonTypes.Primary,
onClick: (btn, ev) => {
let fileUrl = btn.data.ServerRelativeUrl;
// Show the file in a new tab
window.open(fileUrl, "_blank");
}
}
]
}).el
}
}).el);
}
}
}
};
// Render the attachments
rows.push({
columns: [{ control: controlAttachments }]
});
}
};
// Get the fields to render
let fieldNames = getFieldsToRender(props);
// Parse the fields to render
for (let i = 0; i < fieldNames.length; i++) {
let fieldName = fieldNames[i];
let field = props.info.fields[fieldName];
// See if this is the attachment field
if (fieldName == "Attachments") {
// Generate the attachments row
generateAttachmentsRow();
// Increment the total controls
totalControls++;
// Check the next field
continue;
}
// Ensure the field exists
if (field == null) {
// Log
console.error("[List Form] Field '" + fieldName + "' does not exist. Check the list or query.");
continue;
}
// See if the item exists
value[fieldName] = null;
if (props.info.item) {
// Set the value
value[fieldName] = props.info.item[fieldName];
// See if this is a lookup or user field
if (field.FieldTypeKind == SPTypes.FieldType.Lookup || field.FieldTypeKind == SPTypes.FieldType.User) {
// Update the value
value[fieldName] = value[fieldName + "Id"] || (value[fieldName] ? value[fieldName].Id : null) || value[fieldName];
}
// See if this is a file leaf ref
if (fieldName == "FileLeafRef") {
// Update the value
value[fieldName] = value[fieldName] || props.info.item.Title;
}
}
// Determine the control mode
let controlMode = props.controlMode || (props.info.item ? SPTypes.ControlMode.Edit : SPTypes.ControlMode.New);
// See if this is an edit form and we are hiding this field
if (controlMode == SPTypes.ControlMode.Edit && field.SchemaXml.indexOf('ShowInEditForm="FALSE"') > 0) {
continue;
}
// See if this is a new form and we are hiding this field
if (controlMode == SPTypes.ControlMode.New && field.SchemaXml.indexOf('ShowInNewForm="FALSE"') > 0) {
continue;
}
// See if thi sis a new form and this is an associated lookup field
if (controlMode == SPTypes.ControlMode.New && field.IsDependentLookup) {
continue;
}
// See if this is a display form and we are hiding this field
if (controlMode == SPTypes.ControlMode.Display && field.SchemaXml.indexOf('ShowInDisplayForm="FALSE"') > 0) {
continue;
}
// See if this is a read-only field
if (field.ReadOnlyField) {
// Do not render in the new form
if (props.controlMode == SPTypes.ControlMode.New) {
continue;
}
}
// Do not render a hidden taxonomy field
if (field.Hidden && field.FieldTypeKind == SPTypes.FieldType.Note && /_0$/.test(field.Title)) {
continue;
}
// See if this is an invalid field type
if (field.FieldTypeKind == SPTypes.FieldType.Invalid) {
// Ensure it's not a taxonomy field
if (!/^TaxonomyFieldType/.test(field.TypeAsString)) {
continue;
}
}
// Else, see if this is a calculated column
else if (field.FieldTypeKind == SPTypes.FieldType.Calculated) {
// Do not render in the new/edit forms
if (props.controlMode != SPTypes.ControlMode.Display) {
continue;
}
}
// See if this is a lookup field
let lookupFilter = null;
if (field.FieldTypeKind == SPTypes.FieldType.Lookup) {
// Call the filter event
lookupFilter = props.onFilterLookupField ? props.onFilterLookupField(field) : null;
}
// See if there is a custom event for setting the value
if (props.onSetFieldDefaultValue) {
// Call the event to override the value
value[fieldName] = props.onSetFieldDefaultValue(field, value[fieldName]);
}
// Create the control
let fieldControl = Field({
controlMode: props.controlMode,
field,
listInfo: props.info,
lookupFilter,
value: value[fieldName],
onControlRendered: (control, field) => {
// Update the mapper
mapper[field.InternalName].control = control;
},
onValidate: props.onValidate,
onError: msg => {
// Add the refresh link
addRefreshLink();
// Call the event
props.onError ? props.onError(msg) : null;
}
});
// Update the mapper
mapper[fieldName] = fieldControl;
// Add the row
rows.push({
columns: [{
control: fieldControl.controlProps
}]
});
// Increment the total controls
totalControls++;
}
// See if there is a template
let templateFieldNames = null;
if (props.template) {
// Clear the field names for this template
templateFieldNames = [];
// Reset the total controls
totalControls = 0;
// Method to handle internal and custom events
let createEvent = (event, control, templateControl) => {
let templateEvent = templateControl[event];
// Set the event
return (...args) => {
let controlProps = args[0];
// Call the events
control[event](...args);
templateEvent(...args);
// Update the mapper
mapper[controlProps.name] ? mapper[controlProps.name].controlProps = controlProps : null;
};
};
// Method to update the template control
let updateControl = (templateControl) => {
// Get the control from the mapper
let control = templateControl && mapper[templateControl.name] ? mapper[templateControl.name].controlProps : null;
// See if this is a reference to the attachments
if (templateControl && templateControl.name == "Attachments") {
control = templateControl.isDisabled || templateControl.isReadonly ? generateAttachmentsControl(props) : controlAttachments;
}
// Ensure the controls exists
if (control && templateControl) {
// Parse the control keys
for (let key in control) {
// Skip if a value is already defined
if (typeof (templateControl[key]) !== "undefined") {
// See if this is an internal event
if (key == "onControlRendering" || key == "onControlRendered") {
// Create a new event to call both internal and custom events
templateControl[key] = createEvent(key, control, templateControl);
}
// Skip this property
continue;
}
// Update the property
templateControl[key] = control[key];
}
// Add the template field name
templateFieldNames.push(templateControl.name);
// Update the mapper
mapper[templateControl.name] ? mapper[templateControl.name].controlProps = templateControl : null;
}
};
// Parse the template
for (let i = 0; i < props.template.length; i++) {
let row = props.template[i];
// Parse the columns if there are columns
let columns = row.columns || [];
for (let j = 0; j < columns.length; j++) {
let column = columns[j];
// Update the control
updateControl(column.control);
// Increment the total controls
totalControls++;
}
}
}
// Remove the progress bar
progress.el.parentElement ? progress.el.parentElement.removeChild(progress.el) : null;
// Counter for each control
let ctrlCounter = 0;
// Render the form
let form = Components.Form({
el: props.el,
className: props.className,
groupClassName: props.groupClassName,
rowClassName: props.rowClassName,
onControlRendered: control => {
var _a;
// Ensure the control is set
let field = mapper[(_a = control.props) === null || _a === void 0 ? void 0 : _a.name];
if (field && field.control == null) {
field.setControl(control);
}
// See if all of the controls have been rendered
if (++ctrlCounter == totalControls) {
// See if an event exists
if (props.onFormRendered) {
// Execute the form rendered event in another thread
setTimeout(() => { props.onFormRendered(form); }, 10);
}
}
// Return the event
return props.onControlRendered ? props.onControlRendered(control, props.info.fields[control.props.name]) : null;
},
onControlRendering: control => {
let findTemplateControl = (ctrlName) => {
// Parse the template
for (let i = 0; i < props.template.length; i++) {
let row = props.template[i];
// Parse the columns if there are columns
let columns = row.columns || [];
for (let j = 0; j < columns.length; j++) {
let column = columns[j];
// See if this is the control
if (column.control && column.control.name == ctrlName) {
return column.control;
}
}
}
// Not found
return null;
};
let updateReadOnly = (control) => {
// See if this control is readonly
if (control.isReadonly && control.name) {
// Get the control display properties
let dispControl = control.name == "Attachments" ? generateAttachmentsControl(props) : renderDisplay(control.name, props);
if (dispControl) {
let ctrlTemplate = props.template ? findTemplateControl(control.name) : null;
// Update the properties
control.data = ctrlTemplate ? ctrlTemplate.data : dispControl.data;
control.label = ctrlTemplate ? ctrlTemplate.label : dispControl.label;
control.showTime = ctrlTemplate ? ctrlTemplate.showTime : dispControl.showTime;
control.type = ctrlTemplate ? ctrlTemplate.type : dispControl.type;
control.value = ctrlTemplate ? ctrlTemplate.value : dispControl.value;
}
}
};
// Execute the rendering event
let field = props.info.fields[control.name] || {};
let returnVal = props.onControlRendering ? props.onControlRendering(control, field) : null;
if (returnVal && returnVal.then) {
// Wait for the event to complete
returnVal.then((ctrlProps) => {
// Update the properties
updateReadOnly(ctrlProps || control);
});
}
else {
// Update the properties
updateReadOnly(control);
}
},
rows: props.template || rows,
value
});
// Method to get the values
let getValues = () => {
let values = {};
// See if the content type was set
if (props.info.contentType) {
// Set the content type id
values["ContentTypeId"] = props.info.contentType.Id.StringValue;
}
// Clear the image values
images = [];
// Parse the fields
for (let fieldName in props.info.fields) {
// Get the form field and skip disabled/readonly fields
let formField = mapper[fieldName];
if (formField == null || formField.controlProps.isDisabled || formField.controlProps.isReadonly) {
continue;
}
// Get the field value
let fieldValue = formField.getValue();
// Set the item value
values[fieldValue.name] = fieldValue.value;
// See if this is the file leaf ref
if (fieldValue.name == "FileLeafRef") {
// Update the 'Title'
values["Title"] = values["Title"] || values[fieldValue.name];
}
// See if this is an image field
let field = props.info.fields[fieldName];
if (field && field.FieldTypeKind == SPTypes.FieldType.Image) {
// Add the value if it exists
fieldValue.value ? images.push(fieldValue.value) : null;
}
}
// Return the form values
return values;
};
// Create the form object
let formObj = {
appendControls: (controls) => {
// Append the controls
form.appendControls(controls);
// Wait for the controls to be loaded
setTimeout(() => {
// Parse the new controls
for (let i = 0; i < controls.length; i++) {
let control = controls[i].na