TwP-webby 0.9.0
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/History.txt +176 -0
- data/Manifest.txt +173 -0
- data/README.txt +92 -0
- data/Rakefile +50 -0
- data/bin/webby +8 -0
- data/bin/webby-gen +8 -0
- data/examples/blog/Sitefile +7 -0
- data/examples/blog/tasks/blog.rake +72 -0
- data/examples/blog/templates/atom_feed.erb +40 -0
- data/examples/blog/templates/blog/month.erb +22 -0
- data/examples/blog/templates/blog/post.erb +16 -0
- data/examples/blog/templates/blog/year.erb +22 -0
- data/examples/presentation/Sitefile +10 -0
- data/examples/presentation/content/css/uv/twilight.css +137 -0
- data/examples/presentation/content/presentation/_sample_code.txt +10 -0
- data/examples/presentation/content/presentation/index.txt +63 -0
- data/examples/presentation/content/presentation/s5/blank.gif +0 -0
- data/examples/presentation/content/presentation/s5/bodybg.gif +0 -0
- data/examples/presentation/content/presentation/s5/framing.css +23 -0
- data/examples/presentation/content/presentation/s5/iepngfix.htc +42 -0
- data/examples/presentation/content/presentation/s5/opera.css +7 -0
- data/examples/presentation/content/presentation/s5/outline.css +15 -0
- data/examples/presentation/content/presentation/s5/pretty.css +86 -0
- data/examples/presentation/content/presentation/s5/print.css +1 -0
- data/examples/presentation/content/presentation/s5/s5-core.css +9 -0
- data/examples/presentation/content/presentation/s5/slides.css +3 -0
- data/examples/presentation/content/presentation/s5/slides.js +553 -0
- data/examples/presentation/layouts/presentation.txt +43 -0
- data/examples/presentation/templates/_code_partial.erb +13 -0
- data/examples/presentation/templates/presentation.erb +40 -0
- data/examples/tumblog/Sitefile +9 -0
- data/examples/tumblog/content/css/tumblog.css +308 -0
- data/examples/tumblog/content/images/tumblog/permalink.gif +0 -0
- data/examples/tumblog/content/images/tumblog/rss.gif +0 -0
- data/examples/tumblog/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
- data/examples/tumblog/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
- data/examples/tumblog/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
- data/examples/tumblog/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
- data/examples/tumblog/content/tumblog/200807/up-a-tree/index.txt +13 -0
- data/examples/tumblog/content/tumblog/index.txt +37 -0
- data/examples/tumblog/content/tumblog/rss.txt +37 -0
- data/examples/tumblog/layouts/tumblog/default.txt +44 -0
- data/examples/tumblog/layouts/tumblog/post.txt +15 -0
- data/examples/tumblog/lib/tumblog_helper.rb +32 -0
- data/examples/tumblog/tasks/tumblog.rake +30 -0
- data/examples/tumblog/templates/atom_feed.erb +40 -0
- data/examples/tumblog/templates/tumblog/conversation.erb +12 -0
- data/examples/tumblog/templates/tumblog/link.erb +10 -0
- data/examples/tumblog/templates/tumblog/photo.erb +13 -0
- data/examples/tumblog/templates/tumblog/post.erb +12 -0
- data/examples/tumblog/templates/tumblog/quote.erb +11 -0
- data/examples/webby/Sitefile +19 -0
- data/examples/webby/content/communicate/index.txt +28 -0
- data/examples/webby/content/css/background.gif +0 -0
- data/examples/webby/content/css/blueprint/print.css +76 -0
- data/examples/webby/content/css/blueprint/screen.css +696 -0
- data/examples/webby/content/css/coderay.css +96 -0
- data/examples/webby/content/css/site.css +196 -0
- data/examples/webby/content/css/uv/twilight.css +137 -0
- data/examples/webby/content/index.txt +37 -0
- data/examples/webby/content/learn/index.txt +28 -0
- data/examples/webby/content/reference/index.txt +204 -0
- data/examples/webby/content/release-notes/rel-0-9-0/index.txt +73 -0
- data/examples/webby/content/robots.txt +6 -0
- data/examples/webby/content/script/jquery.corner.js +152 -0
- data/examples/webby/content/script/jquery.js +31 -0
- data/examples/webby/content/sitemap.txt +31 -0
- data/examples/webby/content/tips_and_tricks/index.txt +96 -0
- data/examples/webby/content/tutorial/index.txt +131 -0
- data/examples/webby/content/user-manual/index.txt +419 -0
- data/examples/webby/layouts/default.txt +49 -0
- data/examples/webby/templates/page.erb +10 -0
- data/examples/website/Sitefile +7 -0
- data/examples/website/content/css/blueprint/License.txt +21 -0
- data/examples/website/content/css/blueprint/Readme.txt +100 -0
- data/examples/website/content/css/blueprint/compressed/print.css +76 -0
- data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
- data/examples/website/content/css/blueprint/lib/forms.css +45 -0
- data/examples/website/content/css/blueprint/lib/grid.css +193 -0
- data/examples/website/content/css/blueprint/lib/grid.png +0 -0
- data/examples/website/content/css/blueprint/lib/ie.css +30 -0
- data/examples/website/content/css/blueprint/lib/reset.css +39 -0
- data/examples/website/content/css/blueprint/lib/typography.css +116 -0
- data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
- data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
- data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
- data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
- data/examples/website/content/css/blueprint/print.css +68 -0
- data/examples/website/content/css/blueprint/screen.css +22 -0
- data/examples/website/content/css/coderay.css +111 -0
- data/examples/website/content/css/site.css +67 -0
- data/examples/website/content/index.txt +19 -0
- data/examples/website/layouts/default.txt +58 -0
- data/examples/website/lib/breadcrumbs.rb +28 -0
- data/examples/website/templates/_partial.erb +10 -0
- data/examples/website/templates/page.erb +18 -0
- data/examples/website/templates/presentation.erb +40 -0
- data/lib/webby/apps/generator.rb +283 -0
- data/lib/webby/apps/main.rb +221 -0
- data/lib/webby/apps.rb +12 -0
- data/lib/webby/auto_builder.rb +83 -0
- data/lib/webby/builder.rb +183 -0
- data/lib/webby/core_ext/enumerable.rb +11 -0
- data/lib/webby/core_ext/hash.rb +28 -0
- data/lib/webby/core_ext/kernel.rb +21 -0
- data/lib/webby/core_ext/string.rb +163 -0
- data/lib/webby/core_ext/time.rb +9 -0
- data/lib/webby/filters/basepath.rb +97 -0
- data/lib/webby/filters/erb.rb +9 -0
- data/lib/webby/filters/haml.rb +18 -0
- data/lib/webby/filters/markdown.rb +16 -0
- data/lib/webby/filters/outline.rb +309 -0
- data/lib/webby/filters/sass.rb +17 -0
- data/lib/webby/filters/slides.rb +56 -0
- data/lib/webby/filters/textile.rb +16 -0
- data/lib/webby/filters/tidy.rb +76 -0
- data/lib/webby/filters.rb +91 -0
- data/lib/webby/helpers/capture_helper.rb +141 -0
- data/lib/webby/helpers/coderay_helper.rb +69 -0
- data/lib/webby/helpers/graphviz_helper.rb +136 -0
- data/lib/webby/helpers/tag_helper.rb +65 -0
- data/lib/webby/helpers/tex_img_helper.rb +133 -0
- data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
- data/lib/webby/helpers/url_helper.rb +235 -0
- data/lib/webby/helpers.rb +30 -0
- data/lib/webby/link_validator.rb +152 -0
- data/lib/webby/renderer.rb +379 -0
- data/lib/webby/resources/db.rb +251 -0
- data/lib/webby/resources/file.rb +221 -0
- data/lib/webby/resources/layout.rb +63 -0
- data/lib/webby/resources/page.rb +118 -0
- data/lib/webby/resources/partial.rb +79 -0
- data/lib/webby/resources/resource.rb +160 -0
- data/lib/webby/resources/static.rb +52 -0
- data/lib/webby/resources.rb +96 -0
- data/lib/webby/stelan/mktemp.rb +135 -0
- data/lib/webby/stelan/paginator.rb +150 -0
- data/lib/webby/stelan/spawner.rb +339 -0
- data/lib/webby/tasks/build.rake +27 -0
- data/lib/webby/tasks/create.rake +22 -0
- data/lib/webby/tasks/deploy.rake +22 -0
- data/lib/webby/tasks/growl.rake +15 -0
- data/lib/webby/tasks/heel.rake +28 -0
- data/lib/webby/tasks/validate.rake +19 -0
- data/lib/webby.rb +227 -0
- data/spec/core_ext/hash_spec.rb +47 -0
- data/spec/core_ext/string_spec.rb +110 -0
- data/spec/core_ext/time_spec.rb +19 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/webby/apps/generator_spec.rb +111 -0
- data/spec/webby/apps/main_spec.rb +75 -0
- data/spec/webby/helpers/capture_helper_spec.rb +56 -0
- data/spec/webby/resources/file_spec.rb +104 -0
- data/spec/webby/resources_spec.rb +17 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +126 -0
- data/tasks/git.rake +41 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +268 -0
- data/tasks/spec.rake +55 -0
- data/tasks/website.rake +38 -0
- metadata +289 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
require 'hpricot'
|
|
2
|
+
|
|
3
|
+
module Webby
|
|
4
|
+
module Filters
|
|
5
|
+
|
|
6
|
+
# The Outline filter is used to insert outline numbering into HTML heading
|
|
7
|
+
# tags (h1, h2, h3, etc.) and to generate a table of contents based on the
|
|
8
|
+
# heading tags. The table of contents is inserted into the page at the
|
|
9
|
+
# location of the <toc /> tag. If there is no <toc /> tag, then a table of
|
|
10
|
+
# contents will not be created but outline numbering will still take place.
|
|
11
|
+
#
|
|
12
|
+
# If a table of contents is desired without outline number being inserted
|
|
13
|
+
# into the heading tags, this can be specified in the attibutes of the
|
|
14
|
+
# <toc /> tag itself.
|
|
15
|
+
#
|
|
16
|
+
# <toc numbering="off" />
|
|
17
|
+
#
|
|
18
|
+
# This will generate a table of contents, but not insert outline numbering
|
|
19
|
+
# into the heading tags.
|
|
20
|
+
#
|
|
21
|
+
# The Outline filter will only work on valid HTML or XHTML pages. Therefore
|
|
22
|
+
# it should be used after any markup langauge filters (textile, markdown,
|
|
23
|
+
# etc.).
|
|
24
|
+
#
|
|
25
|
+
# The following attributes can be specified in the <toc /> tag itself to
|
|
26
|
+
# control how outline numbering is performed by the filter. The attributes
|
|
27
|
+
# can be used in combination with one another.
|
|
28
|
+
#
|
|
29
|
+
# === numbering
|
|
30
|
+
#
|
|
31
|
+
# If set to "off", this will prevent numbers from being inserted into the
|
|
32
|
+
# page. The default is "on".
|
|
33
|
+
#
|
|
34
|
+
# <toc numbering="off" />
|
|
35
|
+
#
|
|
36
|
+
# === numbering_start
|
|
37
|
+
#
|
|
38
|
+
# This is the number to start with when inserting outline numbers into a
|
|
39
|
+
# page. The default is 1.
|
|
40
|
+
#
|
|
41
|
+
# <toc numbering_start="3" />
|
|
42
|
+
#
|
|
43
|
+
# === toc_style
|
|
44
|
+
#
|
|
45
|
+
# The style of the Table of Contents list to generated. This will be
|
|
46
|
+
# either "ol" for an ordered list or "ul" for an unordered list. The
|
|
47
|
+
# default is an ordered list.
|
|
48
|
+
#
|
|
49
|
+
# <toc toc_style="ul" />
|
|
50
|
+
#
|
|
51
|
+
# === toc_range
|
|
52
|
+
#
|
|
53
|
+
# This limits the numbering to only a subset of the HTML heading tags. The
|
|
54
|
+
# defaul is to number all the heading tags.
|
|
55
|
+
#
|
|
56
|
+
# <toc toc_range="h1-h3" />
|
|
57
|
+
#
|
|
58
|
+
# In this example, only the heading tags h1, h2, and h3 will be numbered
|
|
59
|
+
# and included in the table of contents listing.
|
|
60
|
+
#
|
|
61
|
+
# ==== Example
|
|
62
|
+
#
|
|
63
|
+
# Generate a table of contents using an unordered list, starting with the
|
|
64
|
+
# number 2, and only numbering heading levels 2, 3, and 4.
|
|
65
|
+
#
|
|
66
|
+
# <toc numbering_start="2" toc_style="ul" toc_range="h2-h4" />
|
|
67
|
+
#
|
|
68
|
+
class Outline
|
|
69
|
+
include ERB::Util
|
|
70
|
+
|
|
71
|
+
# call-seq:
|
|
72
|
+
# Outline.new( html )
|
|
73
|
+
#
|
|
74
|
+
# Creates a new outline filter that will operate on the given
|
|
75
|
+
# _html_ string.
|
|
76
|
+
#
|
|
77
|
+
def initialize( str )
|
|
78
|
+
@str = str
|
|
79
|
+
|
|
80
|
+
@cur_level, @base_level, @cur_depth = nil
|
|
81
|
+
@level = [0] * 6
|
|
82
|
+
@h_rgxp = %r/^h(\d)$/o
|
|
83
|
+
|
|
84
|
+
@numbering = true
|
|
85
|
+
@numbering_start = 1
|
|
86
|
+
|
|
87
|
+
@toc = []
|
|
88
|
+
@toc_style = 'ol'
|
|
89
|
+
@toc_range = 'h1-h6'
|
|
90
|
+
@list_opening = nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# call-seq:
|
|
94
|
+
# filter => html
|
|
95
|
+
#
|
|
96
|
+
# Process the original html document passed to the filter when it was
|
|
97
|
+
# created. The document will be scanned for heading tags (h1, h2, etc.)
|
|
98
|
+
# and outline numbering and id attributes will be inserted. A table of
|
|
99
|
+
# contents will also be created and inserted into the page if a <toc />
|
|
100
|
+
# tag is found.
|
|
101
|
+
#
|
|
102
|
+
# For example, if there is a heading tag
|
|
103
|
+
#
|
|
104
|
+
# <h3>Get Fuzzy</h3>
|
|
105
|
+
#
|
|
106
|
+
# somewhere in a page about comic strips, the tag might be altered as such
|
|
107
|
+
#
|
|
108
|
+
# <h3 id="h2_2_1"><span class="heading-num">2.2.1</span>Get Fuzzy</h3>
|
|
109
|
+
#
|
|
110
|
+
# The id attribute is used to generate a linke from the table of contents
|
|
111
|
+
# to this particular heading tag. The original text of the tag is used in
|
|
112
|
+
# the table of contents -- "Get Fuzzy" in this example.
|
|
113
|
+
#
|
|
114
|
+
def filter
|
|
115
|
+
doc = Hpricot.XML(@str)
|
|
116
|
+
|
|
117
|
+
# extract directives from the "toc" tag
|
|
118
|
+
toc_elem = doc.search('toc').first
|
|
119
|
+
|
|
120
|
+
unless toc_elem.nil?
|
|
121
|
+
@numbering = toc_elem['numbering'] !~ %r/off/i
|
|
122
|
+
@numbering_start = Integer(toc_elem['numbering_start']) if toc_elem.has_attribute? 'numbering_start'
|
|
123
|
+
@toc_style = toc_elem['toc_style'] if toc_elem.has_attribute? 'toc_style'
|
|
124
|
+
@toc_range = toc_elem['toc_range'] if toc_elem.has_attribute? 'toc_range'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
unless %w[ul ol].include? @toc_style
|
|
128
|
+
raise ArgumentError, "unknown ToC list type '#{@toc_style}'"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
m = %r/h(\d)\s*-\s*h(\d)/i.match @toc_range
|
|
132
|
+
@toc_range = Integer(m[1])..Integer(m[2])
|
|
133
|
+
@list_opening = build_list_opening(toc_elem)
|
|
134
|
+
|
|
135
|
+
headers = @toc_range.map {|x| "h#{x}"}
|
|
136
|
+
doc.traverse_element(*headers) do |elem|
|
|
137
|
+
text, id = heading_info(elem)
|
|
138
|
+
add_to_toc(text, id) if @toc_range.include? current_level
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
toc_elem.swap(toc) unless toc_elem.nil?
|
|
142
|
+
doc.to_html
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
def build_list_opening( elem )
|
|
149
|
+
lo = "<#{@toc_style}"
|
|
150
|
+
unless elem.nil?
|
|
151
|
+
%w[class style id].each do |atr|
|
|
152
|
+
next unless elem.has_attribute? atr
|
|
153
|
+
lo << " %s=\"%s\"" % [atr, elem[atr]]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
if @toc_style == 'ol' and @numbering_start != 1
|
|
157
|
+
lo << " start=\"#{@numbering_start}\""
|
|
158
|
+
end
|
|
159
|
+
lo << ">"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Returns information for the given heading element. The information is
|
|
163
|
+
# returned as a two element array: [text, id].
|
|
164
|
+
#
|
|
165
|
+
# This method will also insert outline numbering and an id attribute. The
|
|
166
|
+
# outline numbering can be disabled, but the id attribute must be present
|
|
167
|
+
# for TOC generation.
|
|
168
|
+
#
|
|
169
|
+
def heading_info( elem )
|
|
170
|
+
m = @h_rgxp.match(elem.name)
|
|
171
|
+
level = Integer(m[1])
|
|
172
|
+
|
|
173
|
+
self.current_level = level
|
|
174
|
+
text = elem.inner_text
|
|
175
|
+
|
|
176
|
+
lbl = label
|
|
177
|
+
if numbering?
|
|
178
|
+
elem.children.first.before {tag!(:span, lbl, :class => 'heading-num')}
|
|
179
|
+
end
|
|
180
|
+
elem['id'] = "h#{lbl.tr('.','_')}" if elem['id'].nil?
|
|
181
|
+
|
|
182
|
+
return [text, elem['id']]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Set the current heading level. This will set the label and depth as
|
|
186
|
+
# well. An error will be raised if the _level_ is less than the base
|
|
187
|
+
# heading level.
|
|
188
|
+
#
|
|
189
|
+
# The base heading level will be set to the _level_ if it has not already
|
|
190
|
+
# been set. Therefore, the first heading tag encountered defines the base
|
|
191
|
+
# heading level.
|
|
192
|
+
#
|
|
193
|
+
def current_level=( level )
|
|
194
|
+
if @base_level.nil?
|
|
195
|
+
@base_level = @cur_level = level
|
|
196
|
+
@level[@base_level-1] = @numbering_start-1
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if level < @base_level
|
|
200
|
+
raise ::Webby::Error, "heading tags are not in order, cannot outline"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
if level == @cur_level
|
|
204
|
+
@level[level-1] += 1
|
|
205
|
+
elsif level > @cur_level
|
|
206
|
+
@cur_level.upto(level-1) {|ii| @level[ii] += 1}
|
|
207
|
+
else
|
|
208
|
+
@cur_level.downto(level+1) {|ii| @level[ii-1] = 0}
|
|
209
|
+
@level[level-1] += 1
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
@cur_level = level
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Returns the current heading level number.
|
|
216
|
+
#
|
|
217
|
+
def current_level
|
|
218
|
+
@cur_level
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Return the label string for the current heading level.
|
|
222
|
+
#
|
|
223
|
+
def label
|
|
224
|
+
rv = @level.dup
|
|
225
|
+
rv.delete(0)
|
|
226
|
+
rv.join('.')
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Return the nesting depth of the current heading level with respect to the
|
|
230
|
+
# base heading level. This is a one-based number.
|
|
231
|
+
#
|
|
232
|
+
def depth
|
|
233
|
+
@cur_level - @base_level + 1
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Add the given text and id reference to the table of contents.
|
|
237
|
+
#
|
|
238
|
+
def add_to_toc( text, id )
|
|
239
|
+
a = "<a href=\"##{id}\">#{h(text)}</a>"
|
|
240
|
+
@toc << [depth, a]
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Returns the table of contents as a collection of nested ordered lists.
|
|
244
|
+
# This is fully formatted HTML.
|
|
245
|
+
#
|
|
246
|
+
def toc
|
|
247
|
+
ary = []
|
|
248
|
+
|
|
249
|
+
lopen = "<#@toc_style>"
|
|
250
|
+
lclose = "</#@toc_style>"
|
|
251
|
+
prev_depth = open = 0
|
|
252
|
+
|
|
253
|
+
@toc.each do |a|
|
|
254
|
+
cur = a.first
|
|
255
|
+
|
|
256
|
+
# close out the previous list item if we're at the same level
|
|
257
|
+
if cur == prev_depth
|
|
258
|
+
ary << "</li>"
|
|
259
|
+
|
|
260
|
+
# if we are increasing the level, then start a new list
|
|
261
|
+
elsif cur > prev_depth
|
|
262
|
+
ary << if ary.empty? then @list_opening else lopen end
|
|
263
|
+
open += 1
|
|
264
|
+
|
|
265
|
+
# we are decreasing the level; close out tags but ensure we don't
|
|
266
|
+
# close out all the tags (leave one open)
|
|
267
|
+
else
|
|
268
|
+
(prev_depth - cur).times {
|
|
269
|
+
ary << "</li>" << lclose
|
|
270
|
+
open -= 1
|
|
271
|
+
break if open <= 0
|
|
272
|
+
}
|
|
273
|
+
if open > 0
|
|
274
|
+
ary << "</li>"
|
|
275
|
+
else
|
|
276
|
+
ary << lopen
|
|
277
|
+
open += 1
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# add the current element
|
|
282
|
+
ary << "<li>" << a.last
|
|
283
|
+
prev_depth = cur
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# close out the remaingling tags
|
|
287
|
+
ary << "</li>" << lclose
|
|
288
|
+
ary.join("\n")
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Returns +true+ if outline numbering should be inserted into the heading
|
|
292
|
+
# tags. Returns +false+ otherwise.
|
|
293
|
+
#
|
|
294
|
+
def numbering?
|
|
295
|
+
@numbering
|
|
296
|
+
end
|
|
297
|
+
end # class Outline
|
|
298
|
+
|
|
299
|
+
# Generate a outline numbering and/or a table of contents in the input HTML
|
|
300
|
+
# text.
|
|
301
|
+
#
|
|
302
|
+
register :outline do |input|
|
|
303
|
+
Outline.new(input).filter
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
end # module Filters
|
|
307
|
+
end # module Webby
|
|
308
|
+
|
|
309
|
+
# EOF
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
# Render text via the Sass library (part of Haml)
|
|
3
|
+
if try_require('sass', 'haml')
|
|
4
|
+
|
|
5
|
+
Webby::Filters.register :sass do |input, cursor|
|
|
6
|
+
opts = ::Webby.site.sass_options.merge(cursor.page.sass_options || {})
|
|
7
|
+
Sass::Engine.new(input, opts).render
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Otherwise raise an error if the user tries to use sass
|
|
11
|
+
else
|
|
12
|
+
Webby::Filters.register :sass do |input, cursor|
|
|
13
|
+
raise Webby::Error, "'haml' must be installed to use the sass filter"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# EOF
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Webby
|
|
2
|
+
module Filters
|
|
3
|
+
|
|
4
|
+
# The Slides filter is used to generate an S5 presentation from HTML input
|
|
5
|
+
# text. The input HTML is scanned for <h1> tags and slide divs are inserted
|
|
6
|
+
# before each <h1> tag found.
|
|
7
|
+
#
|
|
8
|
+
# When the HTML is rendered into the presentation layout, the result is an
|
|
9
|
+
# S5 presentation -- provided that the layout includes the appropriate S5
|
|
10
|
+
# javascript and CSS files.
|
|
11
|
+
#
|
|
12
|
+
class Slides
|
|
13
|
+
|
|
14
|
+
START_SLIDE = %{<div class="slide">#$/}
|
|
15
|
+
END_SLIDE = %{</div>#$/#$/}
|
|
16
|
+
|
|
17
|
+
# call-seq:
|
|
18
|
+
# Slides.new( html )
|
|
19
|
+
#
|
|
20
|
+
# Creates a new slides filter that will operate on the given
|
|
21
|
+
# _html_ string.
|
|
22
|
+
#
|
|
23
|
+
def initialize( str )
|
|
24
|
+
@str = str
|
|
25
|
+
@open = false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# call-seq:
|
|
29
|
+
# filter => html
|
|
30
|
+
#
|
|
31
|
+
# Process the original html document passed to the filter when it was
|
|
32
|
+
# created. The document will be scanned for H1 heading tags and slide
|
|
33
|
+
# divs will be inserted into the page before each H1 tag that is found.
|
|
34
|
+
#
|
|
35
|
+
def filter
|
|
36
|
+
result = []
|
|
37
|
+
|
|
38
|
+
@str.split(%r/\<h1\>/i).each do |slide|
|
|
39
|
+
next if slide.strip.empty?
|
|
40
|
+
result << START_SLIDE << '<h1>' << slide << END_SLIDE
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result.join
|
|
44
|
+
end
|
|
45
|
+
end # class Slides
|
|
46
|
+
|
|
47
|
+
# Insert slide divs into the input HTML text.
|
|
48
|
+
#
|
|
49
|
+
register :slides do |input|
|
|
50
|
+
Slides.new(input).filter
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end # module Filters
|
|
54
|
+
end # module Webby
|
|
55
|
+
|
|
56
|
+
# EOF
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# If RedCloth is installed, then configure the textile filter
|
|
3
|
+
if try_require('redcloth', 'RedCloth')
|
|
4
|
+
|
|
5
|
+
Webby::Filters.register :textile do |input|
|
|
6
|
+
RedCloth.new(input, %w(no_span_caps)).to_html
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Otherwise raise an error if the user tries to use textile
|
|
10
|
+
else
|
|
11
|
+
Webby::Filters.register :textile do |input|
|
|
12
|
+
raise Webby::Error, "'RedCloth' must be installed to use the textile filter"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# EOF
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'tempfile'
|
|
3
|
+
|
|
4
|
+
module Webby
|
|
5
|
+
module Filters
|
|
6
|
+
|
|
7
|
+
# The Tidy filter is used to process HTML (or XHTML) through the _tidy_
|
|
8
|
+
# program and outpu nicely formatted and correct HTML (or XHTML).
|
|
9
|
+
#
|
|
10
|
+
# Options can be passed to the _tidy_ program via the
|
|
11
|
+
# <code>Webby.site</code> struct. Setting the +tidy_options+ to the string
|
|
12
|
+
# of desired options will do the trick.
|
|
13
|
+
#
|
|
14
|
+
# From a project's Rakefile, include the following line (or one that's more
|
|
15
|
+
# to your liking):
|
|
16
|
+
#
|
|
17
|
+
# SITE.tidy_options = "-indent -wrap 80 -utf8"
|
|
18
|
+
#
|
|
19
|
+
class Tidy
|
|
20
|
+
|
|
21
|
+
# call-seq:
|
|
22
|
+
# Tidy.new( html )
|
|
23
|
+
#
|
|
24
|
+
# Create a new filter that will process the given _html_ through the tidy
|
|
25
|
+
# program.
|
|
26
|
+
#
|
|
27
|
+
def initialize( str )
|
|
28
|
+
@log = ::Logging::Logger[self]
|
|
29
|
+
@str = str
|
|
30
|
+
|
|
31
|
+
# create a temporary file for holding any error messages
|
|
32
|
+
# from the tidy program
|
|
33
|
+
@err = Tempfile.new('tidy_err')
|
|
34
|
+
@err.close
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# call-seq:
|
|
38
|
+
# process => formatted html
|
|
39
|
+
#
|
|
40
|
+
# Process the original HTML text string passed to the filter when it was
|
|
41
|
+
# created and output Tidy formatted HTML or XHTML.
|
|
42
|
+
#
|
|
43
|
+
def process
|
|
44
|
+
cmd = "tidy %s -q -f #{@err.path}" % ::Webby.site.tidy_options
|
|
45
|
+
out = IO.popen(cmd, 'r+') do |tidy|
|
|
46
|
+
tidy.write @str
|
|
47
|
+
tidy.close_write
|
|
48
|
+
tidy.read
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if File.size(@err.path) != 0
|
|
52
|
+
@log.warn File.read(@err.path).strip
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
return out
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end # class Tidy
|
|
59
|
+
|
|
60
|
+
# Render html into html/xhtml via the Tidy program
|
|
61
|
+
if cmd_available? %w[tidy -v]
|
|
62
|
+
register :tidy do |input|
|
|
63
|
+
Filters::Tidy.new(input).process
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Otherwise raise an error if the user tries to use tidy
|
|
67
|
+
else
|
|
68
|
+
register :tidy do |input|
|
|
69
|
+
raise Webby::Error, "'tidy' must be installed to use the tidy filter"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end # module Filters
|
|
74
|
+
end # module Webby
|
|
75
|
+
|
|
76
|
+
# EOF
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Webby
|
|
2
|
+
module Filters
|
|
3
|
+
|
|
4
|
+
class << self
|
|
5
|
+
|
|
6
|
+
# Register a handler for a filter
|
|
7
|
+
def register( filter, &block )
|
|
8
|
+
handlers[filter.to_s] = block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Process input through filters
|
|
12
|
+
def process( renderer, page, input )
|
|
13
|
+
# Start a new cursor for this page
|
|
14
|
+
Cursor.new(renderer, page).start_for(input)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Access a filter handler
|
|
18
|
+
def []( name )
|
|
19
|
+
handlers[name]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#######
|
|
23
|
+
private
|
|
24
|
+
#######
|
|
25
|
+
|
|
26
|
+
# The registered filter handlers
|
|
27
|
+
def handlers
|
|
28
|
+
@handlers ||= {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Instances of this class handle processing a set of filters
|
|
32
|
+
# for a given renderer and page.
|
|
33
|
+
# Note: The instance is passed as the second argument to filters
|
|
34
|
+
# that require two parameters and can be used to access
|
|
35
|
+
# information on the renderer, page, or filters being
|
|
36
|
+
# processed.
|
|
37
|
+
class Cursor
|
|
38
|
+
|
|
39
|
+
attr_reader :renderer, :page, :filters
|
|
40
|
+
def initialize(renderer, page)
|
|
41
|
+
@renderer, @page = renderer, page
|
|
42
|
+
@filters = Array(page.filter)
|
|
43
|
+
@log = Logging::Logger[Webby::Renderer]
|
|
44
|
+
@processed = 0
|
|
45
|
+
@prev_cursor = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def start_for(input)
|
|
49
|
+
@prev_cursor = @renderer.instance_variable_get(:@_cursor)
|
|
50
|
+
@renderer.instance_variable_set(:@_cursor, self)
|
|
51
|
+
filters.inject(input) do |result, filter|
|
|
52
|
+
handler = Filters[filter]
|
|
53
|
+
raise ::Webby::Error, "unknown filter: #{filter.inspect}" if handler.nil?
|
|
54
|
+
|
|
55
|
+
args = [result, self][0, handler.arity]
|
|
56
|
+
handle(filter, handler, *args)
|
|
57
|
+
end
|
|
58
|
+
ensure
|
|
59
|
+
@renderer.instance_variable_set(:@_cursor, @prev_cursor)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# The list of filters yet to be processed
|
|
63
|
+
def remaining_filters
|
|
64
|
+
filters[@processed..-1]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The name of the current filter
|
|
68
|
+
def current_filter
|
|
69
|
+
filters[@processed]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#######
|
|
73
|
+
private
|
|
74
|
+
#######
|
|
75
|
+
|
|
76
|
+
# Process arguments through a single filter
|
|
77
|
+
def handle(filter, handler, *args)
|
|
78
|
+
result = handler.call(*args)
|
|
79
|
+
@processed += 1
|
|
80
|
+
result
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end # class Cursor
|
|
84
|
+
end # class << self
|
|
85
|
+
|
|
86
|
+
end # module Filters
|
|
87
|
+
end # module Webby
|
|
88
|
+
|
|
89
|
+
Webby.require_all_libs_relative_to(__FILE__)
|
|
90
|
+
|
|
91
|
+
# EOF
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
|
|
2
|
+
module Webby::Helpers
|
|
3
|
+
|
|
4
|
+
# Based on code from Rails and Merb.
|
|
5
|
+
#
|
|
6
|
+
module CaptureHelper
|
|
7
|
+
|
|
8
|
+
# Called in pages and partials to store up content for later use. Takes a
|
|
9
|
+
# string and/or a block. First, the string is evaluated, and then the
|
|
10
|
+
# block is captured using the capture() helper provided by the template
|
|
11
|
+
# languages. The two are concatenated together.
|
|
12
|
+
#
|
|
13
|
+
# Content is retrieved by calling the method without a string or a block.
|
|
14
|
+
#
|
|
15
|
+
# ==== Parameters
|
|
16
|
+
# obj<Object>:: The key in the conetnt_for hash.
|
|
17
|
+
# string<String>:: Textual content. Defaults to nil.
|
|
18
|
+
# &block:: A block to be evaluated and concatenated to string.
|
|
19
|
+
#
|
|
20
|
+
# ==== Returns
|
|
21
|
+
# Any content associated with the key (or nil).
|
|
22
|
+
#
|
|
23
|
+
# ==== Example
|
|
24
|
+
# content_for(:foo, "Foo")
|
|
25
|
+
# content_for(:foo) #=> "Foo"
|
|
26
|
+
# content_for(:foo, "Bar")
|
|
27
|
+
# content_for(:foo) #=> "FooBar"
|
|
28
|
+
#
|
|
29
|
+
def content_for( obj, string = nil, &block )
|
|
30
|
+
return @_content_for[obj] unless string || block_given?
|
|
31
|
+
|
|
32
|
+
cur = @_content_for[obj].to_s
|
|
33
|
+
new = string.to_s + (block_given? ? capture_erb(&block) : "")
|
|
34
|
+
@_content_for[obj] = cur + new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns true if there is content for the given key. Otherwise returns
|
|
38
|
+
# false.
|
|
39
|
+
#
|
|
40
|
+
# ==== Parameters
|
|
41
|
+
# obj<Object>:: The key in the conetnt_for hash.
|
|
42
|
+
#
|
|
43
|
+
# ==== Example
|
|
44
|
+
# content_for(:foo, "Foo")
|
|
45
|
+
# content_for?(:foo) #=> true
|
|
46
|
+
# content_for?(:bar) #=> false
|
|
47
|
+
#
|
|
48
|
+
def content_for?( obj )
|
|
49
|
+
@_content_for.key?(obj)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Deletes any content associated with the given object in the content_for
|
|
53
|
+
# hash.
|
|
54
|
+
#
|
|
55
|
+
# ==== Parameters
|
|
56
|
+
# obj<Object>:: The key in the conetnt_for hash.
|
|
57
|
+
#
|
|
58
|
+
# ==== Returns
|
|
59
|
+
# Any content associated with the key (or nil).
|
|
60
|
+
#
|
|
61
|
+
# ==== Example
|
|
62
|
+
# content_for(:foo, "Foo")
|
|
63
|
+
# content_for?(:foo) #=> true
|
|
64
|
+
# delete_content_for(:foo)
|
|
65
|
+
# content_for?(:foo) #=> false
|
|
66
|
+
#
|
|
67
|
+
def delete_content_for( obj )
|
|
68
|
+
@_content_for.delete(obj)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# This method is used to capture content from an ERB filter evaluation. It
|
|
72
|
+
# is useful to helpers that need to process chunks of data during ERB filter
|
|
73
|
+
# processing.
|
|
74
|
+
#
|
|
75
|
+
# ==== Parameters
|
|
76
|
+
# *args:: Arguments to pass to the block.
|
|
77
|
+
# &block:: The ERB block to call.
|
|
78
|
+
#
|
|
79
|
+
# ==== Returns
|
|
80
|
+
# String:: The output of the block.
|
|
81
|
+
#
|
|
82
|
+
# ==== Examples
|
|
83
|
+
# Capture being used in an ERB page:
|
|
84
|
+
#
|
|
85
|
+
# <% @foo = capture_erb do %>
|
|
86
|
+
# <p>Some Foo content!</p>
|
|
87
|
+
# <% end %>
|
|
88
|
+
#
|
|
89
|
+
def capture_erb( *args, &block )
|
|
90
|
+
# get the buffer from the block's binding
|
|
91
|
+
buffer = _erb_buffer(block.binding) rescue nil
|
|
92
|
+
|
|
93
|
+
# If there is no buffer, just call the block and get the contents
|
|
94
|
+
if buffer.nil?
|
|
95
|
+
block.call(*args)
|
|
96
|
+
# If there is a buffer, execute the block, then extract its contents
|
|
97
|
+
else
|
|
98
|
+
pos = buffer.length
|
|
99
|
+
block.call(*args)
|
|
100
|
+
|
|
101
|
+
# extract the block
|
|
102
|
+
data = buffer[pos..-1]
|
|
103
|
+
|
|
104
|
+
# replace it in the original with empty string
|
|
105
|
+
buffer[pos..-1] = ""
|
|
106
|
+
|
|
107
|
+
data
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# This method is used to concatenate content into the ERB output buffer.
|
|
112
|
+
# It is usefule to helpers that need to insert transformed text back into
|
|
113
|
+
# the ERB output buffer.
|
|
114
|
+
#
|
|
115
|
+
# ==== Parameters
|
|
116
|
+
# string<String>:: The string to insert into the ERB output.
|
|
117
|
+
# the_binding<Binding>:: The binding to pass to the buffer.
|
|
118
|
+
#
|
|
119
|
+
def concat_erb( string, the_binding )
|
|
120
|
+
_erb_buffer(the_binding) << string
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Provides direct acccess to the ERB buffer in the conext of the binding.
|
|
124
|
+
#
|
|
125
|
+
# ==== Parameters
|
|
126
|
+
# the_binding<Binding>:: The binding to pass to the buffer.
|
|
127
|
+
#
|
|
128
|
+
# ==== Returns
|
|
129
|
+
# The current ERB output buffer.
|
|
130
|
+
#
|
|
131
|
+
def _erb_buffer( the_binding )
|
|
132
|
+
eval("_erbout", the_binding, __FILE__, __LINE__)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end # module CaptureHelper
|
|
136
|
+
|
|
137
|
+
register(CaptureHelper)
|
|
138
|
+
|
|
139
|
+
end # module Webby::Helpers
|
|
140
|
+
|
|
141
|
+
# EOF
|