<!--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 a very powerful tool to design HTML templates. |
|
For example, we create a `master` view that includes |
basic CSS and HTML style, and defines placeholders for different types of content that should be included. Then we derive different views that are responsible for actual content. |
|
master |
/ | \ |
news page intro |
|
|
Of course the content for the derived views should be also |
be derived from the parent content classes. |
|
## Content |
|
Let's create our `content.h` for the sample hierarchy above. |
|
First we define our `master` content in the `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. |
|
|
<!--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 a very powerful tool to design HTML templates.
|
|
For example, we create a `master` view that includes
|
basic CSS and HTML style, and defines placeholders for different types of content that should be included. Then we derive different views that are responsible for actual content.
|
|
master
|
/ | \
|
news page intro
|
|
|
Of course the content for the derived views should be also
|
be derived from the parent content classes.
|
|
## Content
|
|
Let's create our `content.h` for the sample hierarchy above.
|
|
First we define our `master` content in the `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.
|
|
|
|