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 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.version = "2.1.6"
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
@@ -29,6 +29,8 @@ require 'PageTemplate/commands'
29
29
  # It is a class so that programmers are not confused by being able to
30
30
  # do .new on a module
31
31
  class PageTemplate
32
+ VERSION = "2.1.7"
33
+
32
34
  # Passes arguments straight to Parser.new
33
35
  #
34
36
  # returns: a Parser object.
@@ -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>&lt;- <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>- &gt;</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,11 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require 'ZenWeb'
4
+
5
+ data_dir = "src"
6
+ html_dir = "html"
7
+ sitemap = "/SiteMap.html"
8
+ url = "/"
9
+
10
+ website = ZenWebsite.new(sitemap, data_dir, html_dir)
11
+ website.renderSite
@@ -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
@@ -0,0 +1,4 @@
1
+ body {
2
+ background-color: white;
3
+ color: black;
4
+ }
data/site/footer.txt ADDED
@@ -0,0 +1,2 @@
1
+ <hr />
2
+ <p>Copyright 2002 - 2005 Brian Wisti and Greg Millam</p>
data/site/header.txt ADDED
@@ -0,0 +1,2 @@
1
+ <h1>PageTemplate</h1>
2
+ <hr />
@@ -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>
@@ -0,0 +1,4 @@
1
+ body {
2
+ background-color: white;
3
+ color: black;
4
+ }
@@ -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>&lt;- <a href='install.html'>Getting It</a></p>
16
+ </td>
17
+ <td align='right'><p><a href='programmer.html'>The Programmer&#8217;s Perspective</a>- &gt;</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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;s a good idea to use variable names that make
79
+ sense (<code>name</code> for a person&#8217;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
+ &lt;h1&gt;Hello, [%var name %]&lt;/h1&gt;
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 &#8220;Frank&#8221; sees this
109
+ greeting:</p>
110
+
111
+
112
+ <pre>&lt;h1&gt;Hello, Frank&lt;/h1&gt;</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>&lt;h1&gt;Hello, &lt;/h1&gt;</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
+ &lt;a href="admin.cgi"&gt;Admin&lt;/a&gt;
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
+ &lt;p&gt;Welcome back, [%var login%]!&lt;/p&gt;
175
+ &lt;p&gt;&lt;a href="logout.cgi"&gt;Log Out&lt;/a&gt;&lt;/p&gt;
176
+ [%else%]
177
+ &lt;form name="login" method="post"&gt;
178
+ Login: &lt;input type="text" name="login" /&gt;&lt;br /&gt;
179
+ Password: &lt;input type="password" name="passwd" /&gt;&lt;br /&gt;
180
+ &lt;input type="submit" value="Login" /&gt;
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&#8217;s just easier to say
202
+ &#8220;unless something&#8221; instead of &#8220;if not_something&#8221;. That&#8217;s all. Templates
203
+ should be easy to read, you know? That&#8217;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
+ &lt;ul&gt;
252
+ [%in books%]
253
+ &lt;li&gt;"[%var title%]" by [%var author%]&lt;/li&gt;
254
+ [%end in%]
255
+ &lt;/ul&gt;
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>&lt;ul&gt;&lt;/ul&gt;</code> all by itself.
261
+ That&#8217;s more than a little awkward from a designer&#8217;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>&#8220;Local&#8221; 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&#8217;t find one there,
271
+ it checks its main variable listing and tries to insert that. If it
272
+ can&#8217;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&#8217;s a little example:</p>
318
+
319
+
320
+ <pre>
321
+ &lt;table&gt;
322
+ &lt;tr&gt;&lt;th&gt;#&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Amount&lt;/th&gt;&lt;/tr&gt;
323
+ [%in transactions %]
324
+ [%if __ODD__ %]
325
+ &lt;tr class="odd"&gt;
326
+ [%else%]
327
+ &lt;tr&gt;
328
+ [%endif%]
329
+ &lt;td&gt;[%var num%]&lt;/td&gt;
330
+ &lt;td&gt;[%var description%]&lt;/td&gt;
331
+ &lt;td&gt;[%var amount%]
332
+ &lt;/tr&gt;
333
+ [%endin%]
334
+ &lt;/table&gt;
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
+ &lt;ul&gt;
360
+ [%in books%]
361
+ &lt;li&gt;"[%var title%]" by [%var author%]&lt;/li&gt;
362
+ [%no%]
363
+ &lt;li&gt;I have no favorites today.&lt;/li&gt;
364
+ [%endin%]
365
+ &lt;/ul&gt;
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&#8217;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&#8217;s say you&#8217;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
+ &lt;table&gt;
390
+ [%in listing%]
391
+ &lt;tr&gt;
392
+ &lt;td&gt;[%var item%]&lt;/td&gt;
393
+ &lt;/tr&gt;
394
+ [%no%]
395
+ &lt;tr&gt;
396
+ &lt;td&gt;Listing is empty&lt;/td&gt;
397
+ &lt;/tr&gt;
398
+ [%endin%]
399
+ &lt;/table&gt;
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
+ &lt;table&gt;
414
+ &lt;!-- [%in listing%] --&gt;
415
+ &lt;tr&gt;
416
+ &lt;td&gt;[%var item%]&lt;/td&gt;
417
+ &lt;/tr&gt;
418
+ &lt;!-- [%no%] --&gt;
419
+ &lt;tr&gt;
420
+ &lt;td&gt;Listing is empty&lt;/td&gt;
421
+ &lt;/tr&gt;
422
+ &lt;!-- [%endin%] --&gt;
423
+ &lt;/table&gt;
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&#8217;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&#8217;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&#8217;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
+ &lt;table&gt;
471
+ [%in photos%]
472
+ &lt;tr&gt;
473
+ &lt;td&gt;[%var title%]&lt;/td&gt;
474
+ &lt;td&gt;[%var thumbnail %]&lt;/td&gt;
475
+ &lt;/tr&gt;
476
+ [%endin%]
477
+ &lt;/table&gt;
478
+ </pre>
479
+
480
+ <p>Do you see what I meant when I said &#8220;simple&#8221;? If not, then please let me know.
481
+ I&#8217;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&#8217;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&#8217;ve already reached the end of this designer&#8217;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>