The functions in the FilmFunctions UDF library (refer to Table 22.4) are all related to the film concept, which is in turn somewhat related to the Films table in the ows database. As such, the library is really of interest only to the developers working on the Orange Whip Studios site. It's not going to be of much use to other ColdFusion developers. It is, however, possible to create user-defined functions that have no ties to a particular application. You can think of such functions as general-purpose functions. They are useful for many different types of applications. For instance, consider the javaScriptPopupLink() function used internally by the FilmFunctions library in Listing 22.4. That function isn't expecting any input that is specific to Orange Whip Studios or any other type of application. And its purposeto create pop-up windows easilymight come in handy in any Web-based application. Things to ConsiderYou don't need to do anything special to create a general-purpose function. Go ahead and use the same <cffunction>, <cfargument>, and <cfreturn> syntax you have already learned about. Just bear these things in mind as you go along: Keep the list of arguments as short as possible. ColdFusion will let you create UDFs with many, many arguments, but such functions quickly become unwieldy. If you feel you need to have lots of arguments, consider creating a CFML Custom Tag instead, as discussed in the next chapter. Keep code reuse in mind. If the problem at hand has both an application-specific aspect and a general-purpose aspect, try to isolate the two parts of the problems in two different functions. For instance, the problem of displaying a pop-up window about a film has an application-specific aspect (the film) and a general-purpose aspect (the pop-up window). By creating two different functions, you can reuse the pop-up aspect in situations that don't have anything to do with films. In Chapter 23, you will learn how to create your own Custom Tags and Components (CFCs) as well as functions. Custom Tags are significantly more powerful and flexible than custom functions. Try to use UDFs for simple matters, especially quick retrieval and formatting. Use Custom Tags and Components for more involved processes, especially those you can think of as discrete actions rather than simple "massaging." Writing the SimpleJavaScriptFunctions LibraryAs an example of a general-purpose UDF library, let's consider the SimpleJavaScriptFunctions.cfm library we used earlier, in Listing 22.4. Presently, this library contains only one function, javaScriptPopupLink(), which is responsible for creating a link that opens a pop-up window when clicked. This function supports four arguments, as listed in Table 22.5.
NOTE The popupWidth, popupHeight, popupTop, and popupLeft arguments correspond to the width, height, top, and left values supported by the JavaScript window.open() method. Consult a JavaScript reference for details The function uses all these pieces of information to assemble the HTML code for an anchor element (that is, an <a href> tag) containing the appropriate JavaScript code to get the desired effect. The code is returned as the function's result (as a string). Listing 22.6 is the ColdFusion code required to create javaScriptPopupLink(). NOTE The goal here isn't to teach you about JavaScript (that would take a whole book in itself), but rather to show you how you can distill something like JavaScript code and package it into a UDF for your ColdFusion pages. The nice thing about this kind of abstraction is that people can use the UDF without needing to understand the JavaScript code it generates. Listing 22.6. SimpleJavaScriptFunctions.cfmCreating a General-Purpose UDF<!--- Filename: SimpleJavaScriptFunctions.cfm Created by: Nate Weiss (NMW) Purpose: Creates a library of ColdFusion functions that encapsulate JavaScript ideas ---> <!--- Function: JavaScriptPopupLink() ---> <!--- Returns an HTML link that opens a pop-up window via JavaScript ---> <cffunction name="javaScriptPopupLink" returnType="string" output="false"> <!--- One argument: FilmID ---> <cfargument name="linkURL" type="string" required="Yes"> <cfargument name="linkText" type="string" required="Yes"> <cfargument name="popupWidth" type="numeric" default="300"> <cfargument name="popupHeight" type="numeric" default="200"> <cfargument name="popupTop" type="numeric" default="200"> <cfargument name="popupLeft" type="numeric" default="300"> <!--- These variables are for this function's use only ---> <cfset var features = ""> <cfset var linkCode = ""> <!--- Window features get passed to JavaScript's window.open() command ---> <cfset features = "width=#ARGUMENTS.PopupWidth#," & "height=#ARGUMENTS.PopupHeight#,top=#ARGUMENTS.PopupTop#," & "left=#ARGUMENTS.PopupLeft#,scrollbars=yes"> <!--- Create variable called LinkCode, which contains HTML / JavaScript ---> <!--- needed to display a link that creates a pop-up window when clicked ---> <cfsavecontent variable="linkCode"> <cfoutput> <a href="#ARGUMENTS.linkURL#" onclick=" popupWin = window.open('#ARGUMENTS.linkURL#','myPopup','#features#'); popupWin.focus(); return false;" onmouseover="window.status = '#JSStringFormat(ARGUMENTS.LinkText)#';return true;" onmouseout="window.status = ''; return true;" >#ARGUMENTS.LinkText#</a> </cfoutput> </cfsavecontent> <!--- Return the completed link code ---> <cfreturn linkCode> </cffunction> NOTE This listing includes some JavaScript code, such as window.open(), focus(), window.status, and return true. These are very basic JavaScript concepts. If you aren't familiar with them, consult any reference or online guide. As with the earlier UDF examples in this chapter, the first thing this code does is define the function's arguments with the <cfargument> tag. This is actually the first UDF example that accepts more than one argument. As you can see, you can add as many arguments as you like. Just don't get totally carried away, since functions with dozens of arguments will probably be somewhat harder to use. Next, a variable called features is created; this is the list of "window features" that will be supplied to the JavaScript window.open() method. You can find out more about how to specify window features in a JavaScript reference guide, but the basic idea is that this describes the physical pop-up window, including its position and size. When the function executes, the value of features will be something like this (depending on the actual arguments used): width=300,height=200,top=200,left=300,scrollbars=yes The next block of code uses the <cfsavecontent> tag to create a variable named linkCode. ColdFusion will process and evaluate all the code between the opening and closing <cfsavecontent> tags, then assign the final result to the linkCode variable. This makes it easier to create a variable that contains multiple lines, a variety of quotation marks, and so on. In this kind of situation, it's a lot easier than using the <cfset> tag. You can even use tags like <cfloop> within this type of block. That said, a <cfset> (or several <cfset> tags) would work equally well. The code might just be a bit harder to follow. Within the <cfsavecontent> block, the basic idea is to generate a normal HTML <a> tag, with a normal href attribute. In addition to the href attribute, the <a> tag is also given onclick, onmouseover, and onmouseout attributes. These attributes contain JavaScript code that will execute when the user clicks the link, hovers over the link, and hovers away from the link, respectively. NOTE It is also necessary to use a pair of <cfoutput> tags here to force ColdFusion to evaluate the variables and expressions within this block. The final result (after all number signs (#), tags, and functions have been evaluated) is "captured" by <cfsavecontent> and placed into the linkText variable. See Appendix B for details. The result is the behavior shown earlier in Figure 22.2: when the user clicks the link, a pop-up window appears. If the user's browser doesn't support JavaScript, or if scripting has been disabled, the Film Details page simply appears in the main window (as a normal link would). You can use your browser's View Source option to examine the final HTML and JavaScript code that gets sent to the browser. Another Example Library: ColorFunctionsAt this point, you know just about everything you need to know for creating user-defined functions with ColdFusion MX. Our companion volume, Advanced ColdFusion MX Application Development, has a chapter called "Advanced User-Defined Functions," which covers a few scenarios not discussed here. It also discusses creating UDFs with <cfscript> instead of the <cffunction> tag. Now it's up to you to create the UDFs you need for your own applications! Just to get your brain spinning, I have included the code for another general-purpose UDF library called ColorFunctions.cfm. This UDF library contains three functions, as listed in Table 22.6.
Once you include this UDF library with a <cfinclude> tag, you could use any of these functions in your own templates. For instance, on a Web page, the following would display the message "Hello, World" in a random color: <cfoutput> <div style="color:#getRandColor()#">Hello, World</div> </cfoutput> And this would display the following sentence about two cute forest critters, with each word colored randomly: <cfoutput> #multicolorFormat("The quick red fox jumped over the lazy bear.")# </cfoutput> Listing 22.7 shows the <cffunction> code for the three functions listed above. The code for each of the individual functions is pretty simple. The purpose of this listing is to get you thinking about what kinds of operations UDFs can encapsulate. That said, you are invited to study this listing or adapt it to serve some other purpose. Refer to Appendix C, "ColdFusion Function Reference," for details about the listGetAt(), randRange(), and listLen(), functions used here. Listing 22.7. ColorFunctions.cfmA Library of Functions Related to Colors<!--- Filename: ColorFunctions.cfm Created by: Nate Weiss (NMW) Purpose: Creates a library of user-defined functions related to colors in the browser safety palette ---> <!--- Function: ListGetRandom() ---> <!--- Returns a random element from any comma-separated list ---> <cffunction name="listGetRand" output="false" returnType="string"> <!--- First argument: The comma-separated list ---> <cfargument name="list" type="string" required="Yes"> <!--- Second argument: List delimiter. Default to comma ---> <cfargument name="delim" type="string" required="false" default=","> <cfreturn listGetAt(ARGUMENTS.list, randRange(1, listLen(ARGUMENTS.list, ARGUMENTS.delim)), ARGUMENTS.delim)> </cffunction> <!--- Function: GetRandColor() ---> <!--- Returns a random color in proper html color format ---> <cffunction name="getRandColor" output="false" returnType="string"> <!--- This is a list of hexidecimal values that can be used to specify colors for use on Web pages. Any three of these can be combined to make a color, in the form RRGGBB. For instance, 9900CC is a nice shade of purple. ---> <cfset var hexList = "00,11,22,33,44,55,66,77,88,99,AA,BB,CC,DD,EE,FF"> <!--- Choose 3 of the Hex values randomly and return them all together ---> <cfreturn listGetRand(hexList) & listGetRand(hexList) & listGetRand(hexList)> </cffunction> <!--- Function: MulticolorFormat() ---> <!--- Adds <font> tags to any text such that each word is colored randomly ---> <cffunction name="multicolorFormat" output="false" returnType="string"> <!--- One argument: the text to make multicolored ---> <cfargument name="text" type="string" required="Yes"> <!--- This is what we will end up returning. Start with an empty string. ---> <cfset var string = ""> <cfset var word = ""> <!--- Loop through the list of words, treating spaces as list delimiters ---> <cfloop list="#ARGUMENTS.text#" index="word" delimiters=" "> <!--- Create a <font> tag for this word, using a random color ---> <cfset string = string & ' <font color="#getRandColor()#">#word#</font>'> </cfloop> <!--- Return completed string ---> <cfreturn string> </cffunction> |