require 'ostruct' require 'pp' require 'date' require 'find' require 'runeblog' require 'pathmagic' require 'xlate' def init_liveblog # FIXME - a lot of this logic sucks here = Dir.pwd dir = here loop { dir = Dir.pwd; break if File.exist?("config"); Dir.chdir("..") } Dir.chdir(here) # here??? or dir?? @blog = RuneBlog.new(dir) @root = @blog.root @view = @blog.view @view_name = @blog.view.name unless @view.nil? @vdir = @blog.view.dir rescue "NONAME" @version = RuneBlog::VERSION @theme = @vdir/:themes/:standard end ################## # "dot" commands ################## def dropcap # Bad form: adds another HEAD text = _data _out " " letter = text[0] remain = text[1..-1] _out %[
#{letter}
] _out %[
#{remain}] end def post @meta = OpenStruct.new @meta.num = _args[0] _out " \n " end def post_trailer perma = _var("publish.proto") + "://" + _var("publish.server") + "/" + _var("publish.path") + "/permalink/" + _var("post.aslug") + ".html" tags = _var("post.tags") if tags.empty? taglist = "" else taglist = "Tags: #{tags}" end _out <<~HTML
[Back] [permalink] #{taglist}
HTML # damned syntax highlighting end def faq @faq_count ||= 0 _out "
" if @faq_count == 0 @faq_count += 1 ques = _data.chomp ans = _body_text id = "faq#@faq_count" _out %[ ] _out %[ #{ques}] _out %[

      #{ans}
\n] _out "
" unless @faq_count == 1 _optional_blank_line end def backlink _out %[
[Back]] end def _read_navbar_data dir = @blog.root/:views/@blog.view/"themes/standard/banner/" datafile = dir/"list.data" File.readlines(datafile) end def banner # still experimental enum = _args.each count = 0 span = 1 first = enum.peek if first.start_with?("bgcolor:") enum.next bg = enum.next else bg = nil # bg = white - do nothing end str = "" : ">") _out str _out " " loop do count += 1 arg = enum.next case arg when "image" image = "banner/banner.jpg" _out " " + " " when "image:" image = "banner/#{enum.next}" _out " " + " " when "text" file = "banner/top.html" _out "" + " " when "text:" file = "banner/#{enum.next}" _out "" + " " when "navbar" dir = @blog.root/:views/@blog.view/"themes/standard/banner/" _make_navbar # horiz is default stuff = File.read("banner/navbar.html") _out "" + " " when "vnavbar" dir = @blog.root/:views/@blog.view/"themes/standard/banner/" _make_navbar(:vert) file = "banner/vnavbar.html" _out "" + "" when "//" span = count - 1 _out " \n " + "" else _out " '#{arg}' isn't known" end end _out " " _out "
" + File.read(file) + "" + File.read(file) + "
#{stuff}
" + File.read(file) + "
" rescue => err STDERR.puts "err = #{err}" STDERR.puts err.backtrace.join("\n") gets end def quote _passthru "
" _passthru _body.join(" ") _passthru "
" _optional_blank_line end def categories # does nothing right now end def style fname = _args[0] _passthru %[] end # Move elsewhere later! def h1; _passthru "

#{@_data}

"; end def h2; _passthru "

#{@_data}

"; end def h3; _passthru "

#{@_data}

"; end def h4; _passthru "

#{@_data}

"; end def h5; _passthru "
#{@_data}
"; end def h6; _passthru "
#{@_data}
"; end def hr; _passthru "
"; end def list _out "" _optional_blank_line end def list! _out "" _optional_blank_line end ### inset def inset lines = _body box = "" output = [] lines.each do |line| line = line case line[0] when "/" # Only into inset line[0] = ' ' box << line line.replace(" ") when "|" # Into inset and body line[0] = ' ' box << line output << line else # Only into body output << line end end lr = _args.first wide = _args[1] || "25" stuff = "
" stuff << '' + box + '
' _out "

