<!--toc--> |
|
## Introduction |
|
CppCMS views are actually classes, and thus you can derive one view from other, override different templates and so on. |
|
This gives a developer very powerful tool to design HTML templates. |
This gives a developer a very powerful tool to design HTML templates. |
|
For example, we create a `master` view that includes |
basic CSS and HTML style, defines a placeholders for different |
types of content that should be described. Then we derive |
different views that are responsible on actual content. |
basic CSS and HTML style, and defines placeholders for different types of content that should be described. Then we derive different views that are responsible on actual content. |
|
master |
/ | \ |
news page intro |
|
|
Of course the content for the derived views should be also |
be derived of the parent content classes. |
|
## Content |
|
Let's create our `content.h` for the sample hierarchy above. |
|
First we define our `master` content in `content` namespace. |
|
struct master : public cppcms::base_content { |
std::string title; |
}; |
|
It would include shared information like our web site title. |
|
Then we create a `news` content derived from the master: |
|
struct news : public master { |
std::list<std::string> news_list; |
}; |
|
It would add some set of "news" messages we want to display, we do the same for `page` content: |
|
struct page : public master { |
std::string page_title, page_content; |
}; |
|
With, of course, different data. For the "introduction" page |
we would use the same `master` content as we would |
not need more data. |
|
## Views |
### Master |
|
Let's show our `master.tmpl`: |
|
As usual we define the include and the skin name: |
|
<% c++ #include "content.h" %> |
<% skin myskin %> |
|
Then we define our `master` view |
|
<% view master uses content::master %> |
|
We create some generic title that can be overridden. |
|
<% template title() %><%= title %><% end %> |
|
Define the real content we want to display |
|
<% template page_content() %>Override Me<% end %> |
|
And finally we define our main `render` function |
|
<% template render() %> |
<html> |
<head> |
<title><% include title() %></title> |
</head> |
<body> |
<h1><% include title() %></h1> |
<div id="content"> |
<% include page_content() %> |
</div> |
</body> |
</html> |
<% end template %> |
|
Note: |
|
- We use `title()` in several places |
- We put our placeholders in the locations we want, in our |
case it is one placeholder `page_content()` |
|
Then we finish our `master.tmpl` as usual |
|
<% end view %> |
<% end skin %> |
|
### News |
|
Then we create our `news.tmpl`. As usual we start and end |
it with |
|
<% skin myskin %> |
... |
<% end skin %> |
|
Then we define our view: |
|
<% view news uses content::news extends master %> |
|
Note: |
|
- It `extends master` - i.e. derived from `master` view |
- It uses `content::news` and because `content::news` derived from `content::master` it works. |
|
Then we override a title using original title: |
|
<% template title() %><% include master::title() %> :: News<% end % |
|
And define our central content: |
|
<% template page_content() %> |
<% foreach message in news_list %> |
<ul> |
<% item %> |
<li><%= message %></li> |
<% end %> |
</ul> |
<% end foreach %> |
<% end template %> |
|
### Page |
|
We do the same for `page.tmpl` |
|
<% skin myskin %> |
<% view page uses content::page extends master %> |
<% template title() %><% include master::title() %> :: <%= page_title %><% end %> |
<% template page_content() %> |
<%= page_content | raw %> |
<% end template %> |
<% end view %> |
<% end skin %> |
|
|
### Introduction |
|
Now we create our final `intro` view, but in its case |
we do not add any new content as we don't need it - we reuse `content::master` |
|
<% skin myskin %> |
<% view intro uses content::master extends master %> |
<% template page_content() %> |
<p><a href='<% url "/page" %>'>The Page</a></p> |
<p><a href='<% url "/news" %>'>The News</a></p> |
<% end template %> |
<% end view %> |
<% end skin %> |
|
Note: we use `<% url ... %>` tag from the templates the same way we used it from the application in [this](wikipp/en/page/cppcms_1x_tut_url_mapping) tutorial. |
|
|
## Controller |
|
We create a usual mapping to `intro`, `news` and `page` functions: |
|
dispatcher().assign("",&myapp::intro,this); |
mapper().assign(""); |
|
dispatcher().assign("/news",&myapp::news,this); |
mapper().assign("news","/news"); |
|
dispatcher().assign("/page",&myapp::page,this); |
mapper().assign("page","/page"); |
|
mapper().root("/myapp"); |
|
|
Please note, because there is no direct HTML page |
that renders `master` content we do not create a mapping |
for it. On the other hand we do want to setup the |
shared master content for all links. |
So we create a small function that initializes the content: |
|
void ini(content::master &c) |
{ |
c.title = "My Web Site"; |
} |
|
Then we define our "pages": |
|
|
void intro() |
{ |
content::master c; |
ini(c); |
render("intro",c); |
} |
void page() |
{ |
content::page c; |
ini(c); |
c.page_title = "About"; |
c.page_content = "<p>A page about this web site</p>"; |
render("page",c); |
} |
void news() |
{ |
content::news c; |
ini(c); |
c.news_list.push_back("This is the latest message!"); |
c.news_list.push_back("This is the next message."); |
c.news_list.push_back("This is the last message!"); |
render("news",c); |
} |
|
|
**Notes:** |
|
- Each one of them renders the view it needs |
- Each one of then uses their own content |
- Each one of them calls shared `ini()` function |
to setup the `master` content for all. |
|
## Building |
|
Please note, even thought each view has its own file |
the order of compilation is important so the `page.tmpl` |
would be compiled after `master.tmpl`. So in our |
Makefile we write: |
|
cppcms_tmpl_cc master.tmpl page.tmpl news.tmpl intro.tmpl -o my_skin.cpp |
|
It would not work of `master.tmpl` would not be the |
first in the list. |
|
|
|