amber 0.2.6
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/LICENSE +661 -0
- data/README.md +114 -0
- data/bin/amber +71 -0
- data/lib/amber.rb +76 -0
- data/lib/amber/cli.rb +98 -0
- data/lib/amber/logger.rb +21 -0
- data/lib/amber/menu.rb +141 -0
- data/lib/amber/page_array.rb +61 -0
- data/lib/amber/render/asset.rb +55 -0
- data/lib/amber/render/autolink.rb +78 -0
- data/lib/amber/render/bracketlink.rb +33 -0
- data/lib/amber/render/helpers/haml_helper.rb +54 -0
- data/lib/amber/render/helpers/html_helper.rb +75 -0
- data/lib/amber/render/helpers/language_helper.rb +25 -0
- data/lib/amber/render/helpers/navigation_helper.rb +203 -0
- data/lib/amber/render/layout.rb +66 -0
- data/lib/amber/render/table_of_contents.rb +383 -0
- data/lib/amber/render/template.rb +158 -0
- data/lib/amber/render/view.rb +189 -0
- data/lib/amber/server.rb +113 -0
- data/lib/amber/site.rb +154 -0
- data/lib/amber/site_configuration.rb +132 -0
- data/lib/amber/static_page.rb +151 -0
- data/lib/amber/static_page/filesystem.rb +270 -0
- data/lib/amber/static_page/page_properties.rb +124 -0
- data/lib/amber/static_page/property_set.rb +78 -0
- data/lib/amber/static_page/render.rb +122 -0
- metadata +203 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# A Layout is similar to a layout in Rails (a template that decorates the pages)
|
3
|
+
#
|
4
|
+
|
5
|
+
gem 'tilt', '>= 2.0.0'
|
6
|
+
require 'tilt'
|
7
|
+
require 'haml'
|
8
|
+
|
9
|
+
#Haml::Options.defaults[:format] = :html5
|
10
|
+
|
11
|
+
module Amber
|
12
|
+
module Render
|
13
|
+
|
14
|
+
class Layout
|
15
|
+
def self.load(layout_dir=nil)
|
16
|
+
@layout_dirs ||= []
|
17
|
+
@layout_dirs << layout_dir if layout_dir
|
18
|
+
reload
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.reload
|
22
|
+
@layouts ||= {}
|
23
|
+
@layouts['default'] = DefaultLayout.new
|
24
|
+
@layout_dirs.each do |dir|
|
25
|
+
Dir.glob("#{dir}/*").each do |layout_file|
|
26
|
+
name = File.basename(layout_file).sub(/^([^\.]*).*$/, "\\1")
|
27
|
+
@layouts[name] = Layout.new(layout_file)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.[](layout)
|
33
|
+
@layouts[layout]
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(file_path, &block)
|
37
|
+
if file_path =~ /\.haml$/
|
38
|
+
@template = Tilt::HamlTemplate.new(file_path, {:format => :html5})
|
39
|
+
else
|
40
|
+
@template = Tilt.new(file_path, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def render(view, &block)
|
45
|
+
@template.render(view, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class DefaultLayout < Layout
|
50
|
+
def initialize
|
51
|
+
@template = Tilt::StringTemplate.new {DEFAULT}
|
52
|
+
end
|
53
|
+
DEFAULT = '<!DOCTYPE html>
|
54
|
+
<html>
|
55
|
+
<head>
|
56
|
+
<title>#{ @page.nav_title } - #{@site.title}</title>
|
57
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
58
|
+
</head>
|
59
|
+
<body>
|
60
|
+
#{ yield }
|
61
|
+
</body>
|
62
|
+
</html>'
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,383 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Generates a table of contents for any HTML markup, and adds anchors to headings.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Amber::Render
|
11
|
+
|
12
|
+
##
|
13
|
+
## TABLE OF CONTENTS
|
14
|
+
##
|
15
|
+
|
16
|
+
class TableOfContents
|
17
|
+
#
|
18
|
+
# options:
|
19
|
+
# :content_selector (css selector for headings, nokogiri backend only)
|
20
|
+
# :href_base -- use this href for the toc links
|
21
|
+
# :numeric_prefix -- prefix toc entries and headings with numeric counter (e.g. 1.1.0, 1.2.0, ...)
|
22
|
+
#
|
23
|
+
def initialize(html, options = {})
|
24
|
+
@html = html
|
25
|
+
@toc = TocItem.new
|
26
|
+
@levels = {"h1" => 0, "h2" => 0, "h3" => 0, "h4" => 0}
|
27
|
+
@heading_anchors = {}
|
28
|
+
@options = options
|
29
|
+
@options[:tag] ||= 'ol'
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_html
|
33
|
+
parse_doc unless @parsed
|
34
|
+
# override this!
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_toc
|
38
|
+
parse_doc unless @parsed
|
39
|
+
# override this!
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_doc
|
45
|
+
each_heading(@html) do |heading, heading_text|
|
46
|
+
heading_anchor = anchor_text(heading_text)
|
47
|
+
heading_text = strip_anchors(heading_text)
|
48
|
+
if @options[:numeric_prefix]
|
49
|
+
increment_level(heading)
|
50
|
+
heading_text = level_text + " " + heading_text
|
51
|
+
end
|
52
|
+
@toc.add_heading(heading, heading_text, heading_anchor)
|
53
|
+
'<a name="%s"></a>%s' % [heading_anchor, heading_text]
|
54
|
+
end
|
55
|
+
@parsed = true
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# returns anchor text from heading text.
|
60
|
+
# e.g. First Heading! => first-heading
|
61
|
+
#
|
62
|
+
# if there are duplicates, they get numbered:
|
63
|
+
# heading => heading
|
64
|
+
# heading => heading-2
|
65
|
+
# heading => heading-3
|
66
|
+
#
|
67
|
+
def anchor_text(heading_text)
|
68
|
+
text = nameize(strip_html_tags(heading_text))
|
69
|
+
text_with_suffix = text
|
70
|
+
i = 2
|
71
|
+
while @heading_anchors[text_with_suffix]
|
72
|
+
text_with_suffix = "#{text}-#{i}"
|
73
|
+
i+=1
|
74
|
+
end
|
75
|
+
@heading_anchors[text_with_suffix] = true
|
76
|
+
text_with_suffix
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# convert any string to one suitable for a url.
|
81
|
+
# resist the urge to translit non-ascii slugs to ascii.
|
82
|
+
# it is always much better to keep strings as utf8.
|
83
|
+
#
|
84
|
+
def nameize(str)
|
85
|
+
str = str.dup
|
86
|
+
str.gsub!(/&(\w{2,6}?|#[0-9A-Fa-f]{2,6});/,'') # remove html entitities
|
87
|
+
str.gsub!(/[^- [[:word:]]]/u, '') # remove non-word characters (using unicode definition of a word char)
|
88
|
+
str.strip!
|
89
|
+
str.downcase! # upper case characters in urls are confusing
|
90
|
+
str.gsub!(/\ +/u, '-') # spaces to dashes, preferred separator char everywhere
|
91
|
+
CGI.escape(str)
|
92
|
+
end
|
93
|
+
|
94
|
+
# removes all html markup
|
95
|
+
def strip_html_tags(html)
|
96
|
+
Nokogiri::HTML::DocumentFragment.parse(html, 'UTF-8').children.collect{|child| child.inner_text}.join
|
97
|
+
end
|
98
|
+
|
99
|
+
# remove <a name='x'></a> from html, but leaves all other tags in place.
|
100
|
+
def strip_anchors(html)
|
101
|
+
Nokogiri::HTML::DocumentFragment.parse(html, 'UTF-8').children.collect{|child|
|
102
|
+
if child.name == "text"
|
103
|
+
child.inner_text
|
104
|
+
elsif child.name != 'a' || !child.attributes.detect{|atr| atr[0] == 'name'}
|
105
|
+
child.to_s
|
106
|
+
end
|
107
|
+
}.join
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# prefix headings with text like 1.2.1, if :numeric_prefix => true
|
112
|
+
#
|
113
|
+
def level_text
|
114
|
+
[@levels["h1"], @levels["h2"], @levels["h3"], @levels["h4"]].join(".").gsub(/\.0/, "")
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# keeps a counter of the latest heading at each level
|
119
|
+
#
|
120
|
+
def increment_level(heading)
|
121
|
+
@levels[heading] += 1
|
122
|
+
@levels["h2"] = 0 if heading == "h1"
|
123
|
+
@levels["h3"] = 0 if heading == "h1" || heading == "h2"
|
124
|
+
@levels["h4"] = 0 if heading == "h1" || heading == "h2" || heading == "h3"
|
125
|
+
end
|
126
|
+
|
127
|
+
def each_heading(html, &block)
|
128
|
+
raise 'override me'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
## NOKOGIRI TOC
|
134
|
+
##
|
135
|
+
|
136
|
+
class NokogiriTableOfContents < TableOfContents
|
137
|
+
def to_html
|
138
|
+
super
|
139
|
+
@nokogiri_doc.to_html.gsub(/(<h\d.*?>)\n/, '\1').gsub(/\n(<\/h\d.*?>)/, '\1')
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_toc
|
143
|
+
super
|
144
|
+
ul = Nokogiri::XML::Node.new(@options[:tag], Nokogiri::HTML.fragment(""))
|
145
|
+
@toc.populate_node(ul, @options)
|
146
|
+
ul.to_pretty_html
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def each_heading(html, &block)
|
152
|
+
@nokogiri_doc = Nokogiri::HTML.fragment(html, "UTF-8")
|
153
|
+
if @options[:content_selector]
|
154
|
+
selector = @levels.keys.map {|h| "#{@options[:content_selector]} #{h}" }.join(",")
|
155
|
+
else
|
156
|
+
selector = @levels.keys.join(",")
|
157
|
+
end
|
158
|
+
@nokogiri_doc.css(selector).each do |node|
|
159
|
+
node.inner_html = yield(node.name, node.inner_html)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
## REGEX TOC
|
166
|
+
##
|
167
|
+
|
168
|
+
class RegexTableOfContents < TableOfContents
|
169
|
+
def to_html
|
170
|
+
super
|
171
|
+
@new_html
|
172
|
+
end
|
173
|
+
|
174
|
+
def to_toc
|
175
|
+
super
|
176
|
+
@toc.to_html(@options)
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
HEADING_EX = %r{
|
182
|
+
<\s*((h\d).*?)\s*> # match starting <h1>
|
183
|
+
(.+)? # match innner text
|
184
|
+
<\s*\/\2\s*> # match closing </h1>
|
185
|
+
}x
|
186
|
+
|
187
|
+
def each_heading(html, &block)
|
188
|
+
@new_html = html.gsub(HEADING_EX) do |match|
|
189
|
+
"<%s>%s</%s>" % [$1, yield($2, $3), $2]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
## TOC ITEM
|
196
|
+
##
|
197
|
+
## A tree of TocItems composes the table of contents outline.
|
198
|
+
##
|
199
|
+
|
200
|
+
class TocItem
|
201
|
+
attr_reader :children, :level, :text, :anchor
|
202
|
+
|
203
|
+
def initialize(heading='h0', text=nil, anchor=nil)
|
204
|
+
@level = heading[1].to_i if heading.is_a?(String)
|
205
|
+
@text = text
|
206
|
+
@anchor = anchor
|
207
|
+
@children = []
|
208
|
+
end
|
209
|
+
|
210
|
+
def add_heading(heading, heading_text, heading_anchor)
|
211
|
+
self.parent_for(heading).children << TocItem.new(heading, heading_text, heading_anchor)
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# generates nokogiri html node tree from this toc
|
216
|
+
#
|
217
|
+
def populate_node(node, options)
|
218
|
+
@children.each do |item|
|
219
|
+
li = node.document.create_element("li")
|
220
|
+
li.add_child(li.document.create_element("a", item.text, :href => "#{options[:href_base]}##{item.anchor}"))
|
221
|
+
if item.children.any?
|
222
|
+
ul = li.document.create_element(options[:tag])
|
223
|
+
item.populate_node(ul, options)
|
224
|
+
li.add_child(ul)
|
225
|
+
end
|
226
|
+
node.add_child(li)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# generates html string from this toc
|
232
|
+
#
|
233
|
+
def to_html(options={})
|
234
|
+
html = []
|
235
|
+
tag = options[:tag]
|
236
|
+
indent = options[:indent] || 0
|
237
|
+
str = options[:indent_str] || " "
|
238
|
+
html << '%s<%s>' % [(str*indent), tag]
|
239
|
+
@children.each do |item|
|
240
|
+
html << '%s<li>' % (str*(indent+1))
|
241
|
+
html << '%s<a href="%s#%s">%s</a>' % [str*(indent+2), options[:href_base], item.anchor, item.text]
|
242
|
+
if item.children.any?
|
243
|
+
html << item.to_html({
|
244
|
+
:indent => indent+2,
|
245
|
+
:indent_str => str,
|
246
|
+
:tag => tag,
|
247
|
+
:href_base => options[:href_base]
|
248
|
+
})
|
249
|
+
end
|
250
|
+
html << '%s</li>' % (str*(indent+1))
|
251
|
+
end
|
252
|
+
html << '%s</%s>' % [(str*indent), tag]
|
253
|
+
html.join("\n")
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
# Returns the appropriate TocItem for appending a new item
|
258
|
+
# at a particular heading level.
|
259
|
+
#
|
260
|
+
def parent_for(heading)
|
261
|
+
heading = heading[1].to_i if heading.is_a?(String)
|
262
|
+
if children.any? && children.last.level < heading
|
263
|
+
children.last.parent_for(heading)
|
264
|
+
else
|
265
|
+
self
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
class Nokogiri::XML::Node
|
273
|
+
def to_pretty_html(indent=0)
|
274
|
+
indent_str = " " * indent
|
275
|
+
children_html = []
|
276
|
+
text_html = nil
|
277
|
+
if children.size == 1 && children.first.name == "text"
|
278
|
+
text_html = children.first.content
|
279
|
+
else
|
280
|
+
children.each do |child|
|
281
|
+
if child.name == "text"
|
282
|
+
children_html << "#{" " * (indent+1)}#{child.content}" if !child.content.empty?
|
283
|
+
else
|
284
|
+
children_html << child.to_pretty_html(indent+1)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
attrs = []
|
289
|
+
attributes.each do |attribute|
|
290
|
+
attrs << %(#{attribute[0]}="#{attribute[1]}")
|
291
|
+
end
|
292
|
+
if attrs.any?
|
293
|
+
attr_html = " " + attrs.join(' ')
|
294
|
+
else
|
295
|
+
attr_html = ""
|
296
|
+
end
|
297
|
+
html = []
|
298
|
+
if text_html
|
299
|
+
html << "#{indent_str}<#{name}#{attr_html}>#{text_html}</#{name}>"
|
300
|
+
elsif children_html.any?
|
301
|
+
html << "#{indent_str}<#{name}#{attr_html}>"
|
302
|
+
html += children_html
|
303
|
+
html << "#{indent_str}</#{name}>"
|
304
|
+
else
|
305
|
+
html << "#{indent_str}<#{name}#{attr_html}></#{name}>"
|
306
|
+
end
|
307
|
+
html.join("\n")
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
=begin
|
313
|
+
|
314
|
+
AN ATTEMPT TO GET NOKOGIRI TO OUTPUT REASONABLE HTML5. NO LUCK.
|
315
|
+
|
316
|
+
#
|
317
|
+
# convert a Nokogiri::HTML::Document into well formatted html.
|
318
|
+
# unfortunately, Nokogiri formatting only works on complete documents, so we strip away the <html> tags. :(
|
319
|
+
#
|
320
|
+
def format_doc(doc)
|
321
|
+
INDENT_XSLT.apply_to(doc).to_s.sub("<!DOCTYPE html>\n<html><body>", '').sub('</body></html>', '')
|
322
|
+
end
|
323
|
+
|
324
|
+
# from https://github.com/jarijokinen/html5-beautifier/blob/master/lib/html5-beautifier/xslt/html5-beautifier.xslt
|
325
|
+
# MIT License
|
326
|
+
INDENT_XSLT_STRING = <<EOF
|
327
|
+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
328
|
+
<xsl:output method="html" omit-xml-declaration="yes" encoding="utf-8" />
|
329
|
+
<xsl:param name="indent-increment" select="'__INDENT_STRING__'" />
|
330
|
+
|
331
|
+
<xsl:template name="newline">
|
332
|
+
<xsl:text disable-output-escaping="yes">
|
333
|
+
</xsl:text>
|
334
|
+
</xsl:template>
|
335
|
+
|
336
|
+
<xsl:template match="/">
|
337
|
+
<xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text>
|
338
|
+
<xsl:apply-templates />
|
339
|
+
</xsl:template>
|
340
|
+
|
341
|
+
<xsl:template match="comment() | processing-instruction()">
|
342
|
+
<xsl:param name="indent" select="''" />
|
343
|
+
<xsl:call-template name="newline" />
|
344
|
+
<xsl:value-of select="$indent" />
|
345
|
+
<xsl:copy />
|
346
|
+
</xsl:template>
|
347
|
+
|
348
|
+
<xsl:template match="text()">
|
349
|
+
<xsl:param name="indent" select="''" />
|
350
|
+
<xsl:call-template name="newline" />
|
351
|
+
<xsl:value-of select="$indent" />
|
352
|
+
<xsl:value-of select="normalize-space(.)" />
|
353
|
+
</xsl:template>
|
354
|
+
|
355
|
+
<xsl:template match="text()[normalize-space(.)='']" />
|
356
|
+
|
357
|
+
<xsl:template match="*">
|
358
|
+
<xsl:param name="indent" select="''" />
|
359
|
+
<xsl:call-template name="newline" />
|
360
|
+
<xsl:value-of select="$indent" />
|
361
|
+
<xsl:choose>
|
362
|
+
<xsl:when test="count(child::*) > 0 and __EXCLUDE_ELEMENTS__">
|
363
|
+
<xsl:copy>
|
364
|
+
<xsl:copy-of select="@*" />
|
365
|
+
<xsl:apply-templates select="*|text()">
|
366
|
+
<xsl:with-param name="indent" select="concat($indent, $indent-increment)" />
|
367
|
+
</xsl:apply-templates>
|
368
|
+
<xsl:call-template name="newline" />
|
369
|
+
<xsl:value-of select="$indent" />
|
370
|
+
</xsl:copy>
|
371
|
+
</xsl:when>
|
372
|
+
<xsl:otherwise>
|
373
|
+
<xsl:copy-of select="." />
|
374
|
+
</xsl:otherwise>
|
375
|
+
</xsl:choose>
|
376
|
+
</xsl:template>
|
377
|
+
</xsl:stylesheet>
|
378
|
+
EOF
|
379
|
+
|
380
|
+
INDENT_XSLT = Nokogiri::XSLT(INDENT_XSLT_STRING.gsub('__INDENT_STRING__', ' '))
|
381
|
+
|
382
|
+
|
383
|
+
=end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require 'tilt'
|
3
|
+
require 'RedCloth'
|
4
|
+
require 'rdiscount'
|
5
|
+
|
6
|
+
module Amber
|
7
|
+
module Render
|
8
|
+
class Template
|
9
|
+
|
10
|
+
PROPERTY_HEADER = /^\s*(^(|- )@\w[^\n]*?\n)*/m
|
11
|
+
|
12
|
+
RENDER_MAP = {
|
13
|
+
:text => 'render_textile',
|
14
|
+
:textile => 'render_textile',
|
15
|
+
:md => 'render_markdown',
|
16
|
+
:markdown => 'render_markdown',
|
17
|
+
:html => 'render_raw'
|
18
|
+
}
|
19
|
+
|
20
|
+
TEXTILE_TOC_RE = /^\s*h([1-6])\.\s+(.*)/
|
21
|
+
|
22
|
+
ERB_TAG_RE = /<%=.*?%>/
|
23
|
+
ERB_PLACEHOLDER_RE = /xx erb tag\d+ xx/
|
24
|
+
|
25
|
+
attr_reader :file
|
26
|
+
attr_reader :type
|
27
|
+
attr_reader :content
|
28
|
+
attr_reader :partial
|
29
|
+
|
30
|
+
def initialize(options={})
|
31
|
+
if options[:file]
|
32
|
+
@file = options[:file]
|
33
|
+
@type = type_from_file(@file)
|
34
|
+
elsif options[:content]
|
35
|
+
@content = options[:content]
|
36
|
+
@type = options[:type] # e.g. :haml. required if @content
|
37
|
+
end
|
38
|
+
@partial = options[:partial]
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# returns rendered content or title, depending on render_mode
|
43
|
+
#
|
44
|
+
def render(view, options={})
|
45
|
+
view.locals[:_type] = @type
|
46
|
+
render_mode = options.delete(:mode) || :content
|
47
|
+
toc = options.delete(:toc)
|
48
|
+
|
49
|
+
if render_mode == :title
|
50
|
+
render_title(view)
|
51
|
+
else
|
52
|
+
html = render_html(view)
|
53
|
+
if render_mode == :toc
|
54
|
+
RegexTableOfContents.new(html, options).to_toc
|
55
|
+
elsif toc || render_mode == :toc_and_content
|
56
|
+
toc = RegexTableOfContents.new(html, options)
|
57
|
+
%(<div id="TOC">%s</div>\n\n%s) % [toc.to_toc, toc.to_html]
|
58
|
+
else
|
59
|
+
html
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def render_html(view)
|
67
|
+
if @type == :haml
|
68
|
+
return render_haml(@file, view)
|
69
|
+
else
|
70
|
+
@content ||= File.read(@file, :encoding => 'UTF-8').sub(PROPERTY_HEADER, '') # remove property header
|
71
|
+
if method = RENDER_MAP[@type]
|
72
|
+
content, erb_tags = replace_erb_tags(@content)
|
73
|
+
html = self.send(method, view, content)
|
74
|
+
return render_erb(restore_erb_tags(html, erb_tags), view)
|
75
|
+
else
|
76
|
+
return "sorry, i don't understand how to render `#{@type}`"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def render_erb(string, view)
|
82
|
+
template = Tilt::ERBTemplate.new {string}
|
83
|
+
template.render(view)
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# takes raw markup, and replaces every <%= x %> with a
|
88
|
+
# markup-safe placeholder. erb_tags holds a map of placeholder
|
89
|
+
# to original erb. e.g. {"ERBTAG0" => "<%= 'hi]]"}
|
90
|
+
#
|
91
|
+
def replace_erb_tags(content)
|
92
|
+
counter = 0
|
93
|
+
erb_tags = {}
|
94
|
+
new_content = content.gsub(ERB_TAG_RE) do |match|
|
95
|
+
placeholder = "xx erb tag#{counter} xx"
|
96
|
+
erb_tags[placeholder] = match
|
97
|
+
counter+=1
|
98
|
+
placeholder
|
99
|
+
end
|
100
|
+
return [new_content, erb_tags]
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# replaces erb placeholders with actual erb
|
105
|
+
#
|
106
|
+
def restore_erb_tags(html, erb_tags)
|
107
|
+
html.gsub(ERB_PLACEHOLDER_RE) do |match|
|
108
|
+
erb_tags[match]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def render_title(view)
|
113
|
+
locale = view.locals[:locale]
|
114
|
+
if title = view.page.explicit_title(locale)
|
115
|
+
"<h1>#{title}</h1>\n"
|
116
|
+
else
|
117
|
+
""
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def render_haml(file_path, view)
|
122
|
+
template = Tilt::HamlTemplate.new(file_path, {:format => :html5, :default_encoding => 'UTF-8'})
|
123
|
+
add_bracket_links(view, template.render(view))
|
124
|
+
end
|
125
|
+
|
126
|
+
def render_textile(view, content)
|
127
|
+
content = add_bracket_links(view, content)
|
128
|
+
Autolink.auto_link(RedCloth.new(content).to_html)
|
129
|
+
end
|
130
|
+
|
131
|
+
def render_markdown(view, content)
|
132
|
+
content = add_bracket_links(view, content)
|
133
|
+
RDiscount.new(content, :smart, :autolink).to_html
|
134
|
+
end
|
135
|
+
|
136
|
+
def render_raw(view, content)
|
137
|
+
add_bracket_links(view, content)
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_bracket_links(view, content)
|
141
|
+
content = Bracketlink.bracket_link(content) do |from, to|
|
142
|
+
view.link({from => to})
|
143
|
+
end
|
144
|
+
content
|
145
|
+
end
|
146
|
+
|
147
|
+
def type_from_file(file_path)
|
148
|
+
suffix = File.extname(file_path)
|
149
|
+
if suffix
|
150
|
+
suffix.sub! /^\./, ''
|
151
|
+
suffix = suffix.to_sym
|
152
|
+
end
|
153
|
+
suffix
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|