Magnolia 5.4 reached end of life on November 15, 2018. This branch is no longer supported, see End-of-life policy.

Page tree
Skip to end of metadata
Go to start of metadata

This page explains how to create a page template. First, create a static HTML file based on the Bootstrap Landing Page template. Then transform the prototype into a Magnolia page template and make its content editable.

Download the HTML prototype

It is good practice to create a static HTML prototype first. It gives you an overview of the page you need to build.

Download the prototype and extract it to my-first-website-tutorial/light-modules/one-pager-module/webresources/prototype.

light-modules
└── one-pager-module
    └── webresources
        └── prototype
            ├── 3rd-party-files
            │   ├── bootstrap-theme.min.css
            │   ├── bootstrap.min.css
            │   ├── bootstrap.min.js
            │   ├── jquery.easing.min.js
            │   └── jquery.js
            ├── imgs
            │   ├── car-0_medium.jpg
            │   ├── car-1_medium.jpg
            │   ├── car-2_medium.jpg
            │   ├── car-3_medium.jpg
            │   ├── car-4_medium.jpg
            │   ├── components.jpg
            │   ├── eric-the-viking.jpg
            │   └── intro-bg.jpg
            ├── one-pager.css
            ├── one-pager.js
            └── prototype.html

Study the prototype.html file. It has the following sections:

  • Navigation
  • Intro
  • Three content sections, one of which has a collection of cars

prototype.html
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content=""/>
    <meta name="author" content="">

    <title>Eric's Classic Cars</title>

    <link rel="stylesheet" href="3rd-party-files/bootstrap.min.css ">
    <link rel="stylesheet" href="3rd-party-files/bootstrap-theme.min.css ">
    <link rel="stylesheet" href="one-pager.css?z=123">
    <link href="http://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet"
          type="text/css">
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>

<body>

<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation">
    <div class="container topnav">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand topnav page-scroll" href="#intro">Home</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav navbar-right">
                <li>
                    <a class="page-scroll" href="#intro">Intro</a>
                </li>
                <li>
                    <a class="page-scroll" href="#cars">Cars</a>
                </li>
                <li>
                    <a class="page-scroll" href="#about">About</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

<div class="intro-section" id="intro">
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
                <div class="intro-message">
                    <h1 class="dark">Eric's Classic Cars</h1>

                    <h3>Bootstrap one-pager edited with Magnolia</h3>
                    <hr class="intro-divider">

                </div>
            </div>
        </div>
    </div>
</div>


