Internet Technologies:cxp

Layout management Foundation

Most websites have the same content in every page or in a large number of pages. Headers, footers and navigational elements are just a few examples. Site-wide scripts and stylesheets also fall into this group of resources. However, adding the same content to every page of your website and maintaining it this way is time consuming and error prone. If you want to change the appearance of the page header later, for example, you must edit each page. The correct solution for this problem is to use one or more layout pages.

A layout page serves as a template for all pages or views that refer to it. The pages that link to the layout page are called content pages. Content pages are not complete HTML pages with a body and a head. Instead, they contain only the content that varies from one page to the next. The following example code shows a very simple layout page:

<!-- simplesite.layout --> 
<!DOCTYPE html> 
<html> 
<head> 
  <title>MySite by @(Version())</title> 
</head> 

<body> 
  <div style="font-size:18pt;background-color:#ff0000;color:#efefef;"> 
    MyApplication 
  </div> 

  <!--- result from content page is rendered here --> 
  @RENDER Body 
</body> 
</html> 

What makes this page a layout page other than its filename is the @RENDER Body command. This command causes the result of the content page to be inserted at the same location. Content pages contain a relative reference to their layout page, which is defined using the layout directive. Below is an example of a content page using the simplesite.layout shown above.

<!-- layout1.cxp --> 
<%#page layout="./simplesite.layout" %> 

<!-- Here, we just define the content of the body --> 
<h2>This text and the text in the footer are defined in page layout1.cxp</h2> 
<h3>The heading, colors and the overall page structure are defined in layout file simplesite.layout</h3> 

Layout pages have the extension .layout. The extension prevents layout pages from being accessed directly. You can use the :hasLayout() method of your CXP page to check if your page has a layout associated.

You can find examples of different complexity levels illustrating layouts and their usage in the Xbase++ websamples collection.

Understanding sections

The placement of the @RENDER Body command within the layout page determines where the content of a content page is rendered. In addition to rendering complete content pages, it is also possible to include only specific content provided by the content page within a layout. This is controlled by placing @SECTION <section-name> commands in your content page, and by rendering these sections with @RENDER <section-name> in the layout page. The following example adds a footer section to the content page and renders it in the layout page.

<-- layout2.cxp --> 
<%#page layout="./simplesite.layout" %> 

<!-- Here, we just define the content for the body --> 
<h2>This text and the text in the footer are defined in page layout2.cxp</h2> 
<h3>The heading, colors and the overall page structure are defined in layout file simplesite.layout</h3> 

<!-- Now we select the section named Footer  --> 
<!-- Subsequent HTML markup or content is now collected   --> 
<!-- in the footer section instead of in the body section --> 
@SECTION Footer 
<p>Nothing special today</p> 

Below is the code of the layout page which renders the body as well as the footer sections from the content page using the @RENDER <section-name> command:

<!-- simplesite.layout --> 
<!DOCTYPE html> 
<html> 
 <head> 
   <title>MySite by @(Version())</title> 
 </head> 

 <body> 
   <div style="font-size:18pt;background-color:#ff0000;color:#efefef;"> 
    MyApplication 
   </div> 

  <!--- default content from content page is rendered here --> 
  @RENDER Body 

  <div style="font-size:8pt;background-color:#0000ff;color:#efefef;"> 
     <!---  the "footer" section gets rendered inside the div!  --> 
     @RENDER Footer 
  </div> 
</body> 
</html> 

The rendering of a section can be made optional. Simply use the :hasSection()method as shown in the example below. This way, you can have optional sections in your global layout files, which only some CXP pages in your application generate content for. In the example below, we output some static content if the content page does not provide us with content for the footer section.

@IF ::hasSection("Footer") 
<!--- if the content page has defined a section with the --> 
<!--- name "footer", this section gets rendered here!    --> 
@RENDER Footer 
@ELSE 
<h3>Some alternative static content</h3> 
@ENDIF 

Nested layouts

Layout pages can be nested. It is absolutely legal to reference another layout from a layout page. In fact, layout pages support all features of a CXP page, except that they can not be accessed directly. Instead, layouts need to be referenced in a CXP page for being executed.

A nested layout is a layout which refers to another (outer) layout. This approach is useful when a subset of pages require the same markup, as is often the case when certain sections of a website or web application need to appear slightly different from the others while retaining the same look and feel.

In the layout file below, we output the department description and the content of the content page. We also create a footer section to be rendered in the referenced layout company.layout.

<!-- file: development.cxp --> 
<%#page layout="./development.layout" %> 

<h2>We love to create the future...</h2> 
<% 
::Session:EmployeeCount := 9 
%> 

<h2>@(Milliseconds()) ms since midnight!</h2> 

<!-- file: development.layout --> 
<%#page layout="./company.layout" %> 
<div style="font-size:18pt;background-color:#aaaaaa;color:#efefef;"> 
Development Department<br><small>@(::Session:EmployeeCount)</small> 
</div> 

@RENDER Body 

@SECTION Footer 
<% 
aTips := {; 
          "Not everything that can be counted counts, and not everything that counts can be counted.",; 
          "Imagination is more important than knowledge.",; 
          "There are no facts, only interpretations.",; 
          "The best way to predict the future is to invent it.",; 
          "Well done is better than well said.",; 
          "Research is what I'm doing when I don't know what I'm doing." } 
%> 
<p>@(aTips[RandomInt(1,Len(aTips))])</p> 

<!-- file: company.layout --> 
<!DOCTYPE html> 
<html> 
<head> 
  <title>MyCompany</title> 
</head> 

<body> 
  <div style="font-size:18pt;background-color:#ff0000;color:#efefef;"> 
  MyCompany 
  </div> 

  <!--- content from page/layout referencing this layout is rendered here --> 
  @RENDER Body 

  <div style="font-size:8pt;background-color:#0000ff;color:#efefef;"> 
     @RENDER Footer 
  </div> 
</body> 
</html> 

It is important to explicitly render the body within each layout page using a :renderSection("Body")method call or a @RENDER Body command in your markup. Otherwise, the content will not appear in the outer layout(s).

The order of execution of your Xbase++ code is as follows: first, the development.cxp content page is executed. Afterwards, the referenced development.layout is called and the content created by the CXP page is rendered at the location of the @RENDER Body command. After the content of the development.layout page has been created, the referenced layout page company.layout is executed and again, the content of the inner layout is rendered using the @RENDER Body command. In addition the Footer section from our inner layout is rendered using the @RENDER Body command. In addition the Footer section from our development.layout page is also rendered using the @RENDER Footer command. The final content is then delivered to the client.

The following are some best-practice rules related to layout pages:

Whenever you find yourself adding the same content to more than one CXP page, it is time to consider using layouts for defining this content at a central location, and for sharing it between pages.
Always try to have all your CSS/JS files included in the master layout file.
If a CXP pages requires specific Javascript frameworks to be included, simply add a script section to your master layout file.
Do not have more than 3 to 4 levels of nested layout files. Do not define more than 3 to 4 sections. This is enough even for large websites.
Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.