diff --git a/bin/review-webmaker b/bin/review-webmaker
new file mode 100644
index 000000000..18d9f38f9
--- /dev/null
+++ b/bin/review-webmaker
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+#
+# This program is free software.
+# You can distribute or modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+# For details of the GNU LGPL, see the file "COPYING".
+#
+
+require 'pathname'
+bindir = Pathname.new(__FILE__).realpath.dirname
+$LOAD_PATH.unshift((bindir + '../lib').realpath)
+
+require 'review/webmaker'
+
+ReVIEW::WEBMaker.execute(*ARGV)
diff --git a/lib/review/configure.rb b/lib/review/configure.rb
index 3a46181eb..c94819e2f 100644
--- a/lib/review/configure.rb
+++ b/lib/review/configure.rb
@@ -40,6 +40,9 @@ def self.values
"mathml" => nil, # for HTML
"htmlext" => "html",
"htmlversion" => 5,
+ "imagedir" => "images",
+ "image_ext" => %w(png gif jpg jpeg svg ttf woff otf),
+ "fontdir" => "fonts",
"chapter_file" => 'CHAPS',
"part_file" => 'PART',
diff --git a/lib/review/htmlbuilder.rb b/lib/review/htmlbuilder.rb
index 7d60bcb02..8a02499cf 100644
--- a/lib/review/htmlbuilder.rb
+++ b/lib/review/htmlbuilder.rb
@@ -13,6 +13,7 @@
require 'review/htmlutils'
require 'review/template'
require 'review/textutils'
+require 'review/webtocprinter'
module ReVIEW
@@ -54,17 +55,25 @@ def builder_init_file
@sec_counter = SecCounter.new(5, @chapter)
@nonum_counter = 0
@body_ext = nil
+ @toc = nil
end
private :builder_init_file
def result
+ if @book.config.maker == "webmaker"
+ htmldir = "web/html"
+ localfilename = "layout-web.html.erb"
+ else
+ htmldir = "html"
+ localfilename = "layout.html.erb"
+ end
if @book.htmlversion == 5
- htmlfilename = "./html/layout-html5.html.erb"
+ htmlfilename = File.join(htmldir, "layout-html5.html.erb")
else
- htmlfilename = "./html/layout-xhtml1.html.erb"
+ htmlfilename = File.join(htmldir, "layout-xhtml1.html.erb")
end
- layout_file = File.join(@book.basedir, "layouts", "layout.html.erb")
+ layout_file = File.join(@book.basedir, "layouts", localfilename)
if !File.exist?(layout_file) && File.exist?(File.join(@book.basedir, "layouts", "layout.erb"))
raise ReVIEW::ConfigError, "layout.erb is obsoleted. Please use layout.html.erb."
end
@@ -86,6 +95,12 @@ def result
@stylesheets = @book.config["stylesheet"]
@next = @chapter.next_chapter
@prev = @chapter.prev_chapter
+ @next_title = @next ? compile_inline(@next.title) : ""
+ @prev_title = @prev ? compile_inline(@prev.title) : ""
+
+ if @book.config.maker == "webmaker"
+ @toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
+ end
tmpl = ReVIEW::Template.load(layout_file)
tmpl.result(binding)
diff --git a/lib/review/htmlutils.rb b/lib/review/htmlutils.rb
index 489070f38..41acf493f 100644
--- a/lib/review/htmlutils.rb
+++ b/lib/review/htmlutils.rb
@@ -25,6 +25,7 @@ def escape_html(str)
end
alias_method :escape, :escape_html
+ alias_method :h, :escape_html
def unescape_html(str)
# FIXME better code
diff --git a/lib/review/webmaker.rb b/lib/review/webmaker.rb
new file mode 100644
index 000000000..5221923a9
--- /dev/null
+++ b/lib/review/webmaker.rb
@@ -0,0 +1,297 @@
+# encoding: utf-8
+#
+# This program is free software.
+# You can distribute or modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+# For details of the GNU LGPL, see the file "COPYING".
+#
+require 'optparse'
+require 'yaml'
+require 'fileutils'
+require 'erb'
+
+require 'review'
+require 'review/i18n'
+require 'review/converter'
+require 'erb'
+
+module ReVIEW
+ class WEBMaker
+ include ERB::Util
+
+ attr_accessor :config, :basedir
+
+ def initialize
+ @basedir = nil
+ end
+
+ def self.execute(*args)
+ self.new.execute(*args)
+ end
+
+ def parse_opts(args)
+ cmd_config = Hash.new
+ opts = OptionParser.new
+
+ opts.banner = "Usage: review-webmaker configfile"
+ opts.version = ReVIEW::VERSION
+ opts.on('--help', 'Prints this message and quit.') do
+ puts opts.help
+ exit 0
+ end
+ opts.on('--ignore-errors', 'Ignore review-compile errors.') do
+ cmd_config["ignore-errors"] = true
+ end
+
+ opts.parse!(args)
+ if args.size != 1
+ puts opts.help
+ exit 0
+ end
+
+ return cmd_config, args[0]
+ end
+
+ def build_path
+ @config["docroot"] || "webroot"
+ end
+
+ def remove_old_files(path)
+ FileUtils.rm_rf(path)
+ end
+
+
+ def execute(*args)
+ @config = ReVIEW::Configure.values
+ @config.maker = "webmaker"
+ cmd_config, yamlfile = parse_opts(args)
+
+ @config.merge!(YAML.load_file(yamlfile))
+ # YAML configs will be overridden by command line options.
+ @config.merge!(cmd_config)
+ @config["htmlext"] = "html"
+ I18n.setup(@config["language"])
+ generate_html_files(yamlfile)
+ end
+
+ def generate_html_files(yamlfile)
+ @basedir = File.dirname(yamlfile)
+ @path = build_path()
+ remove_old_files(@path)
+ Dir.mkdir(@path)
+
+ @book = ReVIEW::Book.load(@basedir)
+ @book.config = @config
+
+ copy_stylesheet(@path)
+ copy_frontmatter(@path)
+ build_body(@path, yamlfile)
+ copy_backmatter(@path)
+
+ copy_images(@config["imagedir"], "#{@path}/images")
+
+ copy_resources("covers", "#{@path}/images")
+ copy_resources("adv", "#{@path}/images")
+ copy_resources(@config["fontdir"], "#{@path}/fonts", @config["font_ext"])
+ end
+
+ def build_body(basetmpdir, yamlfile)
+ base_path = Pathname.new(@basedir)
+ builder = ReVIEW::HTMLBuilder.new
+ @converter = ReVIEW::Converter.new(@book, builder)
+ @book.parts.each do |part|
+ htmlfile = nil
+ if part.name.present?
+ if part.file?
+ build_chap(part, base_path, basetmpdir, true)
+ else
+ htmlfile = "part_#{part.number}.#{@config["htmlext"]}"
+ build_part(part, basetmpdir, htmlfile)
+ title = ReVIEW::I18n.t("part", part.number)
+ title += ReVIEW::I18n.t("chapter_postfix") + part.name.strip if part.name.strip.present?
+ end
+ end
+
+ part.chapters.each do |chap|
+ build_chap(chap, base_path, basetmpdir, false)
+ end
+
+ end
+ end
+
+ def build_part(part, basetmpdir, htmlfile)
+ File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
+ @body = ""
+ @body << "
\n"
+ @body << "
#{ReVIEW::I18n.t("part", part.number)}
\n"
+ if part.name.strip.present?
+ @body << "#{part.name.strip}
\n"
+ end
+ @body << "\n"
+
+ @language = @config['language']
+ @stylesheets = @config["stylesheet"]
+ tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
+ tmpl = ReVIEW::Template.load(tmplfile)
+ f.write tmpl.result(binding)
+ end
+ end
+
+ def template_name
+ if @config["htmlversion"].to_i == 5
+ 'web/html/layout-html5.html.erb'
+ else
+ 'web/html/layout-xhtml1.html.erb'
+ end
+ end
+
+ def build_chap(chap, base_path, basetmpdir, ispart)
+ filename = ""
+
+ if ispart.present?
+ filename = chap.path
+ else
+ filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
+ end
+ id = filename.sub(/\.re\Z/, "")
+
+ htmlfile = "#{id}.#{@config["htmlext"]}"
+
+ if @config["params"].present?
+ warn "'params:' in config.yml is obsoleted."
+ end
+
+ begin
+ @converter.convert(filename, File.join(basetmpdir, htmlfile))
+ rescue => e
+ warn "compile error in #{filename} (#{e.class})"
+ warn e.message
+ end
+ end
+
+ def copy_images(resdir, destdir)
+ return nil unless File.exist?(resdir)
+ allow_exts = @config["image_ext"]
+ FileUtils.mkdir_p(destdir)
+ recursive_copy_files(resdir, destdir, allow_exts)
+ end
+
+ def copy_resources(resdir, destdir, allow_exts=nil)
+ if !resdir || !File.exist?(resdir)
+ return nil
+ end
+ allow_exts = @config["image_ext"] if allow_exts.nil?
+ FileUtils.mkdir_p(destdir)
+ recursive_copy_files(resdir, destdir, allow_exts)
+ end
+
+ def recursive_copy_files(resdir, destdir, allow_exts)
+ Dir.open(resdir) do |dir|
+ dir.each do |fname|
+ next if fname.start_with?('.')
+ if FileTest.directory?("#{resdir}/#{fname}")
+ recursive_copy_files("#{resdir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
+ else
+ if fname =~ /\.(#{allow_exts.join("|")})\Z/i
+ FileUtils.mkdir_p(destdir)
+ FileUtils.cp("#{resdir}/#{fname}", destdir)
+ end
+ end
+ end
+ end
+ end
+
+ def copy_stylesheet(basetmpdir)
+ if @config["stylesheet"].size > 0
+ @config["stylesheet"].each do |sfile|
+ FileUtils.cp(sfile, basetmpdir)
+ end
+ end
+ end
+
+ def copy_frontmatter(basetmpdir)
+ build_indexpage(basetmpdir)
+
+ if @config["titlepage"]
+ if @config["titlefile"]
+ FileUtils.cp(@config["titlefile"], "#{basetmpdir}/titlepage.#{@config["htmlext"]}")
+ else
+ build_titlepage(basetmpdir, "titlepage.#{@config["htmlext"]}")
+ end
+ end
+
+ copy_file_with_param("creditfile")
+ copy_file_with_param("originaltitlefile")
+ end
+
+ def build_indexpage(basetmpdir)
+ File.open("#{basetmpdir}/index.html", "w") do |f|
+ if @config["coverimage"]
+ file = File.join("images", @config["coverimage"])
+ @body = <<-EOT
+
+
+
+ EOT
+ else
+ @body = ""
+ end
+ @language = @config['language']
+ @stylesheets = @config["stylesheet"]
+ @toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
+ @next = @book.chapters[0]
+ @next_title = @next ? @next.title : ""
+ tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
+ tmpl = ReVIEW::Template.load(tmplfile)
+ f.write tmpl.result(binding)
+ end
+ end
+
+ def build_titlepage(basetmpdir, htmlfile)
+ File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
+ @body = ""
+ @body << ""
+ @body << "
#{CGI.escapeHTML(@config["booktitle"])}
"
+ if @config["aut"]
+ @body << "#{join_with_separator(@config["aut"], ReVIEW::I18n.t("names_splitter"))}
"
+ end
+ if @config["prt"]
+ @body << "#{join_with_separator(@config["prt"], ReVIEW::I18n.t("names_splitter"))}
"
+ end
+ @body << ""
+
+ @language = @config['language']
+ @stylesheets = @config["stylesheet"]
+ tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
+ tmpl = ReVIEW::Template.load(tmplfile)
+ f.write tmpl.result(binding)
+ end
+ end
+
+ def copy_backmatter(basetmpdir)
+ copy_file_with_param("profile")
+ copy_file_with_param("advfile")
+ if @config["colophon"] && @config["colophon"].kind_of?(String)
+ copy_file_with_param("colophon", "colophon.#{@config["htmlext"]}")
+ end
+ copy_file_with_param("backcover")
+ end
+
+ def copy_file_with_param(name, target_file = nil)
+ if @config[name] && File.exist?(@config[name])
+ target_file ||= File.basename(@config[name])
+ FileUtils.cp(@config[name], File.join(basetmpdir, target_file))
+ end
+ end
+
+ def join_with_separator(value, sep)
+ if value.kind_of? Array
+ value.join(sep)
+ else
+ value
+ end
+ end
+
+ end
+end
+
diff --git a/lib/review/webtocprinter.rb b/lib/review/webtocprinter.rb
new file mode 100644
index 000000000..121d720bc
--- /dev/null
+++ b/lib/review/webtocprinter.rb
@@ -0,0 +1,49 @@
+require 'review'
+require 'review/tocprinter'
+
+module ReVIEW
+ class WEBTOCPrinter < TOCPrinter
+ include HTMLUtils
+
+ def self.book_to_string(book)
+ io = StringIO.new
+ ReVIEW::WEBTOCPrinter.new(1, {}, io).print_book(book)
+ io.seek(0)
+ io.read
+ end
+
+ def print_book(book)
+ @out.puts ''
+ @out.puts "- TOP
\n"
+ book.each_part do |part|
+ print_part(part)
+ end
+ @out.puts '
'
+ end
+
+ def print_part(part)
+ if part.number
+ @out.puts "#{h(part.title)}\n\n"
+ end
+ part.each_chapter do |chap|
+ print_chapter(chap)
+ end
+ if part.number
+ @out.puts "
\n\n"
+ end
+ end
+
+ def print_chapter(chap)
+ chap_node = TOCParser.chapter_node(chap)
+ ext = chap.book.config["htmlext"] || "html"
+ path = chap.path.sub(/\.re/, "."+ext)
+ if chap_node.number && chap.on_CHAPS?
+ label = "#{chap.number} #{chap.title}"
+ else
+ label = chap.title
+ end
+ @out.puts "#{h(label)}\n"
+ end
+
+ end
+end
diff --git a/templates/web/html/layout-html5.html.erb b/templates/web/html/layout-html5.html.erb
new file mode 100644
index 000000000..358dab317
--- /dev/null
+++ b/templates/web/html/layout-html5.html.erb
@@ -0,0 +1,56 @@
+
+
+
+
+
+<% if @stylesheets.present? %>
+<% @stylesheets.each do |style| %>
+
+<% end %>
+<% end%>
+<% if @next.present? %>"><% end %>
+<% if @prev.present? %>"><% end %>
+
+ <%=h @title %> | <%=h @book.config["booktitle"]%>
+
+>
+
+
+
+
+
+ <%= @body %>
+
+
+
+
+
+
+ <% if @javascripts.present? %>
+ <% @javascripts.each do |script| %>
+
+ <% end %>
+ <% end%>
+
+
diff --git a/templates/web/html/layout-xhtml1.html.erb b/templates/web/html/layout-xhtml1.html.erb
new file mode 100644
index 000000000..a88a8d10d
--- /dev/null
+++ b/templates/web/html/layout-xhtml1.html.erb
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+<% if @stylesheets.present? %>
+<% @stylesheets.each do |style| %>
+
+<% end %>
+<% end%>
+
+ <%= @title %>
+
+>
+<% if @error_messages %><%= @error_messages %><% end %>
+<% if @warning_messages %><%= @warning_messages %><% end %>
+<%= @body %>
+
+
diff --git a/test/test_i18n.rb b/test/test_i18n.rb
index f8ed318e8..35e85e458 100644
--- a/test/test_i18n.rb
+++ b/test/test_i18n.rb
@@ -194,11 +194,11 @@ def test_htmlbuilder
def _setup_htmlbuilder
I18n.setup "en"
@builder = HTMLBuilder.new()
- @config = {
+ @config = ReVIEW::Configure[
"secnolevel" => 2, # for IDGXMLBuilder, HTMLBuilder
"stylesheet" => nil, # for HTMLBuilder
"ext" => ".re"
- }
+ ]
@book = Book::Base.new(".")
@book.config = @config
@compiler = ReVIEW::Compiler.new(@builder)