EOS
end
def _write_main(mainfile, pairs, card_title)
# HTML for main area (iframe)
log(str: "Creating #{mainfile}.html", pwd: true)
File.open("#{mainfile}.html", "w") do |f|
_html_body(f) do
f.puts "
#{card_title}
"
pairs.each do |file, title|
f.puts %[#{title} ]
end
end
end
end
def make_main_links
log(enter: __method__)
# FIXME remember strings may not be safe
line = _data.chomp
tag, card_title = *line.split(" ", 2)
cardfile, mainfile = "card-#{tag}", "main-#{tag}"
input = "list.data"
log(str: "Reading #{input}", pwd: true)
pairs = File.readlines(input).map {|line| line.chomp.split(",", 2) }
_write_main(mainfile, pairs, card_title)
widget_relative = (tag != "news") # FIXME kludge!!!
_write_card(cardfile, mainfile, pairs, card_title, tag, relative: widget_relative)
end
log(str: "...returning from method", pwd: true)
end
### inset
def inset
log(enter: __method__)
lines = _body
box = ""
lines.each do |line|
line = line.dup
if line[0] == "/" # Only into inset
line[0] = ' '
box << line.dup + " "
line.replace(" ")
end
if line[0] == "|" # Into inset and body
line[0] = ' '
box << line.dup + " "
end
_passthru(line)
end
lr = _args.first
wide = _args[1] || "25"
_passthru "
"
_passthru ''
_passthru box
_passthru_noline '
'
_optional_blank_line
end
def _errout(*args)
log(str: args.join(" "), enter: __method__)
::STDERR.puts *args
end
def _passthru(line)
log(enter: __method__, args: [line])
return if line.nil?
line = _format(line)
_out line + "\n"
_out "
" if line.empty? && ! @_nopara
end
def _passthru_noline(line)
log(enter: __method__, args: [line])
return if line.nil?
line = _format(line)
_out line
_out "
" if line.empty? && ! @_nopara
end
def title
log(enter: __method__)
raise "'post' was not called" unless @meta
title = @_data.chomp
@meta.title = title
setvar :title, title
_out %[
#{title}
]
_optional_blank_line
end
def pubdate
log(enter: __method__)
raise "'post' was not called" unless @meta
_debug "data = #@_data"
# Check for discrepancy?
match = /(\d{4}).(\d{2}).(\d{2})/.match @_data
junk, y, m, d = match.to_a
y, m, d = y.to_i, m.to_i, d.to_i
@meta.date = ::Date.new(y, m, d)
@meta.pubdate = "%04d-%02d-%02d" % [y, m, d]
_optional_blank_line
end
def image # primitive so far
log(enter: __method__)
_debug "img: huh? "
fname = _args.first
path = "assets/#{fname}"
_out ""
_optional_blank_line
end
def tags
log(enter: __method__)
raise "'post' was not called" unless @meta
_debug "args = #{_args}"
@meta.tags = _args.dup || []
_optional_blank_line
end
def views
log(enter: __method__)
raise "'post' was not called" unless @meta
_debug "data = #{_args}"
@meta.views = _args.dup
_optional_blank_line
end
def pin
log(enter: __method__)
raise "'post' was not called" unless @meta
_debug "data = #{_args}"
# verify only already-specified views?
@meta.pinned = _args.dup
_optional_blank_line
end
def write_post
log(enter: __method__)
raise "'post' was not called" unless @meta
save = Dir.pwd
@postdir.gsub!(/\/\//, "/") # FIXME unneeded?
Dir.mkdir(@postdir) unless Dir.exist?(@postdir) # FIXME remember assets!
Dir.chdir(@postdir)
@meta.views = @meta.views.join(" ") if @meta.views.is_a? Array
@meta.tags = @meta.tags.join(" ") if @meta.tags.is_a? Array
File.write("teaser.txt", @meta.teaser)
fields = [:num, :title, :date, :pubdate, :views, :tags]
fname2 = "metadata.txt"
f2 = File.open(fname2, "w") do |f2|
fields.each {|fld| f2.puts "#{fld}: #{@meta.send(fld)}" }
end
Dir.chdir(save)
rescue => err
puts "err = #{err}"
puts err.backtrace.join("\n")
end
def teaser
log(enter: __method__)
raise "'post' was not called" unless @meta
@meta.teaser = _body_text
setvar :teaser, @meta.teaser
_out @meta.teaser + "\n"
# FIXME
end
def finalize
log(enter: __method__)
unless @meta
puts @live.body
return
end
if @blog.nil?
return @meta
end
@slug = @blog.make_slug(@meta)
slug_dir = @slug
@postdir = @blog.view.dir + "/posts/#{slug_dir}"
STDERR.puts "--- finalize: pwd = #{Dir.pwd} postdir = #@postdir"
write_post
@meta
end
$Dot = self # Clunky! for dot commands called from Functions class
# Find a better way to do this?
class Livetext::Functions
def br(n="1")
# Thought: Maybe make a way for functions to "simply" call the
# dot command of the same name?? Is this trivial??
n = n.empty? ? 1 : n.to_i
" "*n
end
def h1(param); "
#{param}
"; end
def h2(param); "
#{param}
"; end
def h3(param); "
#{param}
"; end
def h4(param); "
#{param}
"; end
def h5(param); "
#{param}
"; end
def h6(param); "
#{param}
"; end
def hr(param=nil)
$Dot.hr
end
def image(param)
""
end
end
###### experimental...
class Livetext::Functions
def _var(name)
::Livetext::Vars[name] || "[:#{name} is undefined]"
end
def link
file, cdata = self.class.param.split("||", 2)
%[]
end
end
###
def _var(name) # FIXME scope issue!
::Livetext::Vars[name] || "[:#{name} is undefined]"
end
def head # Does NOT output tags
log(enter: __method__)
args = _args
args.each do |inc|
self.data = inc
_include
end
# Depends on vars: title, desc, host
defaults = {}
defaults = { "charset" => %[],
"http-equiv" => %[],
"title" => %[\n #{_var(:blog)} | #{_var("blog.desc")}\n ],
"generator" => %[],
"og:title" => %[],
"og:locale" => %[],
"description" => %[],
"og:description" => %[],
"linkc" => %[],
"og:url" => %[],
"og:site_name" => %[],
"style" => %[],
"feed" => %[],
"favicon" => %[\n ]
}
result = {}
lines = _body
lines.each do |line|
line.chomp
word, remain = line.split(" ", 2)
case word
when "viewport"
result["viewport"] = %[]
when "script" # FIXME this is broken
file = remain
text = File.read(file)
result["script"] = Livetext.new.transform(text)
when "style"
result["style"] = %[]
# Later: allow other overrides
when ""; break
else
STDERR.puts "-- got '#{word}'; old value = #{result[word].inspect}"
if defaults[word]
result[word] = %[]
STDERR.puts "-- new value = #{result[word].inspect}"
else
puts "Unknown tag '#{word}'"
end
end
end
hash = defaults.dup.update(result) # FIXME collisions?
# _out " "
hash.each_value {|x| _out " " + x }
_out ""
end
########## newer stuff...
def meta
log(enter: __method__)
args = _args
enum = args.each
str = ""
_out str
end
def recent_posts # side-effect
log(enter: __method__)
_out %[
]
all_teasers
_out %[
]
end
def sidebar
log(enter: __method__)
_out %[
]
_args do |token|
tag = token.chomp.strip.downcase
# FIXME will someone please refactor this horrible code??
# Think of the children!!
mode = tag[0]
tag = tag[1..-1] if mode == "." || mode == ":"
Dir.chdir("widgets/#{tag}") do
name = tag + ".lt3"
case mode
when "." # Only in sidebar, special code
log(str: "DOT About to do: livetext #{name} in #{Dir.pwd}", dir: true)
livetext tag + ".lt3", "card-#{tag}"
log(str: "DOT after livetext call", pwd: true, dir: true)
when ":" # Card AND main, but still special
log(str: "COL About to do: livetext #{name} in #{Dir.pwd}", dir: true)
livetext tag + ".lt3", "card-#{tag}"
system("card-#{tag}.html main-#{tag}.html") # FIXME HTML will be wrong??
log(str: "COL after livetext call", pwd: true, dir: true)
else
log(str: "NRM About to do: livetext #{name} in #{Dir.pwd}", dir: true)
log(str: "livetext #{tag}.lt3 card-#{tag}")
livetext tag + ".lt3", "card-#{tag}"
log(str: "NRM after livetext call", pwd: true, dir: true)
end
_include_file "card-#{tag}.html"
end
end
_out %[
]
end
def stylesheet
log(enter: __method__)
lines = _body
url = lines[0]
integ = lines[1]
cross = lines[2] || "anonymous"
_out %[]
end
def script
log(enter: __method__)
lines = _body
url = lines[0]
integ = lines[1]
cross = lines[2] || "anonymous"
_out %[]
end
### How this next bit works:
###
### all_teasers will call _find_recent_posts
###
### _find_recent_posts will search higher in the directory structure
### for where the posts are (0001, 0002, ...) NOTE: This implies you
### must be in some specific place when this code is run.
### It returns the 20 most recent posts.
###
### all_teasers will then pick a small number of posts and call _teaser
### on each one. (The code in _teaser really belongs in a small template
### somewhere.)
###
def _find_recent_posts
log(enter: __method__)
@vdir = _var(:FileDir).match(%r[(^.*/views/.*?)/])[1]
posts = nil
dir_posts = @vdir + "/posts"
entries = Dir.entries(dir_posts)
posts = entries.grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
posts.select! {|x| File.directory?(x) }
# directories that start with four digits
posts = posts.sort {|a, b| b.to_i <=> a.to_i } # sort descending
posts[0..19] # return 20 at most
end
def all_teasers
log(enter: __method__)
open = <<-HTML
HTML
close = <<-HTML
HTML
text = <<-HTML
HTML
posts = _find_recent_posts
wanted = [5, posts.size].min # estimate how many we want?
enum = posts.each
wanted.times do
postid = File.basename(enum.next)
postid = postid.to_i
text << _teaser(postid) # side effect! calls _out
end
text << ""
File.write("recent.html", text)
_out %[]
end
def _post_lookup(postid) # side-effect
log(enter: __method__, args: [postid])
# .. = templates, ../.. = views/thisview
slug = title = date = teaser_text = nil
dir_posts = @vdir + "/posts"
posts = Dir.entries(dir_posts).grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
posts.select! {|x| File.directory?(x) }
post = posts.select {|x| File.basename(x).to_i == postid }
raise "Error: More than one post #{postid}" if post.size > 1
postdir = post.first
vp = RuneBlog::ViewPost.new(@blog.view, postdir)
vp
end
def _interpolate(str, context) # FIXME move this later
log(str: "Duplicated method?", enter: __method__, args: [str, context])
wrapped = "%[" + str.dup + "]" # could fail...
eval(wrapped, context)
end
def _teaser(slug)
log(enter: __method__, args: [slug])
id = slug.to_i
text = nil
post_entry_name = @theme + "blog/post_entry.lt3"
@_post_entry ||= File.read(post_entry_name)
vp = _post_lookup(id)
nslug, aslug, title, date, teaser_text =
vp.nslug, vp.aslug, vp.title, vp.date, vp.teaser_text
path = vp.path
url = "#{path}/#{aslug}.html" # Should be relative to .blogs!! FIXME
date = Date.parse(date)
date = date.strftime("%B %e %Y")
text = _interpolate(@_post_entry, binding)
text
end
def _card_generic(card_title:, middle:, extra: "")
log(enter: __method__, args: [card_title, middle, extra])
front = <<-HTML
#{card_title}
HTML
tail = <<-HTML
HTML
text = front + middle + tail
_out text + "\n "
end
def card_iframe
log(enter: __method__)
title, lines = _data, _body
lines.map!(&:chomp)
url = lines[0].chomp
stuff = lines[1..-1].join(" ") # FIXME later
middle = <<-HTML
HTML
_card_generic(card_title: title, middle: middle, extra: "bg-dark text-white")
end
def _main(url)
log(enter: __method__, args: [url])
%[href="javascript: void(0)" onclick="javascript:open_main('#{url}')"]
end
def card1
log(enter: __method__)
title, lines = _data, _body
lines.map!(&:chomp)
card_text = lines[0]
url, classname, cdata = lines[1].split(",", 4)
main = _main(url)
middle = <<-HTML
#{card_text}
#{cdata}
HTML
_card_generic(card_title: title, middle: middle, extra: "bg-dark text-white")
end
def card2
log(enter: __method__)
str = _data
file, card_title = str.chomp.split(" ", 2)
card_title = %[#{card_title}]
# FIXME is this wrong??
open = <<-HTML
#{card_title}
HTML
_out open
_body do |line|
url, cdata = line.chomp.split(",", 3)
main = _main(url)
_out %[
]
_out close
end
def tag_cloud
log(enter: __method__)
title = _data
title = "Tag Cloud" if title.empty?
open = <<-HTML
#{title}
HTML
_out open
_body do |line|
line.chomp!
url, classname, cdata = line.split(",", 4)
main = _main(url)
_out %[#{cdata}]
end
close = %[
\n
]
_out close
end
def navbar
log(enter: __method__)
title = _var(:blog)
open = <<-HTML
HTML
first = true
_out open
_body do |line|
href, cdata = line.chomp.strip.split(" ", 2)
main = _main(href)
if first
first = false
_out %[