require 'ostruct' require 'pp' require 'date' require 'find' require 'runeblog' require 'pathmagic' require 'processing' # top = Livetext::Path + "/../plugin/liveblog/" # eval(File.read("#{top}/testing.rb")) def init_liveblog # FIXME - a lot of this logic sucks dir = Dir.pwd.sub(/\.blogs.*/, "") @blog = nil Dir.chdir(dir) { @blog = RuneBlog.new } @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 @reddit_comments = "" @reddit_enabled = @blog.features["reddit"] if @reddit_enabled @reddit_comments = <<~HTML Scroll to reddit comments HTML end rescue => err STDERR.puts "err = #{err}" STDERR.puts err.backtrace.join("\n") # raise "Only works inside a blog repo" 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 _got_python? # Dumb - fix later - check up front as needed # Should also check for praw lib str = `which python3` str.length > 0 end def _reddit_post_url(vdir, date, title, url) _got_python? tmpfile = "/tmp/reddit-post-url.txt" File.open(tmpfile, "w") do |tmp| tmp.puts "[#{date}] #{title}" tmp.puts url end rid = nil Dir.chdir(vdir/:config) { rid = `python3 reddit/reddit_post_url.py` } system("rm #{tmpfile}") rid # returns reddit id end def post_toolbar back_icon = %[Go back] back = %[#{back_icon}] _out <<~HTML
#{back} #@reddit_comments
HTML end def post_trailer perma = _var("publish.proto") + "://" + _var("publish.server") + "/" + _var("publish.path") + "/" + _var("post.aslug") + ".html" tags = _var("post.tags") taglist = tags.empty? ? "" : "Tags: #{tags}" reddit_txt = "" if @reddit_enabled vdir = @blog.root/:views/@blog.view nslug = "#{_var("post.num")}-#{_var("post.aslug")}" date = _var("post.date") rid_file = vdir/:posts/nslug/"reddit.id" rid = File.exist?(rid_file) ? File.read(rid_file).chomp : nil if rid.nil? title = _var("title") rid = _reddit_post_url(vdir, date, title, perma) dump(rid, rid_file) end reddit_txt = <<~HTML HTML # damned syntax highlighting end _out <<~HTML #{reddit_txt}
[Back] [permalink] #{taglist}
HTML end def faq @faq_count ||= 0 _out "
" if @faq_count == 0 @faq_count += 1 ques = _data.chomp ans = _body.join("\n") 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 code lines = _body # _text _out "
\n#{lines}\n
" end def _read_navbar_data vdir = @blog.root/:views/@blog.view dir = vdir/"themes/standard/banner/navbar/" datafile = dir/"list.data" _get_data(datafile) end def banner count = 0 bg = "white" # outside loop wide = nil high = 250 str2 = "" navbar = nil vdir = @blog.root/:views/@blog.view lines = _body.to_a lines.each do |line| count += 1 tag, *data = line.split data ||= [] case tag when "width"; wide = data[0] when "height"; high = data[0] when "bgcolor"; bg = data[0] || "white" when "image" image = data[0] || "banner.jpg" image = "banner"/image wide = data[0] width = wide ? "width=#{wide}" : "" str2 << " " + "\n" when "svg_title" stuff, hash = _svg_title(*data) wide = hash["width"] str2 << " #{stuff}" + "\n" when "text" data[0] ||= "top.html" file = "banner"/data[0] if ! File.exist?(file) src = file.sub(/html$/, "lt3") if File.exist?(src) preprocess src: src, dst: file, call: ".nopara" # , vars: @blog.view.globals else raise "Neither #{file} nor #{src} found" end end str2 << "" + File.read(file) + "" + "\n" when "navbar" navbar = _make_navbar # horiz is default when "vnavbar" navbar = _make_navbar(:vert) when "break" str2 << " \n " + "\n" else str2 << " '#{tag}' isn't known" + "\n" end end _out <<~HTML #{str2}
HTML _out navbar if navbar rescue => err STDERR.puts "err = #{err}" STDERR.puts err.backtrace.join("\n") gets end def _svg_title(*args) width = "95%" height = 90 bgcolor = "black" style = nil size = "" font = "sans-serif" color = "white" xy = "5,5" align = "center" style2 = nil size2 = "" font2 = "sans-serif" color2 = "white" xy2 = "5,5" align2 = "center" e = args.each hash = {} # TODO get rid of hash?? valid = %w[width height bgcolor style size font color xy align style2 size2 font2 color2 xy2 align2] os = OpenStruct.new loop do arg = e.next arg = arg.chop raise "Don't know '#{arg}'" unless valid.include?(arg) os.send(arg+"=", e.next) end x, y = xy.split(",") x2, y2 = xy2.split(",") names = %w[x y x2 y2] + valid names.each {|name| hash[name] = os.send(name) } result = <<~HTML #{Livetext::Vars["view.title"]} #{Livetext::Vars["view.subtitle"]} HTML [result, hash] 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 nlist _out "
    " _body {|line| _out "
  1. #{line}
  2. " } _out "
" _optional_blank_line 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 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/"widgets/pinned/" datafile = dir/"list.data" pins = _get_data?(datafile) pins << "#{@meta.num} #{@meta.title}\n" pins.uniq! File.open(datafile, "w") {|out| pins.each {|pin| out.puts pin } } end _optional_blank_line 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.join("\n") @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("view.title")} | #{_var("view.subtitle")}\n ], "generator" => %[], "og:title" => %[], "og:locale" => %[], "description" => %[], "og:description" => %[], "linkc" => %[], "og:url" => %[], "og:site_name" => %[], # "style" => %[], # ^ FIXME "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") sleep 6; RubyText.stop exit 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) else raise "Nonstandard widget?" end _include_file wtag/tcard end _out %[
] rescue => err puts "err = #{err}" puts err.backtrace.join("\n") sleep 6; RubyText.stop 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 = @root/:views/@blog.view title = _var("view.title") if orient == :horiz name = "navbar.html" li1, li2 = "", "" extra = "navbar-expand-lg" list1 = list2 = "" else name = "vnavbar.html" li1, li2 = '" extra = "" list1, list2 = '', "" end start = <<-HTML
HTML html_file = @blog.root/:views/@blog.view/"themes/standard/banner/navbar"/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/:navbar/basename+".html" href_main = _main(full) if basename == "index" # special case output.puts %[#{li1} #{cdata}(current) #{li2}] else dir = @blog.root/:views/@blog.view/"themes/standard/banner/navbar" dest = vdir/"remote/banner/navbar"/basename+".html" preprocess cwd: dir, src: basename, dst: dest, call: ".nopara" # , debug: true output.puts %[#{li1} #{cdata} #{li2}] 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] fname = "metadata.txt" File.open(fname, "w") do |f| fields.each {|fld| f.puts "#{'%8s' % 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) } posts = posts.select {|x| File.basename(x).to_i == postid } postdir = exactly_one(posts) vp = RuneBlog::ViewPost.new(@blog.view, postdir) vp 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