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. Also read
YAMLinclude 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
5 Comments
Obeliksz
On adding a page I get:
Action execution failed for action: commit
On the console:
Severity type: MINOR
Title: /: [Definition resolution] - Source data processing problem
Problem details: Property [cancel] not found in class [info.magnolia.ui.dialog.definition.ConfiguredFormDialogDefinition], property is not assigned
2018-07-13 13:00:15,427 WARN agnolia.config.source.yaml.YamlConfigurationSource:
Severity type: MINOR
Title: /: [Definition resolution] - Source data processing problem
Problem details: Property [commit] not found in class [info.magnolia.ui.dialog.definition.ConfiguredFormDialogDefinition], property is not assigned
Did I miss something when following the docs or is this related to the new 5.7 version and is not yet covered?
Christoph Meier
Hi Obeliksz
Thanks for the heads-up.
Indeed some things have changed meanwhile and we forget to check the tutorial. I will update it soonish.
To "fix" your issue.
/one-pager-module/dialogs/common/default-dialog-actions.yaml
to/one-pager-module/includes/default-dialog-actions.yaml
/one-pager-module/dialogs/pages/main.yaml
, at the very bottom, the last line should be:To let you understand the underlying issue: The system tried to read
/one-pager-module/dialogs/common/default-dialog-actions.yaml
- expecting it to be a dialog. Howver, it is just a fragment - getting included later on.Such fragments we should store in locations which are not scanned by the system (which means: not within dialogs, templates, apps, fields, and some more).
Per default we recommend the directory
/<light-module-name>/includes
to use for fragments files.I hope this helps.
Obeliksz
Thank you Christoph, it helped, but I'm not there yet...
After doing these changes and doing a maven update project I still get these:
2018-07-16 09:53:07,989 INFO ource.yaml.AbstractFileResourceConfigurationSource: Setting up YamlConfigurationSource to load FormDialogDefinition definitions from resources
2018-07-16 09:53:08,191 WARN agnolia.transformer.ClassPropertyBasedTypeResolver: Encountered the 'class' property but failed to resolved the type from its value: [info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator]
java.lang.ClassNotFoundException: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1309) ~[catalina.jar:9.0.10]
2018-07-16 09:53:08,231 INFO agnolia.config.source.yaml.YamlConfigurationSource: Registered definition from YAML file [/one-pager-module/dialogs/pages/main.yaml]: [dialog] definition [main] with reference id: [one-pager-module:pages/main] from module [one-pager-module] at [pages/main]
2018-07-16 09:53:08,232 WARN agnolia.config.source.yaml.YamlConfigurationSource: 1 major and 1 minor problems have been encountered
2018-07-16 09:53:08,233 WARN agnolia.config.source.yaml.YamlConfigurationSource:
Severity type: MAJOR
Title: /form/tabs/1/fields/0/identifierToPathConverter: [Definition resolution] - Source data processing problem
Problem details: Failed to instantiate an object of type [interface info.magnolia.ui.form.field.converter.IdentifierToPathConverter] due to [No suitable constructor found for class [interface info.magnolia.ui.form.field.converter.IdentifierToPathConverter]], null is returned
2018-07-16 09:53:08,234 WARN agnolia.config.source.yaml.YamlConfigurationSource:
Severity type: MINOR
Title: /form/tabs/1/fields/0/contentPreviewDefinition/contentPreviewClass: [Definition resolution] - Source data processing problem
Problem details: Failed to resolve a class property due to a missing class: [info.magnolia.dam.app.ui.field.DamFilePreviewComponent]
Brice Nzuakue
Hi Christopher Meier,
I still have the issue even after performing your fix.
thanks,
Diogni
Brice Nzuakue
now it works for me