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
<!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">⋅</li>
<li>
<a class="page-scroll" href="#intro">Intro</a>
</li>
<li class="footer-menu-divider">⋅</li>
<li>
<a class="page-scroll" href="#cars">Cars</a>
</li>
<li class="footer-menu-divider">⋅</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
.
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
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
.
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.
Also read YAML - include for further details.
Template script
Create a template script in one-pager-module/templates/pages/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.
- 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
- Copy
one-pager-module/webresources/prototype/one-pager.css
to one-pager-module/webresources/css/
. - Copy
one-pager-module/webresources/prototype/one-pager.js
to one-pager-module/webresources/js/
.
- Edit
one-pager.css
. Remove 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.
- Click Add Page.
- Enter a page name
- Select the "One pager template" template.
- Click Next to open the Page properties dialog.
- Edit the page title and subtitle.
- 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:
<h1>${title}</h1>
<p>${content.subTitle!"No subtitle defined"}</p>
With this:
<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:
<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>
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 at the top of the template script:
[#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">⋅</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--]
<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
.
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:
[#--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
.
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:
[#--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.
[#--
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">⋅</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
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
#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))