<!-- starting with cars here ... -->
<div class="component-section" id="cars">
    <div class="container">
        <div class="row">
            <div class="col-lg-12 col-sm-12">
                <hr class="section-heading-spacer">
                <div class="clearfix"></div>
                <h2 class="section-heading">Classic cars</h2>

                <p class="lead">

                <p>Some of the most classic cars from U.S. and Great Britain.</p>
                </p>
            </div>
        </div>

        <div class="row cars">
            <div class="col-lg-12 col-sm-12">

                <!-- 1-car "repeatable" -->
                <div class="row car">
                    <div class="col-xs-6">
                        <div class="big-box">
                            <img class="img-responsive img-rounded" src="imgs/car-0_medium.jpg"/>
                        </div>
                        <div class="copyright">© Pedro Ribeiro Simões</div>
                    </div>
                    <div class="col-xs-6">
                        <div class="row">
                            <div class="col-xs-12"><h3>Riley Brooklands 1930</h3></div>
                            <div class="col-xs-12">
                                <p>The Riley Nine was one of the most successful light cars produced by the British motor industry
                                    in the inter war period. It was made by the Riley company of Coventry, England with a wide range
                                    of body styles between 1926 and 1938.</p>

                                <p>The car was largely designed by two of the Riley brothers, Percy and Stanley. Stanley was
                                    responsible for the chassis, suspension and body and the older Percy designed the engine.</p>

                                <p>The 1,087 cc four-cylinder engine had hemispherical combustion chambers with the valves
                                    inclined at 45 degrees in a crossflow head. To save the expense and complication of overhead
                                    camshafts, the valves were operated by two camshafts mounted high in the crankcase through short
                                    pushrods and rockers. The engine was mounted in the chassis by a rubber bushed bar that ran
                                    through the block with a further mount at the rear of the gearbox. Drive was to the rear wheels
                                    through a torque tube and spiral bevel live rear axle mounted on semi elliptic springs.</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-lg-12 col-sm-12">
                        <div class="between-car-spacer"></div>
                    </div>
                </div>
                <!-- /. -->


                <!-- 1-car "repeatable" -->
                <div class="row car">
                    <div class="col-xs-6">
                        <div class="big-box">
                            <img class="img-responsive img-rounded" src="imgs/car-1_medium.jpg"/>
                        </div>
                        <div class="copyright">© John Lloyd</div>
                    </div>
                    <div class="col-xs-6">
                        <div class="row">
                            <div class="col-xs-12"><h3>Pontiac Chieftain 1952</h3></div>
                            <div class="col-xs-12">
                                <p>The Pontiac Chieftain is an automobile that was produced by the Pontiac from 1949 to 1958.
                                    Chieftains were one of the first all new car designs to come to Pontiac in the post
                                    World War II years. Previous cars had been 1942 models with minor revisions.</p>

                                <p>The Chieftain was initially introduced with four models: Sedan, Sedan Coupe, Business Coupe
                                    and Deluxe Convertible Coupe. In 1950, a Catalina Coupe was added to the range while a station
                                    wagon was added in 1952, with the demise of the top of the line Streamliner wagon.</p>

                                <p>Some of the more interesting optional items available for the first generation Chieftain
                                    included a radio with seven vacuum tubes, tissue dispenser, under seat heaters, and a Remington
                                    Auto-Home shaver. In 1951, the horsepower on the 8-cylinder rose to 116. The Chieftain came with
                                    a gas gauge, ammeter, oil pressure gauge, and a temperature gauge which had marks for 160, 180,
                                    and 220 degrees Fahrenheit.</p>

                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-lg-12 col-sm-12">
                        <div class="between-car-spacer"></div>
                    </div>
                </div>
                <!-- /. -->


                <!-- 1-car "repeatable" -->
                <div class="row car">
                    <div class="col-xs-6">
                        <div class="big-box">
                            <img class="img-responsive img-rounded" src="imgs/car-2_medium.jpg"/>
                        </div>
                        <div class="copyright">© John Lloyd</div>
                    </div>
                    <div class="col-xs-6">
                        <div class="row">
                            <div class="col-xs-12"><h3>Continental Mark II</h3></div>
                            <div class="col-xs-12">
                                <p>The Continental Mark II is a personal luxury car that was produced by Continental in 1956
                                    and 1957. An attempt to build a post-World War II car to rival the greatest of the pre-War
                                    era, or anything produced in Europe, it is regarded as a rare and elegant classic.</p>

                                <p>Ford wanted a superior and standalone up-market brand – aside from Lincoln – to compete
                                    with General Motors' Cadillac, Packard, and Chrysler Corporation's Imperial brands.</p>

                                <p>The new Continental was not intended to be the largest or most powerful automobile; rather,
                                    the most luxurious and elegant American car available, designed to recapture the spirit of
                                    the great classics of the prewar period—with prices to match. The Mark II's inspiration
                                    was the celebrated V12-powered Lincoln Continental of the 1940s, among the most notable cars
                                    of that War-interrupted decade.</p>

                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-lg-12 col-sm-12">
                        <div class="between-car-spacer"></div>
                    </div>
                </div>
                <!-- /. -->

                <!-- 1-car "repeatable" -->
                <div class="row car">
                    <div class="col-xs-6">
                        <div class="big-box">
                            <img class="img-responsive img-rounded" src="imgs/car-3_medium.jpg"/>
                        </div>
                        <div class="copyright">© John Lloyd</div>
                    </div>
                    <div class="col-xs-6">
                        <div class="row">
                            <div class="col-xs-12"><h3>1927 Hudson</h3></div>
                            <div class="col-xs-12">
                                <p>The Hudson Motor Car Company made Hudson and other brand automobiles in Detroit, Michigan,
                                    from 1909 to 1954. In 1954, Hudson merged with Nash-Kelvinator Corporation to form American
                                    Motors (AMC). The Hudson name was continued through the 1957 model year, after which it
                                    was discontinued.</p>

                                <p>The company had a number of firsts for the auto industry; these included dual brakes, the
                                    use of dashboard oil-pressure and generator warning lights, and the first balanced crankshaft,
                                    which allowed the Hudson straight-six engine, dubbed the "Super Six" (1916), to work at
                                    a higher rotational speed while remaining smooth, developing more power for its size than
                                    lower-speed engines. The dual brake system used a secondary mechanical emergency brake system,
                                    which activated the rear brakes when the pedal traveled beyond the normal reach of the primary
                                    system; a mechanical parking brake was also used. Hudson transmissions also used an oil bath
                                    and cork clutch mechanism that proved to be as durable as it was smooth.</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-lg-12 col-sm-12">
                        <div class="between-car-spacer"></div>
                    </div>
                </div>
                <!-- /. -->

                <!-- 1-car "repeatable" -->
                <div class="row car">
                    <div class="col-xs-6">
                        <div class="big-box">
                            <img class="img-responsive img-rounded" src="imgs/car-4_medium.jpg"/>
                        </div>
                        <div class="copyright">© Pedro Ribeiro Simões</div>
                    </div>
                    <div class="col-xs-6">
                        <div class="row">
                            <div class="col-xs-12"><h3>Fiat Cinquecento</h3></div>
                            <div class="col-xs-12">
                                <p>The Fiat 500 (Italian: Cinquecento) was a city car produced by the Italian manufacturer
                                    Fiat between 1957 and 1975.</p>

                                <p>Launched as the Nuova (new) 500 in July 1957, it was a cheap and practical town car.
                                    Measuring only 2.97 metres (9 feet 9 inches) long, and originally powered by an appropriately
                                    sized 479 cc two-cylinder, air-cooled engine, the 500 redefined the term "small car" and
                                    is considered one of the first city cars.</p>

                                <p>Despite its diminutive size, the 500 proved to be an enormously practical and popular
                                    vehicle throughout Europe. Besides the two-door coupé, it was also available as the
                                    "Giardiniera" station wagon; this variant featured the standard engine laid on its side,
                                    the wheelbase lengthened by 10 cm (3.9 in) to provide a more convenient rear seat,
                                    a full-length sunroof, and larger brakes from the Fiat 600.</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-lg-12 col-sm-12">
                        <div class="between-car-spacer"></div>
                    </div>
                </div>
                <!-- /. -->

            </div>
        </div>
    </div>
