Chienomi

Mimir Yokohamaに用語集機能

ウェブサイト開発

Mimir Yokohamaに用語集機能が追加された。

用語集機能はACCS(PureBuilderに取り込まれる以前の)やAki PHP Content Collection時代に実装されていた。

シンプルにACCSではJavaScript+Ruby/CGIで、本文エレメント(テキストノード)を探索し、文字列を送信してRubyで置き変えたものを返してもらい、innerHTMLを置き換える方式だった。

APCCでは単純に力技で置換えていた。

PureBuilderではこの機能を実現していなかった。 正確には一時期実装していたこともあるが、十分な質でなかったのだ。

そしてついに復活した用語集機能。

Pre Pluginsで処理することも考えたが、Post PluginsでRubyで処理している。

#!/usr/bin/ruby

# Grosarry Support plugin
# Replace article element with <span title="description" class="pb-dictentry">word</span>
# Target should be in article elemnt.
# dictionary is .grossary.rb in PBSimply root.
#
# Sample:
# GROSSARY = {
#   "tech" => {
#     "hack" => "It's beautiful things.",
#     "luser" => "It's bogus."
#   }
# }
#
# and set frontmatter
# grossaries:
#   - tech

require 'yaml'

# Get frontmatter
frontmatter = YAML.load(ENV["pbsimply_doc_frontmatter"])

if !(frontmatter["grossaries"]) || frontmatter["grossaries"].empty?
    ARGF.each {|i| print i }
    exit 0
end

dict = {}


load './.grossary.rb'

frontmatter["grossaries"].each do |i|
    if GROSSARY.key?(i)
        dict.merge! GROSSARY[i]
    else
        STDERR.puts "WARNING: Grossary Support: No category ${i}"
    end
end

pattern = Regexp.compile dict.keys.sort_by {|i| -i.length }.map {|i| Regexp.escape i }.join("|")

ARGF.each do |line|
    if(line =~ /<article/ .. line =~ /<\/article/)
        # in article
        line.gsub!(/<[^>]*>|[^<]*/) do |element|
            if element[0] == "<"
                # Tag
                nil
            else
                # Text
                element.gsub!(pattern) do |matchword|
                    sprintf('<span title="%s" class="pb-dictentry">%s</span>', dict[matchword], matchword)
                end
            end
            element
        end
    end

    print line
end

「辞書をワード長が長い順に並べ替えて|で結合し、正規表現としてコンパイルして置き換える」という手法はかつてのコードで考えたものである。

用語集のページも単純な手法でMarkdownを生成している。

#!/usr/bin/ruby

load './.grossary.rb'

puts <<EOF
---
title: 用語集
date: 2018-07-08
author: Mimir Yokohama
last_update: #{Time.now.strftime("%Y-%m-%d")}
accs: no
pickage: yes
---
EOF

GROSSARY.each do |cat, incat|
    puts '# ' + cat
    puts
    incat.each.sort_by {|k, v| k}.each do |k,v|
        puts '## ' + k
        puts
        puts v
        puts
    end
end

で、今回もライブラリなしのPureJSで処理している。 今回は44行ほどだが、18行は共有化できるものなので、もう少し短くすることも可能だ。 DHTMLのお手本のような初歩的なものである。

Event.stopPropagation()Event.stopPropagationと書いて悩むはめになったけど。