Paired Custom Tags


All of the custom tags you've seen here so far are called empty custom tags because they do not span a region of content or code. Paired custom tags do span, or "wrap," a region of content or code, and act upon that region in some way. You deal with this concept every day; for example:

 <b>I am the very model of a modern major-general.</b> 

The HTML Bold element is a typical paired tag that acts on the span of content between its opening and closing tags. This may seem like baby steps to you, but the exact same process is applied to ColdFusion paired custom tags.

Essentially, a paired tag of any kind always executes twiceonce for the opening tag (Start mode) and once for the closing tag (End mode)and performs a distinct operation in both Start mode and End mode. The HTML Bold tag, for example, in the opening tag establishes the beginning of the content to be modified; the closing tag establishes the end of that content as well as instructs the browser to boldface the content. As you continue reading, keep in mind this concept of a paired tag executing twice and doing something different in each execution.

The Execution Cycle

A paired custom tag goes through three modes of execution, in order, when it is called:

1.

Start mode, which executes immediately after the opening tag, and triggers the first execution of the paired custom tag.

2.

Inactive mode, which is the idle period between the opening and closing tags.

3.

End mode, which executes immediately after the closing tag, and triggers the second execution of the paired custom tag.

In a ColdFusion paired custom tag, the opening tag triggers the first execution, during which ThisTag.ExecutionMode is "Start". ThisTag is a special scope that exists within custom tags and refers to specific properties of the custom tag, such as its current execution mode, whether the custom tag has an end tag (as a paired tag would), and more, as you'll see later in this chapter.

After the first execution of the paired custom tag, the tag goes into Inactive mode during which time the contents in the body of the tag are accumulated into ThisTag.GeneratedContent. The closing tag then triggers the second execution of the paired custom tag, during which ThisTag.ExecutionMode is "End".

You separate Start mode logic from End mode logic using a simple If construct:

 <cfif ThisTag.ExecutionMode EQ "Start"> <cfelse> </cfif> 

We only test for ThisTag.ExecutionMode EQ "Start" and assume that the <cfelse> clause refers to the End mode, even though there are two other execution modes besides Start. This is because Inactive mode isn't actually executed; it's an "idle" mode during which the content is accumulated into ThisTag.GeneratedContent.

Like any other type of custom tag, a paired custom tag may take attributes that can be passed to the logic in the custom tag to modify its behavior. These attributes become part of the Attributes scope just as they do in other types of custom tags. Because attributes are always passed in an opening tag, those attributes are "seen" by and can therefore be used by logic in the Start mode of the paired custom tag. Once an execution mode gains access to something, any other execution modes that follow will also have access; therefore, because the Start mode can access the attributes passed into the tag, so will the Inactive and End modes.

NOTE

The Inactive mode doesn't do any processing of its own, but you'll learn later that it passes process flow to any child tags nested in the body (between the opening and closing tags) of the paired tag. Those child tags can then gain access to the objects seen by their parent tag's Start mode.


The Start mode may execute logic or output content, but it can neither see nor modify any content or code in the body of the paired tag. The Inactive mode is the first point at which the content in the body of the paired tag can be seen, but the only thing the Inactive mode can do with this content is accumulate it into a special variable. The End mode, which can see, access, and modify everything that happened in the execution modes before it, is therefore the most powerful execution mode, and as such it's often where the majority of paired custom tag logic is executed.

Figure 18.1 sums up the execution modes that a paired tag goes through and what typically happens in each mode.

Figure 18.1. The execution cycle of a paired custom tag.


Confusion often exists about ColdFusion paired custom tags because of their added ability to programmatically modify the content in the span between the opening and closing tags, but you'll soon see how to visualize the process in a very simple way that eliminates confusion.

Let's look at a practical example of a paired custom tag that wraps a relatively large passage of content and outputs only a specified portion of that content formatted in a DIV container. We'll call the custom tag truncateQuote, and it's called like this:

[View full width]

<cf_TruncateQuote numberOfCharacters="125"> Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation or any nation so conceived and so dedicated can long endure. We are met on a great battlefield of that war. We have come to dedicate a portion of that field as a final resting-place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. </cf_TruncateQuote>

If you'd like to try this out, type the above call to <cf_TruncateQuote> in a file named Test.cfm.

Listing 18.1 shows cf_TruncateQuote's code, and Figure 18.2 displays the result of calling it. As long as you save this custom tag file within the same directory as the page that calls it (Test.cfm), you can run the calling page and see the results.