</div>
<!-- eof: cars ... -->


<div class="component-section" id="about">
    <div class="container">
        <div class="row">

            <div class="col-lg-5 col-sm-6">
                <hr class="section-heading-spacer">
                <div class="clearfix"></div>
                <h2 class="section-heading">Eric</h2>

                <p class="lead">Eric was born in northern Europe. He loves cars, cats, South Park,
                    Gonzo the Great, Italian food, Belgian beer, crime stories, JavaScript and
                    front-end development.</p>
            </div>


            <div class="col-lg-6 col-sm-6">
                <div class="big-box">
                    <img src="imgs/eric-the-viking.jpg" class="img-responsive img-circle"/>
                </div>
            </div>

        </div>
    </div>
</div>


<!-- Footer -->
<footer>
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
                <ul class="list-inline">
                    <li>
                        <a class="page-scroll" href="#">Home</a>
                    </li>
                    <li class="footer-menu-divider">&sdot;</li>
                    <li>
                        <a class="page-scroll" href="#intro">Intro</a>
                    </li>
                    <li class="footer-menu-divider">&sdot;</li>
                    <li>
                        <a class="page-scroll" href="#cars">Cars</a>
                    </li>
                    <li class="footer-menu-divider">&sdot;</li>
                    <li>
                        <a class="page-scroll" href="#about">About</a>
                    </li>
                </ul>
                <p class="copyright text-muted small">This bootstrap page was inspired by
                    <a href="http://startbootstrap.com/template-overviews/landing-page/">Start Bootstrap
                        - Landing Page</a></p>
                <p class="copyright text-muted small">Car hotos by Pedro Ribeiro Simões and John Lloyd</p>
                <p class="copyright text-muted small">Car descriptions from Wikipedia,
                    <a href="https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License">
                        Creative Commons Attribution-ShareAlike License</a></p>
            </div>
        </div>
    </div>
