runeblog 0.1.76 → 0.1.78

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9820213ad610c3b8f8372fc6ba3e4b276a171e0fcf45392713c862d968aedafe
4
- data.tar.gz: e55b2c905d49352cac5d38b663e02857082277c21dd32644f8cb010c6aa7b054
3
+ metadata.gz: 7e483b3ec658dfbb130d8b2b090107155af6c5371066949ae9d78bf8b4851525
4
+ data.tar.gz: 91ae3aebfefc68e69ddea4aa9cb700a28a572a422f41b9c010b570271069c22e
5
5
  SHA512:
6
- metadata.gz: 6c277ed7f2e698c0750b60cb914f4ad161b1e189d322f1bf28275f59df38196bd219cc5ad2d165a7f2f50242107385a27aa17bfd8cf7b9db4018a64b6b0022c4
7
- data.tar.gz: e888d0b904dbd275a4fd5befe62fb7af5723aed24c7b4a3883e5e6515939883a4f2e8f51640353be60615a618cdc3fdf3421a8bef1d938840a7e32ac49f59ea1
6
+ metadata.gz: bd0a51b5eef53f86f738e51dca6428bf2eefa6373912e023c61819aadef977b30f4e7735d0a3a183944f4071c136d797ba6f32f06e327e663bd75ba84db4efe2
7
+ data.tar.gz: a531739bb62e383d4e660a7f9e630a786934d739badfd179359d63392f23f5486c62b6f53922169b0ee12c319da71edad2fb7ec7839497fa2c3121be4d2bcf6c
Binary file
@@ -3,7 +3,7 @@ class RuneBlog::Default
3
3
  # This will all become much more generic later.
4
4
 
5
5
 
6
- def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
6
+ def RuneBlog.post_template(num: 0, title: "No title", date: nil, view: "test_view",
7
7
  teaser: "No teaser", body: "No body", tags: ["untagged"],
8
8
  views: [], back: "javascript:history.go(-1)", home: "no url")
9
9
  viewlist = (views + [view.to_s]).join(" ")
@@ -11,6 +11,8 @@ def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
11
11
  <<-TEXT
12
12
  .mixin liveblog
13
13
  . ^ get rid of this later
14
+
15
+ .post #{num}
14
16
 
15
17
  .title #{title}
16
18
  .pubdate #{date}
@@ -21,10 +23,6 @@ def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
21
23
  #{teaser}
22
24
  .end
23
25
  #{body}
24
- <hr>
25
- <a href='#{back}' style='text-decoration: none'>Back</a>
26
- <br>
27
- <a href='#{home}' style='text-decoration: none'>Home</a>
28
26
  TEXT
29
27
 
30
28
  end
@@ -1,15 +1,31 @@
1
1
  require 'runeblog_version'
2
2
 
3
+ # Home = Dir.pwd # unless Home
4
+
3
5
  module RuneBlog::Helpers
4
6
 
7
+ def get_root
8
+ if $_blog
9
+ if $_blog.root
10
+ puts "0. Returned: #{$_blog.root}/"
11
+ return $_blog.root + "/"
12
+ else
13
+ puts "1. Returned: ./"
14
+ return "./"
15
+ end
16
+ else
17
+ puts "2. Returned: ./"
18
+ return "./"
19
+ end
20
+ end
21
+
5
22
  def read_config(file, *syms)
6
- # verify(File.exist?(file) => "File #{file} doesn't exist")
23
+ # puts "dir = #{Dir.pwd}"
7
24
  lines = File.readlines(file).map(&:chomp)
8
25
  obj = ::OpenStruct.new
9
26
  lines.each do |line|
10
27
  next if line == "\n" || line[0] == "#"
11
28
  key, val = line.split(/: +/, 2)
12
- # STDERR.puts [key, val].inspect
13
29
  obj.send(key+"=", val)
14
30
  end
15
31
  return obj if syms.empty?
@@ -37,6 +53,8 @@ module RuneBlog::Helpers
37
53
 
38
54
  def write_config(obj, file)
39
55
  hash = obj.to_h