" # kludge!! nopara 0.upto(2) {|i| _passthru output[i] } _passthru stuff 3.upto(output.length-1) {|i| _passthru output[i] } _out "

" # kludge!! para _optional_blank_line end def title raise "'post' was not called" unless @meta title = @_data.chomp @meta.title = title setvar :title, title # FIXME refactor -- just output variables for a template _optional_blank_line end def pubdate 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 _debug "img: huh? " fname = _args.first path = :assets/fname _out "" _optional_blank_line end def tags raise "'post' was not called" unless @meta _debug "args = #{_args}" @meta.tags = _args.dup || [] _optional_blank_line end def views raise "'post' was not called" unless @meta _debug "data = #{_args}" @meta.views = _args.dup _optional_blank_line end def pin raise "'post' was not called" unless @meta _debug "data = #{_args}" # verify only valid views? pinned = @_args @meta.pinned = pinned pinned.each do |pinview| dir = @blog.root/:views/pinview/"themes/standard/widgets/pinned/" datafile = dir/"list.data" if File.exist?(datafile) pins = File.readlines(datafile) else pins = [] end pins << "#{@meta.num} #{@meta.title}\n" pins.uniq! File.open(datafile, "w") do |outfile| pins.each {|pin| outfile.puts pin } end end _optional_blank_line pinned_rebuild # FIXME experimental rescue => err STDERR.puts "err = #{err}" STDERR.puts err.backtrace.join("\n") gets end def write_post raise "'post' was not called" unless @meta @meta.views = @meta.views.join(" ") if @meta.views.is_a? Array @meta.tags = @meta.tags.join(" ") if @meta.tags.is_a? Array _write_metadata rescue => err puts "err = #{err}" puts err.backtrace.join("\n") end def teaser raise "'post' was not called" unless @meta text = _body_text @meta.teaser = text setvar :teaser, @meta.teaser if _args[0] == "dropcap" # FIXME doesn't work yet! letter, remain = text[0], text[1..-1] _out %[

