# -*- coding: utf-8 -*- ### ### ReVIEW::WEBMakerクラスを書き直す ### (でも元がひどすぎるので書き直すにも限界がある) ### require 'pathname' require 'fileutils' require 'erb' require 'review/converter' require 'review/htmlbuilder' require 'review/template' require 'review/webmaker' require_relative './review-maker' module ReVIEW remove_const :WEBMaker class WEBMaker < Maker SCRIPT_NAME = "review-webmaker" def initialize(*args) super @config['htmlext'] = 'html' @docroot = @config['docroot'] || 'webroot' end def generate() remove_old_files() FileUtils.mkdir_p(@docroot) # @book = ReVIEW::Book.load(@basedir) @book.config = @config # copy_stylesheet() copy_frontmatter() build_body() copy_backmatter() # imagedir = @config['imagedir'] destdir = "#{@docroot}/#{imagedir}" copy_images(imagedir, destdir) # copy_resources('covers', destdir) copy_resources('adv', destdir) copy_resources(@config['fontdir'], "#{@docroot}/fonts", @config['font_ext']) end def build_body() base_path = Pathname.new(@basedir) @converter = ReVIEW::Converter.new(@book, new_builder()) @book.parts.each do |part| if part.name.present? if part.file? build_chap(part, base_path, true) else htmlfile = "part_#{part.number}.#{@config['htmlext']}" build_part(part, htmlfile) # title = ReVIEW::I18n.t('part', part.number) # title += ReVIEW::I18n.t('chapter_postfix') + part.name.strip unless part.name.strip.empty? end end part.chapters.each do |chap| build_chap(chap, base_path, false) end end end def new_builder() builder = ReVIEW::WEBBuilder.new() builder.starter_config = @starter_config return builder end def new_renderer() return WEBRenderer.new(@config, @book, @basedir, @starter_config) end def build_part(part, htmlfile) new_renderer().render_part(part, File.join(@docroot, htmlfile)) end def build_chap(chap, base_path, ispart) filename = \ if ispart.present? chap.path else Pathname.new(chap.path).relative_path_from(base_path).to_s end chapter_id = filename.sub(/\.re\Z/, '') htmlfile = "#{chapter_id}.#{@config['htmlext']}" # if @config['params'].present? warn "'params:' in config.yml is obsoleted." end # begin @converter.convert(filename, File.join(@docroot, htmlfile)) rescue => ex warn "compile error in #{filename} (#{ex.class})" warn ex.message generate_errorpage(ex, filename, htmlfile) end end def remove_old_files() math_dir = "./#{@config['imagedir']}/_review_math" FileUtils.rm_rf(math_dir) if @config['imgmath'] && Dir.exist?(math_dir) FileUtils.rm_rf(@docroot) end def copy_images(srcdir, destdir) copy_resources(srcdir, destdir, nil) end def copy_resources(srcdir, destdir, allow_exts=nil) if srcdir && File.exist?(srcdir) FileUtils.mkdir_p(destdir) allow_exts ||= @config['image_ext'] ok = allow_exts && ! allow_exts.empty? ext_rexp = ok ? /\.(#{allow_exts.join('|')})\Z/i : nil _recursive_copy_files(srcdir, destdir, ext_rexp) end end def _recursive_copy_files(srcdir, destdir, ext_rexp) Dir.open(srcdir) do |dir| dir.each do |fname| next if fname.start_with?('.') srcpath = "#{srcdir}/#{fname}" if File.directory?(srcpath) destpath = "#{destdir}/#{fname}" _recursive_copy_files(srcpath, destpath, ext_rexp) elsif ext_rexp.nil? || fname =~ ext_rexp FileUtils.mkdir_p(destdir) FileUtils.cp(srcpath, destdir) end end end end def copy_stylesheet() cssdir = File.join(@docroot, "css") Dir.mkdir(cssdir) unless File.directory?(cssdir) [@config['stylesheet']].flatten.compact.each do |x| FileUtils.cp("css/#{x}", cssdir) end end def copy_frontmatter() generate_indexpage('index.html') # if @config['titlepage'] destfile = "titlepage.#{@config['htmlext']}" if @config['titlefile'] FileUtils.cp(@config['titlefile'], "#{@docroot}/#{destfile}") else generate_titlepage(destfile) end end # _copy_file(@config['creditfile']) _copy_file(@config['originaltitlefile']) end def generate_errorpage(ex, filename, htmlfile) s = new_renderer().render_exception(ex, filename) File.write(File.join(@docroot, htmlfile), s) end def generate_indexpage(htmlfile) s = new_renderer().render_indexpage() File.write(File.join(@docroot, htmlfile), s) rescue => ex generate_errorpage(ex, nil, htmlfile) end def generate_titlepage(htmlfile) s = new_renderer().render_titlepage() File.write(File.join(@docroot, htmlfile), s) end def copy_backmatter() conf = @config ext = conf['htmlext'] _copy_file(conf['profile']) _copy_file(conf['advfile']) _copy_file(conf['colophon'], "colophon.#{ext}") if conf['colophon'].is_a?(String) _copy_file(conf['backcover']) end def _copy_file(srcfile, destfile=nil) if srcfile && File.exist?(srcfile) destfile ||= File.basename(srcfile) FileUtils.cp(srcfile, File.join(@docroot, destfile)) end end end class WEBBuilder < HTMLBuilder def layoutfile "layouts/layout.html5.erb" end end class WEBRenderer < BaseRenderer def initialize(*args) super @language = @config['language'] @stylesheets = @config['stylesheet'] end def layout_template_name() #if @config['htmlversion'].to_i == 5 # 'web/html/layout-html5.html.erb' #else # 'web/html/layout-xhtml1.html.erb' #end "layout.html5.erb" end def render_exception(error, textfile) @error = error @textfile = textfile # return render() end def render_part(part) part_name = part.name.strip # sb = "" sb << "
\n" sb << "