</footer>

<script src="3rd-party-files/jquery.js"></script>
<script src="3rd-party-files/bootstrap.min.js"></script>
<script src="3rd-party-files/jquery.easing.min.js"></script>
<script src="one-pager.js"></script>

</body>
</html>
Open the file in your browser. Or go to http://localhost:8080/magnoliaAuthor/.resources/one-pager-module/webresources/prototype/prototype.html to have Magnolia serve it.

Create a page template

Every Magnolia template needs a definition and a script. A template definition gives the template a name and makes it available to the system. It also tells the system which script renders the content. We also want a dialog definition.

Template definition

Create the file one-pager-module/templates/pages/main.yaml

main.yaml
templateScript: /one-pager-module/templates/pages/main.ftl
renderType: freemarker
visible: true
title: One pager template
dialog: one-pager-module:pages/main
areas:
  content-sections:
#     availableComponents:
#       content-items-list:
#         id: one-pager-module:components/content-items-list
#       textImage:
#         id: one-pager-module:components/textImage
Lines 8-12: The section availableComponents of the content-sections areas is commented for the time being. We will come back to this when adding components.

Dialog definition

Define a page dialog. The dialog defines properties which are stored on the page node:

  • Title 
  • Subtitle
  • Copyright
  • Meta description
  • Meta keywords
  • Background image of the intro section

one-pager-module/dialogs/pages/main.yaml
 form:
  tabs:
    - name: tabText
      label: Title texts
      fields:
        - name: title
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          label: Title
        - name: subTitle
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          label: Subtitle
        - name: copyrightNote
          class: info.magnolia.ui.form.field.definition.RichTextFieldDefinition
          label: Copyright note
          description: Photographers who own the images used on this site
 
    - name: tabBgImage
      label: Background
      fields:
        - name: introBgImage
          class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
          targetWorkspace: dam
          appName: assets
          label: Select image
          description: Background image of the intro section
          identifierToPathConverter:
            class: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator
          contentPreviewDefinition:
            contentPreviewClass: info.magnolia.dam.app.ui.field.DamFilePreviewComponent
    - name: tabMeta
      label: SEO
      fields:
        - name: keywords
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          i18n: true
          label: Keywords
          description: Keywords and description for search engine optimization
          rows: 3
        - name: description
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          i18n: true
          label: Description
          rows: 5
actions: !include /one-pager-module/includes/default-dialog-actions.yaml
Most dialogs have Save and Cancel actions. Create a reusable dialog definition file for them. Save this file in /one-pager-module/includes/default-dialog-actions.yaml.
one-pager-module/includes/default-dialog-actions.yaml
   commit:
    class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
  cancel:
    class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
The !include directive is one possibility to reuse configuration. If you have created the includable fragment after the creation of the file which does include it, save the latter again to force the YAML parser to properly register the dialog definition.

Also read YAML - include for further details.

Template script

Create a template script in one-pager-module/templates/pages/main.ftl.

