Designs & Layouts

In this article, you will be introduced to the basic concepts behind working with designs and layouts in Dynamicweb. First some basic terminology:

  • A layout is a dynamic html file containing the markup for a web page
  • A design is a collection of layouts

The basic idea behind working with designs and layouts in Dynamicweb is to provide you with maximum freedom to create a design, but also allow you to change and apply the design quickly and with a minimum of effort. The overall goal is to:

  • Make it easy to implement and understand templates
  • Provide you with total design freedom
  • Make it trivial to copy a design from one solution to another

This article will teach you the overall of working with designs and layouts in Dynamicweb.

Note: Layout templates support *.htm, *.html and *.cshtml (Razor). XSLT can be used for navigations, but not for entire templates. 

A design – a collection of layouts (e.g. Index.html) and static ressources such as images, javascript, and so on – is installed by being placed inside the main Designs folder; /Files/Templates/Designs.

Each design on a solution should have its own subfolder inside this folder – the name of the folder is the name of the design (Figure 2.1).

Figure 2.1 Installing a design

You can preview the layout from the file manager, by double clicking the .html file – this opens the file in a new browser window – or by accessing the URL where it is located, e.g. yourwebsite.dk/Files/Templates/Designs/Condition/Filename.html

When a new design is uploaded to a solution it will be static – which means it won’t automatically display content created on pages and paragraphs in Dynamicweb.

To make a static design dynamic, all you have to do is add special class attributes to a few key html element in the layout:

  • The dwcontent attribute creates content placeholders – elements inside which page and paragraph content is rendered
  • The dwnavigation attribute creates navigation placeholders – elements inside which a navigation is rendered

Both placeholder types are closely related, but there are some key differences outlined below.

A content placeholder requires an id, a title attribute, and the dwcontent class:

HTML
<div class="dwcontent" id="maincontent" title="Main Content"></div>

All exising content and elements inside a content placeholder are ignored – only content added under the matching content placeholder (Figure 4.2) in the backend will be rendered in frontend.

Figure 4.2 The content placeholder will then be available in the backend

You can add additional classes to the placeholder element using Razor. Just make sure the class name is added using a variable. The additional class name is then added runtime. The dwcontent class name has to be static. 

An example using a variable as additional class names:

@{ var className = "subpage"; if (GetInteger("DwPageId") == 1) { className = "frontpage"; } } <div class="dwcontent @className" title="Placeholder" id="main"> </div>

It is possible to test if a placeholder returns a value by checking if the tag containing the rendering of the content of the placeholder has a value. 

@{ if (!String.IsNullOrEmpty(GetString("DwContent(main)"))) { <div class="dwcontent" title="Placeholder" id="main"> </div> } else { <div>Placeholder has no content</div> } }

Like a content placeholder, a navigation placeholder requires and id, a title, and the dwnavigation class. Futhermore, it must be created from an <ul> element:

HTML
<ul class="dwnavigation" id="topnavigation" title="TopNavigation"></ul>

Dynamicweb uses XML/XSLT to render navigations. The dwnavigation tag uses a set of default values and a default navigation template (LeftNavgationEcom.xslt), but you can customize how the navigation should behave by adding the data-settings attribute to your navigation element:

RAZOR
<ul class="dw-categories dwnavigation" id="leftnavigation" data-settings="startlevel:1;endlevel:4;template:LeftNavigationEcom.xslt;"></ul>

The following data-settings are available to you:

Property

Description

Default value

Possible values

startlevel

The absolute level from which the XML should include navigation items from

1

1-99

endlevel

The absolute level to which the XML should include navigation items to

99

1-99

template

Name of XSLT template used for parsing the navigation XML

LIClean.xslt

Any valid existing navigation XSLT template. Must be placed in /Templates/Navigation, /Templates/Designs/Navigation or /Templates/Design/DesignName/Navigation

expandmode

How the navigation XML expands and which nodes it includes

Path

None, Path, All, Pathonly

parentid

Limits the navigation to items placed under the page with the ID specified

0

Any valid page id

parenttag

Limits the navigation to items placed under the page with a specific navigation tag. It works like parentid setting,