56
+ # Dir.chdir(::Home)
57
+ # puts "--- wc: pwd = #{Dir.pwd}"
40
58
  File.open(file, "w") do |f|
41
59
  hash.each_pair do |key, val|
42
60
  f.puts "#{key}: #{val}"
@@ -45,11 +63,13 @@ module RuneBlog::Helpers
45
63
  end
46
64
 
47
65
  def get_views # read from filesystem
48
- verify(@root => "#@root is nil",
49
- Dir.exist?(@root) => "#@root doesn't exist",
50
- Dir.exist?("#@root/views") => "#@root/views doesn't exist")
51
- dirs = subdirs("#@root/views/").sort
52
- dirs.map {|name| RuneBlog::View.new(name) }
66
+ # Dir.chdir(::Home) do
67
+ verify(@root => "#@root is nil",
68
+ Dir.exist?(@root) => "#@root doesn't exist",
69
+ Dir.exist?("#@root/views") => "#@root/views doesn't exist")
70
+ dirs = subdirs("#@root/views/").sort
71
+ dirs.map {|name| RuneBlog::View.new(name) }
72
+ # end
53
73
  end
54
74
 
55
75
  def new_dotfile(root: "./.blogs/data", current_view: "no_default", editor: "vi")
@@ -57,7 +77,7 @@ module RuneBlog::Helpers
57
77
  Dir.mkdir(".blogs")
58
78
  x = OpenStruct.new
59
79
  x.root, x.current_view, x.editor = root, current_view, editor
60
- write_config(x, RuneBlog::ConfigFile)
80
+ write_config(x, ".blogs/" + RuneBlog::ConfigFile)
61
81
  end
62
82
 
63
83
  def new_sequence
@@ -2,7 +2,34 @@ require 'ostruct'
2
2
  require 'pp'
3
3
  require 'date'
4
4
 
5
- # require 'runeblog' # Now depends explicitly
5
+ require 'livetext'
6
+ require 'runeblog'
7
+
8
+ # ::Home = Dir.pwd unless defined?(::Home)
9
+
10
+ =begin
11
+ 123:def title # side-effect
12
+ 133:def pubdate # side-effect
13
+ 153:def tags # side-effect
14
+ 160:def views # side-effect
15
+ 167:def pin # side-effect
16
+ 218:def write_post # side-effect
17
+ 393:def main # side-effect
18
+ 491:def _post_lookup(postid) # side-effect
19
+ =end
20
+
21
+ def post
22
+ @meta = OpenStruct.new
23
+ @meta.num = _args[0]
24
+ # @live = ::Livetext.new
25
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
26
+ end
27
+
28
+ def _view_from_cwd
29
+ md = Dir.pwd.match(%r[.*/views/(.*?)/])
30
+ return md[1] if md
31
+ nil
32
+ end
6
33
 
7
34
  def quote
8
35
  _passthru "<blockquote>"
@@ -67,28 +94,27 @@ end
67
94
 
68
95
  ### copy_asset
69
96
 
70
- def copy_asset(asset)
71
- vdir = @blog.view.dir
72
- return if File.exist?(vdir + "/assets/" + asset)
73
- top = vdir + "/../../assets/"
74
- if File.exist?(top + asset)
75
- system("cp #{top}/#{asset} #{vdir}/assets/#{asset}")
76
- return
77
- end
78
- raise "Can't find #{asset.inspect}"
79
- end
97
+ # def copy_asset(asset)
98
+ # vdir = @blog.view.dir
99
+ # return if File.exist?(vdir + "/assets/" + asset)
100
+ # top = vdir + "/../../assets/"
101
+ # if File.exist?(top + asset)
102
+ # system("cp #{top}/#{asset} #{vdir}/assets/#{asset}")
103
+ # return
104
+ # end
105
+ # raise "Can't find #{asset.inspect}"
106
+ # end
80
107
 
81
108
  #############
82
109
 
83
110
  def init_liveblog # FIXME - a lot of this logic sucks
