The following tree uses the cfartgallery database to populate a tree where the top level is the art medium, the second level is the artist, and the leaf nodes are individual works of art. When the user clicks on an art work, the application shows the art image.
This example shows how to generate return values that are specific to the level in the tree and the parent value and the use of the LEAFNODE return structure element.
In this application, the CFC return structure keys are specified in lowercase letters, and ColdFusion automatically converts them to uppercase. Notice that the database contains entries only for the painting, sculpture, and photography categories, so just those top-level tree nodes have child nodes.
The following examples shows the main application page:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <!--- The loadimage function displays the image of the selected art. It is called when the user clicks the image item. ---> <script> function loadImage(img) { var imgURL = '<img src="/cfdocs/images/artgallery/'+img+'">'; var imgDiv = document.getElementById('image'); imgDiv.innerHTML = imgURL; } </script> </head> <body> <!--- The form uses a table to place the tree and the image. ---> <cfform name="ex1" action="ex1.cfm" method="post"> <table> <tr valign="top"> <td> <cftree name="mytree" format="html"> <!--- When you use a bind expression, you must have only one cftreeitem, which populates the tree level. ---> <cftreeitem bind="cfc:tree.getItems({cftreeitempath}, {cftreeitemvalue})"> </cftree> </td> <td> <div id="image"></div> </td> </tr> </table> </cfform> </body> </html>
The following example shows the tree.cfc file:
<cfcomponent output="false"> <cfset variables.dsn = "cfartgallery"> <!--- Function to populate the current level of the tree. ---> <cffunction name="getItems" returnType="array" output="false" access="remote"> <cfargument name="path" type="string" required="false" default=""> <cfargument name="value" type="string" required="false" default=""> <cfset var result = arrayNew(1)> <cfset var q = ""> <cfset var s = ""> <!--- The cfif statements determine the tree level. ---> <!--- If there is no value argument, The tree is empty. Get the media types. ---> <cfif arguments.value is ""> <cfquery name="q" datasource="#variables.dsn#"> SELECT mediaid, mediatype FROM media </cfquery> <cfloop query="q"> <cfset s = structNew()> <cfset s.value = mediaid> <cfset s.display = mediatype> <cfset arrayAppend(result, s)> </cfloop> <!--- If the value argument has one list entry, its a media type. Get the artists for the media type.---> <cfelseif listLen(arguments.value) is 1> <cfquery name="q" datasource="#variables.dsn#"> SELECT artists.lastname, artists.firstname, artists.artistid FROM art, artists WHERE art.mediaid = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.value#"> AND art.artistid = artists.artistid GROUP BY artists.artistid, artists.lastname, artists.firstname </cfquery> <cfloop query="q"> <cfset s = structNew()> <cfset s.value = arguments.value & "," & artistid> <cfset s.display = firstName & " " & lastname> <cfset arrayAppend(result, s)> </cfloop> <!--- We only get here when populating an artist's works. ---> <cfelse> <cfquery name="q" datasource="#variables.dsn#"> SELECT art.artid, art.artname, art.price, art.description, art.largeimage, artists.lastname, artists.firstname FROM art, artists WHERE art.mediaid = <cfqueryparam cfsqltype="cf_sql_integer" value="#listFirst(arguments.value)#"> AND art.artistid = artists.artistid AND artists.artistid = <cfqueryparam cfsqltype="cf_sql_integer" value="#listLast(arguments.value)#"> </cfquery> <cfloop query="q"> <cfset s = structNew()> <cfset s.value = arguments.value & "," & artid> <cfset s.display = artname & " (" & dollarFormat(price) & ")"> <cfset s.href = "javaScript:loadImage('#largeimage#');"> <cfset s.children=arrayNew(1)> <!--- leafnode=true prevents node expansion and further calls to the bind expression. ---> <cfset s.leafnode=true> <cfset arrayAppend(result, s)> </cfloop> </cfif> <cfreturn result> </cffunction> </cfcomponent>
Binding other controls to a tree
ColdFusion tags that use bind expressions can bind to the selected node of a tree by using the following formats:
The bind expression is evaluated each time a select event occurs on an item in the tree. If you specify any other event in the bind parameter, it is ignored.
You can use the following JavaScript functions to manage an HTML format tree:
Function |
Description |
---|---|
ColdFusion.Tree.getTreeObject |
Gets the underlying Yahoo User Interface Library TreeView JavaScript object. |
ColdFusion.Tree.refresh |
Manually refreshes a tree. |
For more information, see the ColdFusion.Tree.getTreeObject and ColdFusion.Tree.refresh functions in the CFML Reference.
The ColdFusion rich text editor lets users enter and format rich HTML text by using an icon-driven interface based on the open source FCKeditor Ajax widget. The editor includes numerous formatting controls, and icons for such standard operations as searching, printing, and previewing text. This topic does not cover the text editor controls. For detailed information on the editor icons and controls, see http://wiki.fckeditor.net/UsersGuide.
The following example shows a simple rich text editor. When a user enters text and clicks the Enter button, the application refreshes and displays the formatted text above the editor region.
<html xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> <!--- Display the text if the form has been submitted with text. ---> <cfif isdefined("form.text01") AND (form.text01 NEQ "")> <cfoutput>#form.text01#</cfoutput><br /> </cfif> <!--- A form with a basic rich text editor and a submit button. ---> <cfform name="form01" > <cftextarea richtext=true name="text01" /> <cfinput type="submit" value="Enter" name="submit01"/> </cfform> </body> </html>
Configuring the rich text editor
You can customize the rich text editor in many ways. The cftextarea attributes support some basic customization techniques. For more detailed information, see the FCKEditor website at http://wiki.fckeditor.net/.
You can use the following techniques to control the appearance of the toolbar:
The editor has a single toolbar consisting of a set of active icons and fields, and separators. The toolbar attribute lets you select the toolbar configuration. The attribute value specifies the name of a toolbar set, which you define in a FCKConfig.ToolbarSets entry in the cf_webRoot/CFIDE/scripts/ajax/FCKEditor/fckconfig.js file.
The rich text editor comes configured with two toolbar sets: the Default set, which contains all supported editing controls, and a minimal Basic set. By default, the editor uses the Default set. To create a custom toolbar named BasicText with only text-editing controls, create the following entry in the fckconfig.js file, and specify toolbar="BasicText" in the textarea tag.
FCKConfig.ToolbarSets["BasicText"] = [ ['Source','DocProps','-','NewPage','Preview'], ['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'], ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'], ['Bold','Italic','Underline'], ['Outdent','Indent'], ['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'], '/', ['Style','FontFormat','FontName','FontSize'], ['TextColor','BGColor'], ['FitWindow','-','About'] ];
This configuration defines a toolbar with two rows that contain a subset of the full tool set designed to support basic text editing.
Follow these rules when you define a toolbar:
For a complete list of the valid toolbar entries, see the Default configuration in fckconfig.js.
You can add custom styles that users can chose in the Styles selector and apply to selected text. To create a custom style, add a Style element to /CFIDE/scripts/ajax/FCKEditor/fckstyles.xml. The Style XML element has the following format:
For example, the following definition creates a style that makes the selected text bold and underlined:
<Style name="Custom Bold And Underline " element="span"> <Attribute name="style" value="font-weight: bold; text-decoration: underline;"/> </Style>
You can use a custom XML file, instead of fckstyles.xml, to define your styles. If you do so, specify the filepath in the stylesXML attribute.
The editor includes a set of basic templates that insert HTML formatting into the textarea control. For example, the Image and Title template puts a placeholder for an image on the left of the area, and a title and text to the right of the image. Then you can right-click the image area to specify the image source and other properties, and replace the placeholder title and text.
You create your own templates by creating entries in cf_webRoot/CFIDE/scripts/ajax/FCKEditor/fcktemplates.xml file. Each template XML entry has the following format:
<Template title="template title" image="template image">
<Description>template description</Description>
<Html>
<![CDATA[
HTML to insert in the text area when the user selects the template.
]]>
</Html>
</Template>
The template title, image and description appear in the Templates dialog box that appears when the user clicks the template icon on the rich text editor toolbar.
The following example template defines a title followed by text:
<Template title="Title and Text" image="template1.gif"> <Description>A Title followed by text.</Description> <Html> <![CDATA[ <h3>Type the title here</h3> Type the text here ]]> </Html> </Template>
The name "Title and Text" and the template1.gif image appear in the template selection dialog box.
You can use a custom XML file, instead of fcktemplates.xml, to define your templates. If you do so, specify the file path in the templatesXML attribute.
To create a custom skin that you can specify in the skin attribute, create a subdirectory of the cf_webRoot/CFIDE/scripts/ajax/FCKeditor/editor/skins directory. The name of this subdirectory is the name that you use to specify the skin in the skin attribute. The custom skin directory must contain an images subdirectory and have the following files:
Place all other images used by the skin (those that are specified in the CSS files) in the images subfolder.
The most common way of customizing the skin is to make changes to the fck_editor.css and fck_dialog.css files. For information on the skin format and contents, see the comments in those files.
The HTML format cfinput control with a type value of datefield lets users select dates from a pop-up calendar or enter the dates directly in the input box. When you use the control, you must keep the following considerations in mind:
The following example shows a simple tabbed layout where each tab contains a form with several datefield controls.:
<html> <head> </head> <body> <cflayout type="tab" tabheight="250px" style="width:400px;"> <cflayoutarea title="test" overflow="visible"> <br> <cfform name="mycfform1"> <div style="float:left;">Date 1: </div> <cfinput type="datefield" name="mydate1"><br><br><br> <div style="float:left;">Date 2: </div> <cfinput type="datefield" name="mydate2" value="15/1/2007"><br><br><br> <div style="float:left;">Date 3: </div> <cfinput type="datefield" name="mydate3" required="yes"><br><br><br> <div style="float:left;">Date 4: </div> <cfinput type="datefield" name="mydate4" required="no"><br><br><br> </cfform> </cflayoutarea> <cflayoutarea title="Mask" overflow="visible"> <cfform name="mycfform2"> <br> <div style="float:left;">Date 1: </div> <cfinput type="datefield" name="mydate5" mask="dd/mm/yyyy"> (dd/mm/yyyy)<br><br><br> <div style="float:left;">Date 2: </div> <cfinput type="datefield" name="mydate6" mask="mm/dd/yyyy"> (mm/dd/yyyy)<br><br><br> <div style="float:left;">Date 3: </div> <cfinput type="datefield" name="mydate7" mask="d/m/yy"> (d/m/yy)<br><br><br> <div style="float:left;">Date 4: </div> <cfinput type="datefield" name="mydate8" mask="m/d/yy"> (m/d/yy)<br><br><br> </cfform> </cflayoutarea> </cflayout> </body> </html>
When you create a text input (type="text") in an HTML format form, you can use the autosuggest attribute to specify a static or dynamic source that provides field completion suggestions as the user types. Use the autosuggestMinLength attribute to specify the number of characters the user must type before first displaying any suggestions.
<div style="float: left"> Name: </div> <cfinput name="userName" type="text" autosuggest="Andrew, Jane, Robert"> <br><br><br>
The control can suggest entries from a static list of values. To use a static suggestion list, specify the list entries in the autosuggest attribute, and separate the entries by the character specified by the delimiter attribute (by default, a comma), as the following example shows:
<cfinput type="text" autosuggest="Alabama,Alaska,Arkansas,Arizona,Maryland,Minnesota,Missouri" name="city" delimiter="\">
In this example, if you type the character a (in uppercase or lowercase) in the cfinput control, the list of states that start with A appears in a drop-down list. You navigate to a selection by using the arrow keys, and press Enter to select the item.
You can also have the control suggest values from a dynamically generated suggestion list. To use a dynamic list, specify a CFC function, JavaScript function, or URL in the autosuggest attribute. Use the autosuggestBindDelay attribute to specify the minimum time between function invocations as the user types, and thereby limit the number of requests that are sent to the server. If you use a dynamic list, the input field has an icon to its right that animates while suggestions are fetched.
When you use a bind expression you must include a {cfautosuggestvalue} bind parameter in the function call or URL parameters. This parameter binds to the user input in the input control and passes it to the function or page.
A CFC or JavaScript autosuggest function must return the suggestion values as a one-dimensional array or as a comma-delimited list.
The HTTP response body from a URL must consist only of the array or list of suggestion values in JSON format. In ColdFusion you can use the serializeJSON function to convert an array to JSON format. If an array with the suggestions is named nodeArray, for example, the following line would specify the only output on a CFML page that is called by using a bind expression with a URL:
<cfoutput>#serializeJSON(nodeArray)#</cfoutput>
You do not have to limit the returned data to values that match the cfautosuggestvalue contents, because the client-side code displays only the values that match the user input. In fact, the called function or page does not even have to use the value of the cfautosuggestvalue parameter that you pass to it. You should, however, use the parameter if the returned data would otherwise be long.
The following example shows how you can a bind expression to populate autosuggest lists. The Last Name text box displays an autosuggest list with all last names in the database that match the keys typed in the box. The First Name text box uses binding to the Last Name text box to display only the first names that correspond to the last name and the text entered in the box. The database query limits the responses to only include results that match the autosuggest criteria, so the autosuggest list displays all the returned results, and the suggestions only match if the database entry has a case-correct match.
To test this example with the cfdocexamples database, type S in the first box and the autosuggest list shows Smith and Stewart. If you select Smith and enter A or J in the First Name box, you get a name suggestion.
The following example shows the application:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> <cfform> Last Name:<br /> <cfinput type="text" name="lastName" autosuggest="cfc:suggestcfc.getLNames({cfautosuggestvalue})"><br /> <br /> First Name:<br /> <cfinput type="text" name="firstName" autosuggest="cfc:suggestcfc.getFNames({cfautosuggestvalue},{lastName})"> </cfform> </body> </html>
The following example shows the suggestcfc.cfc file:
<cfcomponent> <cffunction name="getLNames" access="remote" returntype="array" output="false"> <cfargument name="suggestvalue" required="true"> <!--- The function must return suggestions as an array. ---> <cfset var myarray = ArrayNew(1)> <!--- Get all unique last names that match the typed characters. ---> <cfquery name="getDBNames" datasource="cfdocexamples"> SELECT DISTINCT LASTNAME FROM Employees WHERE LASTNAME LIKE <cfqueryparam value="#suggestvalue#%" cfsqltype="cf_sql_varchar"> </cfquery> <!--- Convert the query to an array. ---> <cfloop query="getDBNames"> <cfset arrayAppend(myarray, lastname)> </cfloop> <cfreturn myarray> </cffunction> <cffunction name="getFNames" access="remote" returntype="array" output="false"> <cfargument name="suggestvalue" required="true"> <cfargument name="lastName" required="true"> <cfset var myarray = ArrayNew(1)> <cfquery name="getFirstNames" datasource="cfdocexamples"> <!--- Get the first names that match the last name and the typed characters. ---> SELECT FIRSTNAME FROM Employees WHERE LASTNAME = <cfqueryparam value="#lastName#" cfsqltype="cf_sql_varchar"> AND FIRSTNAME LIKE <cfqueryparam value="#suggestvalue & '%'#" cfsqltype="cf_sql_varchar"> </cfquery> <cfloop query="getFirstNames"> <cfset arrayAppend(myarray, Firstname)> </cfloop> <cfreturn myarray> </cffunction> </cfcomponent>