PageTemplate 2.1.6 → 2.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changes +11 -0
- data/Rakefile +4 -2
- data/lib/PageTemplate.rb +2 -0
- data/lib/PageTemplate/parser.rb +5 -0
- data/site/Makefile +15 -0
- data/site/MySubpageRenderer.rb +43 -0
- data/site/PageNavRenderer.rb +37 -0
- data/site/RedClothRenderer.rb +20 -0
- data/site/Site.rb +11 -0
- data/site/SiteNewsRenderer.rb +23 -0
- data/site/XhtmlTemplateRenderer.rb +141 -0
- data/site/base.css +4 -0
- data/site/footer.txt +2 -0
- data/site/header.txt +2 -0
- data/site/html/SiteMap.html +43 -0
- data/site/html/base.css +4 -0
- data/site/html/designer.html +524 -0
- data/site/html/index.html +267 -0
- data/site/html/install.html +125 -0
- data/site/html/programmer.html +289 -0
- data/site/html/version2.html +103 -0
- data/site/src/SiteMap +8 -0
- data/site/src/designer +410 -0
- data/site/src/index +165 -0
- data/site/src/install +80 -0
- data/site/src/metadata.txt +4 -0
- data/site/src/programmer +235 -0
- data/site/src/version2 +59 -0
- data/test.rb +9 -0
- metadata +59 -28
data/Changes
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
2.1.7:
|
2
|
+
Changes:
|
3
|
+
Added PageTemplate::VERSION constant
|
4
|
+
"gem" target in Rakefile uses PageTemplate::VERSION when building gems
|
5
|
+
Added Namespace#delete
|
6
|
+
2.1.6:
|
7
|
+
Oops. Forgot to put in changes.
|
8
|
+
2.1.5:
|
9
|
+
Oops. Forgot to put in changes.
|
10
|
+
2.1.4:
|
11
|
+
Oops. Forgot to put in changes.
|
1
12
|
2.1.3:
|
2
13
|
Bugfixes:
|
3
14
|
HTGlossary didn't survive the change from 2.0 to 2.1. I've
|
data/Rakefile
CHANGED
@@ -54,14 +54,16 @@ end
|
|
54
54
|
|
55
55
|
spec = Gem::Specification.new do |s|
|
56
56
|
s.name = "PageTemplate"
|
57
|
-
s.
|
57
|
+
s.require_path = "lib"
|
58
|
+
$LOAD_PATH.push s.require_path
|
59
|
+
require s.name
|
60
|
+
s.version = PageTemplate::VERSION
|
58
61
|
s.author = "Brian Wisti"
|
59
62
|
s.email = "brianwisti@rubyforge.org"
|
60
63
|
s.homepage = "http://coolnamehere.com/products/pagetemplate"
|
61
64
|
s.platform = Gem::Platform::RUBY
|
62
65
|
s.summary = "A simple templating system for Web sites."
|
63
66
|
s.files = Dir.glob("**/*")
|
64
|
-
s.require_path = "lib"
|
65
67
|
s.autorequire = "PageTemplate.rb"
|
66
68
|
s.test_file = "test.rb"
|
67
69
|
s.has_rdoc = true
|
data/lib/PageTemplate.rb
CHANGED
data/lib/PageTemplate/parser.rb
CHANGED
@@ -122,6 +122,11 @@ class PageTemplate
|
|
122
122
|
end
|
123
123
|
alias_method :[], :get
|
124
124
|
|
125
|
+
# Removes an entry from the Namespace
|
126
|
+
def delete(key)
|
127
|
+
@values.delete(key)
|
128
|
+
end
|
129
|
+
|
125
130
|
# parser: most namespace objects won't be a parser, but pass this
|
126
131
|
# query up to the parser object.
|
127
132
|
def parser
|
data/site/Makefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
all: site css
|
2
|
+
css:
|
3
|
+
cp base.css html/
|
4
|
+
site:
|
5
|
+
ruby Site.rb
|
6
|
+
images: site
|
7
|
+
mkdir html/images
|
8
|
+
cp extras/images/* html/images/
|
9
|
+
doc:
|
10
|
+
cp -R extras/doc/PageTemplate html/doc
|
11
|
+
clean:
|
12
|
+
rm -rf html
|
13
|
+
|
14
|
+
test-install:
|
15
|
+
sudo cp -Rf html/* /var/www/html
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Class SubpageRenderer
|
6
|
+
|
7
|
+
Generates a list of known subpages in a format compatible with
|
8
|
+
TextToHtmlRenderer.
|
9
|
+
|
10
|
+
=== Methods
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
class MySubpageRenderer < GenericRenderer
|
15
|
+
|
16
|
+
=begin
|
17
|
+
|
18
|
+
--- SubpageRenderer#render(content)
|
19
|
+
|
20
|
+
Renders a list of known subpages in a format compatible with
|
21
|
+
TextToHtmlRenderer. Adds the list to the end of the content.
|
22
|
+
|
23
|
+
=end
|
24
|
+
|
25
|
+
def render(content)
|
26
|
+
subpages = @document.subpages.clone
|
27
|
+
if (subpages.length > 0) then
|
28
|
+
push("\n\n")
|
29
|
+
push("<h2>Subpages:</h2>\n\n")
|
30
|
+
subpages.each_index { | index |
|
31
|
+
url = subpages[index]
|
32
|
+
doc = @website[url]
|
33
|
+
title = doc.fulltitle
|
34
|
+
|
35
|
+
push("* <A HREF=\"#{url}\">#{title}</A>\n")
|
36
|
+
}
|
37
|
+
push("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
return content + self.result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
2
|
+
|
3
|
+
class PageNavRenderer < GenericRenderer
|
4
|
+
def render(content)
|
5
|
+
# I know there's a quicker way to do this, but I'm in a hurry.
|
6
|
+
this_url = @document.url
|
7
|
+
doc_order = @sitemap.doc_order
|
8
|
+
this_index = doc_order.index(this_url)
|
9
|
+
forward = backward = " "
|
10
|
+
|
11
|
+
last_url = doc_order[this_index - 1]
|
12
|
+
last_page = @sitemap.documents[last_url]
|
13
|
+
if last_page and File.dirname(last_url) == File.dirname(this_url)
|
14
|
+
title = last_page.title
|
15
|
+
url = File.basename(last_url)
|
16
|
+
backward = "<p><- <a href='#{url}'>#{title}</a></p>\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
next_url = doc_order[this_index + 1]
|
20
|
+
next_page = @sitemap.documents[next_url]
|
21
|
+
if next_page and File.dirname(next_url) == File.dirname(this_url)
|
22
|
+
title = next_page.title
|
23
|
+
url = File.basename(next_url)
|
24
|
+
forward = "<p><a href='#{url}'>#{title}</a>- ></p>\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
push("<table width='100%' border='0'><tr>\n")
|
28
|
+
push("<td>#{backward}</td>\n")
|
29
|
+
push("<td align='right'>#{forward}</td>\n")
|
30
|
+
push("</tr></table>\n")
|
31
|
+
|
32
|
+
push(content)
|
33
|
+
|
34
|
+
return self.result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
2
|
+
|
3
|
+
# Hands content off to the RedCloth text formatter for rendering.
|
4
|
+
#
|
5
|
+
# + Set Attributes in the 'RedClothAttributes' metadata.
|
6
|
+
# + filter_html -- HTML not created by RedCloth is escaped
|
7
|
+
# + filter_styles -- style markup specifier is disabled
|
8
|
+
# + See http://www.whytheluckystiff.net/ruby/redcloth/
|
9
|
+
class RedClothRenderer < GenericRenderer
|
10
|
+
require 'redcloth'
|
11
|
+
|
12
|
+
def render(content)
|
13
|
+
attributes = []
|
14
|
+
if @document.metadata.has_key?('RedClothAttributes')
|
15
|
+
attributes = @document['RedClothAttributes']
|
16
|
+
end
|
17
|
+
rc = RedCloth::new(content, attributes)
|
18
|
+
return rc.to_html(:textile)
|
19
|
+
end
|
20
|
+
end
|
data/site/Site.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
2
|
+
|
3
|
+
class SiteNewsRenderer < GenericRenderer
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
def render(content)
|
7
|
+
newsfile = 'news.yml'
|
8
|
+
newsitems = YAML.load(File.open(newsfile).read())
|
9
|
+
limit = @document['NewsLimit']
|
10
|
+
|
11
|
+
if newsitems
|
12
|
+
newsitems.each do |item|
|
13
|
+
push("\n<div class='newsitem'>\n\nh3. #{item['title']}\n\np(date). #{item['date']}\n\n#{item['content']}\n</div>\n")
|
14
|
+
if limit
|
15
|
+
limit -= 1
|
16
|
+
break if limit == 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
return self.result
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'ZenWeb/HtmlRenderer'
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Class HtmlTemplateRenderer
|
6
|
+
|
7
|
+
Generates a consistant HTML page header and footer, including a
|
8
|
+
navigation bar, title, subtitle, and appropriate META tags.
|
9
|
+
|
10
|
+
=== Methods
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
class XhtmlTemplateRenderer < HtmlRenderer
|
15
|
+
|
16
|
+
=begin
|
17
|
+
|
18
|
+
--- HtmlTemplateRenderer#render(content)
|
19
|
+
|
20
|
+
Renders a standardized HTML header and footer. This currently also
|
21
|
+
includes a navigation bar and a list of subpages, which will
|
22
|
+
probably be broken out to their own renderers soon.
|
23
|
+
|
24
|
+
Metadata variables used:
|
25
|
+
|
26
|
+
+ author
|
27
|
+
+ banner - graphic at the top of the page, usually a logo
|
28
|
+
+ bgcolor - defaults to not being defined
|
29
|
+
+ copyright
|
30
|
+
+ description
|
31
|
+
+ dtd (default: 'DTD HTML 4.0 Transitional')
|
32
|
+
+ email - used in a mailto in metadata
|
33
|
+
+ keywords
|
34
|
+
+ rating (default: 'general')
|
35
|
+
+ stylesheet - reference to a CSS file
|
36
|
+
+ style - CSS code directly (for smaller snippets)
|
37
|
+
+ subtitle
|
38
|
+
+ title (default: 'Unknown Title')
|
39
|
+
+ icbm - longitude and latitude for geourl.org
|
40
|
+
+ icbm_title - defaults to the page title
|
41
|
+
|
42
|
+
=end
|
43
|
+
|
44
|
+
def render(content)
|
45
|
+
author = @document['author']
|
46
|
+
banner = @document['banner']
|
47
|
+
bgcolor = @document['bgcolor']
|
48
|
+
dtd = @document['dtd'] || 'DTD HTML 4.0 Transitional'
|
49
|
+
copyright = @document['copyright']
|
50
|
+
description = @document['description']
|
51
|
+
email = @document['email']
|
52
|
+
keywords = @document['keywords']
|
53
|
+
rating = @document['rating'] || 'general'
|
54
|
+
stylesheet = @document['stylesheet']
|
55
|
+
subtitle = @document['subtitle']
|
56
|
+
title = @document['title'] || 'Unknown Title'
|
57
|
+
icbm = @document['icbm']
|
58
|
+
icbm_title = @document['icbm_title'] || @document['title']
|
59
|
+
charset = @document['charset']
|
60
|
+
style = @document['style']
|
61
|
+
|
62
|
+
titletext = @document.fulltitle
|
63
|
+
|
64
|
+
# TODO: iterate over a list of metas and add them in one nicely organized block
|
65
|
+
|
66
|
+
# header
|
67
|
+
push([
|
68
|
+
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">',
|
69
|
+
"<head>\n",
|
70
|
+
"<title>#{titletext}</title>\n",
|
71
|
+
stylesheet ? "<link rel=\"STYLESHEET\" href=\"#{stylesheet}\" type=\"text/css\" title=\"#{stylesheet}\">\n" : [],
|
72
|
+
style ? "<style>\n#{style}\n</style>" : [],
|
73
|
+
"</head>\n",
|
74
|
+
"<body>\n"
|
75
|
+
])
|
76
|
+
|
77
|
+
self.navbar
|
78
|
+
|
79
|
+
if banner then
|
80
|
+
push("<img src=\"#{banner}\" /><br />\n")
|
81
|
+
unless (subtitle) then
|
82
|
+
push("<h3>#{title}</h3>\n")
|
83
|
+
end
|
84
|
+
else
|
85
|
+
push("<h1>#{title}</h1>\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
push([
|
89
|
+
subtitle ? "<h2>#{subtitle}</h2>\n" : [],
|
90
|
+
"<hr />\n\n",
|
91
|
+
content,
|
92
|
+
"<hr />\n\n",
|
93
|
+
])
|
94
|
+
|
95
|
+
self.navbar
|
96
|
+
|
97
|
+
push("\n</body>\n</html>\n")
|
98
|
+
|
99
|
+
return self.result
|
100
|
+
end
|
101
|
+
|
102
|
+
=begin
|
103
|
+
|
104
|
+
--- HtmlTemplateRenderer#navbar
|
105
|
+
|
106
|
+
Generates a navbar that contains a link to the sitemap, search
|
107
|
+
page (if any), and a fake "breadcrumbs" trail which is really just
|
108
|
+
a list of all of the parent titles up the chain to the top.
|
109
|
+
|
110
|
+
=end
|
111
|
+
|
112
|
+
def navbar
|
113
|
+
|
114
|
+
sep = " / "
|
115
|
+
search = @website["/Search.html"]
|
116
|
+
|
117
|
+
push([
|
118
|
+
"<p class=\"navbar\">\n",
|
119
|
+
"<a href=\"#{@sitemap.url}\">Sitemap</a>",
|
120
|
+
search ? " | <a href=\"#{search.url}\"><em>Search</em></a>" : [],
|
121
|
+
" || ",
|
122
|
+
])
|
123
|
+
|
124
|
+
path = []
|
125
|
+
current = @document
|
126
|
+
while current and current != current.parent do
|
127
|
+
current = current.parent
|
128
|
+
path.unshift(current) if current
|
129
|
+
end
|
130
|
+
|
131
|
+
push([
|
132
|
+
path.map{|doc| ["<a href=\"#{doc.url}\">#{doc['title']}</a>\n", sep]},
|
133
|
+
@document['title'],
|
134
|
+
"</p>\n",
|
135
|
+
])
|
136
|
+
|
137
|
+
return []
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
data/site/base.css
ADDED
data/site/footer.txt
ADDED
data/site/header.txt
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
2
|
+
<HTML>
|
3
|
+
<HEAD>
|
4
|
+
<TITLE>SiteMap: There are 6 pages in this website.</TITLE>
|
5
|
+
<LINK REL="STYLESHEET" HREF="base.css" type="text/css" title="base.css">
|
6
|
+
<META NAME="rating" CONTENT="general">
|
7
|
+
<META NAME="GENERATOR" CONTENT="ZenWeb v. 2.17.0 http://www.zenspider.com/ZSS/Products/ZenWeb/">
|
8
|
+
<META NAME="keywords" CONTENT="sitemap, website">
|
9
|
+
<META NAME="description" CONTENT="This page links to every page in the website.">
|
10
|
+
<link rel="up" href="index.html" title="PageTemplate">
|
11
|
+
<link rel="contents" href="" title="SiteMap">
|
12
|
+
<link rel="top" href="index.html" title="PageTemplate">
|
13
|
+
</HEAD>
|
14
|
+
<BODY>
|
15
|
+
<h1>Yo!</h1>
|
16
|
+
<hr />
|
17
|
+
<P class="navbar">
|
18
|
+
<A HREF="">Sitemap</A> || <A HREF="index.html">PageTemplate</A>
|
19
|
+
/ SiteMap</P>
|
20
|
+
<H1>SiteMap</H1>
|
21
|
+
<H2>There are 6 pages in this website.</H2>
|
22
|
+
<HR SIZE="3" NOSHADE>
|
23
|
+
|
24
|
+
<UL>
|
25
|
+
<LI><A HREF="index.html">PageTemplate</A></LI>
|
26
|
+
<LI><A HREF="install.html">Getting It</A></LI>
|
27
|
+
<LI><A HREF="designer.html">The Designer's Perspective</A></LI>
|
28
|
+
<LI><A HREF="programmer.html">The Programmer's Perspective</A></LI>
|
29
|
+
<LI><A HREF="version2.html">PageTemplate Version 2: What's New?</A></LI>
|
30
|
+
<LI><A HREF="">SiteMap: There are 6 pages in this website.</A></LI>
|
31
|
+
</UL>
|
32
|
+
<HR SIZE="3" NOSHADE>
|
33
|
+
|
34
|
+
<P class="navbar">
|
35
|
+
<A HREF="">Sitemap</A> || <A HREF="index.html">PageTemplate</A>
|
36
|
+
/ SiteMap</P>
|
37
|
+
|
38
|
+
<h1>Yo!</h1>
|
39
|
+
<hr />
|
40
|
+
<h1>Yo!</h1>
|
41
|
+
<hr />
|
42
|
+
</BODY>
|
43
|
+
</HTML>
|
data/site/html/base.css
ADDED
@@ -0,0 +1,524 @@
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
|
2
|
+
<title>The Designer's Perspective</title>
|
3
|
+
<link rel="STYLESHEET" href="base.css" type="text/css" title="base.css">
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<h1>Yo!</h1>
|
7
|
+
<hr />
|
8
|
+
<p class="navbar">
|
9
|
+
<a href="SiteMap.html">Sitemap</a> || <a href="index.html">PageTemplate</a>
|
10
|
+
/ The Designer's Perspective</p>
|
11
|
+
<h1>The Designer's Perspective</h1>
|
12
|
+
<hr />
|
13
|
+
|
14
|
+
<table width='100%' border='0'><tr>
|
15
|
+
<td><p><- <a href='install.html'>Getting It</a></p>
|
16
|
+
</td>
|
17
|
+
<td align='right'><p><a href='programmer.html'>The Programmer’s Perspective</a>- ></p>
|
18
|
+
</td>
|
19
|
+
</tr></table>
|
20
|
+
|
21
|
+
<h2>Who Are You?</h2>
|
22
|
+
|
23
|
+
|
24
|
+
<p>You are the esteemed Web Designer, aesthetically talented and
|
25
|
+
perhaps artistically inclined. You know what makes a good Web page.
|
26
|
+
You are not a programmer, though. It’s horrible when you have to go
|
27
|
+
down to the caves where they keep the developers to explain
|
28
|
+
where a simple login form belongs. You also don’t want to
|
29
|
+
remember where their odd-looking programming code is supposed to go
|
30
|
+
in your beautiful page. You want a simple, clean way of describing
|
31
|
+
the dynamic elements of site pages.</p>
|
32
|
+
|
33
|
+
|
34
|
+
<p>Okay, I’ve had too much coffee. This page explains how templating
|
35
|
+
works, and how to put PageTemplate to use when laying out the <span class="caps">HTML</span>
|
36
|
+
of your page.</p>
|
37
|
+
|
38
|
+
|
39
|
+
<h2>What’s a Template?</h2>
|
40
|
+
|
41
|
+
|
42
|
+
<p>When you are designing pages for a dynamic site or Web application,
|
43
|
+
there are a lot of details you won’t know in advance. Some examples
|
44
|
+
might include login information, the contents of a shopping cart,
|
45
|
+
or maybe even the contents of the page! Templates
|
46
|
+
allow you to put placeholders within your <span class="caps">HTML</span> to show where that login
|
47
|
+
information is displayed and how it is formatted. A good template
|
48
|
+
system does not require you to remember code while you’re designing:
|
49
|
+
you just make the page, and let programmers worry about filling it with
|
50
|
+
data.</p>
|
51
|
+
|
52
|
+
|
53
|
+
<p>In PageTemplate, those placeholders are referred to as <em>directives</em>.</p>
|
54
|
+
|
55
|
+
|
56
|
+
<h2>How Do I Use PageTemplate In My Pages?</h2>
|
57
|
+
|
58
|
+
|
59
|
+
<p>PageTemplate uses a simple language which you can embed
|
60
|
+
in your page. You should be able to use your favorite design tools to
|
61
|
+
create an attractive template. My favorite design tool happens to be
|
62
|
+
<a href="geekery/editors/emacs/index.html">GNU/Emacs</a>, but the odds are that
|
63
|
+
the designers out there lean towards something a little friendlier, like
|
64
|
+
<a href="http://www.dreamweaver.com/">Macromedia Dreamweaver</a>. With the default syntax,
|
65
|
+
all of us can be happy.</p>
|
66
|
+
|
67
|
+
|
68
|
+
<p>PageTemplate directives are indicated by being wrapped in between
|
69
|
+
<code>[%</code> and <code>%]</code> characters. If any of those characters are missing, PageTemplate
|
70
|
+
decides it is not a directive, and leaves it alone.</p>
|
71
|
+
|
72
|
+
|
73
|
+
<h3>Variables</h3>
|
74
|
+
|
75
|
+
|
76
|
+
<p>The major directives require <em>variables</em>, which are just
|
77
|
+
names for the value your want inserted, checked, or otherwise
|
78
|
+
accessed. It’s a good idea to use variable names that make
|
79
|
+
sense (<code>name</code> for a person’s name, <code>title</code> for the title of the page, etc.).</p>
|
80
|
+
|
81
|
+
|
82
|
+
<h3>Value Substitution</h3>
|
83
|
+
|
84
|
+
|
85
|
+
<p>Substitution is the easiest concept to master. When PageTemplate
|
86
|
+
comes across a value directive, it replaces that directive with some text.</p>
|
87
|
+
|
88
|
+
|
89
|
+
<h4>Syntax</h4>
|
90
|
+
|
91
|
+
|
92
|
+
<pre>
|
93
|
+
[%var variable %]
|
94
|
+
</pre>
|
95
|
+
|
96
|
+
<h4>Example</h4>
|
97
|
+
|
98
|
+
|
99
|
+
<pre>
|
100
|
+
<h1>Hello, [%var name %]</h1>
|
101
|
+
</pre>
|
102
|
+
|
103
|
+
<p>Every time that PageTemplate sees <code>[%var name %]</code> in
|
104
|
+
your template, it will replace that directive with the text
|
105
|
+
associated with <code>name</code>.</p>
|
106
|
+
|
107
|
+
|
108
|
+
<p>The programmer works his magic, and the visitor “Frank” sees this
|
109
|
+
greeting:</p>
|
110
|
+
|
111
|
+
|
112
|
+
<pre><h1>Hello, Frank</h1></pre>
|
113
|
+
|
114
|
+
<p>If <code>name</code> is not set, nothing is inserted. The greeting header would end up
|
115
|
+
looking like this:</p>
|
116
|
+
|
117
|
+
|
118
|
+
<pre><h1>Hello, </h1></pre>
|
119
|
+
|
120
|
+
<h3>If</h3>
|
121
|
+
|
122
|
+
|
123
|
+
<p>The <code>if</code> directive tells PageTemplate to only display a chunk of content when
|
124
|
+
some condition is true. If the condition is not true, PageTemplate skips the
|
125
|
+
block and moves on.</p>
|
126
|
+
|
127
|
+
|
128
|
+
<h4>Syntax</h4>
|
129
|
+
|
130
|
+
|
131
|
+
<pre>
|
132
|
+
[%if condition %]
|
133
|
+
chunk
|
134
|
+
[%endif%]
|
135
|
+
</pre>
|
136
|
+
|
137
|
+
<h4>Example</h4>
|
138
|
+
|
139
|
+
|
140
|
+
<pre>
|
141
|
+
[%if pageowner%]
|
142
|
+
<a href="admin.cgi">Admin</a>
|
143
|
+
[%endif%]
|
144
|
+
</pre>
|
145
|
+
|
146
|
+
<p>In this example, if the application tells PageTemplate that
|
147
|
+
<code>pageowner</code> is true, PageTemplate inserts a link to
|
148
|
+
an administrative page. Otherwise, nothing happens here.</p>
|
149
|
+
|
150
|
+
|
151
|
+
<h3>If/Else</h3>
|
152
|
+
|
153
|
+
|
154
|
+
<p>The <code>else</code> directive adds extra power to <code>if</code>, by indicating a chunk of
|
155
|
+
content to use when a condition is not true.</p>
|
156
|
+
|
157
|
+
|
158
|
+
<h4>Syntax</h4>
|
159
|
+
|
160
|
+
|
161
|
+
<pre>
|
162
|
+
[%if value%]
|
163
|
+
chunk
|
164
|
+
[%else%]
|
165
|
+
alternate chunk
|
166
|
+
[%endif%]
|
167
|
+
</pre>
|
168
|
+
|
169
|
+
<h4>Example</h4>
|
170
|
+
|
171
|
+
|
172
|
+
<pre>
|
173
|
+
[%if login%]
|
174
|
+
<p>Welcome back, [%var login%]!</p>
|
175
|
+
<p><a href="logout.cgi">Log Out</a></p>
|
176
|
+
[%else%]
|
177
|
+
<form name="login" method="post">
|
178
|
+
Login: <input type="text" name="login" /><br />
|
179
|
+
Password: <input type="password" name="passwd" /><br />
|
180
|
+
<input type="submit" value="Login" />
|
181
|
+
[%endif%]
|
182
|
+
</pre>
|
183
|
+
|
184
|
+
<p>This is the situation where I use <code>else</code> directives the
|
185
|
+
most. If the visitor is logged in to a Web application, she
|
186
|
+
is shown a brief welcoming message. If not, then she will see a
|
187
|
+
login form.</p>
|
188
|
+
|
189
|
+
|
190
|
+
<p>This example also shows a convenient approach to <code>if</code>
|
191
|
+
conditions. We <em>could</em> make up a special <code>logged_in</code>
|
192
|
+
variable, but since all we care about here is the presence of a login,
|
193
|
+
we have PageTemplate test that as if it were a regular condition.</p>
|
194
|
+
|
195
|
+
|
196
|
+
<h3>Unless</h3>
|
197
|
+
|
198
|
+
|
199
|
+
<p>Sometimes you only want to display a chunk if something is false, but
|
200
|
+
nothing if the condition is true. That description twisted my brain
|
201
|
+
a little bit. Think of it this way. Sometimes it’s just easier to say
|
202
|
+
“unless something” instead of “if not_something”. That’s all. Templates
|
203
|
+
should be easy to read, you know? That’s what this directive is for:
|
204
|
+
making some of the logic in your template easier to read.</p>
|
205
|
+
|
206
|
+
|
207
|
+
<h4>Syntax</h4>
|
208
|
+
|
209
|
+
|
210
|
+
<pre>
|
211
|
+
[%unless condition %]
|
212
|
+
chunk
|
213
|
+
[%end unless%]
|
214
|
+
</pre>
|
215
|
+
|
216
|
+
<h4>Example</h4>
|
217
|
+
|
218
|
+
|
219
|
+
<pre>
|
220
|
+
[%unless launched%]
|
221
|
+
Product Launch Coming Soon!
|
222
|
+
[%end unless%]
|
223
|
+
</pre>
|
224
|
+
|
225
|
+
<h3>In</h3>
|
226
|
+
|
227
|
+
|
228
|
+
<p>Use the <code>in</code> directive when you want PageTempate to insert the same chunk
|
229
|
+
repeatedly for a list of items. It can grab values from the item to be
|
230
|
+
inserted in <code>value</code> directives within the chunk. If there is no list of items,
|
231
|
+
the <code>in</code> chunk is skipped.</p>
|
232
|
+
|
233
|
+
|
234
|
+
<p>The <code>in</code> directive is the most complex, and requires more explanation of its
|
235
|
+
details.</p>
|
236
|
+
|
237
|
+
|
238
|
+
<h4>Syntax</h4>
|
239
|
+
|
240
|
+
|
241
|
+
<pre>
|
242
|
+
[%in list%]
|
243
|
+
some text and [%var value%]
|
244
|
+
[%end in%]
|
245
|
+
</pre>
|
246
|
+
|
247
|
+
<h4>Example</h4>
|
248
|
+
|
249
|
+
|
250
|
+
<pre>
|
251
|
+
<ul>
|
252
|
+
[%in books%]
|
253
|
+
<li>"[%var title%]" by [%var author%]</li>
|
254
|
+
[%end in%]
|
255
|
+
</ul>
|
256
|
+
</pre>
|
257
|
+
|
258
|
+
<p>It presents a list of favorite albums, along with the band that produced it.
|
259
|
+
If there was no such list, then PageTemplate would not insert anything, and
|
260
|
+
we would be left with <code><ul></ul></code> all by itself.
|
261
|
+
That’s more than a little awkward from a designer’s point of view, but
|
262
|
+
the <code>no</code> directive presentd in a few moments helps us work around that.</p>
|
263
|
+
|
264
|
+
|
265
|
+
<h4>“Local” Values</h4>
|
266
|
+
|
267
|
+
|
268
|
+
<p>When stepping through a list, PageTemplate works a little magic with
|
269
|
+
<code>value</code> directives. First it examines the list item to see
|
270
|
+
if it has a value for the variable named. If it can’t find one there,
|
271
|
+
it checks its main variable listing and tries to insert that. If it
|
272
|
+
can’t find a value in the main variable listing, it inserts nothing for
|
273
|
+
that <code>value</code> directive.</p>
|
274
|
+
|
275
|
+
|
276
|
+
This logic works for nested lists, too. If you have an
|
277
|
+
<code>in</code> directive embedded in another <code>in</code> directive,
|
278
|
+
(say, a list of books written by each one of a list of your favorite
|
279
|
+
authors), PageTemplate first looks in the innermost list (the books) for
|
280
|
+
a name, then the next list out (the authors), and finally the main
|
281
|
+
variable listing.
|
282
|
+
|
283
|
+
<h4>Loop Metavariables</h4>
|
284
|
+
|
285
|
+
|
286
|
+
<p><em>Metavariables</em> were added in 1.2 so that you can fine-tune your lists, loops, and tables. They are special
|
287
|
+
flags that are set during certain times in a loop: the first time through, the last time through, during
|
288
|
+
odd trips through the loop, etcetera. Metavariables are uppercased and wrapped in double underscores to
|
289
|
+
emphasize that they are not normal variables.</p>
|
290
|
+
|
291
|
+
|
292
|
+
<p>Here are all of the metavariables that are defined in <code>in</code> blocks.</p>
|
293
|
+
|
294
|
+
|
295
|
+
<table>
|
296
|
+
<tr>
|
297
|
+
<th>variable </th>
|
298
|
+
<th>description </th>
|
299
|
+
</tr>
|
300
|
+
<tr>
|
301
|
+
<td> <code>__FIRST__</code> </td>
|
302
|
+
<td> true if this is the first time through the loop. </td>
|
303
|
+
</tr>
|
304
|
+
<tr>
|
305
|
+
<td> <code>__LAST__</code> </td>
|
306
|
+
<td> true if this is the last time through the loop. </td>
|
307
|
+
</tr>
|
308
|
+
<tr>
|
309
|
+
<td> <code>__ODD__</code> </td>
|
310
|
+
<td> true on odd-numbered steps through the loop (1st, 3rd, 5th) </td>
|
311
|
+
</tr>
|
312
|
+
</table>
|
313
|
+
|
314
|
+
|
315
|
+
|
316
|
+
|
317
|
+
<p>And to give a little idea of metavariables in action, here’s a little example:</p>
|
318
|
+
|
319
|
+
|
320
|
+
<pre>
|
321
|
+
<table>
|
322
|
+
<tr><th>#</th><th>Description</th><th>Amount</th></tr>
|
323
|
+
[%in transactions %]
|
324
|
+
[%if __ODD__ %]
|
325
|
+
<tr class="odd">
|
326
|
+
[%else%]
|
327
|
+
<tr>
|
328
|
+
[%endif%]
|
329
|
+
<td>[%var num%]</td>
|
330
|
+
<td>[%var description%]</td>
|
331
|
+
<td>[%var amount%]
|
332
|
+
</tr>
|
333
|
+
[%endin%]
|
334
|
+
</table>
|
335
|
+
</pre>
|
336
|
+
|
337
|
+
<h3>In/No</h3>
|
338
|
+
|
339
|
+
|
340
|
+
<p>The <code>no</code> directive allows you to use an alternate chunk
|
341
|
+
for an <code>in</code> if there is no list available.</p>
|
342
|
+
|
343
|
+
|
344
|
+
<h4>Syntax</h4>
|
345
|
+
|
346
|
+
|
347
|
+
<pre>
|
348
|
+
[%in list%]
|
349
|
+
[%var value%]
|
350
|
+
[%no%]
|
351
|
+
Nothing in the list
|
352
|
+
[%endin%]
|
353
|
+
</pre>
|
354
|
+
|
355
|
+
<h4>Example</h4>
|
356
|
+
|
357
|
+
|
358
|
+
<pre>
|
359
|
+
<ul>
|
360
|
+
[%in books%]
|
361
|
+
<li>"[%var title%]" by [%var author%]</li>
|
362
|
+
[%no%]
|
363
|
+
<li>I have no favorites today.</li>
|
364
|
+
[%endin%]
|
365
|
+
</ul>
|
366
|
+
</pre>
|
367
|
+
|
368
|
+
<p>This extends the earlier example by providing an alternate chunk
|
369
|
+
to use if there is no list named <code>books</code>. Now
|
370
|
+
the <acronym title="Hypertext Markup Language"><span class="caps">HTML</span></acronym>
|
371
|
+
formatting is a little more appropriate. Instead of displaying
|
372
|
+
an empty list, it shows a list item declaring that there is no list.</p>
|
373
|
+
|
374
|
+
|
375
|
+
<p>I think I hurt my head with that last sentence.</p>
|
376
|
+
|
377
|
+
|
378
|
+
<h4>Lists and <span class="caps">WYSIWYG </span>Editors</h4>
|
379
|
+
|
380
|
+
|
381
|
+
<p>Here’s a specific problem that might pop up when you are using
|
382
|
+
a <acronym title="What You See Is What You Get"><span class="caps">WYSIWYG</span></acronym>
|
383
|
+
editor. Let’s say you’re embedding a list into a table, so that each
|
384
|
+
item in the list gets one table row. Dreamweaver is probably not
|
385
|
+
going to like this style:</p>
|
386
|
+
|
387
|
+
|
388
|
+
<pre>
|
389
|
+
<table>
|
390
|
+
[%in listing%]
|
391
|
+
<tr>
|
392
|
+
<td>[%var item%]</td>
|
393
|
+
</tr>
|
394
|
+
[%no%]
|
395
|
+
<tr>
|
396
|
+
<td>Listing is empty</td>
|
397
|
+
</tr>
|
398
|
+
[%endin%]
|
399
|
+
</table>
|
400
|
+
</pre>
|
401
|
+
|
402
|
+
<p>The problem is that the <code>in listing</code>, <code>no</code>,
|
403
|
+
and <code>endin</code> directives are in locations that make for
|
404
|
+
invalid <span class="caps">HTML</span>, and might not be allowed by your editor.</p>
|
405
|
+
|
406
|
+
|
407
|
+
<p>It turns out that the solution is simple, though maybe a little
|
408
|
+
awkward. Wrap the offending directives in <span class="caps">HTML</span> comments, like this
|
409
|
+
example shows:</p>
|
410
|
+
|
411
|
+
|
412
|
+
<pre>
|
413
|
+
<table>
|
414
|
+
<!-- [%in listing%] -->
|
415
|
+
<tr>
|
416
|
+
<td>[%var item%]</td>
|
417
|
+
</tr>
|
418
|
+
<!-- [%no%] -->
|
419
|
+
<tr>
|
420
|
+
<td>Listing is empty</td>
|
421
|
+
</tr>
|
422
|
+
<!-- [%endin%] -->
|
423
|
+
</table>
|
424
|
+
</pre>
|
425
|
+
|
426
|
+
<p>Your fancy editor should be able to handle this, and PageTemplate
|
427
|
+
should be able to understand it just fine. The only side effect
|
428
|
+
is that you will have some empty comments in your final page.</p>
|
429
|
+
|
430
|
+
|
431
|
+
<p>The other solution is to use <a href="geekery/editors/vim/index.html">Vim</a>,
|
432
|
+
<a href="http://www.xemacs.org/">XEmacs</a>, or some other effective
|
433
|
+
non-<acronym title="What You See Is What You Get"><span class="caps">WYSIWYG</span></acronym>
|
434
|
+
editor. Personal preference, of course. I know that Dreamweaver and GoLive
|
435
|
+
cost good money, and you aren’t going to toss them aside just because I say
|
436
|
+
so. Hopefully this workaround will suit your needs.</p>
|
437
|
+
|
438
|
+
|
439
|
+
<h3>Include</h3>
|
440
|
+
|
441
|
+
|
442
|
+
<p>The <code>include</code> directive is very simple to use, but it gives you a whole lot of
|
443
|
+
extra power. It allows you to include content that comes from another
|
444
|
+
files, including templates. This can be useful when building a page out of
|
445
|
+
smaller component templates.</p>
|
446
|
+
|
447
|
+
|
448
|
+
<h4>Syntax</h4>
|
449
|
+
|
450
|
+
|
451
|
+
<pre>[%include filename %]</pre>
|
452
|
+
|
453
|
+
<p><code>filename</code> can point to a real file in a particular directory, or it could be a
|
454
|
+
placeholder variable name. If PageTemplate can’t find that file, it displays a simple message stating
|
455
|
+
that the file was not found. The idea for this is to make it easier for developers to debug problems during
|
456
|
+
testing, rather than for you to wonder why there’s a blank space where your menu text should be.</p>
|
457
|
+
|
458
|
+
|
459
|
+
<h4>Example</h4>
|
460
|
+
|
461
|
+
|
462
|
+
<pre>
|
463
|
+
[%include menu %]
|
464
|
+
</pre>
|
465
|
+
|
466
|
+
<p>Meanwhile, we have something like this in <em>menu.txt</em></p>
|
467
|
+
|
468
|
+
|
469
|
+
<pre>
|
470
|
+
<table>
|
471
|
+
[%in photos%]
|
472
|
+
<tr>
|
473
|
+
<td>[%var title%]</td>
|
474
|
+
<td>[%var thumbnail %]</td>
|
475
|
+
</tr>
|
476
|
+
[%endin%]
|
477
|
+
</table>
|
478
|
+
</pre>
|
479
|
+
|
480
|
+
<p>Do you see what I meant when I said “simple”? If not, then please let me know.
|
481
|
+
I’m still working on this part of the manual.</p>
|
482
|
+
|
483
|
+
|
484
|
+
<h3>Comments</h3>
|
485
|
+
|
486
|
+
|
487
|
+
<p>Every once in a while you want to make a comment about your template, but not have it show up the
|
488
|
+
<span class="caps">HTML</span> markup that goes to the visitor. Comments are perfect for that. They are eaten up and spit aside
|
489
|
+
by PageTemplate when reading your template file, and the visitor never sees them.</p>
|
490
|
+
|
491
|
+
|
492
|
+
<h4>Syntax</h4>
|
493
|
+
|
494
|
+
|
495
|
+
<pre>
|
496
|
+
[%-- comment --%]
|
497
|
+
</pre>
|
498
|
+
|
499
|
+
<h2>Customized Syntax</h2>
|
500
|
+
|
501
|
+
|
502
|
+
<p>One of PageTemplate’s features is the ability to come up with your
|
503
|
+
own directive syntax. If you feel that the default syntax is
|
504
|
+
less than ideal, discuss a new system with your developers. If
|
505
|
+
you are the lone designer/developer, talk to yourself for a bit. We
|
506
|
+
all need some quality time to ourselves occasionally. Working together,
|
507
|
+
you and the developers <em>(or you and your split personalities)</em>
|
508
|
+
can come up with a syntax that is much more comfortable.</p>
|
509
|
+
|
510
|
+
|
511
|
+
<h2>Conclusion</h2>
|
512
|
+
|
513
|
+
|
514
|
+
<p>Yes, we’ve already reached the end of this designer’s tutorial.
|
515
|
+
Now go make with the pretty pages!</p><hr />
|
516
|
+
|
517
|
+
<p class="navbar">
|
518
|
+
<a href="SiteMap.html">Sitemap</a> || <a href="index.html">PageTemplate</a>
|
519
|
+
/ The Designer's Perspective</p>
|
520
|
+
|
521
|
+
<h1>Yo!</h1>
|
522
|
+
<hr />
|
523
|
+
</body>
|
524
|
+
</html>
|