Listing 18.1. truncateQuote.cfmImplementing a Paired Tag

[View full width]

 <!--- Author: Adam Phillip Churvis -- ProductivityEnhancement.com ---> <!--- Truncates and formats a body of text ---> <cfparam name="Attributes.numberOfCharacters" type="numeric" default="300"> <cfif ThisTag.ExecutionMode EQ "Start">   <div style="border: 1px solid Black; width:300px;"> <cfelse>   ...   </div>   <cfset ThisTag.GeneratedContent = Left(ThisTag.GeneratedContent, Attributes .numberOfCharacters)> </cfif> 

Figure 18.2. The result of calling cf_TruncateQuote on The Gettysburg Address.


The most confusing thing for most developers is why that ellipsis appears at the end of the truncated quote and not before, since it appears in order in the code. The answer lies in how content is accumulated during the Inactive mode and modified in the End mode.

The Concept of GeneratedContent

As mentioned earlier, during Inactive mode a paired custom tag accumulates the content that spans the range between the opening and closing tags into a special variable named ThisTag.GeneratedContent. Since a paired custom tag has only two opportunities to run (once in Start mode and once in End mode), and since you can't yet see or modify ThisTag.GeneratedContent in the Start mode, the only place you can modify ThisTag.GeneratedContent is in the End mode. In the same way that the closing HTML Bold tag modifies the contents between it and the opening tag, so does ColdFusion by manipulating ThisTag.GeneratedContent in the End mode.

But why does the ellipsis appear at the end? It's because of the way ColdFusion prepares and outputs the results of running a paired custom tagsort of like preparing a sandwich in reverse (from the top down) and then serving it, as Figure 18.3 shows.

Figure 18.3. The "sandwich" model of how paired custom tags generate output.


ColdFusion gathers into a buffer any content that is output during Start mode. Then in Inactive mode the content accumulated in ThisTag.GeneratedContent is added to the buffer. Then in End mode any content that is output directly during the End mode is added to the buffer. Any manipulation of ThisTag.GeneratedContent by the End mode is performed after this "sandwich" has been assembled in order. The completed package is then output from the buffer as a single chunk of content.

So even though the ellipsis appeared before the manipulation of ThisTag.GeneratedContent, the ellipsis was directly output by the End mode, so it was placed after ThisTag.GeneratedContent.

Custom Tags That May Be Called as Paired or Empty

There are times when you might need similar functionality that applies to an entire ColdFusion page or only a section of a page, but that behaves a little differently in each case. For example, you might want to create a custom tag that makes checking for authentication and authorization easy to apply. So if you wanted to ensure that users attempting to access a ColdFusion page were both authenticated and authorized with the ADMIN role, you could call the custom tag as an empty (nonpaired) tag at the top of the page like this:

 <cf_Auth roles="ADMIN"> <p>You won't see this page unless you're logged in and have been assigned the ADMIN role.</p> 

And if you wanted to prevent only a portion of a page from being displayed unless the user is both authenticated and authorized with the ADMIN role, you could call the custom tag as a paired tag like this:

[View full width]

<cf_Auth roles="ADMIN"> <p>You won't see this section unless you're logged in and have been assigned the ADMIN role.</p> </cf_Auth> <p>You'll see this section no matter who you are, and you don't have to be logged in, either.</p>

But you want the tag to react differently in each case. If it's called as an empty tag and the user isn't authorized, you want to redirect to a page that tells the user they have insufficient privileges; on the other hand, if the tag is called as a paired tag under the same conditions, then anything in the body of the tag is disregardedboth content and code. To determine whether a custom tag is called as an empty tag or a paired tag, you check the value of ThisTag.HasEndTag.

ThisTag.HasEndTag

As mentioned earlier, the ThisTag scope contains a variable named ThisTag.HasEndTag that describes whether or not a custom tag has a corresponding closing tag (i.e., it is a paired tag). Here's how you would use HasEndTag in our scenario:

 <!--- Check to see if the user is logged in ---> <cflogin>   <cfif ThisTag.HasEndTag>     <!--- If this tag is called as a paired tag and the user is not logged in,     exit the tag now to prevent execution of any code between the start and     end tags. --->     <cfexit method="ExitTag">   <cfelse>     <!--- If this tag is not called as a paired tag and the user is not logged     in, redirect to the login form. --->     <cflocation url="#Application.urlRoot#/login/LoginForm.cfm" addtoken="No">   </cfif> </cflogin> 