#{letter}
] _out %[
#{remain}] + "\n" else _out @meta.teaser + "\n" end end def finalize return unless @meta return @meta if @blog.nil? @slug = @blog.make_slug(@meta) slug_dir = @slug @postdir = @blog.view.dir/:posts/slug_dir write_post @meta end def head # Does NOT output tags 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 if defaults[word] result[word] = %[] else puts "Unknown tag '#{word}'" end end end hash = defaults.dup.update(result) # FIXME collisions? hash.each_value {|x| _out " " + x } end ########## newer stuff... def meta args = _args enum = args.each str = "" _out str end def recent_posts # side-effect _out <<-HTML
HTML end def _make_class_name(app) if app =~ /[-_]/ words = app.split(/[-_]/) name = words.map(&:capitalize).join else name = app.capitalize end return name end def _load_local(widget) Dir.chdir("widgets/#{widget}") do rclass = _make_class_name(widget) found = (require("./#{widget}") if File.exist?("#{widget}.rb")) code = found ? ::RuneBlog::Widget.class_eval(rclass) : nil code end rescue => err STDERR.puts err.to_s STDERR.puts err.backtrace.join("\n") exit end def pinned_rebuild view = @blog.view view = _args[0] unless _args.empty? Dir.chdir(@blog.root/:views/view/"themes/standard/") do wtag = "widgets/pinned" code = _load_local("pinned") if code Dir.chdir(wtag) do widget = code.new(@blog) widget.build end # _include_file wtag/"pinned-card.html" end end end def _handle_standard_widget(tag) wtag = :widgets/tag code = _load_local(tag) if code Dir.chdir(wtag) do widget = code.new(@blog) widget.build end end end def sidebar _debug "--- handling sidebar\r" if _args.include? "off" _body { } # iterate, do nothing return end _out %[
] standard = %w[pinned pages links news] _body do |token| tag = token.chomp.strip.downcase wtag = :widgets/tag raise "Can't find #{wtag}" unless Dir.exist?(wtag) tcard = "#{tag}-card.html" case when standard.include?(tag) _handle_standard_widget(tag) when tag == "ad" num = rand(1..4) img = "widgets/ad/ad#{num}.png" src, dst = img, @root/:views/@view_name/"remote/widgets/ad/" system!("cp #{src} #{dst}") # , show: true) File.open(wtag/"vars.lt3", "w") do |f| f.puts ".set ad.image = #{img}" end xlate cwd: wtag, src: tag, dst: tcard, force: true # , deps: depend # , debug: true end _include_file wtag/tcard # depend = %w[card.css main.css custom.rb local.rb] # depend += ["#{wtag}.lt3", "#{wtag}.rb"] # depend.map! {|x| @blog.view.dir/"themes/standard/widgets"/wtag/x } # _debug "--- call xlate #{tag} src = #{tag} dst = #{tcard}\r" end _out %[
] rescue => err puts "err = #{err}" puts err.backtrace.join("\n") exit end def stylesheet lines = _body url = lines[0] integ = lines[1] cross = lines[2] || "anonymous" _out %[] end def script lines = _body url = lines[0] integ = lines[1] cross = lines[2] || "anonymous" _out %[] 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 end ### def tag_cloud title = _data title = "Tag Cloud" if title.empty? open = <<-HTML
#{title}
HTML _out open _body do |line| line.chomp! url, classname, cdata = line.split(",", 3) main = _main(url) _out %[#{cdata}] end close = %[
\n
\n
] _out close end def vnavbar str = _make_navbar(:vert) end def hnavbar str = _make_navbar # horiz is default end def navbar str = _make_navbar # horiz is default end def _make_navbar(orient = :horiz) vdir = @blog.view.dir title = _var(:blog) extra = "" extra = "navbar-expand-lg" if orient == :horiz start = <<-HTML HTML name = (orient == :horiz) ? "navbar.html" : "vnavbar.html" html_file = @blog.root/:views/@blog.view/"themes/standard/banner"/name output = File.new(html_file, "w") output.puts start lines = _read_navbar_data lines = ["index Home"] + lines unless _args.include?("nohome") lines.each do |line| basename, cdata = line.chomp.strip.split(" ", 2) full = :banner/basename+".html" href_main = _main(full) if basename == "index" # special case output.puts %[] else dir = @blog.root/:views/@blog.view/"themes/standard/banner" xlate cwd: dir, src: basename, dst: vdir/"remote/banner"/basename+".html" # , debug: true output.puts %[] end end output.puts finish output.close return File.read(html_file) end ################## # helper methods ################## def _html_body(file, css = nil) file.puts "" if css file.puts " " file.puts " " file.puts " " end file.puts " " yield file.puts " \n" end def _errout(*args) ::STDERR.puts *args end def _passthru(line) return if line.nil? line = _format(line) _out line + "\n" _out "

" if line.empty? && ! @_nopara end def _passthru_noline(line) return if line.nil? line = _format(line) _out line _out "

" if line.empty? && ! @_nopara end def _write_metadata File.write("teaser.txt", @meta.teaser) fields = [:num, :title, :date, :pubdate, :views, :tags, :pinned] fname2 = "metadata.txt" f2 = File.open(fname2, "w") do |f2| fields.each {|fld| f2.puts "#{fld}: #{@meta.send(fld)}" } end end def _post_lookup(postid) # side-effect # .. = 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 wrapped = "%[" + str.dup + "]" # could fail... eval(wrapped, context) end def _card_generic(card_title:, middle:, extra: "") front = <<-HTML

#{card_title}
HTML tail = <<-HTML
HTML text = front + middle + tail _out text + "\n " end def _var(name) # FIXME scope issue! ::Livetext::Vars[name] || "[:#{name} is undefined]" end def _main(url) %[href="javascript: void(0)" onclick="javascript:open_main('#{url}')"] end def _blank(url) %[href='#{url}' target='blank'] end