• Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL

Chapter 4. Handling a Fuseaction > Section 11: fbx_layouts.cfm and Layout Files

Section 11: fbx_layouts.cfm and Layout Files

Fusebox has a place for everything. Application-wide settings such as variable constants and DSN names go in the root fbx_settings.cfm. Circuit-wide settings such as security logic go in each circuit’s fbx_settings.cfm. The fbx_switch.cfm serves as a roadmap to a circuit by showing the fuses that make up each fuseaction. The individual fuses do the work of the application and run the code needed to satisfy each request. What about layouts: headers, footers, and nested tables?

Two pieces make up Fusebox’s layout structure: circuit-level fbx_layouts.cfm files and layout files. In short, the fbx_layouts.cfm file tells the framework which layout file to use for this request, and the layout file contains the page elements and the results of the fuseaction execution. Let’s cover them one at a time.


The first part of section 11 looks like this:

 1 <cfset FB_.circuitalias = fusebox.Circuits[fusebox.TargetCircuit] > 
 2 <cfset FB_.layoutpath = fusebox.Circuits[fusebox.TargetCircuit] > 
 3 <cfloop condition="Len(FB_.layoutpath) GT 0"> 
 4   <cfif StructKeyExists(FB_.ReverseCircuitPath, FB_.circuitalias)> 
 5     <cftry> 
 6       <cfset fusebox.thisCircuit = FB_.ReverseCircuitPath[FB_.circuitalias] > 
 7       <cfcatch> 
 8         <cfset fusebox.thisCircuit = ""> 
 9       </cfcatch> 
10    </cftry> 
11    <cfscript> 
12    if (fusebox.thisCircuit EQ fusebox.Targetcircuit) fusebox.IsTargetCircuit=TRUE; 
13      else fusebox.IsTargetCircuit=FALSE; 
14    if (fusebox.thisCircuit EQ fusebox.HomeCircuit) fusebox.IsHomeCircuit=TRUE; 
15      else fusebox.IsHomeCircuit=FALSE; 
16    fusebox.ThisLayoutPath=ListRest(FB_.layoutpath,"/"); 
17    if (Len(fusebox.thislayoutpath)) fusebox.thislayoutpath=fusebox.thislayoutpath & "/"; 
18    fusebox.currentPath=fusebox.thislayoutpath; 
19    fusebox.rootPath=repeatString("../", ListLen(fusebox.thislayoutpath, '/')); 
20    </cfscript> 
21    <cftry> 
22      <cfinclude template="#fusebox.thislayoutpath#fbx_Layouts.cfm"> 
23      <cfcatch> 
24        <cfset fusebox.layoutfile = ""><cfset fusebox.layoutdir = ""> 
25      </cfcatch> 
26    </cftry> 


Lines 1 and 2 create two FB_ structure variables to hold the currently executing circuit. Line 3 begins the looping of nested layouts. Starting at the target circuit, the entire rest of the code in this section will loop once per circuit. Each time through the loop, lines 6 and 8 set the value of fusebox.thisCircuit to the currently executing circuit. Lines 13–15 continue to create variables that are available for use in the fbx_layouts.cfm and layout files. These same API variables were set in section 9, discussed earlier.

The real action of this code occurs in lines 16–22. fusebox.thisLayoutPath contains the path to the current circuit. The first time through the loop, this path is the same as the path to the target circuit. Each time through the loop, however, the core file resets this variable to the appropriate path to reach the fbx_layouts.cfm file for the current circuit. You might notice that fusebox.thisLayoutPath contains the same value as fusebox.currentPath. We recommend not using fusebox.thisLayoutPath in favor of using fusebox.currentPath. fusebox.thisLayoutPath is superfluous and might become deprecated in a future release.

Now that fbx_layouts.cfm is included, what does it do? What is its purpose?

Here is an example fbx_layouts.cfm:

<cfif dateCompare(now(),createDate(year(now()),"12","26"),"d") LTE 0> 
  <cfset fusebox.layoutFile="#fusebox.rootPath#layouts/lay_christmas.cfm"> 
  <cfset fusebox.layoutFile="#fusebox.rootPath#layouts/lazy_default.cfm"> 

Similar in brevity to fbx_switch.cfm, fbx_layouts.cfm sets only one variable: fusebox.layoutFile. That API variable tells the core file where to find the layout file relative to the circuit. This fbx_layouts.cfm example seems simple; you will find that in real applications, fbx_layouts.cfm files often are simple. Most applications use one layout file per circuit. The entire site is usually wrapped in one “global” style wrapper containing the top-level navigation links. Some circuits might also add their own navigation links. For the most part, however, the fbx_layouts.cfm ’s job is a simple one.

That does not mean that fbx_layouts.cfm ’s job has to be simple. fbx_layouts.cfm can contain any code you want. Here is a slightly more powerful example:

<cfparam name="client.layoutScheme" default="white"> 
<cfset fusebox.layoutFile="#fusebox.rootPath#layouts/lay_#client.layoutScheme#.cfm"> 


Using this example, the application can present an individualized layout for each user, depending on chosen preferences. If John Barker likes the “peasoup” layout scheme, his layout file would be lay_peasoup.cfm.