but where parentid is a unique key, the parent tag can be on several pages in different

languages – and the value is language/website context sensitive.

 

A name from the parent tag field on a pages properties, navigation dialog.

areaid

Limits the navigation to items placed under the website with the ID specified

0

Any valid website id (these can be seen under the Websites module)

sitemapmode

Specifies which items to include in the XML. If set to true, hidden navigation items are included, but not items where show in sitemap is not set. If set to false, hidden items are not included, but do not show in sitemap are included.

False

True or False

 

Often, it is useful to generate or assign dynamic values to an HTML attribute using razor:

@foreach (LoopItem i in GetLoop("Pages")) { <a href="@i.GetValue(Gallery.List.Page.Link)">... }

This works in all templates except layout templates; they are loaded as DOM in the Dynamicweb layout engine, and having a code block with “ inside an attribute value makes the DOM parser fail.

Instead you should define a variable in a code block and use that variable as the attribute value:

RAZOR
@* Correct syntax of Razor in attribute values in layout files *@ @{ var attributeValue = GetValue("DwPageName"); } <div id="@attributeValue">Correct syntax</div> @* Wrong syntax of Razor in attribute values in layout files*@ <div id="GetValue("DwPageName")">Wrong syntax</div>

When a design has been uploaded and made dynamic, a layout from it can be selected as the default layout for a website. This means that new pages created on that website will use the that layour by default.

To select a default layout on a website:

  • Open the website settings
  • Switch to the layout tab
  • Use the layout dropdown to select the default layout (Figure 8.1)
  • Save

And that's all – all pages on the website will now use this layout, unless another layout is explicitly selected.

After selecting a default layout, only alternative layouts from the same design can be selected on pages under this website.

As explained above, a design is a collection of layouts – but let’s dig a little deeper. Most designs consist of:

  • A master template which contains markup shared across layouts
  • A set of layout templates used control the structure of content on a page
  • A set of paragraph templates which control how content added using paragraphs is rendered
  • A set of app templates which control how content published using one of the Dynamicweb apps is rendered

Read more about templates and other resources below.

A master template is a template which contains all the markup is reused across layouts. The concept is known from ASP.NET and works in the same manner – typically, a master page contains e.g. a header, navigations, a footer, etc.

In the master page markup, you then use the @ContentPlaceholder() method to specify where layout-content should be rendered:

<!-- THIRD NAVBAR: Breadcrumb --> <div id="breadcrumb"> <div class="fluid-container"> <ol class="dwnavigation breadcrumb" id="bread" data-settings="template:Breadcrumb.xslt;expandmode:all"></ol> </div> </div> <!-- Render Template content --> @ContentPlaceholder()

On the other side of the equation, the Master template must be included in each layout file.

A layout typically includes paragraph content – either from a standard paragraph, an item-based paragraph, or output from an app such as the Product Catalog app or the Forum app.

Paragraphs are always associated with a particular content placeholder – the one they are listed under on the page. How content from a paragraph is rendered depends on the paragraph template used. Like layout templates, paragraph templates can be selected explicitly on each paragraph, but you can also create default paragraph templates which are then used as a fallback.

Paragraph templates can be located in several places:

  • Designs/Paragraphs contains paragraph templates available to all designs
  • Designs/[yourdesign]/Paragraph contains design-specific paragraph templates
  • Designs/YourDesign/YourLayout/Paragraph contains layout-specific templates

Paragraph templates for standard paragraphs use a set of standard template tags to retrieve content:

RAZOR
<div>@GetValue("ParagraphHeader")</div> <div>@GetValue("ParagraphText")</div> <div>@GetValue("ParagraphImage")</div> <div>@GetValue("ParagraphModule")</div>

Dynamicweb applies a template to a paragraph in the following order:

  • If a template is selected on the paragraph it will be used
  • Else, if the content placeholder has a paragraph template specified it will be used
  • Else, if the nearest paragraph template folder contains a template called 'Default.cshtml' that template will be used
  • Else, if the first template in the nearest Paragraph template folder will be used
  • Else, the first template in the /Files/Templates/Paragraph folder will be used