#{i18n('part', part.number)}

\n" sb << "

#{part_name}

\n" if part_name.present? sb << "
\n" @body = sb # return render() end def render_indexpage() if @config['coverimage'] imgfile = File.join(@config['imagedir'], @config['coverimage']) else imgfile = nil end # sb = "" if imgfile sb << "
\n" sb << " \n" sb << "
\n" end @body = sb @toc = ReVIEW::WEBTOCPrinter.book_to_html(@book, nil) @next = @book.chapters[0] @next_title = @next ? @next.title : '' # return render() end def render_titlepage() author = @config['aut'] ? _join_names(@config.names_of('aut')) : nil publisher = @config['pbl'] ? _join_names(@config.names_of('pbl')) : nil # sb = "" sb << "
\n" sb << "

#{h @config.name_of('booktitle')}

\n" sb << "

#{author}

\n" if author sb << "

#{publisher}

\n" if publisher sb << "
\n" @body = sb # return render() end private def _join_names(names) sep = i18n('names_splitter') return [names].flatten.join(sep) end end class WEBTOCPrinter def self.book_to_html(book, current_chapter) printer = self.new(nil, nil, nil) arr = printer.handle_book(book, current_chapter) html = printer.render_html(arr) return html end def render_html(arr) tag, attr, children = arr tag == "book" or raise "internal error: tag=#{tag.inspect}" buf = "\n" return buf end def parse_inline(str) builder = HTMLBuilder.new builder.instance_variable_set('@book', @_book) @compiler ||= Compiler.new(builder) return @compiler.text(str) end def _render_li(arr, buf, n) tag, attr, children = arr case tag when "part" buf << "
  • #{parse_inline(attr[:label])}\n" buf << " \n" buf << "
  • \n" when "chapter" buf << "
  • #{parse_inline(attr[:label])}" if children && !children.empty? buf << "\n \n" buf << "
  • \n" else buf << "\n" end when "section" buf << "
  • #{parse_inline(attr[:label])}
  • \n" end buf end def handle_book(book, current_chapter) @_book = book children = [] book.each_part do |part| if part.number children << handle_part(part, current_chapter) else part.each_chapter do |chap| children << handle_chapter(chap, current_chapter) end end end # attrs = { title: book.config['booktitle'], subtitle: book.config['subtitle'], } return ["book", attrs, children] end def handle_part(part, current_chapter) children = [] part.each_chapter do |chap| children << handle_chapter(chap, current_chapter) end # attrs = { number: part.number, title: part.title, #label: "#{I18n.t('part_short', part.number)} #{part.title}", label: "#{I18n.t('part', part.number)} #{part.title}", } return ["part", attrs, children] end def handle_chapter(chap, current_chapter) children = [] if current_chapter.nil? || chap == current_chapter chap.headline_index.each do |sec| next if sec.number.present? && sec.number.length >= 2 children << handle_section(sec, chap) end end # chap_node = TOCParser.chapter_node(chap) ext = chap.book.config['htmlext'] || 'html' path = chap.path.sub(/\.re\z/, ".#{ext}") label = if chap_node.number && chap.on_chaps? "#{I18n.t('chapter_short', chap.number)} #{chap.title}" else chap.title end # attrs = { number: chap_node.number, title: chap.title, label: label, path: path, } return ["chapter", attrs, children] end def handle_section(sec, chap) if chap.number && sec.number.length > 0 number = [chap.number] + sec.number label = "#{number.join('.')} #{sec.caption}" else number = nil label = sec.caption end attrs = { number: number, title: sec.caption, label: label, anchor: "h#{number ? number.join('-') : ''}", } return ["section", attrs, []] end end end