84
- @blog, num, @live = Livetext.parameters # live is Livetext instance
85
- @live ||= Livetext.new(nil)
86
- @meta = OpenStruct.new
87
- @meta.num = num
88
- @root = @blog.root rescue nil
89
- @view = @blog.view.name rescue nil
90
- @vdir = @blog.view.dir rescue nil
91
- # @body = ""
111
+ @blog = $_blog = RuneBlog.new(false)
112
+ @root = @blog.root
113
+ @view = @blog.view
114
+ @view_name = @blog.view.name
115
+ @vdir = @blog.view.dir
116
+ @version = RuneBlog::VERSION
117
+ @theme = @vdir + "/themes/standard/"
92
118
  end
93
119
 
94
120
  def _errout(*args)
@@ -109,14 +135,19 @@ def _passthru_noline(line)
109
135
  _out "<p>" if line.empty? && ! @_nopara
110
136
  end
111
137
 
112
- def title
138
+ def title # side-effect
139
+ raise "'post' was not called" unless @meta
113
140
  title = @_data.chomp
114
141
  @meta.title = title
115
- _out "<h1>#{title}</h1>"
142
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
143
+ # @live.setvar :title, title
144
+ setvar :title, title
145
+ _out %[<h1 class="post-title">#{title}</h1><br>]
116
146
  _optional_blank_line
117
147
  end
118
148
 
119
- def pubdate
149
+ def pubdate # side-effect
150
+ raise "'post' was not called" unless @meta
120
151
  _debug "data = #@_data"
121
152
  # Check for discrepancy?
122
153
  match = /(\d{4}).(\d{2}).(\d{2})/.match @_data
@@ -124,6 +155,7 @@ def pubdate
124
155
  y, m, d = y.to_i, m.to_i, d.to_i
125
156
  @meta.date = ::Date.new(y, m, d)
126
157
  @meta.pubdate = "%04d-%02d-%02d" % [y, m, d]
158
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
127
159
  _optional_blank_line
128
160
  end
129
161
 
@@ -135,22 +167,28 @@ def image # primitive so far
135
167
  _optional_blank_line
136
168
  end
137
169
 
138
- def tags
170
+ def tags # side-effect
171
+ raise "'post' was not called" unless @meta
139
172
  _debug "args = #{_args}"
140
173
  @meta.tags = _args.dup || []
174
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
141
175
  _optional_blank_line
142
176
  end
143
177
 
144
- def views
178
+ def views # side-effect
179
+ raise "'post' was not called" unless @meta
145
180
  _debug "data = #{_args}"
146
181
  @meta.views = _args.dup # + ["main"]
182
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
147
183
  _optional_blank_line
148
184
  end
149
185
 
150
- def pin
186
+ def pin # side-effect
187
+ raise "'post' was not called" unless @meta
151
188
  _debug "data = #{_args}"
152
189
  # verify only already-specified views?
153
190
  @meta.pinned = _args.dup
191
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
154
192
  _optional_blank_line
155
193
  end
156
194
 
@@ -166,7 +204,7 @@ end
166
204
 
167
205
  def list!
168
206
  _out "<ul>"
169
- lines = _body.each # {|line| @body << "<li>#{line}</li>" }
207
+ lines = _body.each
170
208
  loop do
171
209
  line = lines.next
172
210
  line = _format(line)
@@ -181,7 +219,9 @@ def list!
181
219
  end
182
220
 
183
221
  def asset
222
+ raise "'post' was not called" unless @meta
184
223
  @meta.assets ||= {}
224
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
185
225
  list = _args
186
226
  # For now: copies, doesn't keep record
187
227
  # Later: Add to file and uniq; use in publishing
@@ -190,27 +230,35 @@ def asset
190
230
  end
191
231
 
192
232
  def assets
233
+ raise "'post' was not called" unless @meta
193
234
  @meta.assets ||= []
194
235
  @meta.assets += _body
236
+ # STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
195
237
  _optional_blank_line
196
238
  end
197
239
 
198
- def write_post(meta)
240
+ def write_post # side-effect
241
+ raise "'post' was not called" unless @meta
242
+ # return
199
243
  save = Dir.pwd
200
244
  @postdir.gsub!(/\/\//, "/") # FIXME unneeded?
201
245
  Dir.mkdir(@postdir) unless Dir.exist?(@postdir) # FIXME remember assets!
202
246
  Dir.chdir(@postdir)
203
- meta.views = meta.views.join(" ")
204
- meta.tags = meta.tags.join(" ") rescue ""
205
- File.write("body.txt", @live.body) # Actually HTML...
206
- File.write("teaser.txt", meta.teaser)
247
+ STDERR.puts "------ cd into #@postdir"
248
+ @meta.views = @meta.views.join(" ")
249
+ @meta.tags = @meta.tags.join(" ") rescue ""
250
+ # STDERR.puts ">>>> #{__method__}: writing #{@live.body.size} bytes to #{Dir.pwd}/body.txt"
251
+ # File.write("body.txt", @live.body) # Actually HTML...
252
+ # p Dir.pwd
253
+ File.write("teaser.txt", @meta.teaser)
207
254
 
208
255
  fields = [:num, :title, :date, :pubdate, :views, :tags]
209
256
 
210
257
  fname2 = "metadata.txt"
211
258
  f2 = File.open(fname2, "w") do |f2|
212
- fields.each {|fld| f2.puts "#{fld}: #{meta.send(fld)}" }
259
+ fields.each {|fld| f2.puts "#{fld}: #{@meta.send(fld)}" }
213
260
  end
261
+ STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
214
262
  Dir.chdir(save)
215
263
  rescue => err
216
264
  puts "err = #{err}"
@@ -218,20 +266,29 @@ rescue => err
218
266
  end
219
267
 
220
268
  def teaser
221
- # STDERR.puts "--- teaser: pwd = #{Dir.pwd}"
269
+ raise "'post' was not called" unless @meta
222
270
  @meta.teaser = _body_text
271
+ STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
223
272
  _out @meta.teaser + "\n"
273
+ STDERR.puts "TEASER cwd = #{Dir.pwd}"
274
+ # file = @vdir + "/teaser.txt"
275
+ # File.write(file, @meta.teaser)
224
276
  # FIXME
225
277
  end
226
278
 
227
279
  def finalize
280
+ unless @meta
281
+ puts @live.body
282
+ return
283
+ end
228
284
  if @blog.nil?
229
- puts @live.body if @emit
230
- return @live.body
285
+ return @meta # @live.body
231
286
  end
287
+
232
288
  @slug = @blog.make_slug(@meta)
233
- @postdir = @blog.view.dir + "/#@slug"
234
- write_post(@meta) # FIXME
289
+ slug_dir = @slug
290
+ @postdir = @blog.view.dir + "/posts/#{slug_dir}"
291
+ write_post
235
292
  @meta
236
293
  end
237
294
 
@@ -264,3 +321,364 @@ class Livetext::Functions
264
321
  end
265
322
 
266
323
  end
324
+
325
+ ###### experimental...
326
+
327
+ class Livetext::Functions
328
+
329
+ def _var(name)
330
+ ::Livetext::Vars[name] || "[:#{name} is undefined]"
331
+ end
332
+
333
+
334
+ def link
335
+ file, cdata = self.class.param.split("||", 2)
336
+ %[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}#{file}" title="#{_var(:title)}">]
337
+ end
338
+
339
+ end
340
+
341
+ ###############
342
+
343
+
344
+ def _var(name) # FIXME later
345
+ ::Livetext::Vars[name] || "[:#{name} is undefined]"
346
+ end
347
+
348
+ def head
349
+ # Depends on vars: title, desc, host
350
+ defaults = {}
351
+ defaults = { "charset" => %[<meta charset="utf-8">],
352
+ "http-equiv" => %[<meta http-equiv="X-UA-Compatible" content="IE=edge">],
353
+ "title" => %[<title>\n #{_var(:title)} | #{_var(:desc)}\n </title>],
354
+ "generator" => %[<meta name="generator" content="Runeblog v #@version">],
355
+ "og:title" => %[<meta property="og:title" content="#{_var(:title)}">],
356
+ "og:locale" => %[<meta property="og:locale" content="en_US">],
357
+ "description" => %[<meta name="description" content="#{_var(:desc)}">],
358
+ "og:description" => %[<meta property="og:description" content="#{_var(:desc)}">],
359
+ "linkc" => %[<link rel="canonical" href="#{_var(:host)}">],
360
+ "og:url" => %[<meta property="og:url" content="#{_var(:host)}">],
361
+ "og:site_name" => %[<meta property="og:site_name" content="#{_var(:title)}">],
362
+ "style" => %[<link rel="stylesheet" href="../assets/application.css">],
363
+ "feed" => %[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}/feed.xml" title="#{_var(:title)}">],
364
+ "favicon" => %[<link rel="shortcut icon" type="image/x-icon" href="../assets/favicon.ico">\n <link rel="apple-touch-icon" href="../assets/favicon.ico">]
365
+ }
366
+ result = {}
367
+ lines = _body
368
+ lines.each do |line|
369
+ line.chomp
370
+ word, remain = line.split(" ", 2)
371
+ case word
372
+ when "viewport"
373
+ result["viewport"] = %[<meta name="viewport" content="#{remain}">]
374
+ when "script"
375
+ file = remain
376
+ text = File.read(file)
377
+ result["script"] = Livetext.new.transform(text)
378
+ when "style"
379
+ result["style"] = %[<link rel="stylesheet" href="('/assets/#{remain}')">]
380
+ # Later: allow other overrides
381
+ when ""; break
382
+ else
383
+ puts "Unknown tag '#{word}'"
384
+ end
385
+ end
386
+ hash = defaults.dup.update(result) # FIXME collisions?
387
+ _out "<html lang=en_US>"
388
+ _out "<head>"
389
+ hash.each_value {|x| _out " " + x }
390
+ _out "</head>"
391
+ _out "<body>"
392
+ end
393
+
394
+ ########## newer stuff...
395
+
396
+ def meta
397
+ args = _args
398
+ enum = args.each
399
+ str = "<meta"
400
+ arg = enum.next
401
+ loop do
402
+ if arg.end_with?(":")
403
+ str << " " << arg[0..-2] << "="
404
+ a2 = enum.next
405
+ str << %["#{a2}"]
406
+ else
407
+ STDERR.puts "=== meta error?"
408
+ end
409
+ arg = enum.next
410
+ end
411
+ str << ">"
412
+ _out str
413
+ end
414
+
415
+ def main # side-effect
416
+ _out %[<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12">]
417
+ which = _args[0]
418
+ STDERR.puts "--- inside #main: which = #{which.inspect}"
419
+ case which
420
+ when "recent_posts"
421
+ all_teasers # FIXME does nothing yet
422
+ when "post"
423
+ self.data = "post-index.lt3"
424
+ _include
425
+ end
426
+ _out %[</div>]
427
+ end
428
+
429
+ def sidebar
430
+ _out %[<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">]
431
+ _body do |line|
432
+ tag = line.chomp.strip
433
+ self.data = "sidebar/#{tag.downcase}.lt3"
434
+ _include
435
+ end
436
+ _out %[</div>]
437
+ end
438
+
439
+ def sidebar2
440
+ _out %[<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">]
441
+ _args do |line|
442
+ tag = line.chomp.strip
443
+ self.data = "sidebar/#{tag.downcase}.lt3"
444
+ _include
445
+ end
446
+ _out %[</div>]
447
+ end
448
+
449
+ def stylesheet
450
+ lines = _body
451
+ url = lines[0]
452
+ integ = lines[1]
453
+ cross = lines[2] || "anonymous"
454
+ _out %[<link rel="stylesheet" href="#{url}" integrity="#{integ}" crossorigin="#{cross}"></link>]
455
+ end
456
+
457
+ def script
458
+ lines = _body
459
+ url = lines[0]
460
+ integ = lines[1]
461
+ cross = lines[2] || "anonymous"
462
+ _out %[<script src="#{url}" integrity="#{integ}" crossorigin="#{cross}"></script>]
463
+ end
464
+
465
+ ### How this next bit works:
466
+ ###
467
+ ### all_teasers will call _find_recent_posts
468
+ ###
469
+ ### _find_recent_posts will search higher in the directory structure
470
+ ### for where the posts are (0001, 0002, ...) NOTE: This implies you
471
+ ### must be in some specific place when this code is run.
472
+ ### It returns the 20 most recent posts.
473
+ ###
474
+ ### all_teasers will then pick a small number of posts and call _teaser
475
+
476
+ ### on each one. (The code in _teaser really belongs in a small template
477
+ ### somewhere.)
478
+ ###
479
+
480
+ def _find_recent_posts
481
+ STDERR.puts "--- frp: $FileDir = #{_var(:FileDir)}"
482
+ @vdir = _var(:FileDir).match(%r[(^.*/views/.*?)/])[1]
483
+ posts = nil
484
+ dir_posts = @vdir + "/posts"
485
+ entries = Dir.entries(dir_posts)
486
+ STDERR.puts "--- frp: dir_posts = #{dir_posts} ent = #{entries.inspect}"
487
+ posts = entries.grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
488
+ posts.select! {|x| File.directory?(x) }
489
+ # directories that start with four digits
490
+ posts = posts.sort {|a, b| b.to_i <=> a.to_i } # sort descending
491
+ posts[0..19] # return 20 at most
492
+ end
493
+
494
+ def all_teasers
495
+ STDERR.puts "-- inside #all_teasers..."
496
+ open = <<-HTML
497
+ <section class="posts">
498
+ HTML
499
+ close = <<-HTML
500
+ </section>
501
+ HTML
502
+ STDERR.puts "=== at01"
503
+ _out open
504
+ # FIXME: Now do the magic...
505
+ STDERR.puts "=== at02"
506
+ posts = _find_recent_posts
507
+ STDERR.puts "=== at03"
508
+ wanted = [5, posts.size].min # estimate how many we want?
509
+ STDERR.puts "=== at04"
510
+ enum = posts.each
511
+ STDERR.puts "=== at05"
512
+ wanted.times do
513
+ STDERR.puts "=== at06 (loop)"
514
+ postid = File.basename(enum.next)
515
+ STDERR.puts "=== at07"
516
+ postid = postid.to_i
517
+ STDERR.puts "=== at08"
518
+ _teaser(postid)
519
+ STDERR.puts "=== at09"
520
+ end
521
+ _out close
522
+ end
523
+
524
+ def _post_lookup(postid) # side-effect
525
+ # .. = templates, ../.. = views/thisview
526
+ slug = title = date = teaser_text = nil
527
+
528
+ dir_posts = @vdir + "/posts"
529
+ posts = Dir.entries(dir_posts).grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
530
+ posts.select! {|x| File.directory?(x) }
531
+
532
+ post = posts.select {|x| File.basename(x).to_i == postid }
533
+ raise "Error: More than one post #{postid}" if post.size > 1
534
+ postdir = post.first
535
+ fname = "#{postdir}/teaser.txt"
536
+ teaser_text = File.read(fname).chomp
537
+ # FIXME dumb hacks...
538
+ mdfile = "#{postdir}/metadata.txt"
539
+ lines = File.readlines(mdfile)
540
+ title = lines.grep(/title:/).first[7..-1].chomp
541
+ date = lines.grep(/pubdate:/).first[9..-1].chomp
542
+ slug = postdir
543
+ [slug, title, date, teaser_text]
544
+ end
545
+
546
+ def _interpolate(str, context) # FIXME move this later
547
+ wrapped = "%[" + str.dup + "]" # could fail...
548
+ eval(wrapped, context)
549
+ end
550
+
551
+ def _teaser(slug)
552
+ id = slug.to_i
553
+ text = nil
554
+ post_entry_name = @theme + "blog-_postentry.lt3"
555
+ @_post_entry ||= File.read(post_entry_name)
556
+ slug = title = date = teaser_text = nil
557
+ slug, title, date, teaser_text = _post_lookup(id)
558
+ # vdir = File.expand_path("../../..")
559
+ url = "#@vdir/#{slug}.html"
560
+ date = Date.parse(date)
561
+ date = date.strftime("%B %e<br>%Y")
562
+ text = _interpolate(@_post_entry, binding)
563
+ # File.write("../../../generated/#{slug}.html", text)
564
+ _out text
565
+ end
566
+
567
+ def card_iframe
568
+ title = _data
569
+ lines = _body
570
+ url = lines[0].chomp
571
+ stuff = lines[1..-1].join(" ") # FIXME later
572
+ text = <<-HTML
573
+ <div class="card mb-3">
574
+ <div class="card-body">
575
+ <h5 class="card-title">#{title}</h5>
576
+ <iframe src="#{url}" #{stuff}
577
+ style="border: 0" height="350"
578
+ frameborder="0" scrolling="no">
579
+ </iframe>
580
+ </div>
581
+ </div>
582
+ HTML
583
+ _out text
584
+ rescue
585
+ puts @live.body
586
+ end
587
+
588
+ def card1
589
+ card_title = _data
590
+ lines = _body
591
+ lines.map!(&:chomp)
592
+ card_text = lines[0]
593
+ url, target, classname, cdata = lines[1].split(",", 4)
594
+ text = <<-HTML
595
+ <div class="card bg-dark text-white mb-3">
596
+ <div class="card-body">
597
+ <h5 class="card-title">#{card_title}</h5>
598
+ <p class="card-text">#{card_text}</p>
599
+ <a href="#{url}" target="#{target}" class="#{classname}">#{cdata}</a>
600
+ </div>
601
+ </div>
602
+ HTML
603
+ _out text + "\n "
604
+ rescue
605
+ puts @live.body
606
+ end
607
+
608
+ def card2
609
+ card_title = _data
610
+ open = <<-HTML
611
+ <div class="card mb-3">
612
+ <div class="card-body">
613
+ <h5 class="card-title">#{card_title}</h5>
614
+ </div>
615
+ <ul class="list-group list-group-flush">
616
+ HTML
617
+ _out open
618
+ _body do |line|
619
+ url, target, cdata = line.chomp.split(",", 3)
620
+ _out %[<li class="list-group-item"><a href="#{url}" target="#{target}">#{cdata}</a> </li>]
621
+ end
622
+ close = %[ </ul>\n </div>]
623
+ _out close
624
+ rescue
625
+ puts @live.body
626
+ end
627
+
628
+ def tag_cloud
629
+ title = _data
630
+ title = "Tag Cloud" if title.empty?
631
+ open = <<-HTML
632
+ <div class="card mb-3">
633
+ <div class="card-body">
634
+ <h5 class="card-title">#{title}</h5>
635
+ HTML
636
+ _out open
637
+ _body do |line|
638
+ line.chomp!
639
+ url, target, classname, cdata = line.split(",", 4)
640
+ _out %[<a href="#{url}" target="#{target}" class="#{classname}">#{cdata}</a>]
641
+ end
642
+ rescue
643
+ puts @live.body
644
+ end
645
+
646
+ def navbar
647
+ title = _var(:title)
648
+ open = <<-HTML
649
+ <nav class="navbar navbar-expand-lg navbar-light bg-light">
650
+ <a class="navbar-brand" href="index.html">#{title}</a>
651
+ <button class="navbar-toggler"
652
+ type="button"
653
+ data-toggle="collapse"
654
+ data-target="#navbarSupportedContent"
655
+ aria-controls="navbarSupportedContent"
656
+ aria-expanded="false"
657
+ aria-label="Toggle navigation">
658
+ <span class="navbar-toggler-icon"></span>
659
+ </button>
660
+
661
+ <div class="collapse navbar-collapse pull-right"
662
+ id="navbarSupportedContent">
663
+ <ul class="navbar-nav mr-auto">
664
+ HTML
665
+ close = <<-HTML
666
+ </ul>
667
+ </div>
668
+ </nav>
669
+ HTML
670
+
671
+ first = true
672
+ _out open
673
+ _body do |line|
674
+ href, cdata = line.chomp.strip.split(" ", 2)
675
+ if first
676
+ first = false
677
+ _out %[<li class="nav-item active"> <a class="nav-link" href="#{href}">#{cdata}<span class="sr-only">(current)</span></a> </li>]
678
+ else
679
+ _out %[<li class="nav-item"> <a class="nav-link" href="#{href}">#{cdata}</a> </li>]
680
+ end
681
+ end
682
+ _out close
683
+ end
684
+