To understand how to make a page template for Skyline CMS we'll have a look at a standard 3 column template with a main menu and a submenu. You can download the template and the required helper, images and stylesheets here.
How to create a page template
Files
|-app
|-helpers
|-menu_helper.rb
|-templates
|-page
|-default
|-_footer.html.erb
|-_head.html.erb
|-_header.html.erb
|-_sub_navigation.html.erb
|-_top_navigation.html.erb
|-index.html.erb
|-public
|-images
|-stylesheets
The files in the public folder are self explanatory but let's have a closer look at the app folder.
Helpers
Templates in Skyline are rendered as views in Rails so you can use all the things you would normaly use in erb templates.
In our example template we use the menu helper to create an array of all the pages starting from a given page. This helps us to render the top (all the pages starting from root) and sub menu (all the pages starting from the current page).
menu_helper.rb
module MenuHelper
# Create a menu structure starting at a certain page
#
# ==== Parameters
# page<Page>:: Startpoint for menu
#
# ==== Options
# :depth<Integer>:: Depth for menu (default = 1)
#
# --
def menu(page,options={})
options.reverse_merge! :depth => 1
depth = options[:depth]
base = {:page => page, :children => []}
return base if options[:depth] == 0
base[:children] = page.children.in_navigation.published.map{|child| menu(child,:depth => (depth - 1))}
base
end
end
Templates
In the templates/page folder you can find several partials and the index.html.erb that will be rendered when the template is selected for a page.
Most of the code in the files is self explanatory, but there are some custom Skyline things that I'll explain down here.
_head.html.erb
<title><%= article_version.data.title_tag %></title>
<%= content_tag "meta", "", :name => "description", :content => article_version.data.meta_description_tag if article_version.data.meta_description_tag.present? %>
The page is identified by article_version and the page properties are stored in data. The title_tag method show above checks wether there is a custom title tag and autmatically sets the correct tag.
As there is no fall back for a description tag we only write one if one is set for the page.
_top_navigation.html.erb
<% nesting = article_version.page.nesting %>
<% m = @menu || menu(nesting[0]) %>
<ul>
<% is_active = Skyline::Page.root == article_version.page %>
<li class="<%= "active" if is_active %>">
<%= link_to Skyline::Page.root.published_publication_data.andand.navigation_title, Skyline::Page.root.url %>
</li>
<li>
<% m[:children].each do |p| %>
<% is_active = p[:page] == article_version.page || nesting.include?(p[:page]) %>
<li class="<%= "active" if is_active %>">
<%= link_to p[:page].published_publication_data.andand.navigation_title, p[:page].url %>
</li>
<% end %>
</ul>
Our top navigation shows all the pages in the first level under the root node plus the root node (home page) itself.
To achieve this we use the nesting method of page.
Nesting returns an array of all the pages starting from the root node up to and including the current page.
As we want to show the pages of the root node we pass nesting[0] to the menu helper and then loop through the array returned by the helper.
_sub_navigation.html.erb
<% nesting = article_version.page.nesting %>
<% m = @menu[1] || menu(nesting[1],:depth => 2) %>
<div id="leftbar">
<% if m[:children].any? %>
<ul id="navigation">
<% m[:children].each do |p| %>
<% is_active = p[:page] == article_version.page || p[:children].detect{|c| c[:page] == article_version.page} %>
<li class="<%= "active" if is_active %> <%= "last" if p == m[:children].last %>">
<%= link_to p[:page].published_publication_data.andand.navigation_title, p[:page].url %>
<% if p[:children].any? && is_active %>
<ul>
<% p[:children].each do |sp| %>
<li class="<%= "active" if sp[:page] == article_version.page %>">
<%= link_to sp[:page].published_publication_data.andand.navigation_title, sp[:page].url %>
</li>
<% end %>
</ul>
<% end %>
</li>
<% end %>
</ul>
<% end %>
</div>
In our example the sub menu shows all the pages under the selected level. So this time we pass nesting[1] to the menu helper. As we also want to show the children of a selected sub page we pass :depth => 2 to our menu helper.
Then we loop through the array to build our submenu.
The is_active variable is set if the page we're processing is the same as the current page or one of its children. If that is the case we render the next level.
<% is_active = p[:page] == article_version.page || p[:children].detect{|c| c[:page] == article_version.page} %>
index.html.erb
<%= render :partial => "default/head" %>
<% page_sections = page_sections_per_column(article_version) %>
<% nesting = article_version.page.nesting %>
<% @menu = menu(nesting[0],:depth => 2) %>
<body>
<div id="visual" class="blue">
<div id="body">
<div class="wrapper">
<div id="content">
<h1><%= article_version.data.title %></h1>
<% assign(:heading_level,1) %>
<% page_sections.each_with_index do |page_section, i| %>
<% next if i == 1 || page_section.nil? %>
<%= render_collection(page_section) %>
<% end %>
<%= @body %>
</div>
<div id="sidebar">
<% if page_sections[1] %>
<%= render_collection(page_sections[1]) %>
<% end %>
</div>
<%= render :partial => "default/sub_navigation" %>
<%= render :partial => "default/footer" %>
</div>
</div>
<%= render :partial => "default/header", :locals => {:nesting => nesting} %>
</div>
</body>
</html>
Our index now only needs to include the necessary partials and render all the sections in the right place.
By default Skyline uses a splitter section to divide the page into columns. The helper page_sections_per_column(article_version) collects all the sections of a page and returns an array with sections per column.
After that it's just a matter of choosing where to render each column.
<% page_sections.each_with_index do |page_section, i| %>
<% next if i == 1 || page_section.nil? %>
<%= render_collection(page_section) %>
<% end %>
In our example we've defined the first column as our content column. Here we will render all the sections except the ones for the sidebar (page_sections[1]).
