variables.cftDebug = false;
var inputParameters = Duplicate(arguments.parameters);
var currentValue = arguments.value; // the field's current value
var readOnly = (arguments.displayMode EQ 'readonly') ? true : false;
var currentObj = "";
var currentData = StructNew();
var widgetScript = "";
var widgetData = StructNew();
var vFilePath = ""; // NOT NEEDED -> "ram://#arguments.fieldName#_widget_options.ini";
var v = 1;
var vFld = "";
var vFieldCnt = 0;
var vFieldData = StructNew();
var vFldLabel = "";
var vFldName = "";
var vFldProps = StructNew();
var vFldPropsArray = ArrayNew(1);
var bCnt = 0;
var fKey = 0;
var groupPrefix = "group_";
var defaultGroupName = groupPrefix & "all";
var groupsAPI = Server.CommonSpot.ObjectFactory.getObject("Groups");
var groupQry = groupsAPI.getNamesGivenIDs(request.user.GroupList);
var groupName = "";
var q = 1;
var defaultData = StructNew();
var renderedData = StructNew();
var renderedErrors = ArrayNew(1);
var fld = "";
var opt = "";
var wcFieldType = "";
var wcFieldName = "";
var wcFieldLabel = "";
var wcFieldValue = '';
var wcOptionName = "";
var wcOptionLabel = "";
var wcOptionValue = "";
var wcOptionValueDomID = '';
var wcOptionSelected = false;
var fldHasDefault = false;
var fldHasDescription = false;
var fldLabelContainerDivClass = "cfgFieldLabelContainer";
var fldControlContainerInnerDivClass = "";
var fldDescriptionDivClass = "cfgFieldDescription";
var optionValueDelimiter = ';'; // SEMI-COLON - used to delimit Configuration Options
var valueLabelDelimiter = '|'; // PIPE - used to delimit Option Value|Label Pairs
var savedValueDelimiter = ';'; // SEMI-COLON OLD: SPACE - used to delimit saved values
var maxOptionLabelChars = 60;
var fieldid = arguments.FIELDID;
var formid = arguments.FORMID;
var elementFormName = '';
var siteDir = request.site.dir;
/* WidgetScript INI folder Defaults */
var widgetDefaultName = "";
var widgetDefaultDir = "/_cs_widgets";
var widgetConfigDir = "/config";
/* WidgetScript INI file Defaults */
var scriptFileExt = "ini";
var scriptFileName = "";
var scriptFileNameCustom = "";
var scriptFilePath = "";
var fullScriptDir = "";
var fullScriptPath = "";
var fullScriptPathCustom = "";
var fileWriteData = "";
var errorMsg = "";
//var scriptFileName = "widget-config";
//var scriptFileName = "widget-config-" & fieldid;
//var scriptFileNameCustom = scriptFileName & "_custom";
//WriteDump(var=arguments,expand=false);
inputParameters = setDefaultParameters(argumentCollection=arguments);
//WriteDump(var=inputParameters,expand=false);
if ( LEN(currentValue) )
{
currentObj = DeserializeJSON(TRIM(currentValue));
if ( StructKeyExists(currentObj,"Data") )
currentData = currentObj.Data;
}
// Get the Element Form Name for the specific form type
elementFormName = getElementFormName(elementType=formType,formID=formid);
//WriteDump(elementFormName);
if ( LEN(TRIM(elementFormName)) EQ 0 )
{
errorMsg = "The Element Form name could not be resolved from provided Form ID!";
WriteOutput(errorMsg);
throw(errorMsg);
}
else
{
// Build the Widget defualt name
widgetDefaultName = LCASE(TRIM(REREPLACENOCASE(elementFormName,"[^A-Za-z0-9]","-","all")));
// Build the Widget default script path
widgetScriptDefaultDir = widgetDefaultDir & "/" & widgetDefaultName & widgetConfigDir & "/";
}
//if ( StructKeyExists(inputParameters,"widgetScript") )
// widgetScript = inputParameters.widgetScript;
// (OLD) Write INI config data to a RAM Disk File
// FileWrite(vFilePath,widgetScript);
// Get the Path from the Field Properties
if ( StructKeyExists(inputParameters,"widgetScriptDirPath") AND LEN(TRIM(inputParameters.widgetScriptDirPath)) )
scriptFilePath = inputParameters.widgetScriptDirPath;
else
{
scriptFilePath = widgetScriptDefaultDir;
// TODO: What do we do if we don't have a file path configured
//errorMsg = "No WidgetSyntax file configured!";
//WriteOutput(errorMsg);
//throw(errorMsg);
}
// Build the WidgetScript config file name form the Form Name
scriptFileName = widgetDefaultName & "-" & fieldid;
scriptFileNameCustom = scriptFileName & "_custom";
if ( Left(scriptFilePath,1) EQ "/" )
siteDir = reReplace(request.site.dir,"/$","");
if ( Right(scriptFilePath,1) NEQ "/" )
scriptFilePath = scriptFilePath & "/";
// Pre-packaged WidgetScript INI File Path
fullScriptPath = siteDir & scriptFilePath & scriptFileName & "." & scriptFileExt;
// Custom WidgetScript INI File Path
fullScriptPathCustom = siteDir & scriptFilePath & scriptFileNameCustom & "." & scriptFileExt;
// If we don't have a standard script file, create one
if ( !FileExists(fullScriptPath) )
{
if ( LEN(TRIM(inputParameters.widgetScript)) )
fileWriteData = fixSavedDataFileSectionBrackets(str=inputParameters.widgetScript);
fileWriteStatus = application.ADF.utils.writeINIfile(filePath=fullScriptPath,dataString=fileWriteData,overwrite=false,charSet="utf-8");
//WriteDump(fileWriteStatus);
}
// Look for a "custom" version of the widget script file
// - if no custom is found then load the default
if ( FileExists(fullScriptPathCustom) )
vFilePath = fullScriptPathCustom;
else if ( FileExists(fullScriptPath) )
vFilePath = fullScriptPath;
else
{
// TODO: What do we do if we STILL don't have a script file or a custom script file?
errorMsg = "A WidgetSyntax File has not been configured!";
WriteOutput(errorMsg);
throw(errorMsg);
}
//WriteDump(var=vFilePath,expand=false);
// Read the INI config data from RAM and serialize it into a Structure
widgetData = parseINI(vFilePath);
//WriteDump(var=widgetData,expand=false);
// Loop over the widgetData built from the INI config data
if ( !StructIsEmpty(widgetData) AND StructKeyExists(widgetData,"config") AND StructKeyExists(widgetData.config,"fields") )
{
for ( v=1; v LTE ListLen(widgetData.config.fields,optionValueDelimiter); v=v+1 ) {
// Get the List Item
vFld = ListGetAt(widgetData.config.fields,v,optionValueDelimiter);
// For the Field Labels convert all underscores(_) to spaces
vFldLabel = TRIM(REPLACE(vFld,"_"," ","all"));
// For the Field Names convert all non-AlphaNumeric chars to underscores(_)
vFldName = TRIM(REREPLACENOCASE(vFld,"[^A-Za-z0-9]","_","all"));
// If we don't have a vFld key OR its not a struct... skip it
if ( StructKeyExists(widgetData,vFldName) AND IsStruct(widgetData[vFldName]) )
{
// Build an Array for fixed FieldName Keys and Labels (used to render field in order)
vFldProps = StructNew();
vFldProps.FieldName = vFldName;
vFldProps.FieldLabel = vFldLabel;
// Set the custom label
if ( StructKeyExists(widgetData[vFldName],"label") AND LEN(TRIM(widgetData[vFldName]["label"])) )
vFldProps.FieldLabel = widgetData[vFldName]["label"];
ArrayAppend(vFldPropsArray,vFldProps);
if ( !StructKeyExists(vFieldData,vFldName) )
{
vFieldData[vFldName] = StructNew();
vFieldData[vFldName]['options'] = "";
vFieldData[vFldName]['description'] = "";
vFieldData[vFldName]['type'] = "";
//['default'] - since empty string might be a default value we don't want a key if a default is not defined
// Set the Default set of options
if ( StructKeyExists(widgetData[vFldName],defaultGroupName) )
vFieldData[vFldName]['options'] = widgetData[vFldName][defaultGroupName];
// Override the OPTIONS if we are approved by the Group Check for the currently logged in user
groupName = "";
for ( q=1; q LTE groupQry.RecordCount; q=q+1 )
{
// Convert Spaces to underscource in the groupName
groupName = TRIM(LCASE(REREPLACE(groupQry.name[q],"[\s]","_","all")));
groupName = groupPrefix & groupName;
if ( StructKeyExists(widgetData[vFldName],groupName) )
{
vFieldData[vFldName]['options'] = widgetData[vFldName][groupName];
break;
}
}
// set the default selected option
if ( StructKeyExists(widgetData[vFldName],"default") )
vFieldData[vFldName]['default'] = widgetData[vFldName]["default"];
// set the description
if ( StructKeyExists(widgetData[vFldName],"description") )
vFieldData[vFldName]['description'] = widgetData[vFldName]["description"];
// set the type
if ( StructKeyExists(widgetData[vFldName],"type") )
vFieldData[vFldName]['type'] = widgetData[vFldName]["type"];
}
}
}
}
// Count the new vFieldData structure
vFieldCnt = StructCount(vFieldData);
application.ADF.scripts.addHeaderCSS(cftWidgetConfigCSS,"SECONDARY");
application.ADF.scripts.addFooterJS(cftWidgetConfigJS,"SECONDARY");
defaultData = StructNew();
renderedData = StructNew();
renderedErrors = ArrayNew(1);
wcFieldLabel = fld.FieldLabel;
wcFieldName = fld.FieldName;
fldHasDescription = false;
fldHasDefault = false;
wcFieldType = vFieldData[wcFieldName]['type'];
wcFieldValue = '';
fldHasDefault = StructKeyExists(vFieldData[wcFieldName],"default");
fldHasDescription = YesNoFormat(StructKeyExists(vFieldData[wcFieldName],"description") && LEN(TRIM(vFieldData[wcFieldName].description)));
fldLabelContainerDivClass = "cfgFieldLabelContainer";
if ( fldHasDescription )
fldLabelContainerDivClass = "cfgFieldLabelContainerTall";
fldControlContainerInnerDivClass = "";
if ( LEN(TRIM(wcFieldType)) )
fldControlContainerInnerDivClass = "cfgField-" & lcase(wcFieldType);
if ( StructKeyExists(currentData,wcFieldName) )
wcFieldValue = currentData[wcFieldName];
else if ( StructKeyExists(vFieldData[wcFieldName],"default") )
{
// Convert default value list to Space Delimited
wcFieldValue = ListChangeDelims(vFieldData[wcFieldName]["default"],savedValueDelimiter,optionValueDelimiter,0);
}
#renderTextInputControl(ctrlName=wcFieldName,ctrlDomID=wcFieldName,ctrlValue=wcFieldValue)#
#renderNumericInputControl(ctrlName=wcFieldName,ctrlDomID=wcFieldName,ctrlValue=wcFieldValue)#
wcOptionValue = '';
wcOptionName = '';
wcOptionSelected = false;
wcOptionValueDomID = '';
// Get the Value/Text options (pipe delimited) for the Selection List --->
if ( ListLen(opt,valueLabelDelimiter) GT 1 )
{
wcOptionValue = ListFirst(opt,valueLabelDelimiter);
wcOptionName = ListRest(Replace(opt,"_"," ","ALL"),valueLabelDelimiter);
}
else
{
wcOptionValue = opt;
wcOptionName = Replace(opt,"_"," ","ALL");
}
wcFldNameDomID = wcFieldName & "_checkbox";
wcFldOptionValueDomID = wcFldNameDomID & "." & Replace(wcOptionValue,"[^0-9A-Za-z ]","-","ALL");
// Set the Selected Option
if ( StructKeyExists(currentData,wcFieldName) )
{
// If we have a current value for this field... does current value match the option
if ( ListFindNoCase(currentData[wcFieldName],wcOptionValue,savedValueDelimiter) )
wcOptionSelected = true;
}
else if ( StructKeyExists(vFieldData[wcFieldName],"default") AND ListFindNoCase(vFieldData[wcFieldName]['default'],wcOptionValue,optionValueDelimiter) )
wcOptionSelected = true;
// Build the inital defaultData structure from the renderData and renderErrors
defaultData.data = renderedData;
defaultData.errors = renderedErrors;
// Serialize into JSON the defaultData structure
currentValue = serializeJSON(defaultData);
currentValue = HTMLEditFormat(currentValue);
var inputParameters = duplicate(arguments.parameters);
if ( NOT StructKeyExists(inputParameters, "widgetScript") )
inputParameters.widgetScript = "";
// Validate if the property field has been defined
if ( NOT StructKeyExists(inputParameters, "fldID") OR LEN(inputParameters.fldID) LTE 0 )
inputParameters.fldID = arguments.fieldName;
return inputParameters;
var opt = 1;
var retStr = '';
var infoObj = '';
var infoObjType = '';
var argData = StructNew();
var infoData = '';
var infoMethod = '';
var argName = '';
var infoDataKey = '';
var validFormType = false;
switch (arguments.elementType)
{
case 'Global Custom Element': case 'Local Custom Element':
infoObjType = "CustomElement";
infoMethod = "getInfo";
argName = "elementID";
infoDataKey = "name";
validFormType = true;
break;
case 'Custom Metadata Form':
infoObjType = 'MetadataForm';
infoMethod = "getForms";
argName = "ID";
infoDataKey = "formName";
validFormType = true;
break;
case 'simpleform': // this is here so we remember this dlgtype
validFormType = false;
//infoObjType = 'SimpleFormElement';
//infoMethod = "getList";
break;
default:
validFormType = false;
}
if ( validFormType )
{
argData[argName] = arguments.formid;
// Get the Element Info based on element type
infoObj = Server.CommonSpot.ObjectFactory.getObject(infoObjType);
// Get the Element Info based on element type
infoData = getElementInfo(objType=infoObjType,methodName=infoMethod,args=argData);
// USE the ACF Workaround (above) for Dynamic method names instead ( getElementInfo() )
//infoObj = Server.CommonSpot.ObjectFactory.getObject(infoObjType);
//infoData = infoObj[infoMethod](argumentCollection=argData);
if ( StructKeyExists(infoData,infoDataKey) )
retStr = infoData[infoDataKey];
}
return retStr;
var result = '';
var methodResult = "";
var infoObj = '';
var allowedElementTypes = "CustomElement,MetadataForm";
var allowedMethods = "getInfo,getForms";
var methodAllowed = false;
if ( ListFind(allowedElementTypes,arguments.objType) )
{
infoObj = Server.CommonSpot.ObjectFactory.getObject(arguments.objType);
methodAllowed = true;
}
else
methodAllowed = false;
if ( methodAllowed AND ListFind(allowedMethods,arguments.methodName) )
methodAllowed = true;
else
methodAllowed = false;
arguments.str = REReplace(arguments.str, "(\r\n|\n\r|\n|\r)(\[)","#CHR(13)##CHR(10)##CHR(13)##CHR(10)#[", "all");
arguments.str = REReplace(arguments.str, "(\r\n|\n\r|\n|\r)(##\[)","#CHR(13)##CHR(10)##CHR(13)##CHR(10)###[", "all");
return arguments.str;
/*
parseINI(iniPath)
Parses a textfile in the INI format and returns a structure of variables grouped by sections
*/
public struct function parseINI(iniPath)
{
try
{
var retData = {};
var prop = "";
var section = "";
var sections = getProfileSections(arguments.iniPath);
var sectionFix = "";
// If there are no sections in the ini file, return a single level struct of name=value pairs
if ( StructIsEmpty(sections) )
{
return parseSimpleINI(iniPath=arguments.iniPath);
}
for (section in sections)
{
// Replace non AlphaNumeric chars with underscores in all section Keys
sectionFix = TRIM(REREPLACENOCASE(section,"[^A-Za-z0-9]","_","all"));
retData[sectionFix] = {};
for (prop in listToArray(sections[section]))
{
// PT GAC - Make sure props that start with pounds are not included
if ( Left(prop,1) NEQ "##" )
retData[sectionFix][prop] = getProfileString(arguments.iniPath, section, prop);
}
}
return retData;
}
catch( java.io.FileNotFoundException e )
{
throw(type="widget_configurator.parseINI.filenotfound", message="Ini file not found in path '#arguments.iniPath#'");
}
catch (any e)
{
throw(type="widget_configurator.parseINI.error", message=e.getMessage());
}
}
/*
parseSimpleINI
Parses a simple INI file that contains name=value pairs with no sections and returns a single level struct
*/
private struct function parseSimpleINI(iniPath)
{
var iniFile = FileOpen(arguments.iniPath, "read", "utf-8");
var line = "";
var retData = {};
while( !FileIsEOF(iniFile) )
{
line = fileReadLine(iniFile);
// Ignore empty (spacer) lines, as well as comment lines (;)
if (len(line) && left(trim(line), 1) != ";")
{
retData[trim(listFirst(line, "="))] = trim(listLast(line, "="));
}
}
FileClose(iniFile);
return retData;
}
private any function getValidationJS(required string formName, required string fieldName, required boolean isRequired)
{
if (arguments.isRequired)
return 'hasValue(document.#arguments.formName#.#arguments.fieldName#, "TEXT")';
return '';
}
private boolean function isMultiline()
{
return true;
}
/*public numeric function getMinHeight()
{
return 200;
}*/
/*public numeric function getMinWidth()
{
return 800;
}*/
// if your renderer makes use of CommonSpot registered resources, implement getResourceDependencies() and return a list of them, like this
public string function getResourceDependencies()
{
return "jQuery,jQueryJSON";
// if this renderer extends another one that may require its own resources, it should include those too, like this:
// return listAppend(super.getResourceDependencies(), "jQuery,jQueryJSON");
}
// if your renderer needs to load resources other than what's returned by its getResourceDependencies(() method,...
// ...or if it uses the ADF scripts methods to load them, directly or indirectly via app-level methods, do that here
// you could do this if some resources are loaded conditionally, based on context, page metadata, etc.
// IMPORTANT: getResourceDependencies() still should return the full list of all resources that MIGHT be loaded, so exports can ensure they exist on a target system
// by implementing loadResourceDependencies(), you're taking responsibility for keeping getResourceDependencies() in sync with it in that sense
public void function loadResourceDependencies()
{
application.ADF.scripts.loadJQuery();
application.ADF.scripts.loadJQueryJSON();
// if this renderer extends another one that may require its own resources, it should load those too, like this:
//super.loadResourceDependencies();
}