Although this code tests only the authentication portion of the security check, it gives you a clear idea of how you can create a custom tag that can adapt its behavior based on how it is called, either as an empty tag or as a paired tag.

Using CFEXIT to Control Custom Tag Processing Flow

Paired custom tags aren't relegated to only modifying content; they can also prevent code in the body of the paired tag from being executed, or they can control the flow of logic in such code. Let's see how this works.

Notice the <cfexit method="ExitTag"> in the preceding code. It tells the flow of logic to ignore the remainder of the custom tag and continue immediately after the end tag. So if the user hasn't logged in yet, the <cflogin> section executes and, if the custom tag was called as a paired tag, it ignores the rest of the custom tag, its execution cycles, its outputeverything. Any content wrapped with this custom tag will not display, and any wrapped code will not be executed.

Keep this principle in mind as you review Listing 18.2, which is the completed <cf_Auth> custom tag.

Listing 18.2. Auth.cfmUsing CFEXIT to Control Custom Tag Processing Flow
 <!--- Author: Adam Phillip Churvis -- ProductivityEnhancement.com ---> <!--- Ensures that user is authenticated and authorized ---> <cfparam name="Attributes.roles" type="string" default=""> <cfif ThisTag.ExecutionMode EQ "Start">   <!--- Check to see if the user is logged in --->   <cflogin>     <cfif ThisTag.HasEndTag>       <!--- If this tag is called as a paired tag and the user is not logged in,       exit the tag now to prevent execution of any code between the start and       end tags. --->       <cfexit method="ExitTag">     <cfelse>       <!--- If this tag is not called as a paired tag and the user is not logged       in, redirect to the login form. --->       <cflocation url="#Application.urlRoot#/login/LoginForm.cfm" addtoken="No">     </cfif>   </cflogin>   <!--- Check to see if the user must be a member of one or more roles --->   <cfif Len(Trim(Attributes.roles)) GT 0>     <!--- We must now see if at least one of the user's roles match those in     Attributes.roles --->     <!--- Loop over the list of required roles --->     <cfset inRole = FALSE>     <cfloop list="#Attributes.roles#" index="currentRole">       <cfif IsUserInRole(currentRole)>         <!--- If Attributes.memberOf is "AnyOfTheseRoles", and there is a match,         the user may access content. --->         <cfset inRole = TRUE>         <cfbreak>       </cfif>     </cfloop>     <!--- Check to see if the user may access content. --->     <cfif NOT inRole>       <cfif ThisTag.HasEndTag>         <!--- If this tag is called as a paired tag and the user cannot access         content, exit the tag now to prevent execution of any code between the         start and end tags. --->         <cfexit method="ExitTag">       <cfelse>         <!--- If this tag is not called as a paired tag and the user cannot         access content, redirect to the login form. --->         <cflocation url="#Application.urlRoot#/login/InsufficientPrivileges.cfm"           addtoken="No">       </cfif>     </cfif>   </cfif> </cfif> 

<cfexit> has three possible methods: ExitTag, which exits the entire custom tag; ExitTemplate, which exits the current execution mode of the custom tag and continues with the next; and Loop, which exits the End mode and starts over again in the Inactive mode (most often used to repetitively execute nested child tags). As you'll see later in this chapter, if the body of the paired tag contains nested child tags, Inactive mode passes processing to the first such child tag.

Table 18.2. <cfexit> Methods' Effect on Flow Control

METHOD

LOCATION

BEHAVIOR

ExitTag

Calling page

Terminate processing

 

Start mode

Continue after end tag

 

End mode

Continue after end tag

ExitTemplate

Calling page

Terminate processing

 

Start mode

Jump down to Inactive mode

 

End mode

Continue after end tag

Loop

Calling page

(Error)

 

Start mode

(Error)

 

End mode

Jump back into Inactive mode


We'll go deeper into <cfexit> later in this chapter when we start leveraging the more advanced aspects of custom tag design.



Advanced Macromedia ColdFusion MX 7 Application Development
Advanced Macromedia ColdFusion MX 7 Application Development
ISBN: 0321292693
EAN: 2147483647
Year: 2006
Pages: 240
Authors: Ben Forta, et al

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net