PageTemplate 2.1.3 → 2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +1 -1
- data/Rakefile +1 -1
- data/lib/PageTemplate/parser.rb +13 -8
- data/setup-usage.txt +1 -1
- 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 +3 -1
- metadata +29 -2
data/Changes
CHANGED
data/Rakefile
CHANGED
data/lib/PageTemplate/parser.rb
CHANGED
@@ -176,11 +176,20 @@ class PageTemplate
|
|
176
176
|
class FileSource < Source
|
177
177
|
attr_reader :paths
|
178
178
|
|
179
|
+
# initialize looks for the following in the args Hash:
|
180
|
+
# * include_paths = a list of file paths
|
181
|
+
# * include_path = a single file path string
|
182
|
+
# (kept for backwards compatibility)
|
179
183
|
def initialize(args = {})
|
180
184
|
@args = args
|
181
|
-
|
182
|
-
|
183
|
-
@
|
185
|
+
if @args['include_paths']
|
186
|
+
@paths = @args['include_paths']
|
187
|
+
elsif @args['include_path']
|
188
|
+
@paths = [ @args['include_path'] ]
|
189
|
+
else
|
190
|
+
@paths = [Dir.getwd,'/']
|
191
|
+
end
|
192
|
+
@paths = @paths.compact
|
184
193
|
@cache = Hash.new(nil)
|
185
194
|
@mtime = Hash.new(0)
|
186
195
|
end
|
@@ -204,20 +213,16 @@ class PageTemplate
|
|
204
213
|
return "[ Unable to open file #{fn} because of #{er.message} ]"
|
205
214
|
end
|
206
215
|
end
|
207
|
-
|
208
216
|
def cache(name,cmds)
|
209
217
|
fn = get_filename(name)
|
210
218
|
@cache[fn] = cmds.dup
|
211
219
|
@mtime[fn] = Time.now.to_i
|
212
220
|
end
|
213
|
-
|
214
|
-
# Return the absolute pathname of the first name +file+
|
215
|
-
# found in the include_paths.
|
216
221
|
def get_filename(file)
|
217
222
|
file = file.gsub(/\.\.\//,'')
|
218
|
-
file.untaint
|
219
223
|
@paths.each do |path|
|
220
224
|
fn = File.join(path,file)
|
225
|
+
fn.untaint
|
221
226
|
return fn if File.exists?(fn)
|
222
227
|
end
|
223
228
|
return nil
|
data/setup-usage.txt
CHANGED
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>
|