Cms Implementation from Scratch using TagLib
This Tutorial shows how to implement the CMS. It is based on the TagLib and Observers Design from OSWD.
This is the first part of the complete Tutorial that shows how to create a complete community/platform.
It is a lot simpler than the Implement a Cms from scratch which uses the Java calls instead of taglibs.
The final version of this design is available for download (since this HowTo is still work-in-progress so is the download)
TODO
- update paths to correct installation
Preparation
- download and install the corinis ccm (get the zip or the setup.exe)
- download the Observers Design and extract it to INSTALLATIONFOLDER/webroot/observers
When talking about folders I will use the short name, here is a list so you find the right ones:
- INSTALLATIONFOLDER: The default installation directory (normally: "C:\Program Files\Corinis CCM\")
- webroot: where all the jsp files/images/etc. are (normally: "C:\Program Files\Corinis CCM\tomcat\webapps\example_1\webroot\")
- XSL folder: all xsls are fond there (normally: "C:\Program Files\Corinis CCM\tomcat\webapps\example_1\webroot\WEB-INF\xsl\")
- templates: the cms templates are found in webroot\WEB-INF\templates but you should normally use the cms to edit the templates
What to implement
We will implement almost all features available in the design, here is a description what we will do (there will be a second part of this to implement some of the more advanced features):
page title
The page title will be hardcoded - so it has actually nothing to do with corinis.
subtitle
The subtitle will be read from the cms. We will add an invisible field (like a metatag) that is read in this position.
path
The path will be added with the cms filemanager and a simple xsl
special toplinks
The home link will be hardcoded, so will the sitemap. The rest will be read from the cms.
navigation
The navigation will be created similar to the path, only a little more xsl magic will be applied.
latest news
The latest news will be created by getting fields from the cms.
content
The content layout will consist of two repeatables, with a few checkbox options to apply styles and define where the image will be. The content structure wll look like this:
- header (edit)
- abstract (richedit)
- content (repeatable)
- header (text)
- text(repeatable)
- image (image)
- text (richedit)
- teaser (teaser)
The fields header and abstract will be available on ALL pages and templates and we will use this information to create the teaser and newsareas.
Step 1: the page title and initialisation
First you have to rename the index.html to index.jsp, so it will be recognized by tomcat.
At the very beginning of the page (right after the DOCTYPE) add:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd"> <%@ taglib uri="/corinisTags" prefix="corinis" %>
You can also change the title of the page (line 16):
<h1><a id="top"></a><a href="index.html">Observers - with Corinis CCM</a></h1>
We will also put the cms in place (line 37):
<!-- ### content include starts ### --> <div class="mainbox"> <corinis:cms/> <h3>The Observers Design</h3>
For now we will keep the static content and put the cms just above it, since we might need to lookup some definitions from there while implementing. We will remove it as soon as the templates are ready.
If you go to http://localhost/observers/ you will see the cms already at work, altough the styles are a little bit messy, but we will address this next.
Step 2: fix the template
We will now fix the template a little bit, so the page looks correct.
Go to http://localhost/corinis and log in with name: admin and pass: admin
Now click on templates and click on startpage.xhtml to edit the template, or simply create the file if it does not exit.
the new layout:
<corinis>
<h3>
<corinis-field name="header" type="text" />
</h3>
<p>
<corinis-field type="richedit" name="abstract"/>
</p>
<corinis-repeatable name="content">
<corinis-exist name="header">
<h4>
<corinis-field name="header" type="text" />
</h4>
</corinis-exist>
<p>
<corinis-repeatable name="text">
<corinis-field name="image" type="image" style="float:left;margin-right:10px;"/>
<corinis-field name="content" type="richedit" />
<corinis-field name="external" type="teaser" xsl="demo/modules/Cms/teaser.xsl" />
</corinis-repeatable>
</p>
<br/>
</corinis-repeatable>
</corinis>
Save it and change the content.xhtml to the same content (we make it a little different later).
The content.xhtml is the default content layout. The startpage.xhtml is used for the startpage. There are two layouts because you normally want your startpage a little more fancy than a normal content page.
The tags used are described in Templates.
if you refresh http://localhost/observers/ you will see that the layout looks much better now. You may change some content in the cms. Make sure you send the document life, otherwise you won't see any change (Qm->life).
Step 3: The navigation
Next thing to do is to implement the navigation on the left side. To make everything a little easier to understand we first implement the navigation without any fancy dynamic stuff (like show the path).
At line 109 add:
<div class="navbox"> <corinis:cms function="getFileManagerComplete" xsl="show.xsl"/> <div class="inactive"><p><a href="index.html">Some category</a></p></div>
this will display the xml tree for of the filemanager. You will see it on the left side once you refresh the page. This is what the show.xsl is for. It helps creating the xsl when you know how the xml tree looks like :)
Now for the xsl for the navigation:
Change the code like this (line 109):
<div class="navbox"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:for-each select="/CMSFILEMANAGER/ENTRY/ENTRY"> <div class="active"> <p> <a href="?Document_id={ID}> <xsl:value-of select="NAME"/> </a> </p> <ul> <xsl:for-each select="ENTRY"> <li> <a href="?Document_id={ID}> <xsl:value-of select="NAME"/> </a> </li> </xsl:for-each> </ul> </div> </xsl:for-each> </xsl:template> </xsl:stylesheet> </corinis:cms> <div class="inactive"><p><a href="index.html">Some category</a></p></div>
We use the inline xsl function. If you want to find out more about xsl I would suggest that you read http://www.w3schools.com/xsl/
Basically we iterate through the xml tree displaying the first two levels of documents, creating the divs and links for the navigation. If you did everything right, you will have a nice navigation on the left side. It works already, click on a few links and the content changes.
Now we will make the navigation more dynamic. Use this snippet instead of the last one and see what happens:
<div class="navbox"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:for-each select="/CMSFILEMANAGER/ENTRY/ENTRY"> <div> <xsl:choose> <xsl:when test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="class">inactive</xsl:attribute> </xsl:otherwise> </xsl:choose> <p> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </p> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <ul> <xsl:for-each select="ENTRY"> <li> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:if> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </li> </xsl:for-each> </ul> </xsl:if> </div> </xsl:for-each> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!--class="navbox"-->
You can now remove the static navigation (until the </div>).
There is only one problem with this kind of navigation: it works only for the first two levels, since we want a multi-level navigation we use <xsl:template> instead of <xsl:for-each>:
<div class="navbox"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[@type=0]" /> <ul> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[@type=1]" /> </ul> </xsl:template> <!-- matches all entries --> <xsl:template match="ENTRY"> <xsl:choose> <!-- for all folders: --> <xsl:when test="@type=0"> <div> <xsl:choose> <xsl:when test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="class">inactive</xsl:attribute> </xsl:otherwise> </xsl:choose> <p> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </p> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:apply-templates select="ENTRY[@type=0]" /> <ul> <xsl:apply-templates select="ENTRY[not(@type=0)]" /> </ul> </xsl:if> </div> </xsl:when> <!-- all documents --> <xsl:otherwise> <li> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:if> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </li> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!--class="navbox"-->
At this point you should also make sure that all links pointing to index.html now point to index.jsp (I did a search-replace and found it 16 times).
Show the path
To implement the path (right under the title)
, we use pretty much the same technique as with the navigation (line 36):
<!-- ### quick navigation ends ### --> <div class="path"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:text>Path: </xsl:text> <a href="index.jsp"><xsl:text>Home</xsl:text></a> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[(@activedoc='true') or (@activedocpath='true')]" /> </xsl:template> <!-- matches all entries --> <xsl:template match="ENTRY"> <xsl:choose> <xsl:when test="@activedoc='true'"> <xsl:text> > </xsl:text> <xsl:value-of select="NAME"/> </xsl:when> <xsl:otherwise> <xsl:text> > </xsl:text> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> <xsl:apply-templates select="ENTRY[(@activedoc='true') or (@activedocpath='true')]" /> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!-- class="path" -->
Maybe you notice that >. You cant use < or > in xsl (the parser doesnt allow that), so you have to escape such entities. As a quickreference use the escape code table?.
Step 4: The news box
The news box is a nice little addon so its easier to keep track of things.
we implement it by getting a list of all documents available and sorting them by last-change date. Then we take the first 5 and display em (without the root document id=0.. since it might be changed quite a lot, but people might notice this anyway).
The attribute parentFolder="-2" in the function "getFileManager" will display all files in a flat tree (no structure).
Line 150;
<!--class="navbox"--> <div class="newsbox"> <h5>Latest News</h5> <corinis:cms name="header,abstract" function="getFileManager" parentFolder="-2" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:for-each select="/CMSFILEMANAGER/ENTRY[not(ID=0)]"> <xsl:sort select="LDATECHANGED" order="descending"/> <xsl:if test="position() < 5"> <p> <a href="?Document_id={ID}"> <strong><xsl:value-of select="DATECHANGED"/></strong><br/> <xsl:value-of select="CONTENT/header"/> </a><br/> <xsl:value-of select="CONTENT/abstract"/> </p> <p> <a href="?Document_id={ID}"> Read more » </a> </p> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!--class="newsbox"-->
Little things
The header and subheader
On the top of the page the header and subheader of the current page will be displayed. This is done with the <corinis:cms function="get" name="fieldname"/> tag.
The fieldname is specified in the template (<corinis-field type="edit" name="header"/>). You can include this by doing (line 18):
<h1> <a id="top"></a><a href="index.html">Observers - <corinis:cms function="get" name="header"/></a> </h1> <div class="header_mid"> </div> <!-- class="header_mid" --> <h2> <a href="index.html"><corinis:cms function="get" name="subheader"/></a> </h2>
the very bottom
at the bottom you have some basic info about the page, like its url and the date it has been changed the last time.
http://www.your-domain-here.com/pagename.html Last Change: Wed, 12 Oct 2005 16:58:26 +0200
The current url is easily imlemented using java:
<address><%=request.getRequestURL()%></address>
To get the date when the document has been last changed use the TagLib function:
Last Change: <corinis:cms function="changed"/><br />
Next steps…
We now have the cms implemented in the design. We got a template to work with, a working breadcrumb navigation and a few infos directly embedded in the the design.
Since this is getting longer than I thought I will put the rest in a second page: HowTo/en/Implementation/Cms%20(from%20scratch%20-%20taglib%20part%202)?
The finished jsp for part 1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd" > <%@ taglib uri="/corinisTags" prefix="corinis" %> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>The Observers Design - <corinis:cms function="get" name="header"/></title> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <meta http-equiv="content-language" content="EN" /> <style type="text/css">@import url("style.css");</style> <link rel="stylesheet" type="text/css" href="style_print.css" media="print" /> </head> <body> <h1> <a id="top"></a><a href="index.jsp">Observers - <corinis:cms function="get" name="header"/></a> </h1> <div class="header_mid"> </div> <!-- class="header_mid" --> <h2> <a href="index.jsp"><corinis:cms function="get" name="subheader"/></a> </h2> <!-- ### quick navigation starts ### --> <div class="quicknav"> <a href="index.jsp">Home</a> | <a href="index.jsp">Contact</a> | <a href="index.jsp">Sitemap</a> | <a href="index.jsp">Legal</a> </div> <!-- class="quicknav" --> <!-- ### quick navigation ends ### --> <div class="path"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:text>Path: </xsl:text> <a href="index.jsp"><xsl:text>Home</xsl:text></a> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[(@activedoc='true') or (@activedocpath='true')]" /> </xsl:template> <!-- matches all entries --> <xsl:template match="ENTRY"> <xsl:choose> <xsl:when test="@activedoc='true'"> <xsl:text> > </xsl:text> <xsl:value-of select="NAME"/> </xsl:when> <xsl:otherwise> <xsl:text> > </xsl:text> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> <xsl:apply-templates select="ENTRY[(@activedoc='true') or (@activedocpath='true')]" /> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!-- class="path" --> <!-- ### main container starts ### --> <div class="container"> <!-- ### content include starts ### --> <div class="mainbox"> <corinis:cms/> </div> <!-- class="main" --> <!-- ### content ends ### --> <!-- ### left box starts ### --> <div class="leftbox"> <div class="navbox"> <corinis:cms function="getFileManagerComplete" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[@type=0]" /> <ul> <xsl:apply-templates select="/CMSFILEMANAGER/ENTRY/ENTRY[@type=1]" /> </ul> </xsl:template> <!-- matches all entries --> <xsl:template match="ENTRY"> <xsl:choose> <!-- for all folders: --> <xsl:when test="@type=0"> <div> <xsl:choose> <xsl:when test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="class">inactive</xsl:attribute> </xsl:otherwise> </xsl:choose> <p> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </p> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:apply-templates select="ENTRY[@type=0]" /> <ul> <xsl:apply-templates select="ENTRY[not(@type=0)]" /> </ul> </xsl:if> </div> </xsl:when> <!-- all documents --> <xsl:otherwise> <li> <xsl:if test="(@activedoc = 'true') or (@activedocpath = 'true')"> <xsl:attribute name="class">active</xsl:attribute> </xsl:if> <a href="?Document_id={ID}"> <xsl:value-of select="NAME"/> </a> </li> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!--class="navbox"--> <div class="newsbox"> <h5>Latest News</h5> <corinis:cms name="header,abstract" function="getFileManager" parentFolder="-2" xsl="inline"> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <xsl:for-each select="/CMSFILEMANAGER/ENTRY[not(ID=0)]"> <xsl:sort select="LDATECHANGED" order="descending"/> <xsl:if test="position() < 5"> <p> <a href="?Document_id={ID}"> <strong><xsl:value-of select="DATECHANGED"/></strong><br/> <xsl:value-of select="CONTENT/header"/> </a><br/> <xsl:value-of select="CONTENT/abstract"/> </p> <p> <a href="?Document_id={ID}"> Read more » </a> </p> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> </corinis:cms> </div> <!--class="newsbox"--> </div> <!-- class="leftbox" --> <!-- ### left box ends ### --> <!-- ### right side box starts ### --> <div class="rightbox"> <div class="section"> <h5>Log In To This Site</h5> <form class="login" method="post" action=""> <p> Email Address:<br /> <input type="text" size="23" name="email" /> <br /> Password: (<a href="index.jsp">forgotten</a>)<br/> <input type="password" size="23" name="password" /> <br /> Upon Login:<br /> <select name="login_action"> <option value="remember_me">Remember me</option> <option value="do_nothing">Do nothing</option> </select> <input class="button" type="submit" value="Log in"/> </p> </form> <p> New? <a href="index.jsp">Register »</a><br /> </p> </div> <!--class="section"--> <div class="section"> <h5>Search</h5> <form class="qs" method="get" action="your-search-script-here.pl"> <p> <input class="textfield" type="text" name="q" value="" size="23" maxlength="255" /> <input class="button" type="submit" name="sa" value="Go" /> <a href="index.jsp">Advanced »</a> </p> </form> </div> <!--class="section"--> <div class="section"> <h5>View As</h5> <p> <a href="index.jsp">RSS</a> | <a href="index.jsp">RSS 2.0</a> | <a href="index.jsp">Atom</a> </p> </div> <!--class="section"--> <div class="section"> <h5>Quick Links</h5> <ul> <li class="extern"> <a href="http://www.oswd.org/">OSWD</a> </li> <li class="extern"> <a href="http://www.slashdot.org/">Slashdot</a> </li> <li class="extern"> <a href="http://www.kuro5hin.org/">Kuro5hin</a> </li> </ul> <p> </p> </div> <!--class="section"--> </div> <!-- class="rightbox" --> <!-- ### right side box ends ### --> <div class="toplink"> <a href="#top"> <img src="arrow_top.gif" alt="top" width="9" height="7" />top </a> </div> <!-- class="toplink" --> <!-- ### main box ends ### --> <!-- ### footer starts ### --> <div class="footer"> <address><%=request.getRequestURL()%></address> Last Change: <corinis:cms function="changed"/><br /> In case of questions or problems, please contact the <a href="mailto:webmaster [at] your-domain-here.com">Webmaster</a>. </div> <!-- class="footer" --> <!-- ### footer ends ### --> </div> <!-- class="container" --> </body> </html>
Attachments
-
observer1.png
(109.9 KB) -
added by niko 6 years ago.
-
observer2.png
(10.7 KB) -
added by niko 6 years ago.
-
observer3.png
(3.4 KB) -
added by niko 6 years ago.
-
observer4.png
(684 bytes) -
added by niko 6 years ago.
-
observer5.png
(8.4 KB) -
added by niko 6 years ago.
-
observer6.png
(2.6 KB) -
added by niko 6 years ago.
-
observer7.png
(1.3 KB) -
added by niko 6 years ago.
-
observer8.png
(8.7 KB) -
added by niko 6 years ago.
-
observer9.png
(1.7 KB) -
added by niko 6 years ago.
-
observer10.png
(677 bytes) -
added by niko 6 years ago.
-
observer11.png
(556 bytes) -
added by niko 6 years ago.
-
observer12.png
(872 bytes) -
added by niko 6 years ago.
-
observer13.png
(91.0 KB) -
added by niko 6 years ago.
-
observer14.png
(2.3 KB) -
added by niko 6 years ago.
-
observer15.png
(17.0 KB) -
added by niko 6 years ago.










