Creating a Name/Value Attribute Editor in Oracle WebCenter Sites
![image](https://www.function1.com/sites/default/files/field/image/PullDownList.png)
There are times when the attribute editors built into WebCenter Sites don't have all the functionality you might need. For instance, you may want to create a custom pull-down list, where the items or names that show in the list are not the same as the value that gets saved to the database. In this article, we'll discuss how to create an attribute editor that can display a list of choices that are mapped to other values, displaying properly when your asset is reloaded.
The first step will be to create a new attribute editor from the admin UI. In this example, let's assume we have an attribute using this editor where the value will be the HTML color code that is being used in a template. We would want the user to see the name of the color rather than the code so that it's more user-friendly (i.e., Red, Blue, etc). Let's call it ColorPicker and also have the type of String. For the XML field, use XML in the listing below. Our code will split the name and value by the colon.
<?XML VERSION="1.0"?><PRESENTATIONOBJECT NAME="ColorPicker"><NAMEVALUEPULLDOWN><ITEM>Red:#FF0000</ITEM><ITEM>Green:#00FF00</ITEM><ITEM>Blue:#0000FF</ITEM></NAMEVALUEPULLDOWN></PRESENTATIONOBJECT>
For the code portions, we are going to create 3 elements. The first one will be based on the OpenMarket/Gator/AttributeTypes/PULLDOWN.xml that ships with sites. It's going to call another element that will parse the values for us. For this example, just create all 3 elements under OpenMarket/Gator/AttributeTypes. This first one will be called OpenMarket/Gator/AttributeTypes/NameValuePULLDOWN.xml. Copy the code listing below into it. The XML file is quite long but there are only a few lines that are changed from the original. Those changes are explained after the listing.
<?xml version="1.0" ?> <!DOCTYPE FTCS SYSTEM "futuretense_cs.dtd"> <FTCS Version="1.1"> <!-- OpenMarket/Gator/AttributeTypes/PULLDOWN - - INPUT - - OUTPUT - --> <!-- - The PULLDOWN attribute editor can be used with all attribute types except url. - Single valued attributes will be displayed in a pulldown while multi valued - attributes will be displayed in a multi select box. - - Note for asset type attributes: This type of attribute can only be populated - by a Query asset and that Query must return both a 'value' column and an - 'assetid' column which is the id of the asset. --> <IF COND="Variables.MultiValueEntry=no"> <THEN> <tr> <callelement NAME="OpenMarket/Gator/FlexibleAssets/Common/DisplayAttributeName"/> <td></td> <if COND="Variables.RequiredAttr=true"> <then> <setvar NAME="RequireInfo" VALUE="*Variables.cs_SingleInputName*Variables.currentAttrName*ReqTrue*Variables.AttrType*text!"/> </then> <else> <setvar NAME="RequireInfo" VALUE="*Variables.cs_SingleInputName*Variables.currentAttrName*ReqFalse*Variables.AttrType*text!"/> </else> </if> <presentation.getprimaryattributevalue NAME="Variables.PresInst" ATTRIBUTE="FONTSIZE" VARNAME="size"/> <presentation.getprimarychildvalues NAME="Variables.PresInst" ELEMENT="QUERYASSETNAME" LISTVARNAME="queryasset"/> <IF COND="IsVariable.size=false"> <THEN> <SETVAR NAME="size" VALUE="1"/> </THEN> <ELSE> <SETVAR NAME="size" VALUE="Variables.size"/> </ELSE> </IF> <td> <setvar NAME="doDefaultDisplay" VALUE="no"/> <IF COND="IsList.queryasset=true"> <THEN> <IF COND="queryasset.#numRows!=0"> <THEN> <setvar NAME="errno" VALUE="0"/> <SETVAR NAME="assetnameOrg" VALUE="Variables.assetname"/> <if COND="IsError.Variables.errno=false"> <then> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownQueryImpl"> <ARGUMENT NAME="queryAssetName" VALUE="queryasset.value"/> </CALLELEMENT> <SETVAR NAME="assetname" VALUE="Variables.assetnameOrg"/> <REMOVEVAR NAME="queryAssetName"/> </then> <else> <br/><XLAT.STREAM KEY="dvin/AT/Forms/ErrorOnLoad" errno="Variables.errno" queryassetvalue="queryasset.value" EVALALL="false"/> </else> </if> </THEN> <ELSE> <presentation.getvalues NAME="Variables.PresInst" LISTVARNAME="PulldownValues"/> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/NameValuePullDownParseValues"/> <if COND="IsList.PulldownValues=true"> <then> <if COND="PulldownValues.#numRows!=0"> <then> <SELECT NAME="Variables.cs_SingleInputName" id="Variables.cs_SingleInputName" REPLACEALL="Variables.cs_SingleInputName" dojoType="fw.dijit.UISimpleSelect" size="1"> <if COND="Variables.defaultFormStyle=true"> <then> <script event='startup' type='dojo/connect'> <![CDATA[ dojo.addClass(this.domNode, 'defaultFormStyle'); ]]> </script> </then> </if> <if COND="Variables.RequiredAttr!=true"> <then> <OPTION VALUE="Variables.empty" REPLACEALL="Variables.empty"> </OPTION> </then> </if> <IF COND="Variables.AttrType=asset"> <THEN> <loop LIST="PulldownValues"> <if COND="PulldownValues.assetid=Variables.MyAttrVal"> <then> <OPTION VALUE="PulldownValues.assetid" SELECTED="yes" REPLACEALL="PulldownValues.assetid"/><STRING.STREAM VALUE="PulldownValues.value"/> </then> <else> <OPTION VALUE="PulldownValues.assetid" REPLACEALL="PulldownValues.assetid"/><STRING.STREAM VALUE="PulldownValues.value"/> </else> </if> </loop> </THEN> <ELSE> <IF COND="Variables.AttrType=float"> <THEN> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"/> </THEN> <ELSE> <IF COND="Variables.AttrType=money"> <THEN> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"/> </THEN> <ELSE> <IF COND="Variables.AttrType=date"> <THEN> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"/> </THEN> <ELSE> <loop LIST="pulldownListPairs"> <STRING.ENCODE VARNAME="encodedString" VALUE="pulldownListPairs.value"/> <if COND="pulldownListPairs.value=Variables.MyAttrVal"> <then> <OPTION VALUE="Variables.encodedString" SELECTED="yes" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="pulldownListPairs.name"/> </then> <else> <OPTION VALUE="Variables.encodedString" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="pulldownListPairs.name"/> </else> </if> </loop> </ELSE> </IF> </ELSE> </IF> </ELSE> </IF> </ELSE> </IF> </SELECT> </then> <else> <XLAT.STREAM KEY="dvin/AT/Forms/NoValuesAvailable"/> </else> </if> </then> </if> </ELSE> </IF> </THEN> </IF> </td> </tr> </THEN> <ELSE> <presentation.getprimaryattributevalue NAME="Variables.PresInst" ATTRIBUTE="FONTSIZE" VARNAME="size"/> <presentation.getprimarychildvalues NAME="Variables.PresInst" ELEMENT="QUERYASSETNAME" LISTVARNAME="queryasset"/> <IF COND="IsVariable.size=false"> <THEN> <SETVAR NAME="size" VALUE="1"/> </THEN> <ELSE> <SETVAR NAME="size" VALUE="Variables.size"/> </ELSE> </IF> <tr> <callelement NAME="OpenMarket/Gator/FlexibleAssets/Common/DisplayAttributeName"/> <if COND="Variables.RequiredAttr=true"> <then> <setvar NAME="RequireInfo" VALUE="*Variables.cs_SingleInputName*Variables.currentAttrName*ReqTrue*Variables.AttrType*text!"/> </then> <else> <setvar NAME="RequireInfo" VALUE="*Variables.cs_SingleInputName*Variables.currentAttrName*ReqFalse*Variables.AttrType*text!"/> </else> </if> <td></td> <td> <setvar NAME="doDefaultDisplay" VALUE="no"/> <IF COND="IsList.queryasset=true"> <THEN> <IF COND="queryasset.#numRows!=0"> <THEN> <setvar NAME="errno" VALUE="0"/> <SETVAR NAME="assetnameOrg" VALUE="Variables.assetname"/> <if COND="IsError.Variables.errno=false"> <then> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownQueryImpl"> <ARGUMENT NAME="queryAssetName" VALUE="queryasset.value"/> </CALLELEMENT> <SETVAR NAME="assetname" VALUE="Variables.assetnameOrg"/> <REMOVEVAR NAME="queryAssetName"/> <INPUT TYPE="hidden" NAME="MSVariables.AttrName" VALUE="yes" REPLACEALL="Variables.AttrName"/> </then> <else> <br/><XLAT.STREAM KEY="dvin/AT/Forms/ErrorOnLoad" errno="Variables.errno" queryassetvalue="queryasset.value" EVALALL="false"/> </else> </if> </THEN> <ELSE> <presentation.getvalues NAME="Variables.PresInst" LISTVARNAME="PulldownValues"/> <if COND="IsList.PulldownValues=true"> <then> <if COND="PulldownValues.#numRows!=0"> <then> <setvar NAME="MyAttrVals" VALUE="Variables.empty"/> <setvar NAME="firsttime" VALUE="true"/> <if COND="IsList.AttrValueList=true"> <then> <loop LIST="AttrValueList"> <if COND="Variables.firsttime=true"> <then> <setvar NAME="firsttime" VALUE="false"/> <setvar NAME="MyAttrVals" VALUE="AttrValueList.value"/> </then> <else> <setvar NAME="MyAttrVals" VALUE="Variables.MyAttrVals_#PD#_AttrValueList.value"/> </else> </if> </loop> </then> </if> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var avialableItems_Variables.AttrID = []; </script> </REPLACEALL> <IF COND="Variables.AttrType=asset"> <THEN> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var storeStructure_Variables.AttrID = {title: 'value', value: 'assetid'}; </script> </REPLACEALL> <loop LIST="PulldownValues"> <REPLACEALL LIST="Variables.AttrID,PulldownValues.assetid,PulldownValues.value" > <script type='text/javascript'> avialableItems_Variables.AttrID.push({assetid:'PulldownValues.assetid', value:'PulldownValues.value'}); </script> </REPLACEALL> </loop> </THEN> <ELSE> <IF COND="Variables.AttrType=float"> <THEN> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var storeStructure_Variables.AttrID = {title: 'name', value: 'value'}; </script> </REPLACEALL> <loop LIST="PulldownValues"> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"> <ARGUMENT NAME="currFloatval" VALUE="PulldownValues.value"/> </CALLELEMENT> <REPLACEALL LIST="Variables.AttrID,PulldownValues.value,Variables.currFloatval" > <script type='text/javascript'> avialableItems_Variables.AttrID.push({name:'PulldownValues.value', value:'Variables.currFloatval'}); </script> </REPLACEALL> </loop> </THEN> <ELSE> <IF COND="Variables.AttrType=money"> <THEN> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var storeStructure_Variables.AttrID = {title: 'name', value: 'value'}; </script> </REPLACEALL> <loop LIST="PulldownValues"> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"> <ARGUMENT NAME="currFloatval" VALUE="PulldownValues.value"/> </CALLELEMENT> <REPLACEALL LIST="Variables.AttrID,PulldownValues.value,Variables.currFloatval" > <script type='text/javascript'> avialableItems_Variables.AttrID.push({name:'PulldownValues.value', value:'Variables.currFloatval'}); </script> </REPLACEALL> </loop> </THEN> <ELSE> <IF COND="Variables.AttrType=date"> <THEN> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var storeStructure_Variables.AttrID = {title: 'name', value: 'value'}; </script> </REPLACEALL> <loop LIST="PulldownValues"> <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/PullDownCompareValues"> <ARGUMENT NAME="currDateval" VALUE="PulldownValues.value"/> </CALLELEMENT> <REPLACEALL LIST="Variables.AttrID,PulldownValues.value,Variables.currDateval" > <script type='text/javascript'> avialableItems_Variables.AttrID.push({name:'PulldownValues.value', value:'Variables.currDateval'}); </script> </REPLACEALL> </loop> </THEN> <ELSE> <REPLACEALL LIST="Variables.AttrID" > <script type='text/javascript'> var storeStructure_Variables.AttrID = {title: 'value', value: 'value'}; </script> </REPLACEALL> <loop LIST="PulldownValues"> <REPLACEALL LIST="Variables.AttrID,PulldownValues.value" > <script type='text/javascript'> avialableItems_Variables.AttrID.push({value:'PulldownValues.value'}); </script> </REPLACEALL> </loop> </ELSE> </IF> </ELSE> </IF> </ELSE> </IF> </ELSE> </IF> <REPLACEALL LIST="Variables.id,Variables.AttrName,Variables.AttrID,Variables.cs_SingleInputName,Variables.MyAttrVals" > <div> <div id='PullDown_Variables.AttrID'></div> </div> <script type='text/javascript'> <![CDATA[ dojo.addOnLoad(function() { var nodeName = 'Variables.cs_SingleInputName'; var transferBoxStore_Variables.AttrID = new dojo.data.ItemFileReadStore ({ data: { items: avialableItems_Variables.AttrID } }); var pullDownNode = dojo.byId('PullDown_Variables.AttrID'), pullDownWid_Variables.AttrID = new fw.dijit.UITransferBox({ value: 'Variables.MyAttrVals', store: transferBoxStore_Variables.AttrID, size: 10, cs_environment: '', maxVals: -1, muliValueDelim: '_#PD#_', storeStructure: storeStructure_Variables.AttrID, name: "_" + nodeName, id:"MultiVal_Variables.AttrName_Variables.id", title1: fw.util.getString('fatwire/wem/admin/common/Available'), title2: fw.util.getString('fatwire/wem/admin/common/Selected'), queryExpr: '${0}', sort:'none', onChange: function(){ var divNode = dojo.byId('pullDownInputWrapper_Variables.AttrID'), valueStr = "", i = 0, values = this.get('value'); dojo.query("input[name=" + nodeName + "]").forEach(dojo.destroy); if (values.length === 0) values = ['']; var pullDownVCNode = dojo.query("input[name=Variables.AttrNameVC]")[0]; pullDownVCNode = values.length; dojo.forEach(values,function(v){ dojo.create('input', { type: 'hidden', name: nodeName, value: v}, divNode); }); } }, pullDownNode); dojo.safeMixin(pullDownWid_Variables.AttrID, { startup: function(){ this.inherited(arguments); var divNode = dojo.byId('pullDownInputWrapper_Variables.AttrID'), valueStr = "", i = 0, values = this.get('value'); dojo.query("input[name=" + nodeName + "]").forEach(dojo.destroy); if (values.length === 0) values = ['']; var pullDownVCNode = dojo.query("input[name=Variables.AttrNameVC]")[0]; pullDownVCNode = values.length; dojo.forEach(values,function(v){ dojo.create('input', { type: 'hidden', name: nodeName, value: v}, divNode); }); } }); pullDownWid_Variables.AttrID.startup(); }); ]]> </script> <div id="pullDownInputWrapper_Variables.AttrID"></div> </REPLACEALL> <INPUT TYPE="hidden" NAME="MSVariables.AttrName" VALUE="yes" REPLACEALL="Variables.AttrName"/> </then> <else> <XLAT.STREAM KEY="dvin/AT/Forms/NoValuesAvailable"/> </else> </if> </then> </if> </ELSE> </IF> </THEN> </IF> </td> </tr> </ELSE> </IF> </FTCS>
The changes from the built in PULLDOWN.xml are as follows:
- we make a call to another new element at line 70, <CALLELEMENT NAME="OpenMarket/Gator/AttributeTypes/NameValuePullDownParseValues"/>. We will create this element next.
- We modify line 86 to look like this, <OPTION VALUE="Variables.empty" REPLACEALL="Variables.empty"> </OPTION>.
- We change the section starting at line 119.
<loop LIST="PulldownValues"> <STRING.ENCODE VARNAME="encodedString" VALUE="PulldownValues.value"/> <if COND="PulldownValues.value=Variables.MyAttrVal"> <then> <OPTION VALUE="Variables.encodedString" SELECTED="yes" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="PulldownValues.value"/> </then> <else> <OPTION VALUE="Variables.encodedString" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="PulldownValues.value"/> </else> </if> </loop>
It now uses the new variables that we set in our new element.
<loop LIST="pulldownListPairs">
<STRING.ENCODE VARNAME="encodedString" VALUE="pulldownListPairs.value"/>
<if COND="pulldownListPairs.value=Variables.MyAttrVal">
<then>
<OPTION VALUE="Variables.encodedString" SELECTED="yes" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="pulldownListPairs.name"/>
</then>
<else>
<OPTION VALUE="Variables.encodedString" REPLACEALL="Variables.encodedString"/><STRING.STREAM VALUE="pulldownListPairs.name"/>
</else>
</if>
</loop>
The second element we'll create is OpenMarket/Gator/AttributeTypes/NameValuePullDownParseValues as noted in the listing above. It will be a JSP. Copy the code listing below into it. This element is simple but includes a helper class that makes up most of it. This element will parse our list of names values and create the list used in the XML element.
<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld" %><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld" %><%@ page import="COM.FutureTense.Interfaces.*, COM.FutureTense.Util.IterableIListWrapper, java.util.ArrayList, java.util.List, java.util.Arrays" %><cs:ftcs> <%-- Element logic --%> <% IList values = ics.GetList("PulldownValues"); // iterate the list of dropdown values from the attribute editor and split them up into name and value // and place in another list for use in the namevaluepulldown xml element DynamicIList listPairs = new DynamicIList("pulldownListPairs", new String[] {"name", "value"}); for (IList row : new IterableIListWrapper(values)) { String value = row.getValue(row.getColumnName(0)); if (value != null && !value.equals("")){ String [] parts = value.split(":"); if(parts.length == 2){ listPairs.addRow(new Object [] {parts[0], parts[1]}); } } } ics.RegisterList("pulldownListPairs", listPairs); %> <%! private class DynamicIList implements IList { private String[] columnNames; private String name = null; private int currentRow; private List<Object[]> data; public DynamicIList(String name, String... columnNames) { this.name = name; if (columnNames == null) throw new IllegalArgumentException("Can't create list without columns"); this.columnNames = columnNames; for (int i = 0; i < this.columnNames.length; i++) { this.columnNames[i] = this.columnNames[i].toLowerCase(); } this.currentRow = 0; this.data = new ArrayList<Object[]>(); } @Override public String getName() { return name; } @Override public boolean hasData() { return data.size() > 0; } @Override public int numColumns() { return columnNames.length; } @Override public int currentRow() { return currentRow + 1; } @Override public String getValue(String s) throws NoSuchFieldException { return String.valueOf(getObject(s)); } @Override public Object getObject(String s) throws NoSuchFieldException { return data.get(currentRow)[findColIndex(s)]; } private int findColIndex(String colName) throws NoSuchFieldException { int idx = 0; colName = colName.toLowerCase(); for(; idx < columnNames.length; idx++) { if (colName.equals(columnNames[idx])) { return idx; } } throw new NoSuchFieldException(colName); } @Override public byte[] getFileData(String s) throws IllegalArgumentException, NoSuchFieldException { throw new UnsupportedOperationException(); } @Override public String getFileString(String s) throws NoSuchFieldException { throw new UnsupportedOperationException(); } @Override public void flush() { data.clear(); currentRow = 0; } @Override public String getColumnName(int i) throws ArrayIndexOutOfBoundsException { return columnNames[i]; } @Override public int numRows() { return data.size(); } @Override public boolean moveTo(int i) { if (i <= data.size()) { currentRow = i - 1; return true; } return false; } @Override public boolean atEnd() { return currentRow == data.size(); } @Override public boolean moveToRow(int how, int i) { if (how == first) return moveTo(1); if (how == last) return moveTo(data.size()); if (how == gotorow) return moveTo(i); if (how == next) return moveTo(currentRow+2); if (how == prev) return moveTo(currentRow); return false; } @Override public int numIndirectColumns() { return 0; } @Override public String getIndirectColumnName(int i) { return null; } @Override public IList clone(String s) { String[] newCols = new String[columnNames.length]; System.arraycopy(columnNames,0,newCols,0, columnNames.length); DynamicIList list = new DynamicIList(s, newCols); for (Object[] row : data) { Object[] newRow = new Object[columnNames.length]; System.arraycopy(row, 0, newRow, 0, columnNames.length); list.addRow(newRow); } return list; } @Override public void rename(String s) { name = s; } @Override public boolean stringInList(String s) { for (Object[] row : data) { for (Object o : row) { if (o.equals(s)) return true; } } return false; } /** * Add a row to the existing IList. Row data must be added in the exact same column order * that corresponds to the column names stored in the list. * @param rowData array of row data, matching the column order */ public void addRow(Object ... rowData) { if (rowData.length == columnNames.length) { data.add(rowData); } else { throw new IllegalArgumentException("Columns don't match. Expect "+columnNames.length+" columns"); } } public void addColumn(String name, List<String> columnData){ List<String> temp = new ArrayList<String>(Arrays.asList(columnNames)); temp.add(name); columnNames = temp.toArray(new String[temp.size()]); for(int i = 0; i < columnData.size(); i++){ List<Object> tempRow = new ArrayList<Object>(Arrays.asList(data.get(i))); tempRow.add(columnData.get(i)); data.set(i,tempRow.toArray()); } } } %> </cs:ftcs>
The final element we need is one that will be used to display the asset form when it's not in edit mode. If we don't include this then the right value won't be selected.
Create another JSP element called OpenMarket/Gator/AttributeTypes/DisplayNameValuePullDown, copy the listing below into it.
<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld" %><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld" %><%@ page import="COM.FutureTense.Interfaces.*, COM.FutureTense.Util.IterableIListWrapper" %><cs:ftcs> <%-- Element logic --%> <% // get the current value of the attribute // use it to look up the display name String selectedValue = ics.GetVar("ContentDetails:Attribute_" + ics.GetVar("AttrName")); String displayValue = ""; // this needs to be set or else the output of this element will be ignored ics.SetVar("doDefaultDisplay", "no"); // get the list of values from our attribute editor FTValList args = new FTValList(); args.setValString("NAME", ics.GetVar("PresInst")); args.setValString("LISTVARNAME", "PulldownValues"); ics.runTag("presentation.getvalues", args); // loop the list of editor values and then parse them and do the lookup // break once we find the name to match our value key IList values = ics.GetList("PulldownValues"); if (values != null){ for (IList row : new IterableIListWrapper(values)) { String value = row.getValue(row.getColumnName(0)); if (value != null && !value.equals("")){ String [] parts = value.split(":"); if(parts.length == 2){ if (parts[1].equals(selectedValue)){ displayValue = parts[0]; break; } } } } } %> <ics:callelement element="OpenMarket/Xcelerate/UIFramework/Util/RowSpacer" /> <tr> <ics:callelement element="OpenMarket/Gator/FlexibleAssets/Common/DisplayAttributeName" /> <td></td> <td class="form-inset"> <span><%=displayValue %></span> </td> </tr> </cs:ftcs>
For the final step, we'll need to update the presentationobject.dtd file in sites. At the top where all the elements are defined and separated by |, add another "| NameValuePULLDOWN". Further down, where each editor is defined, add the following section:
<!ELEMENT NameValuePULLDOWN ((ITEM)* | QUERYASSETNAME)>
<!ATTLIST NameValuePULLDOWN FONTSIZE CDATA #IMPLIED>
Note: Your server/JSK needs to be restarted for the changes to this file to take effect.
Now we have a pulldown list that allows the user to create an asset with the choices of (Red, Green, Blue), but also saves the HTML color code value behind the scenes. You can now easily create additional attribute editors by modifying the choices present in the XML field to use with other attributes. This allows you to present names/keys that make sense to users creating sites content but with values that can be useful value to a developer building the templates to display the content.
- Log in to post comments