/* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is comprised of the ADF directory The Initial Developer of the Original Code is PaperThin, Inc. Copyright (c) 2009-2022. All Rights Reserved. By downloading, modifying, distributing, using and/or accessing any files in this directory, you agree to the terms and conditions of the applicable end user license agreement. */ /* *************************************************************** */ /* Author: PaperThin, Inc. Name: widgets_1_0.cfc Summary: Widgetcomponent functions for the ADF Library Version: 1.0 History: 2016-07-05 - GAC - Created 2016-03-01 - GAC - Added buildCustomWidgetCssPaths() and loadCustomWidgetCSS() methods 2016-03-02 - GAC - Added verifyRenderHandlerMetadata() 2017-04-10 - GAC - Added buildOptionData() 2017-05-05 - GAC - Added methods to help calculate Bootstrap Two Column Grid classes */ component displayname="widgets_1_0" extends="ADF.lib.libraryBase" hint="Widget component functions for the ADF Library" output="no" { /* PROPERTIES */ property name="version" type="string" default="1_0_5"; property name="type" value="singleton"; property name="wikiTitle" value="Widgets_1_0"; /* *************************************************************** Author: PaperThin, Inc. Name: $getWidgetConfigData Summary: Builds the widget configuration data structure from the bound ElementInfo.RenderHandlerMetaData based on the passed in field name. Returns: Struct Arguments: Struct - customMetdata String - configFieldName (can be a coma-delimited list of field names) History: 2016-07-05 - GAC - Created 2016-11-01 - GAC - Updated to handle adding additional field data to the config struct 2017-02-24 - GAC - Updated to handle numeric values in standard field data */ public struct function getWidgetConfigData(required struct customMetdata, required string configFieldName) { var retData = StructNew(); var widgetObj = StructNew(); var configFindArray = ArrayNew(1); var f = 0; var fld = ""; for ( f=1; f LTE ListLen(arguments.configFieldName); f=f+1) { fld = ListGetAt(arguments.configFieldName,f); configFindArray = StructFindKey(arguments.customMetdata,fld); if ( ArrayLen(configFindArray) AND StructKeyExists(configFindArray[1],"value") ) { widgetObj = StructNew(); if ( IsJSON(TRIM(configFindArray[1].value)) AND !IsNumeric(configFindArray[1].value) ) { widgetObj = DeserializeJSON(TRIM(configFindArray[1].value)); if ( StructKeyExists(widgetObj,"Data") ) StructAppend(retData,widgetObj.Data,false); // Do not overwrite existing keys } else { // Do not overwrite existing keys if ( !StructKeyExists(widgetObj,fld) AND isSimpleValue(configFindArray[1].value) ) retData[fld] = configFindArray[1].value; } } } return retData; } /* *************************************************************** Author: PaperThin, Inc. Name: $buildClassValue Summary: Builds a space delimited class string. If the passed in class is 'none' then it does not add it to the string. Returns: String Arguments: String - classStr String - newClass History: 2016-07-05 - GAC - Created 2016-10-24 - GAC - Updated to handle the inherit option as a newClass value 2017-03-30 - GAC - Updated to remove comma or semi-colon delimiters if found in newClass value lists */ public string function buildClassValue(string classStr='',string newClass='') { var retStr = TRIM(arguments.classStr); var stripOptions = 'none,inherit'; // list of ITEMS to remove from the returned Class List var stripOpt = ''; var stripPos = 0; var s = 1; var c = 1; var className = ''; var classListDelimiter = ' '; // SPACE arguments.newClass = TRIM(arguments.newClass); if ( LEN(arguments.newClass) ) { // Replace any semi-colons with the classListDelimiter arguments.newClass = ListChangeDelims(arguments.newClass,classListDelimiter,";",0); // Replace any commas with the classListDelimiter arguments.newClass = ListChangeDelims(arguments.newClass,classListDelimiter,",",0); // Walk through the list of options that need to be striped and remove any we find for ( s=1; s LTE ListLen(stripOptions,","); s=s+1 ) { // Get the item to strip out stripOpt = TRIM(ListGetAt(stripOptions,s,",")); // Look through the newClass value if we find the any items to strip remove them stripPos = ListFindNoCase(arguments.newClass,stripOpt,classListDelimiter); if ( stripPos GT 0 ) arguments.newClass = ListDeleteAt(arguments.newClass,stripPos,classListDelimiter); } // Walk through the list of newClass items and make sure we are not adding any duplicates for ( c=1; c LTE ListLen(arguments.newClass,classListDelimiter); c=c+1 ) { // Get the className value className = TRIM(ListGetAt(arguments.newClass,c,classListDelimiter)); // Make sure the className is not already in the list before we add it to the current list of classes if ( ListFindNoCase(retStr,className,classListDelimiter,false) EQ 0 ) retStr = listAppend(retStr,className,classListDelimiter); } } return TRIM(retStr); } /* *************************************************************** Author: PaperThin, Inc. Name: $buildOptionData Summary: Builds a structure key by the option list items with a value of true. Returns: Struct Arguments: String - optionStr History: 2016-04-10 - GAC - Created 2017-10-16 - GAC - Updated the default delimiter to match the CS10.5 selection list delimiter */ public struct function buildOptionData(string optionStr='', string delimiter=',') { var retData = StructNew(); var s = 1; var optKey = ''; for ( s=1; s LTE ListLen(arguments.optionStr,arguments.delimiter); s=s+1 ) { optKey = TRIM(ListGetAt(arguments.optionStr,s,arguments.delimiter)); if ( LEN(optKey) ) retData[optKey] = true; } return retData; } /* *************************************************************** Author: PaperThin, Inc. Name: $calcBootstrapClearFix Summary: Calculates the clear fix struct Returns: Struct Arguments: String - classes - the bootstrap grid row layout classes History: 2016-07-05 - JTP - Created */ public struct function calcBootstrapClearFix(required string classes) { var pos = 0; var retStruct = StructNew(); retStruct.lg = 0; retStruct.md = 0; retStruct.sm = 0; pos = FindNoCase( 'sm-', arguments.classes ); if( pos ) retStruct.sm = Trim( Mid(arguments.classes, pos + 3, 2) ); // returns 2 digit number or 1 digit + space, which then gets trimmed pos = FindNoCase( 'md-', arguments.classes ); if( pos ) retStruct.md = Trim( Mid(arguments.classes, pos + 3, 2) ); // returns 2 digit number or 1 digit + space, which then gets trimmed else retStruct.md = retStruct.sm; pos = FindNoCase( 'lg-', arguments.classes ); if( pos ) retStruct.lg = Trim( Mid(arguments.classes, pos + 3, 2) ); // returns 2 digit number or 1 digit + space, which then gets trimmed else retStruct.lg = retStruct.md; return retStruct; } /* *************************************************************** Author: PaperThin, Inc. Name: $renderBootstrapClearFix Summary: Renders clear fix div when appropriate Returns: VOID Arguments: Numeric - count Struct - clearFixStruct History: 2016-07-05 - JTP - Created */ public void function renderBootstrapClearFix(required numeric count, required struct clearFixStruct) { var remainder = ''; var list = 'lg,md,sm'; var i = 0; var cnt = 0; var incr = 0; var size = ''; for( i=1; i lte ListLen(list); i=i+1 ) { size = ListGetAt(list,i); if( StructKeyExists(arguments.clearFixStruct, size) ) { cnt = arguments.clearFixStruct[size]; if( cnt gt 0 ) { incr = 12 / cnt; remainder = arguments.count MOD incr; if( remainder eq 0 ) WriteOutput('
'); } } } } /* *************************************************************** Author: PaperThin, Inc. Name: $verifyRenderHandlerMetadata Summary: Verifies that the Render Handler is bound to a Custom Metadata form Returns: Boolean Arguments: Struct - rhCaller String - metadataFields Struct - rhElementInfo Boolean - requireMetadata History: 2017-03-03 - GAC - Created */ public boolean function verifyRenderHandlerMetadata(struct rhCaller=StructNew(), string metadataFields="", struct rhElementInfo=StructNew(), boolean requireMetadata=false ) { var errMsg = ""; var mdFormIDList = ""; var mdFieldName = ""; var f = 1; var x = 1; var fieldsExist = true; var mdObj = ""; var mdFormID = 0; var mdFormQry = ""; var queryService = ""; var objQueryResult = ""; var queryResult = ""; // Render handler Custom Metadata Form Binding Error handling if ( !StructKeyExists(arguments.rhCaller,"handlerforms") OR !IsQuery(arguments.rhCaller.handlerforms) OR arguments.rhCaller.handlerforms.RecordCount EQ 0 ) { errMsg = "Please verify the binding between the selected Layout Render Handler and the Configuration Metadata Form for this Widget!"; if ( request.user.id gt 0 AND server.commonspot.udf.security.authorok() == 1 ) { WriteOutput(' '); } // Log Error //application.ADF.log.addLogEntry(message=errMsg); return false; } else { mdFormIDList = ValueList(arguments.rhCaller.handlerforms.ID); } // If we have a Bound Form check for specific Metadata form fields if ( LEN(TRIM(arguments.metadataFields)) AND LEN(TRIM(mdFormIDList)) ) { mdObj = Server.CommonSpot.ObjectFactory.getObject("MetadataForm"); for ( f=1; f LTE ListLen(mdFormIDList);f=f+1 ) { mdFormID = ListGetAt(mdFormIDList,f); mdFormQry = mdObj.getFields(formID=mdFormID); // If we get metadata form hits then we need to look for the fields if ( mdFormQry.RecordCount ) { for ( x=1; x LTE ListLen(arguments.metadataFields);x=x+1 ) { mdFieldName = ListGetAt(arguments.metadataFields,x); queryService = new query(); queryService.setName("myQuery"); queryService.setDBType("query"); queryService.setAttributes(srcQuery=mdFormQry); objQueryResult = queryService.execute(sql="SELECT ID FROM srcQuery WHERE lower(NAME) = '#lcase(mdFieldName)#'"); queryResult = objQueryResult.getResult(); // If field can not be found set to false and get out now!! if ( !queryResult.RecordCount ) { fieldsExist = false; break; } } } if ( !fieldsExist ) break; } // Output error if we don't find any of the fields if ( !fieldsExist ) { errMsg = "Please verify the required Fields exist in the bound Widget Configuration Metadata Form!"; if ( request.user.id gt 0 AND server.commonspot.udf.security.authorok() == 1 ) { WriteOutput(' '); } // Log Error // application.ADF.log.addLogEntry(message=errMsg,cfcatch=arguments.metadataFields); return false; } } // Render Handler Custom Metadata Form Config Data Error handling if ( arguments.requireMetadata AND StructIsEmpty(arguments.rhElementInfo.RenderHandlerMetaData) ) { errMsg = "Please open the Custom Properties for this Layout Render Handler and select configuration options for this Widget!"; if ( request.user.id gt 0 AND server.commonspot.udf.security.authorok() == 1 ) { WriteOutput(' '); } // Log Error // application.ADF.log.addLogEntry(message=errMsg); return false; } return true; } /* *************************************************************** Author: PaperThin, Inc. Name: $loadCustomWidgetCSS Summary: Loads a Custom CSS Resource Based on an Existing Resource Name or Alias Returns: VOID Arguments: String - resourceName String - resourceGroup String - customSuffix History: 2017-02-24 - GAC - Created */ public void function loadCustomWidgetCSS(required string resourceName, string resourceGroup="TERTIARY", string customSuffix='_custom') // resourceGroup: PRIMARY, SECONDARY, TERTIARY) { var resData = buildCustomWidgetCssPaths(resourceName=arguments.resourceName,customSuffix=arguments.customSuffix); var resDir = ""; var resURL = ""; if ( StructKeyExists(resData,"cssDir") ) resDir = resData.cssDir; if ( StructKeyExists(resData,"cssURL") ) resURL = resData.cssURL; /* Load Custom Unregistered CSS */ if ( LEN(TRIM(resDir)) AND LEN(TRIM(resURL)) ) { if ( FileExists(resDir) ) Server.CommonSpot.UDF.Resources.loadUnregisteredResource(resURL,"stylesheet","head",arguments.resourceGroup); } } /* *************************************************************** Author: PaperThin, Inc. Name: $buildCustomWidgetCssPath Summary: Build the CSS File Path of a Custom Resource Based on an Existing Resource Name or Alias Returns: String Arguments: String - resourceName String - customSuffix History: 2017-02-24 - GAC - Created */ public struct function buildCustomWidgetCssPaths(required string resourceName, string customSuffix='_custom') { var retData = StructNew(); var resSrcPath = ""; var resSrcURL = ""; var resSpecArray = ArrayNew(1); var resSpecs = ""; var resDir = ""; var resURL = ""; var resFileName = ""; var resCustomFileName = ""; var suffixFindText = ".css"; var suffixReplaceText = arguments.customSuffix & suffixFindText; retData.cssDir = ""; retData.cssURL = ""; // Make sure we have a registered resource if ( StructKeyExists(Request.Site.CS_Resources.Resources_by_name,arguments.resourceName) ) { resSpecs = Request.Site.CS_Resources.Resources_by_name[arguments.resourceName]; // Get the CSS headItems Array from the resSpecs Struct if ( StructKeyExists(resSpecs,"HEADITEMS") ) resSpecArray = resSpecs.HEADITEMS; // Get the CSS Source Path if ( ArrayLen(resSpecArray) AND StructKeyExists(resSpecArray[1],"SourcePath") ) resSrcPath = resSpecArray[1].SourcePath; // Get the CSS Source Path if ( ArrayLen(resSpecArray) AND StructKeyExists(resSpecArray[1],"SourceURL") ) resSrcURL= resSpecArray[1].SourceURL; // Get the Directory from Source URL if ( LEN(TRIM(resSrcURL)) AND ListLast(resSrcURL,".") EQ "css" ) resURL = GetDirectoryFromPath(resSrcURL); // Build the Custom File Path from the Source Path if ( LEN(TRIM(resSrcPath)) AND ListLast(resSrcPath,".") EQ "css" ) { // Get the Directory resDir = GetDirectoryFromPath(resSrcPath); // Build the Resource File Name resFileName = ListLast(resSrcPath,"/"); // Build the Custom File Name resCustomFileName = ReplaceNoCase(resFileName,suffixFindText,suffixReplaceText,"one"); } // Build the Custom File Path if ( LEN(TRIM(resDir)) ) retData.cssDir = resDir & resCustomFileName; if ( LEN(TRIM(resURL)) ) retData.cssURL = resURL & resCustomFileName; } return retData; } /* *************************************************************** Author: PaperThin, Inc. Name: $loadCustomWidgetJS Summary: Loads a Custom JS Resource Based on an Existing Resource Name or Alias Returns: VOID Arguments: String - resourceName String - resourceGroup String - customSuffix History: 2017-05-04 - GAC - Created */ public void function loadCustomWidgetJS(required string resourceName, string resourceGroup="TERTIARY", string customSuffix='_custom') // resourceGroup: PRIMARY, SECONDARY, TERTIARY) { var resData = buildCustomWidgetCssPaths(resourceName=arguments.resourceName,customSuffix=arguments.customSuffix); var resDir = ""; var resURL = ""; if ( StructKeyExists(resData,"cssDir") ) resDir = resData.cssDir; if ( StructKeyExists(resData,"cssURL") ) resURL = resData.cssURL; /* Load Custom Unregistered CSS */ if ( LEN(TRIM(resDir)) AND LEN(TRIM(resURL)) ) { if ( FileExists(resDir) ) Server.CommonSpot.UDF.Resources.loadUnregisteredResource(resURL,"JavaScript","foot",arguments.resourceGroup); } } /* *************************************************************** Author: PaperThin, Inc. Name: $buildCustomWidgetJsPaths Summary: Build the JS File Path of a Custom Resource Based on an Existing Resource Name or Alias Returns: String Arguments: String - resourceName String - customSuffix History: 2017-02-24 - GAC - Created */ public struct function buildCustomWidgetJsPaths(required string resourceName, string customSuffix='_custom') { var retData = StructNew(); var resSrcPath = ""; var resSrcURL = ""; var resSpecArray = ArrayNew(1); var resSpecs = ""; var resDir = ""; var resURL = ""; var resFileName = ""; var resCustomFileName = ""; var suffixFindText = ".js"; var suffixReplaceText = arguments.customSuffix & suffixFindText; retData.cssDir = ""; retData.cssURL = ""; // Make sure we have a registered resource if ( StructKeyExists(Request.Site.CS_Resources.Resources_by_name,arguments.resourceName) ) { resSpecs = Request.Site.CS_Resources.Resources_by_name[arguments.resourceName]; // Get the CSS headItems Array from the resSpecs Struct if ( StructKeyExists(resSpecs,"FOOTITEMS") ) resSpecArray = resSpecs.FOOTITEMS; // Get the CSS Source Path if ( ArrayLen(resSpecArray) AND StructKeyExists(resSpecArray[1],"SourcePath") ) resSrcPath = resSpecArray[1].SourcePath; // Get the CSS Source Path if ( ArrayLen(resSpecArray) AND StructKeyExists(resSpecArray[1],"SourceURL") ) resSrcURL= resSpecArray[1].SourceURL; // Get the Directory from Source URL if ( LEN(TRIM(resSrcURL)) AND ListLast(resSrcURL,".") EQ "js" ) resURL = GetDirectoryFromPath(resSrcURL); // Build the Custom File Path from the Source Path if ( LEN(TRIM(resSrcPath)) AND ListLast(resSrcPath,".") EQ "js" ) { // Get the Directory resDir = GetDirectoryFromPath(resSrcPath); // Build the Resource File Name resFileName = ListLast(resSrcPath,"/"); // Build the Custom File Name resCustomFileName = ReplaceNoCase(resFileName,suffixFindText,suffixReplaceText,"one"); } // Build the Custom File Path if ( LEN(TRIM(resDir)) ) retData.cssDir = resDir & resCustomFileName; if ( LEN(TRIM(resURL)) ) retData.cssURL = resURL & resCustomFileName; } return retData; } /* ***************************************** */ /* Bootstrap Two Column Grid Functions */ /* ***************************************** */ /* buildBootstrapTwoColumnClassData(firstColumnClassList,secondColumnClassList,firstColumnPosition) - Builds grid column class list for 2 columns given the class list for one of the columns */ public array function buildBootstrapTwoColumnClassData(string firstColumnClassList="",string secondColumnClassList="",string firstColumnPosition="") { var retArr = ArrayNew(1); var knownColStr = ''; var otherColStr = ''; var list = 'lg,md,sm,xs'; var colData = calcBootstrapTwoColumns(firstColumnClassList=arguments.firstColumnClassList,secondColumnClassList=arguments.secondColumnClassList); var otherStruct = StructNew(); var knownStruct = StructNew(); var i = 1; var sizeKey = ''; var otherSize = ''; var otherClass = ''; var otherColStr = ''; var otherPosClass = ''; var knownSize = ''; var knownClass = ''; var knownColStr = ''; var knownPosClass = ''; retArr[1] = ''; retArr[2] = ''; // Only Process ONE column of data... if both are provided if ( LEN(TRIM(arguments.firstColumnClassList)) ) { //knownColStr = arguments.firstColumnClassList; otherStruct = colData[2]; knownStruct = colData[1]; } else if ( LEN(TRIM(arguments.secondColumnClassList)) ) { //knownColStr = arguments.secondColumnClassList; otherStruct = colData[1]; knownStruct = colData[2]; } // Build Other Columns List for( i=1; i lte ListLen(list); i=i+1 ) { sizeKey = ListGetAt(list,i); if( StructKeyExists(otherStruct, sizeKey) ) { otherSize = otherStruct[sizeKey]; if( StructKeyExists(knownStruct, sizeKey) ) knownSize = knownStruct[sizeKey]; if ( (IsNumeric(otherSize) AND otherSize GT 0) AND (IsNumeric(knownSize) AND knownSize GT 0) ) { otherClass = "col-" & sizeKey & "-" & otherSize; otherColStr = ListAppend(otherColStr, otherClass, " "); knownClass = "col-" & sizeKey & "-" & knownSize ; knownColStr = ListAppend(knownColStr, knownClass, " "); if ( arguments.firstColumnPosition EQ "right" AND knownSize GT 0 ) { otherPosClass = "col-" & sizeKey & "-pull-" & knownSize; otherColStr = ListAppend(otherColStr, otherPosClass, " "); knownPosClass = "col-" & sizeKey & "-push-" & otherSize; knownColStr = ListAppend(knownColStr, knownPosClass, " "); } } else { if ( otherSize EQ "hidden" ) { otherPosClass = otherSize & "-" & sizeKey; otherColStr = ListAppend(otherColStr, otherPosClass, " "); } if ( knownSize EQ "hidden" ) { knownPosClass = knownSize & "-" & sizeKey; knownColStr = ListAppend(knownColStr, knownPosClass, " "); } } } } if ( LEN(TRIM(arguments.firstColumnClassList)) ) { retArr[1] = knownColStr; retArr[2] = otherColStr; } else if ( LEN(TRIM(arguments.secondColumnClassList)) ) { retArr[1] = otherColStr; retArr[2] = knownColStr ; } return retArr; } /* calcBootstrapTwoColumns(firstColumnClassList,secondColumnClassList) - Builds column structure data for 2 columns given the class list for one of the columns */ public array function calcBootstrapTwoColumns(string firstColumnClassList="",string secondColumnClassList="") { var retData = ArrayNew(1); var firstStruct = StructNew(); var secStruct = StructNew(); // Parse the First Column Data, in provided if ( LEN(TRIM(arguments.firstColumnClassList)) ) firstStruct = _parseBootstrapColumns(classList=arguments.firstColumnClassList); // Parse the Second Column Data, in provided if ( LEN(TRIM(arguments.secondColumnClassList)) ) secStruct = _parseBootstrapColumns(classList=arguments.secondColumnClassList); // Build the Column Data for the "Other" Column (not provided) if ( !StructIsEmpty(firstStruct) AND StructIsEmpty(secStruct) ) { // Build the Columns for the Second Column secStruct = _buildBootstrapOtherTwoColumnData(columnData=firstStruct); } else if ( !StructIsEmpty(secStruct) AND StructIsEmpty(firstStruct) ) { // Build the Columns for the First Column firstStruct = _buildBootstrapOtherTwoColumnData(columnData=secStruct); } // At this point, we should have complementary column data for 2 columns arrayAppend(retData,firstStruct); arrayAppend(retData,secStruct); return retData; } /* _parseBootstrapColumns(classList) - Builds a struct with the size (or hidden) property for each column size */ private struct function _parseBootstrapColumns(string classList="") { var sPos = 0; var hPos = 0; var list = 'lg,md,sm,xs'; var i = 0; var retStruct = StructNew(); for( i=1; i lte ListLen(list); i=i+1 ) { sizeKey = ListGetAt(list,i); // Add the size key to the return structure retStruct[sizeKey] = 0; // look for col-{size}- in the provided class list sPos = FindNoCase( 'col-#sizeKey#-', arguments.classList ); // look for hidden-{size}} in the provided class list hPos = FindNoCase( 'hidden-#sizeKey#', arguments.classList ); if( sPos ) retStruct[sizeKey] = Trim( Mid(arguments.classList, sPos + 7, 2) ); // returns 2 digit number or 1 digit + space, which then gets trimmed else if ( hPos ) retStruct[sizeKey] = "hidden"; } return retStruct; } /* _buildBootstrapOtherTwoColumnData(classList) - Builds a struct with the size property for each column size for the "Other" Column */ private struct function _buildBootstrapOtherTwoColumnData(struct columnData=StructNew()) { var retStruct = StructNew(); var list = 'lg,md,sm,xs'; var gridSize = 12; var i = 1; var sizeKey = ''; var knownSize = 0; var otherSize = gridSize; for( i=1; i lte ListLen(list); i=i+1 ) { sizeKey = ListGetAt(list,i); // Add the size key to the return structure retStruct[sizeKey] = 0; if( StructKeyExists(arguments.columnData, sizeKey) ) { knownSize = arguments.columnData[sizeKey]; if ( IsNumeric(knownSize) AND knownSize GT 0 AND knownSize LT gridSize ) { // Subtract the Known size from the Grid Size otherSize = gridSize - knownSize; if ( otherSize GT 0 AND otherSize LT gridSize ) retStruct[sizeKey] = otherSize; else retStruct[sizeKey] = 0; } } } return retStruct; } }