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;
checked="checked">
fldDescriptionDivClass = "cfgFieldDescription"; if ( LEN(TRIM(vFieldData[wcFieldName]['description'])) GT 65 ) fldDescriptionDivClass = "cfgFieldDescriptionWrap";
#TRIM(vFieldData[wcFieldName]['description'])#
No Fields with Options have been configured!
// 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(); }