X-Git-Url: https://git.draconx.ca/gitweb/homepage.git/blobdiff_plain/1dc021529f88ca4f1ebfed76ffe6378272a23032..HEAD:/lib/helpers.rb diff --git a/lib/helpers.rb b/lib/helpers.rb index faa40c3..24d37e4 100644 --- a/lib/helpers.rb +++ b/lib/helpers.rb @@ -1,6 +1,6 @@ # Nick's web site: Ruby helpers for processing # -# Copyright © 2018 Nick Bowler +# Copyright © 2018-2022 Nick Bowler # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,6 +15,18 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +require 'nokogiri' +require 'fastimage' + +use_helper Nanoc::Helpers::Blogging +use_helper Nanoc::Helpers::Breadcrumbs +use_helper Nanoc::Helpers::Rendering + +Xmlns = { + 'xhtml' => 'http://www.w3.org/1999/xhtml' +}.freeze +$counters = {} + def to_xhtml(subpath = "", item = @item) if item.identifier =~ '/index.*' ret = "/" + subpath + "/index.xhtml" @@ -27,10 +39,149 @@ end def item_source(item = @item) filename = "content" + item.identifier + filebase = filename.chomp(File.extname(filename)) + + [ if item.binary? then filebase + ".yaml" end, + filename].compact.find { |f| File.file? f } +end + +def item_uri(item = @item, rep: :default) + return item.path(rep: rep).sub(%r{/index[.][^.]*$}, "/") +end + +def rep_uri(rep = @rep) + return rep.path.sub(%r{/index[.][^.]*$}, "/") +end + +def find_license(license) + matches = @items.find_all("/license/" + license + ".*") + + raise("License not defined: " + license) if !matches.length + return matches.sort_by { |item| item.identifier } [0] +end + +# Return the first paragraph of the given item as a string. +def item_longdesc(item) + xml = Nokogiri::XML("" + + item.compiled_content(snapshot: :rawbody) + + "") - if File.file? filename then - return filename + p = xml.xpath('//xhtml:p', Xmlns) + if p.empty? then nil else p[0].xpath('string(.)') end +end + +def counter(name = :default, item = @item) + $counters[item] ||= {} + $counters[item][name] ||= 0 + + name.to_s.capitalize + " " + ($counters[item][name] += 1).to_s +end + +# Return a hash containing :src, :width and :height based on an image item rep. +def img_rep_attrs(item, rep) + rep = :large if item.reps[rep].raw_path.nil? + attrs = {} + + attrs[:src] ||= item_uri(item, rep: rep) + attrs[:width], attrs[:height] = FastImage.size(item.reps[rep].raw_path) + + return attrs +end + +def embed_img(item, rep: :large, caption: nil, block_attrs: {}, img_attrs: {}) + return "[image not found]" unless item + + img_attrs[:alt] ||= item[:title] + caption ||= img_attrs[:alt] + caption = caption.strip + caption.gsub!(/\s+/, " ") + + img_attrs = img_rep_attrs(item, rep).merge(img_attrs) + block_attrs[:href] = item_uri(item, rep: :info) + + b = Nokogiri::XML::Builder.new do |xml| + xml.a(block_attrs) { + xml.img(img_attrs) + unless caption.empty? + xml << " ⁠" + xml.small { xml << caption } + end + } end + b.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION) +end +def gallery_img(item, rep: :medium, caption: nil, alt: nil) + attrs = { alt: alt, "generate-gallery" => "generate-gallery" } + embed_img(item, rep: rep, caption: caption, img_attrs: attrs) +end + +def floating_img(item, rep: :medium, caption: nil, alt: nil, left: nil) + battrs = { class: if left then "left" else "right" end } + attrs = { alt: alt } + + embed_img(item, rep: rep, caption: caption, + block_attrs: battrs, img_attrs: attrs) +end + +def expand_copyright(copyright) + result = { :years => {} } + + /^([-–[:digit:][:space:],]*)(.*)$/.match(copyright) do |m| + m[1].split(/\s*,\s*/).each do |range| + lo, hi = range.split(/[^[:digit:]]+/) + for y in (lo..hi||lo) + result[:years][y] = 1 + end + end + + result[:years] = result[:years].keys.sort + result[:name] = m[2] + return result + end + + return nil +end + +def path_to_rep(path) + @items.find_all(File::dirname(path) + "/*").each do |item| + item.reps.each do |rep| + return rep if rep.path == path + end + end return nil end + +def find_images(item = @item) + return [] if item.binary? + + result = {} + doc = Nokogiri::HTML(item.compiled_content(snapshot: :pre)) + doc.xpath("//img/@src").each do |imgsrc| + rep = path_to_rep(imgsrc.value) + if rep + result[rep.item.identifier] ||= rep.item + end + end + return result.values +end + +def human_filesize(size) + units = ["B", "KiB", "MiB", "GiB"] + prec = 0 + + for unit in units + if (size < 1024) + break + end + + size /= 1024.0 + prec = 1 + end + + sprintf("%.*f %s", prec, size + 0.05, unit) +end + +def license_shortname(item) + item.fetch(:shortname, File::basename(item.identifier.without_ext).upcase) +end