This might seem like an unnecessarily complex system just to manipulate the colors of the web site. After all, that sort of functionality is commonly referred to as “candy.” It usually does not satisfy system requirements, but it can be fun.

If all you did with different layout files was create new color schemes, then you would not be taking full advantage of the power of nested layouts. Although we will cover them in detail in Chapter 9, “Nested Layouts,” let’s discuss briefly how they relate to the Fusebox framework that is processing a request.

Layout Files

After the core file includes the fbx_layouts.cfm file, the resulting API variable— fusebox.layoutFile —is set. This is the second half of the code in section 11:

 1     <cftry> 
 2       <cfif Len(fusebox.layoutfile)> 
 3         <cfsavecontent variable="fusebox.layout"> 
 4           <cfoutput><cfinclude template="#fusebox.thislayoutpath##fusebox.layoutdir##fusebox.layoutfile#"></cfoutput> 
 5         </cfsavecontent> 
 6       </cfif> 
 7     <cfcatch> 
 8       <cfif fusebox.suppressErrors> 
 9         <cfoutput>I could not find the layoutfile...</cfoutput><cfabort> 
  <cfset FB_.layoutpath = ListDeleteAt(FB_.layoutpath, ListLen(FB_.layoutpath, "/"), "/")> 
  <cfset FB_.circuitalias = ListDeleteAt(FB_.circuitalias, ListLen(FB_.circuitalias, "/"), "/")> 


Based on the value of fusebox.layoutFile, this section of code <cfinclude> s the layout file to be used for this request. Line 2 decides whether to run this code section. If the fusebox.layoutFile is set to "" (blank), then no layout file is to be used, and this section is skipped.

Line 3 opens a <cfsavecontent> tag. The results of <cfinclude> ing the layout file will be stored in the variable fusebox.layout, as specified in the variable attribute of the tag. Doesn’t that overwrite the existing value? The core file already has content saved from the processing of fbx_switch.cfm and all the fuses.

That brings up an interesting feature of <cfsavecontent>. Here is an example of it:

<cfsavecontent variable="layout"> 
I am the fuseaction 
<cfsavecontent variable="layout"> 

In this example, the variable layout is not overwritten. As we want it to, the output appears like this:

I am the fuseaction 

To output the initial results of the <cfsavecontent> tag, we had to output #layout#. That occurs between lines 4–14. The layout file is <cfinclude> d, and the layout file is what outputs the value of fusebox.layout. Here is an example layout file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<table cellspacing="2" cellpadding="2" border="0"> 
  <td colspan="2"><cfinclude template="dsp_navigation.cfm"></td> 
  <td rowspan="2" valign="top"><cfoutput>#fusebox.layout#</cfoutput></td> 
  <td valign="top"><cfmodule template="#request.self#"fuseaction="news.topStories"></td> 
    <td><cfmodule template="#request.self#"fuseaction="horoscopes.readToday" DOB="#client.DOB#"></td> 
<div align="center">Copyright &copy;Third Wheel Bikes, thirdwheelbikes.com</div> 


This layout file contains the HTML formatting to correctly display the page to a browser. It contains some navigational controls in the top row of a table. The rest of the table contains three elements: the output of the fuseaction, which is stored in fusebox.layout; the output of another fuseaction, which by the name of the fuseaction, tells us that it outputs the top news stories for the day; and the output of another fuseaction, which displays the horoscope that is customized for the user’s date of birth. Finally, the layout file displays copyright information to appear on every page and closes the HTML formatting.

What if the application gives the user preferences as to which portal elements to display? If the user does not want to see horoscopes, then some CFML logic can surround the <cfmodule> tag in that table cell. By arranging page elements together into one display page, the layout file serves as a master layout control. A web designer mocks up complex pages with multiple elements on each display. Then, you extract the sections into fuseactions and reassemble them into the total page layout.

A complete discussion of nested layouts occurs in Chapter 9 “Nested Layouts,” so hold your questions until then. For now, the core file is only concerned with outputting the value of fusebox.layout.

Let’s finish the code in section 11. Lines 7–11 handle missing layout files. If the fbx_layouts.cfm file specifies a non-existent layout file, then the error is caught here. Lines 14 and 15 finish off section 11 by removing one level of the circuit mapping in preparation for the next circuit to be handled. Remember that section 11 is run inside a <cfloop>, which loops from circuit to circuit, up the circuit chain to the root circuit.

Nested Layouts

The <cfinclude> of fbx_layouts.cfm and the layout file that is defined there occur once per circuit, starting at the target circuit, and proceeding up to the root circuit. The effect that this nesting has on layouts is more dramatic than the error handling. Because the circuits are nested one inside the other, the effect is that of a Russian doll; the parent wraps each circuit up to the root. Of course fbx_layouts.cfm is completely optional, so you can leave out a circuit with no ill effect. Doing so just removes that layer’s wrapping. In most cases, each circuit does not apply its own layout. Occasionally, some circuits have their own wrapper, and the root almost always contains the global wrapper.

That is it for nested layouts for the time being. Although more could be covered, we cannot do it all here. You are probably wondering how much more of the core there is to cover! We have saved a complete explanation of the benefits and practical uses of nested layouts for Chapter 9.

  • Creative Edge
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint