runeblog 0.2.3 → 0.2.5
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.
- checksums.yaml +4 -4
- data/empty_view.tgz +0 -0
- data/lib/BAD.liveblog.rb +724 -0
- data/lib/KEEP.liveblog +646 -0
- data/lib/NEW-liveblog.rb +757 -0
- data/lib/OLD-liveblog.rb +661 -0
- data/lib/default.rb +1 -0
- data/lib/global.rb +5 -0
- data/lib/helpers-blog.rb +40 -14
- data/lib/liveblog.rb +7 -3
- data/lib/logging.rb +58 -0
- data/lib/post.rb +9 -0
- data/lib/publish.rb +7 -0
- data/lib/runeblog.rb +112 -43
- data/lib/runeblog_version.rb +1 -1
- data/lib/view.rb +8 -0
- data/runeblog.gemspec +1 -1
- data/test/make_blog.rb +8 -2
- data/themes/standard/blog/index.lt3 +3 -4
- data/themes/standard/blog/recent.lt3 +2 -0
- data/themes/standard/widgets/news/news.lt3 +1 -2
- data/themes/standard/widgets/pages/disclaim.html +6 -0
- data/themes/standard/widgets/pages/disclaim.lt3 +2 -3
- data/themes/standard/widgets/pages/faq.html +7 -0
- data/themes/standard/widgets/pages/faq.lt3 +1 -1
- data/themes/standard/widgets/pages/lifestory.html +7 -0
- data/themes/standard/widgets/pages/lifestory.lt3 +1 -1
- data/themes/standard/widgets/pages/like-dislike.html +7 -0
- data/themes/standard/widgets/pages/like-dislike.lt3 +1 -1
- data/themes/standard/widgets/pages/list.data +4 -4
- data/themes/standard/widgets/pages/pages.lt3 +2 -0
- metadata +14 -3
- data/themes/standard/widgets/pages/main.lt3 +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b72b0b4ca22d08e40c691a27c1a9affa94dc9c3f8ff1063d85f7b72be8b83838
|
4
|
+
data.tar.gz: d1919b3fef470e70acb7b7f8cc5f36f6ed7cb58176ee36e424e09691e83bd495
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a4feafd8e972f87280c3f4fbe43321d62de61a6eb9913deef08790e967c94d09fd2f451e7235f3cc4cc0620dd92087cb0c39ef6bb1fed6afe6a197fc1fc5450
|
7
|
+
data.tar.gz: d5a9fec4a3412ff28a1acf607f60614a1c3ed4d1fdbdf43747b5250e4f6930503028ad8ba2d866ea4c00695b6b81bf52a376e9e642b906427f84bb09a5711718
|
data/empty_view.tgz
ADDED
Binary file
|
data/lib/BAD.liveblog.rb
ADDED
@@ -0,0 +1,724 @@
|
|
1
|
+
stale? and livetext are duplicated from helpers-blog
|
2
|
+
|
3
|
+
def stale?(src, dst)
|
4
|
+
log(enter: __method__, args: [src, dst])
|
5
|
+
return true unless File.exist?(dst)
|
6
|
+
return true if File.mtime(src) > File.mtime(dst)
|
7
|
+
return false
|
8
|
+
end
|
9
|
+
|
10
|
+
def livetext(src, dst=nil)
|
11
|
+
log(enter: __method__, args: [src, dst])
|
12
|
+
src += ".lt3" unless src.end_with?(".lt3")
|
13
|
+
if dst
|
14
|
+
dst += ".html" unless dst.end_with?(".html")
|
15
|
+
else
|
16
|
+
dst = src.sub(/.lt3$/, "")
|
17
|
+
end
|
18
|
+
# return unless stale?(src, dst)
|
19
|
+
system("livetext #{src} >#{dst}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def post
|
23
|
+
log(enter: __method__)
|
24
|
+
@meta = OpenStruct.new
|
25
|
+
@meta.num = _args[0]
|
26
|
+
_out " <!-- Post number #{@meta.num} -->\n "
|
27
|
+
end
|
28
|
+
|
29
|
+
def quote
|
30
|
+
log(enter: __method__)
|
31
|
+
_passthru "<blockquote>"
|
32
|
+
_passthru _body
|
33
|
+
_passthru "</blockquote>"
|
34
|
+
_optional_blank_line
|
35
|
+
end
|
36
|
+
|
37
|
+
def categories # does nothing right now
|
38
|
+
log(str: "Does nothing yet", enter: __method__)
|
39
|
+
end
|
40
|
+
|
41
|
+
def style
|
42
|
+
log(enter: __method__)
|
43
|
+
fname = _args[0]
|
44
|
+
_passthru %[<link rel="stylesheet" href="???/etc/#{fname}')">]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Move elsewhere later!
|
48
|
+
|
49
|
+
def h1; _passthru "<h1>#{@_data}</h1>"; end
|
50
|
+
def h2; _passthru "<h2>#{@_data}</h2>"; end
|
51
|
+
def h3; _passthru "<h3>#{@_data}</h3>"; end
|
52
|
+
def h4; _passthru "<h4>#{@_data}</h4>"; end
|
53
|
+
def h5; _passthru "<h5>#{@_data}</h5>"; end
|
54
|
+
def h6; _passthru "<h6>#{@_data}</h6>"; end
|
55
|
+
|
56
|
+
def hr; _passthru "<hr>"; end
|
57
|
+
|
58
|
+
def list
|
59
|
+
log(enter: __method__)
|
60
|
+
_out "<ul>"
|
61
|
+
_body {|line| _out "<li>#{line}</li>" }
|
62
|
+
_out "</ul>"
|
63
|
+
_optional_blank_line
|
64
|
+
end
|
65
|
+
|
66
|
+
def list!
|
67
|
+
log(enter: __method__)
|
68
|
+
_out "<ul>"
|
69
|
+
lines = _body.each
|
70
|
+
loop do
|
71
|
+
line = lines.next
|
72
|
+
line = _format(line)
|
73
|
+
if line[0] == " "
|
74
|
+
_out line
|
75
|
+
else
|
76
|
+
_out "<li>#{line}</li>"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
_out "</ul>"
|
80
|
+
_optional_blank_line
|
81
|
+
end
|
82
|
+
|
83
|
+
def _html_body(file)
|
84
|
+
log(enter: __method__, args: [file])
|
85
|
+
file.puts "<html>\n <body>"
|
86
|
+
yield
|
87
|
+
file.puts " </body>\n</html>"
|
88
|
+
end
|
89
|
+
|
90
|
+
def _write_card(cardfile, mainfile, pairs, card_title, tag, relative: true)
|
91
|
+
# HTML for sidebar card
|
92
|
+
log(str: "Creating #{cardfile}.html", pwd: true)
|
93
|
+
File.open("#{cardfile}.html", "w") do |f|
|
94
|
+
f.puts <<-EOS
|
95
|
+
<div class="card mb-3">
|
96
|
+
<div class="card-body">
|
97
|
+
<h5 class="card-title">
|
98
|
+
<a href="javascript: void(0)"
|
99
|
+
onclick="javascript:open_main('widgets/#{tag}/#{mainfile}.html')"
|
100
|
+
style="text-decoration: none; color: black">#{card_title}</a>
|
101
|
+
</h5>
|
102
|
+
<!-- <ul class="list-group list-group-flush"> -->
|
103
|
+
EOS
|
104
|
+
log(str: "Writing data pairs to #{cardfile}.html", pwd: true)
|
105
|
+
top = relative ? "widgets/#{tag}/" : ""
|
106
|
+
pairs.each do |file, title|
|
107
|
+
f.puts <<-EOS
|
108
|
+
<li class="list-group-item"> <a href="javascript: void(0)"
|
109
|
+
onclick="javascript:open_main('#{top}#{file}')">#{title}</a> </li>
|
110
|
+
EOS
|
111
|
+
end
|
112
|
+
f.puts <<-EOS
|
113
|
+
<!-- </ul> -->
|
114
|
+
</div>
|
115
|
+
</div>
|
116
|
+
EOS
|
117
|
+
end
|
118
|
+
|
119
|
+
def _write_main(mainfile, pairs, card_title)
|
120
|
+
# HTML for main area (iframe)
|
121
|
+
log(str: "Creating #{mainfile}.html", pwd: true)
|
122
|
+
File.open("#{mainfile}.html", "w") do |f|
|
123
|
+
_html_body(f) do
|
124
|
+
f.puts "<h1>#{card_title}</h1>"
|
125
|
+
pairs.each do |file, title|
|
126
|
+
f.puts %[<a style="text-decoration: none; font-size: 24px" href="#{file}">#{title}</a> <br>]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def make_main_links
|
133
|
+
log(enter: __method__)
|
134
|
+
# FIXME remember strings may not be safe
|
135
|
+
line = _data.chomp
|
136
|
+
tag, card_title = *line.split(" ", 2)
|
137
|
+
cardfile, mainfile = "card-#{tag}", "main-#{tag}"
|
138
|
+
input = "list.data"
|
139
|
+
log(str: "Reading #{input}", pwd: true)
|
140
|
+
pairs = File.readlines(input).map {|line| line.chomp.split(",", 2) }
|
141
|
+
_write_main(mainfile, pairs, card_title)
|
142
|
+
widget_relative = (tag != "news") # FIXME kludge!!!
|
143
|
+
_write_card(cardfile, mainfile, pairs, card_title, tag, relative: widget_relative)
|
144
|
+
end
|
145
|
+
log(str: "...returning from method", pwd: true)
|
146
|
+
end
|
147
|
+
|
148
|
+
### inset
|
149
|
+
|
150
|
+
def inset
|
151
|
+
log(enter: __method__)
|
152
|
+
lines = _body
|
153
|
+
box = ""
|
154
|
+
lines.each do |line|
|
155
|
+
line = line.dup
|
156
|
+
if line[0] == "/" # Only into inset
|
157
|
+
line[0] = ' '
|
158
|
+
box << line.dup + " "
|
159
|
+
line.replace(" ")
|
160
|
+
end
|
161
|
+
if line[0] == "|" # Into inset and body
|
162
|
+
line[0] = ' '
|
163
|
+
box << line.dup + " "
|
164
|
+
end
|
165
|
+
_passthru(line)
|
166
|
+
end
|
167
|
+
lr = _args.first
|
168
|
+
wide = _args[1] || "25"
|
169
|
+
_passthru "<div style='float:#{lr}; width: #{wide}%; padding:8px; padding-right:12px; font-family:verdana'>"
|
170
|
+
_passthru '<b><i>'
|
171
|
+
_passthru box
|
172
|
+
_passthru_noline '</i></b></div>'
|
173
|
+
_optional_blank_line
|
174
|
+
end
|
175
|
+
|
176
|
+
def _errout(*args)
|
177
|
+
log(str: args.join(" "), enter: __method__)
|
178
|
+
::STDERR.puts *args
|
179
|
+
end
|
180
|
+
|
181
|
+
def _passthru(line)
|
182
|
+
log(enter: __method__, args: [line])
|
183
|
+
return if line.nil?
|
184
|
+
line = _format(line)
|
185
|
+
_out line + "\n"
|
186
|
+
_out "<p>" if line.empty? && ! @_nopara
|
187
|
+
end
|
188
|
+
|
189
|
+
def _passthru_noline(line)
|
190
|
+
log(enter: __method__, args: [line])
|
191
|
+
return if line.nil?
|
192
|
+
line = _format(line)
|
193
|
+
_out line
|
194
|
+
_out "<p>" if line.empty? && ! @_nopara
|
195
|
+
end
|
196
|
+
|
197
|
+
def title
|
198
|
+
log(enter: __method__)
|
199
|
+
raise "'post' was not called" unless @meta
|
200
|
+
title = @_data.chomp
|
201
|
+
@meta.title = title
|
202
|
+
setvar :title, title
|
203
|
+
_out %[<h1 class="post-title">#{title}</h1><br>]
|
204
|
+
_optional_blank_line
|
205
|
+
end
|
206
|
+
|
207
|
+
def pubdate
|
208
|
+
log(enter: __method__)
|
209
|
+
raise "'post' was not called" unless @meta
|
210
|
+
_debug "data = #@_data"
|
211
|
+
# Check for discrepancy?
|
212
|
+
match = /(\d{4}).(\d{2}).(\d{2})/.match @_data
|
213
|
+
junk, y, m, d = match.to_a
|
214
|
+
y, m, d = y.to_i, m.to_i, d.to_i
|
215
|
+
@meta.date = ::Date.new(y, m, d)
|
216
|
+
@meta.pubdate = "%04d-%02d-%02d" % [y, m, d]
|
217
|
+
_optional_blank_line
|
218
|
+
end
|
219
|
+
|
220
|
+
def image # primitive so far
|
221
|
+
log(enter: __method__)
|
222
|
+
_debug "img: huh? <img src=#{_args.first}></img>"
|
223
|
+
fname = _args.first
|
224
|
+
path = "assets/#{fname}"
|
225
|
+
_out "<img src=#{path}></img>"
|
226
|
+
_optional_blank_line
|
227
|
+
end
|
228
|
+
|
229
|
+
def tags
|
230
|
+
log(enter: __method__)
|
231
|
+
raise "'post' was not called" unless @meta
|
232
|
+
_debug "args = #{_args}"
|
233
|
+
@meta.tags = _args.dup || []
|
234
|
+
_optional_blank_line
|
235
|
+
end
|
236
|
+
|
237
|
+
def views
|
238
|
+
log(enter: __method__)
|
239
|
+
raise "'post' was not called" unless @meta
|
240
|
+
_debug "data = #{_args}"
|
241
|
+
@meta.views = _args.dup
|
242
|
+
_optional_blank_line
|
243
|
+
end
|
244
|
+
|
245
|
+
def pin
|
246
|
+
log(enter: __method__)
|
247
|
+
raise "'post' was not called" unless @meta
|
248
|
+
_debug "data = #{_args}"
|
249
|
+
# verify only already-specified views?
|
250
|
+
@meta.pinned = _args.dup
|
251
|
+
_optional_blank_line
|
252
|
+
end
|
253
|
+
|
254
|
+
def write_post
|
255
|
+
log(enter: __method__)
|
256
|
+
raise "'post' was not called" unless @meta
|
257
|
+
save = Dir.pwd
|
258
|
+
@postdir.gsub!(/\/\//, "/") # FIXME unneeded?
|
259
|
+
Dir.mkdir(@postdir) unless Dir.exist?(@postdir) # FIXME remember assets!
|
260
|
+
Dir.chdir(@postdir)
|
261
|
+
@meta.views = @meta.views.join(" ") if @meta.views.is_a? Array
|
262
|
+
@meta.tags = @meta.tags.join(" ") if @meta.tags.is_a? Array
|
263
|
+
File.write("teaser.txt", @meta.teaser)
|
264
|
+
|
265
|
+
fields = [:num, :title, :date, :pubdate, :views, :tags]
|
266
|
+
|
267
|
+
fname2 = "metadata.txt"
|
268
|
+
f2 = File.open(fname2, "w") do |f2|
|
269
|
+
fields.each {|fld| f2.puts "#{fld}: #{@meta.send(fld)}" }
|
270
|
+
end
|
271
|
+
Dir.chdir(save)
|
272
|
+
rescue => err
|
273
|
+
puts "err = #{err}"
|
274
|
+
puts err.backtrace.join("\n")
|
275
|
+
end
|
276
|
+
|
277
|
+
def teaser
|
278
|
+
log(enter: __method__)
|
279
|
+
raise "'post' was not called" unless @meta
|
280
|
+
@meta.teaser = _body_text
|
281
|
+
setvar :teaser, @meta.teaser
|
282
|
+
_out @meta.teaser + "\n"
|
283
|
+
# FIXME
|
284
|
+
end
|
285
|
+
|
286
|
+
def finalize
|
287
|
+
log(enter: __method__)
|
288
|
+
unless @meta
|
289
|
+
puts @live.body
|
290
|
+
return
|
291
|
+
end
|
292
|
+
if @blog.nil?
|
293
|
+
return @meta
|
294
|
+
end
|
295
|
+
|
296
|
+
@slug = @blog.make_slug(@meta)
|
297
|
+
slug_dir = @slug
|
298
|
+
@postdir = @blog.view.dir + "/posts/#{slug_dir}"
|
299
|
+
STDERR.puts "--- finalize: pwd = #{Dir.pwd} postdir = #@postdir"
|
300
|
+
write_post
|
301
|
+
@meta
|
302
|
+
end
|
303
|
+
|
304
|
+
$Dot = self # Clunky! for dot commands called from Functions class
|
305
|
+
|
306
|
+
# Find a better way to do this?
|
307
|
+
|
308
|
+
class Livetext::Functions
|
309
|
+
|
310
|
+
def br(n="1")
|
311
|
+
# Thought: Maybe make a way for functions to "simply" call the
|
312
|
+
# dot command of the same name?? Is this trivial??
|
313
|
+
n = n.empty? ? 1 : n.to_i
|
314
|
+
"<br>"*n
|
315
|
+
end
|
316
|
+
|
317
|
+
def h1(param); "<h1>#{param}</h1>"; end
|
318
|
+
def h2(param); "<h2>#{param}</h2>"; end
|
319
|
+
def h3(param); "<h3>#{param}</h3>"; end
|
320
|
+
def h4(param); "<h4>#{param}</h4>"; end
|
321
|
+
def h5(param); "<h5>#{param}</h5>"; end
|
322
|
+
def h6(param); "<h6>#{param}</h6>"; end
|
323
|
+
|
324
|
+
def hr(param=nil)
|
325
|
+
$Dot.hr
|
326
|
+
end
|
327
|
+
|
328
|
+
def image(param)
|
329
|
+
"<img src='#{param}'></img>"
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
###### experimental...
|
335
|
+
|
336
|
+
class Livetext::Functions
|
337
|
+
def _var(name)
|
338
|
+
::Livetext::Vars[name] || "[:#{name} is undefined]"
|
339
|
+
end
|
340
|
+
|
341
|
+
def link
|
342
|
+
file, cdata = self.class.param.split("||", 2)
|
343
|
+
%[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}#{file}" title="#{_var(:title)}">]
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
###
|
348
|
+
|
349
|
+
def _var(name) # FIXME scope issue!
|
350
|
+
::Livetext::Vars[name] || "[:#{name} is undefined]"
|
351
|
+
end
|
352
|
+
|
353
|
+
def head # Does NOT output <head> tags
|
354
|
+
log(enter: __method__)
|
355
|
+
args = _args
|
356
|
+
args.each do |inc|
|
357
|
+
self.data = inc
|
358
|
+
_include
|
359
|
+
end
|
360
|
+
# Depends on vars: title, desc, host
|
361
|
+
defaults = {}
|
362
|
+
defaults = { "charset" => %[<meta charset="utf-8">],
|
363
|
+
"http-equiv" => %[<meta http-equiv="X-UA-Compatible" content="IE=edge">],
|
364
|
+
"title" => %[<title>\n #{_var(:blog)} | #{_var("blog.desc")}\n </title>],
|
365
|
+
"generator" => %[<meta name="generator" content="Runeblog v #@version">],
|
366
|
+
"og:title" => %[<meta property="og:title" content="#{_var(:blog)}">],
|
367
|
+
"og:locale" => %[<meta property="og:locale" content="#{_var(:locale)}">],
|
368
|
+
"description" => %[<meta name="description" content="#{_var("blog.desc")}">],
|
369
|
+
"og:description" => %[<meta property="og:description" content="#{_var("blog.desc")}">],
|
370
|
+
"linkc" => %[<link rel="canonical" href="#{_var(:host)}">],
|
371
|
+
"og:url" => %[<meta property="og:url" content="#{_var(:host)}">],
|
372
|
+
"og:site_name" => %[<meta property="og:site_name" content="#{_var(:blog)}">],
|
373
|
+
"style" => %[<link rel="stylesheet" href="etc/blog.css">],
|
374
|
+
"feed" => %[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}/feed.xml" title="#{_var(:blog)}">],
|
375
|
+
"favicon" => %[<link rel="shortcut icon" type="image/x-icon" href="../etc/favicon.ico">\n <link rel="apple-touch-icon" href="../etc/favicon.ico">]
|
376
|
+
}
|
377
|
+
result = {}
|
378
|
+
lines = _body
|
379
|
+
lines.each do |line|
|
380
|
+
line.chomp
|
381
|
+
word, remain = line.split(" ", 2)
|
382
|
+
case word
|
383
|
+
when "viewport"
|
384
|
+
result["viewport"] = %[<meta name="viewport" content="#{remain}">]
|
385
|
+
when "script" # FIXME this is broken
|
386
|
+
file = remain
|
387
|
+
text = File.read(file)
|
388
|
+
result["script"] = Livetext.new.transform(text)
|
389
|
+
when "style"
|
390
|
+
result["style"] = %[<link rel="stylesheet" href="('/etc/#{remain}')">]
|
391
|
+
# Later: allow other overrides
|
392
|
+
when ""; break
|
393
|
+
else
|
394
|
+
STDERR.puts "-- got '#{word}'; old value = #{result[word].inspect}"
|
395
|
+
if defaults[word]
|
396
|
+
result[word] = %[<meta property="#{word}" content="#{remain}">]
|
397
|
+
STDERR.puts "-- new value = #{result[word].inspect}"
|
398
|
+
else
|
399
|
+
puts "Unknown tag '#{word}'"
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
hash = defaults.dup.update(result) # FIXME collisions?
|
404
|
+
|
405
|
+
# _out "<!-- "; _out hash.inspect; _out "--> "
|
406
|
+
hash.each_value {|x| _out " " + x }
|
407
|
+
_out "<body>"
|
408
|
+
end
|
409
|
+
|
410
|
+
########## newer stuff...
|
411
|
+
|
412
|
+
def meta
|
413
|
+
log(enter: __method__)
|
414
|
+
args = _args
|
415
|
+
enum = args.each
|
416
|
+
str = "<meta"
|
417
|
+
arg = enum.next
|
418
|
+
loop do
|
419
|
+
if arg.end_with?(":")
|
420
|
+
str << " " << arg[0..-2] << "="
|
421
|
+
a2 = enum.next
|
422
|
+
str << %["#{a2}"]
|
423
|
+
else
|
424
|
+
STDERR.puts "=== meta error?"
|
425
|
+
end
|
426
|
+
arg = enum.next
|
427
|
+
end
|
428
|
+
str << ">"
|
429
|
+
_out str
|
430
|
+
end
|
431
|
+
|
432
|
+
def recent_posts # side-effect
|
433
|
+
log(enter: __method__)
|
434
|
+
_out %[<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12">]
|
435
|
+
all_teasers
|
436
|
+
_out %[</div>]
|
437
|
+
end
|
438
|
+
|
439
|
+
def sidebar
|
440
|
+
log(enter: __method__)
|
441
|
+
_out %[<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">]
|
442
|
+
_args do |token|
|
443
|
+
tag = token.chomp.strip.downcase
|
444
|
+
# FIXME will someone please refactor this horrible code??
|
445
|
+
# Think of the children!!
|
446
|
+
mode = tag[0]
|
447
|
+
tag = tag[1..-1] if mode == "." || mode == ":"
|
448
|
+
Dir.chdir("widgets/#{tag}") do
|
449
|
+
name = tag + ".lt3"
|
450
|
+
case mode
|
451
|
+
when "." # Only in sidebar, special code
|
452
|
+
log(str: "DOT About to do: livetext #{name} in #{Dir.pwd}", dir: true)
|
453
|
+
livetext tag + ".lt3", "card-#{tag}"
|
454
|
+
log(str: "DOT after livetext call", pwd: true, dir: true)
|
455
|
+
when ":" # Card AND main, but still special
|
456
|
+
log(str: "COL About to do: livetext #{name} in #{Dir.pwd}", dir: true)
|
457
|
+
livetext tag + ".lt3", "card-#{tag}"
|
458
|
+
system("card-#{tag}.html main-#{tag}.html") # FIXME HTML will be wrong??
|
459
|
+
log(str: "COL after livetext call", pwd: true, dir: true)
|
460
|
+
else
|
461
|
+
log(str: "NRM About to do: livetext #{name} in #{Dir.pwd}", dir: true)
|
462
|
+
log(str: "livetext #{tag}.lt3 card-#{tag}")
|
463
|
+
livetext tag + ".lt3", "card-#{tag}"
|
464
|
+
log(str: "NRM after livetext call", pwd: true, dir: true)
|
465
|
+
end
|
466
|
+
_include_file "card-#{tag}.html"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
_out %[</div>]
|
470
|
+
end
|
471
|
+
|
472
|
+
def stylesheet
|
473
|
+
log(enter: __method__)
|
474
|
+
lines = _body
|
475
|
+
url = lines[0]
|
476
|
+
integ = lines[1]
|
477
|
+
cross = lines[2] || "anonymous"
|
478
|
+
_out %[<link rel="stylesheet" href="#{url}" integrity="#{integ}" crossorigin="#{cross}"></link>]
|
479
|
+
end
|
480
|
+
|
481
|
+
def script
|
482
|
+
log(enter: __method__)
|
483
|
+
lines = _body
|
484
|
+
url = lines[0]
|
485
|
+
integ = lines[1]
|
486
|
+
cross = lines[2] || "anonymous"
|
487
|
+
_out %[<script src="#{url}" integrity="#{integ}" crossorigin="#{cross}"></script>]
|
488
|
+
end
|
489
|
+
|
490
|
+
|
491
|
+
### How this next bit works:
|
492
|
+
###
|
493
|
+
### all_teasers will call _find_recent_posts
|
494
|
+
###
|
495
|
+
### _find_recent_posts will search higher in the directory structure
|
496
|
+
### for where the posts are (0001, 0002, ...) NOTE: This implies you
|
497
|
+
### must be in some specific place when this code is run.
|
498
|
+
### It returns the 20 most recent posts.
|
499
|
+
###
|
500
|
+
### all_teasers will then pick a small number of posts and call _teaser
|
501
|
+
|
502
|
+
### on each one. (The code in _teaser really belongs in a small template
|
503
|
+
### somewhere.)
|
504
|
+
###
|
505
|
+
|
506
|
+
def _find_recent_posts
|
507
|
+
log(enter: __method__)
|
508
|
+
@vdir = _var(:FileDir).match(%r[(^.*/views/.*?)/])[1]
|
509
|
+
posts = nil
|
510
|
+
dir_posts = @vdir + "/posts"
|
511
|
+
entries = Dir.entries(dir_posts)
|
512
|
+
posts = entries.grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
|
513
|
+
posts.select! {|x| File.directory?(x) }
|
514
|
+
# directories that start with four digits
|
515
|
+
posts = posts.sort {|a, b| b.to_i <=> a.to_i } # sort descending
|
516
|
+
posts[0..19] # return 20 at most
|
517
|
+
end
|
518
|
+
|
519
|
+
def all_teasers
|
520
|
+
log(enter: __method__)
|
521
|
+
open = <<-HTML
|
522
|
+
<section class="posts">
|
523
|
+
HTML
|
524
|
+
close = <<-HTML
|
525
|
+
</section>
|
526
|
+
HTML
|
527
|
+
|
528
|
+
text = <<-HTML
|
529
|
+
<html>
|
530
|
+
<head><link rel="stylesheet" href="etc/blog.css"></head>
|
531
|
+
<body>
|
532
|
+
HTML
|
533
|
+
posts = _find_recent_posts
|
534
|
+
wanted = [5, posts.size].min # estimate how many we want?
|
535
|
+
enum = posts.each
|
536
|
+
wanted.times do
|
537
|
+
postid = File.basename(enum.next)
|
538
|
+
postid = postid.to_i
|
539
|
+
text << _teaser(postid) # side effect! calls _out
|
540
|
+
end
|
541
|
+
text << "</body></html>"
|
542
|
+
File.write("recent.html", text)
|
543
|
+
_out %[<iframe id="main" style="width: 100vw; height: 100vh; position: relative;" src='recent.html' width=100% frameborder="0" allowfullscreen></iframe>]
|
544
|
+
end
|
545
|
+
|
546
|
+
def _post_lookup(postid) # side-effect
|
547
|
+
log(enter: __method__, args: [postid])
|
548
|
+
# .. = templates, ../.. = views/thisview
|
549
|
+
slug = title = date = teaser_text = nil
|
550
|
+
|
551
|
+
dir_posts = @vdir + "/posts"
|
552
|
+
posts = Dir.entries(dir_posts).grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
|
553
|
+
posts.select! {|x| File.directory?(x) }
|
554
|
+
|
555
|
+
post = posts.select {|x| File.basename(x).to_i == postid }
|
556
|
+
raise "Error: More than one post #{postid}" if post.size > 1
|
557
|
+
postdir = post.first
|
558
|
+
vp = RuneBlog::ViewPost.new(@blog.view, postdir)
|
559
|
+
vp
|
560
|
+
end
|
561
|
+
|
562
|
+
def _interpolate(str, context) # FIXME move this later
|
563
|
+
log(str: "Duplicated method?", enter: __method__, args: [str, context])
|
564
|
+
wrapped = "%[" + str.dup + "]" # could fail...
|
565
|
+
eval(wrapped, context)
|
566
|
+
end
|
567
|
+
|
568
|
+
def _teaser(slug)
|
569
|
+
log(enter: __method__, args: [slug])
|
570
|
+
id = slug.to_i
|
571
|
+
text = nil
|
572
|
+
post_entry_name = @theme + "blog/post_entry.lt3"
|
573
|
+
@_post_entry ||= File.read(post_entry_name)
|
574
|
+
vp = _post_lookup(id)
|
575
|
+
nslug, aslug, title, date, teaser_text =
|
576
|
+
vp.nslug, vp.aslug, vp.title, vp.date, vp.teaser_text
|
577
|
+
path = vp.path
|
578
|
+
url = "#{path}/#{aslug}.html" # Should be relative to .blogs!! FIXME
|
579
|
+
date = Date.parse(date)
|
580
|
+
date = date.strftime("%B %e<br>%Y")
|
581
|
+
text = _interpolate(@_post_entry, binding)
|
582
|
+
text
|
583
|
+
end
|
584
|
+
|
585
|
+
def _card_generic(card_title:, middle:, extra: "")
|
586
|
+
log(enter: __method__, args: [card_title, middle, extra])
|
587
|
+
front = <<-HTML
|
588
|
+
<div class="card #{extra} mb-3">
|
589
|
+
<div class="card-body">
|
590
|
+
<h5 class="card-title">#{card_title}</h5>
|
591
|
+
HTML
|
592
|
+
|
593
|
+
tail = <<-HTML
|
594
|
+
</div>
|
595
|
+
</div>
|
596
|
+
HTML
|
597
|
+
text = front + middle + tail
|
598
|
+
_out text + "\n "
|
599
|
+
end
|
600
|
+
|
601
|
+
def card_iframe
|
602
|
+
log(enter: __method__)
|
603
|
+
title, lines = _data, _body
|
604
|
+
lines.map!(&:chomp)
|
605
|
+
url = lines[0].chomp
|
606
|
+
stuff = lines[1..-1].join(" ") # FIXME later
|
607
|
+
middle = <<-HTML
|
608
|
+
<iframe src="#{url}" #{stuff}
|
609
|
+
style="border: 0" #{stuff}
|
610
|
+
frameborder="0" scrolling="no">
|
611
|
+
</iframe>
|
612
|
+
HTML
|
613
|
+
|
614
|
+
_card_generic(card_title: title, middle: middle, extra: "bg-dark text-white")
|
615
|
+
end
|
616
|
+
|
617
|
+
def _main(url)
|
618
|
+
log(enter: __method__, args: [url])
|
619
|
+
%[href="javascript: void(0)" onclick="javascript:open_main('#{url}')"]
|
620
|
+
end
|
621
|
+
|
622
|
+
def card1
|
623
|
+
log(enter: __method__)
|
624
|
+
title, lines = _data, _body
|
625
|
+
lines.map!(&:chomp)
|
626
|
+
|
627
|
+
card_text = lines[0]
|
628
|
+
url, classname, cdata = lines[1].split(",", 4)
|
629
|
+
main = _main(url)
|
630
|
+
|
631
|
+
middle = <<-HTML
|
632
|
+
<p class="card-text">#{card_text}</p>
|
633
|
+
<a #{main} class="#{classname}">#{cdata}</a>
|
634
|
+
HTML
|
635
|
+
|
636
|
+
_card_generic(card_title: title, middle: middle, extra: "bg-dark text-white")
|
637
|
+
end
|
638
|
+
|
639
|
+
def card2
|
640
|
+
log(enter: __method__)
|
641
|
+
str = _data
|
642
|
+
file, card_title = str.chomp.split(" ", 2)
|
643
|
+
card_title = %[<a #{_main(file)} style="text-decoration: none; color: black">#{card_title}</a>]
|
644
|
+
|
645
|
+
# FIXME is this wrong??
|
646
|
+
|
647
|
+
open = <<-HTML
|
648
|
+
<div class="card mb-3">
|
649
|
+
<div class="card-body">
|
650
|
+
<h5 class="card-title">#{card_title}</h5>
|
651
|
+
<ul class="list-group list-group-flush">
|
652
|
+
HTML
|
653
|
+
_out open
|
654
|
+
_body do |line|
|
655
|
+
url, cdata = line.chomp.split(",", 3)
|
656
|
+
main = _main(url)
|
657
|
+
_out %[<li class="list-group-item"><a #{main}}">#{cdata}</a> </li>]
|
658
|
+
end
|
659
|
+
close = %[ </ul>\n </div>\n </div>]
|
660
|
+
_out close
|
661
|
+
end
|
662
|
+
|
663
|
+
def tag_cloud
|
664
|
+
log(enter: __method__)
|
665
|
+
title = _data
|
666
|
+
title = "Tag Cloud" if title.empty?
|
667
|
+
open = <<-HTML
|
668
|
+
<div class="card mb-3">
|
669
|
+
<div class="card-body">
|
670
|
+
<h5 class="card-title">#{title}</h5>
|
671
|
+
HTML
|
672
|
+
_out open
|
673
|
+
_body do |line|
|
674
|
+
line.chomp!
|
675
|
+
url, classname, cdata = line.split(",", 4)
|
676
|
+
main = _main(url)
|
677
|
+
_out %[<a #{main} class="#{classname}">#{cdata}</a>]
|
678
|
+
end
|
679
|
+
close = %[ </div>\n </div>]
|
680
|
+
_out close
|
681
|
+
end
|
682
|
+
|
683
|
+
def navbar
|
684
|
+
log(enter: __method__)
|
685
|
+
title = _var(:blog)
|
686
|
+
|
687
|
+
open = <<-HTML
|
688
|
+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
689
|
+
<a class="navbar-brand" href="index.html">#{title}</a>
|
690
|
+
<button class="navbar-toggler"
|
691
|
+
type="button"
|
692
|
+
data-toggle="collapse"
|
693
|
+
data-target="#navbarSupportedContent"
|
694
|
+
aria-controls="navbarSupportedContent"
|
695
|
+
aria-expanded="false"
|
696
|
+
aria-label="Toggle navigation">
|
697
|
+
<span class="navbar-toggler-icon"></span>
|
698
|
+
</button>
|
699
|
+
<div class="collapse navbar-collapse pull-right"
|
700
|
+
id="navbarSupportedContent">
|
701
|
+
<ul class="navbar-nav mr-auto">
|
702
|
+
HTML
|
703
|
+
close = <<-HTML
|
704
|
+
</ul>
|
705
|
+
</div>
|
706
|
+
</nav>
|
707
|
+
HTML
|
708
|
+
|
709
|
+
first = true
|
710
|
+
_out open
|
711
|
+
_body do |line|
|
712
|
+
href, cdata = line.chomp.strip.split(" ", 2)
|
713
|
+
main = _main(href)
|
714
|
+
if first
|
715
|
+
first = false
|
716
|
+
_out %[<li class="nav-item active"> <a class="nav-link" href="#{href}">#{cdata}<span class="sr-only">(current)</span></a> </li>]
|
717
|
+
else
|
718
|
+
main = _main("navbar/#{href}")
|
719
|
+
_out %[<li class="nav-item"> <a class="nav-link" #{main}>#{cdata}</a> </li>]
|
720
|
+
end
|
721
|
+
end
|
722
|
+
_out close
|
723
|
+
end
|
724
|
+
|