main.ftl
[#assign title = content.title!"Eric's Classic Cars"]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="${content.keywords!""}"/>
    <meta name="description" content="${content.description!""}"/>
    <meta name="author" content="">

    <title>${title}</title>

    [#--bootstrap css--]
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap.min.css ">
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap-theme.min.css ">
    [#--Custom CSS--]
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/css/one-pager.css?z=123">
    <link href="http://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css">
    [#--HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries--]
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
    [@cms.page /]
</head>
<body>
  <h1>${title}</h1>
  <p>${content.subTitle!"No subtitle defined"}</p>

    [#--jquery and bootstrap js--]
    <script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/jquery.js"></script>
    <script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap.min.js"></script>
    <script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/jquery.easing.min.js"></script>
    [#--custom js--]
    <script src="${ctx.contextPath}/.resources/one-pager-module/webresources/js/one-pager.js"></script>
</body>
</html>

Note the following things:

  • Lines 1, 12, 28: We create a Freemarker variable title and assign the page title to it using the content rendering context object. We use the variable in the <title> and <h1> tags.
  • Lines 8, 9: Expressions ${content.keywords!""} and ${content.description!""} for the respective meta tags.
  • References to JavaScript and CSS files from Bootstrap and jQuery.
  • Line 18: Resource reference ${ctx.contextPath}/.resources/one-pager-module/webresources/css/one-pager.css. This file does not yet exist.

Copy resource files

Copy resource files to the folders the script references.

  1. Create the folder /one-pager-module/webresources/bootstrap-3.3.5 and copy the following files from the prototype into the folder:
    • bootstrap-theme.min.css
    • bootstrap.min.css
    • bootstrap.min.js
    • jquery.easing.min.js
    • jquery.js
  2. Copy  one-pager-module/webresources/prototype/one-pager.css  to  one-pager-module/webresources/css/ .
  3. Copy one-pager-module/webresources/prototype/one-pager.js to one-pager-module/webresources/js/.
  4. Edit one-pager.cssRemove the line  background: url(imgs/intro-bg.jpg) no-repeat center center;  from the .intro-section.

Create a page

Now try to create a page in the Pages app with the new "One pager template" template.

  1. Click Add Page.
  2. Enter a page name
  3. Select the "One pager template" template.
  4. Click Next to open the Page properties dialog. 
  5. Edit the page title and subtitle.
  6. Save changes.

If it works, proceed with the tutorial.

Structure and style the intro section

Edit the template script main.ftl. Remove the first two lines of the <body> element and replace them with an intro section that applies Bootstrap classes for structure and style.

We introduce the built-in Freemarker directive has_content. We use the built-in to check if the user entered a subtitle. If there is no content we don't need to create the <h3> element at all.

Replace this:

templates/pages/main.ftl
<h1>${title}</h1>
<p>${content.subTitle!"No subtitle defined"}</p>

With this:

templates/pages/main.ftl
<div class="intro-section" id="intro">
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
                <div class="intro-message">
                    <h1 class="dark">${title}</h1>
                [#if content.subTitle?has_content]
                    <h3>${content.subTitle}</h3>
                [/#if]
                    <hr class="intro-divider">
                </div>
            </div>
        </div>
    </div>
</div>
[#--eof: intro-section--]
Refresh the Magnolia page to see the effect.

Background image

Display a background image in the intro section. Add the following snippet inside the <head> element in the template script:

templates/pages/main.ftl
    <style>
        [#if content.introBgImage?has_content]
            [#assign assetRendition = damfn.getRendition(content.introBgImage, "xxlarge")! /]
            [#if assetRendition?has_content]
            .intro-section {
                background: url(${assetRendition.getLink()}) no-repeat center center;
                background-size: cover;
            }
            [/#if]
        [/#if][#-- eof: introBgImage --]
    </style>
Open the page properties dialog and go the Background tab to select an image. You can find the Jaguar image you see above in /cars/007-cars/intro-bg.jpg in the Magnolia DAM or upload your own.

Navigation

The prototype contains two in-page navigation menus, one at the top and one at the bottom of the page. If you study the html you realize that both menus contain very similar code. Let's remove this duplication and "outsource" the menu code to a Freemarker macro and use it twice.

createSectionNav macro

Create a macro that renders a list of anchor links. The anchors are page areas that you will create in a moment. 

Add the following snippet at the top of the template script:

templates/pages/main.ftl
[#macro createSectionNav page areaName="content-sections" type="top" ]
 
    [#assign ulClass = "default-ul-class" ]
    [#assign isTop = false ]
    [#if type=="top"]
        [#assign ulClass = "nav navbar-nav navbar-right" ]
        [#assign isTop = true ]
    [#elseif type=="bottom"]
        [#assign ulClass = "list-inline" ]
    [/#if]
 
<ul class="${ulClass}">
    [#if isTop]
        <li><a class="page-scroll" href="#intro">Home</a></li>
    [#else]
        <li><a class="page-scroll" href="#intro">Intro</a></li>
    [/#if]
 
    [#if cmsfn.contentByPath(page.@path+"/"+areaName)?exists]
        [#list cmsfn.children(cmsfn.contentByPath(page.@path+"/"+areaName), "mgnl:component") as component]
            [#assign navTitle = component.sectionName!component.headline!/]
            [#if navTitle?has_content]
                [#if !isTop]<li class="footer-menu-divider">&sdot;</li>[/#if]
                <li><a class="page-scroll" href="#${component.@uuid}">${component.sectionName!component.headline!component.@uuid}</a></li>
            [/#if]
        [/#list]
    [/#if]
</ul>
[/#macro]

Top navigation

Call the macro at the top of the page to create a top menu.

Add the following snippet right after the opening <body> tag.

top navigation
[#--top navigation--]
<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation">
    <div class="container topnav">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand topnav" href="#intro">Home</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        [#--dynamic part of top-nav--]
            [@createSectionNav page=content areaName="content-sections" type="top" /]
        </div>
    </div>
</nav>
[#--eof: top navigation--]
Note the macro calls [@createSectionNav page=content areaName="content-sections" type="top" /]. The macro takes the following parameters:

  • page: content of the page as a ContentMap.

  • areaName: name of the area definition node.

  • type: location of the menu, top or bottom.

Footer navigation

Call the macro again in the page footer to create a bottom menu.

Add the following snippet before the closing </body> tag and before the <script> elements:

templates/pages/main.ftl
[#--Footer--]
<footer>
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
            [#--footer-nav--]
            [@createSectionNav page=content areaName="content-sections" type="bottom" /]
            [#if content.copyrightNote?has_content]<div class="copyright">${cmsfn.decode(content).copyrightNote}</div>[/#if]
            </div>
        </div>
    </div>
</footer>
[#--eof: Footer--]

content-sections area

The page template defines one area – content-sections.

templates/pages/main.yaml
areas:
  content-sections:
    availableComponents:
#      content-items-list:
#        id: one-pager-module:components/content-items-list
#      textImage:
#        id: one-pager-module:components/textImage 
We haven't rendered the area on the page yet. Add the following snippet between the intro and the footer section:
templates/pages/main.ftl
[#--eof: intro-section--]
 
 
[@cms.area name="content-sections"/]
 
 
[#--Footer--]

Template script final version

Here you can see the final version of the template script - the way it should like - after you have followed all the above steps.

one-pager-module/templates/pages/main.ftl
[#--
 This macro renders the section navigation(s) on top and in footer section.
 - Param page: must be the content (contentMap) of a page.
 - Param areaName: the name of the area node which contains the content-section components.
 - Param type: "top" or "bottom".
--]
[#macro createSectionNav page areaName="content-sections" type="top" ]

    [#assign ulClass = "default-ul-class" ]
    [#assign isTop = false ]
    [#if type=="top"]
        [#assign ulClass = "nav navbar-nav navbar-right" ]
        [#assign isTop = true ]
    [#elseif type=="bottom"]
        [#assign ulClass = "list-inline" ]
    [/#if]

<ul class="${ulClass}">
    [#if isTop]
        <li><a class="page-scroll" href="#intro">Home</a></li>
    [#else]
        <li><a class="page-scroll" href="#intro">Intro</a></li>
    [/#if]

    [#if cmsfn.contentByPath(page.@path+"/"+areaName)?exists]
        [#list cmsfn.children(cmsfn.contentByPath(page.@path+"/"+areaName), "mgnl:component") as component]
            [#assign navTitle = component.sectionName!component.headline!/]
            [#if navTitle?has_content]
                [#if !isTop]<li class="footer-menu-divider">&sdot;</li>[/#if]
                <li><a class="page-scroll" href="#${component.@uuid}">${component.sectionName!component.headline!component.@uuid}</a></li>
            [/#if]
        [/#list]
    [/#if]
</ul>
[/#macro]

[#assign title = content.title!"Welcome to Eric's cars page :-)"]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="${content.keywords!""}"/>
    <meta name="description" content="${content.description!""}"/>
    <meta name="author" content="">

    <title>${title}</title>

[#--bootstrap css--]
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap.min.css ">
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap-theme.min.css ">
[#--Custom CSS--]
    <link rel="stylesheet" href="${ctx.contextPath}/.resources/one-pager-module/webresources/css/one-pager.css?z=123">
    <link href="http://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css">
[#--HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries--]
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
[@cms.page /]
    <style>
        [#if content.introBgImage?has_content]
            [#assign assetRendition = damfn.getRendition(content.introBgImage, "xxlarge")! /]
            [#if assetRendition?has_content]
            .intro-section {
                background: url(${assetRendition.getLink()}) no-repeat center center;
                background-size: cover;
            }
            [/#if]
        [/#if][#-- eof: introBgImage --]
    </style>
</head>
<body>
[#--top navigation--]
<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation">
    <div class="container topnav">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand topnav" href="#intro">Home</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        [#--dynamic part of top-nav--]
            [@createSectionNav page=content areaName="content-sections" type="top" /]
        </div>
    </div>
</nav>
[#--eof: top navigation--]

<div class="intro-section" id="intro">
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
                <div class="intro-message">
                    <h1 class="dark">${title}</h1>
                [#if content.subTitle?has_content]
                    <h3>${content.subTitle}</h3>
                [/#if]
                    <hr class="intro-divider">
                </div>
            </div>
        </div>
    </div>
</div>
[#--eof: intro-section--]


[@cms.area name="content-sections"/]


[#--Footer--]
<footer>
    <div class="container">
        <div class="row">
            <div class="col-lg-12">
            [#--footer-nav--]
            [@createSectionNav page=content areaName="content-sections" type="bottom" /]
            [#if content.copyrightNote?has_content]<div class="copyright">${cmsfn.decode(content).copyrightNote}</div>[/#if]
            </div>
        </div>
    </div>
</footer>
[#--eof: Footer--]

[#--jquery and bootstrap js--]
<script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/jquery.js"></script>
<script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/bootstrap.min.js"></script>
<script src="${ctx.contextPath}/.resources/one-pager-module/webresources/bootstrap-3.3.5/jquery.easing.min.js"></script>
[#--custom js--]
<script src="${ctx.contextPath}/.resources/one-pager-module/webresources/js/one-pager.js"></script>
</body>
</html>

Files overview 

You should now have the following files for the page template:

light-modules/
└── one-pager-module
    ├── README.md
    ├── dialogs
    │   ├── components
    │   └── pages
    │       └── main.yaml
    ├── includes
    │   └── default-dialog-actions.yaml
    ├── templates
    │   ├── components
    │   └── pages
    │       ├── main.ftl
    │       └── main.yaml
    └── webresources
        ├── bootstrap-3.3.5
        │   ├── bootstrap-theme.min.css
        │   ├── bootstrap.min.css
        │   ├── bootstrap.min.js
        │   ├── jquery.easing.min.js
        │   └── jquery.js
        ├── css
        │   └── one-pager.css
        └── js
            └── one-pager.js

You can download the complete one-pager-module directory as a ZIP from our Git server. It also includes the prototype which is not shown on the files tree above.

Components and the files shown previously from the prototype directory are not shown here.


Next: Accessing content on the server side


  • No labels