Layout templates control the structure of all content shown on a certain page type – e.g. a landing pages, a contact page, a newsletter page, etc. Most layout templates inherit content – like a header, one or more navigations, and a footer – from a master template.

This is done by including the master template above all other includes and variables:

RAZOR
@MasterPageFile("master.cshtml") @using System.Web @using System.Net; @using Newtonsoft.Json; @using Newtonsoft.Json.Linq; @{ string [] stringSeparators = new string[] {", ", " and ", "|", ","}; string title = @GetString("Item.Title"); string [] titles; titles = @title.Split(stringSeparators, StringSplitOptions.None); }

Then, before parsing of a page commences, the master template is merged with the layout template and the layout template content is inserted in the master template where the @ContentPlaceholder() method is located.

Layout templates, in turn, include paragraph content by defining one or more containers as content placeholders, as described above.

As mentioned above, some paragraph types can have an app attached – for instance a product catalog app, a forum app, a forms for editors app, and so on. Output from the app is merged with the paragraph template where the ParagraphModule tag is placed, as described in the previous section.

An app may use more than one template – the product catalog, for instance, uses one template to render a list of products and another to render a single product in more detail.

Static content in your templates – images, CSS, JS and so on – is referenced using the relative path to the content in relation to the template.

Let’s say you want to reference a javascript file called GeneralMethods.js, which is located in Files/Templates/Designs/Yourdesign/js/, the master template for that design – you don’t have to reference the full server path, you can reference the relative location like this:

HTML
<script type="text/javascript" src="js/GeneralMethods.js"></script>

On the other hand, if the static content is located outside the design folder the full path must be referenced. We recommend that you use a clear and ordered structure from the beginning, placing CSS in a CSS-folder, images in an Images folder, JavaScript in a /JS folder, and so on.

Layout templates are parsed whenever they are changed, and the parsed versions are generated in a subfolder called _parsed, with .parsed added to the file name (Figure 15.1. The parser relies on valid html/xml, and will try to fix minor issues – but if the markup is in bad shape, parsing might not work as expected.

Figure 15.1 Parsed layout templates

The parsing process handles a number of things which Dynamicweb relies on to work as intended, for instance:

  • Title & meta tags
  • Stylesheet and javascript tags
  • References to static content, such as images, CSS and JS
  • Content placeholders
  • Navigations
  • Search forms

You can, if you want to, disable parsing on the headnode by setting the data-setting disableparsing to true:

HTML
<head data-settings = "disableparsing:true;"> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head>

If set to true, the head node will not be parsed and all content (title, meta tags, static resources, etc,) are not inserted.

Content placeholders are parsed using the following rules:

  • The dwcontent class is removed from the element
  • The title attribute is removed
  • The inner html of the element is replaced with the template tag @GetValue(“DwContent(YourContentPlaceholderID)”)

An unparsed content placeholder could look like.

<div class="row dwcontent" id="maincontent" title="Content area"> </div>

After parsing, it could look like:

<div class="row" id="maincontent">@GetValue("DwContent(maincontent)")</div>

Navigations are parsed using the following rule:

  • The UL element is removed, and replaced with the template tag @GetValue(“DwNavigation(YourNavigationID)”)

An unparsed navigation element:

<ul class="dw-categories dwnavigation" id="leftnavigation" data-settings="startlevel:1;endlevel:4;template:LeftNavigationEcom.xslt;"> </div>

A parsed navigation element:

@GetValue("DwNavigation(leftnavigation)")

The parser consists of a number of rules, which determine where it inserts elements such as template tags.

If the location chosen by the parser is causing problems, e.g. because of the sequence of CSS files, you can overrule the parsing procedure by inserting the template tag in the original layout template at the desired location. The parser will not insert tags if they already exist.

Placeholder tags like dwcontent and dwnavigation cannot be overruled, since they are system critical, but you can still override the parser in some ways.

If, for instance, you want to keep your markup and text after parsing, you can manually insert the relevant template tags in the location the parser would have put them, and avoid the parser replacing your own text and markup completely:

For content placeholders, use @GetValue(“DwContent(YourContentPlaceholderID)”)

For navigation, use @GetValue(“DwNavigation(YourNavigationPlaceholderID)”)