review-retrovert 0.3.3 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/retrovert.yml +39 -0
  3. data/.gitignore +2 -2
  4. data/.ruby-version +1 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +67 -1
  7. data/README.md +6 -3
  8. data/lib/review/retrovert/converter.rb +231 -6
  9. data/lib/review/retrovert/version.rb +1 -1
  10. data/review-retrovert.gemspec +1 -1
  11. data/testdata/mybook/.gitignore +7 -0
  12. data/testdata/mybook/README.md +43 -0
  13. data/testdata/mybook/Rakefile +16 -0
  14. data/testdata/mybook/catalog.yml +33 -0
  15. data/testdata/mybook/config-starter.yml +139 -0
  16. data/testdata/mybook/config.yml +375 -0
  17. data/testdata/mybook/contents/00-preface.re +83 -0
  18. data/testdata/mybook/contents/01-install.re +272 -0
  19. data/testdata/mybook/contents/02-tutorial.re +1008 -0
  20. data/testdata/mybook/contents/03-syntax.re +2613 -0
  21. data/testdata/mybook/contents/04-customize.re +728 -0
  22. data/testdata/mybook/contents/05-faq.re +328 -0
  23. data/testdata/mybook/contents/06-bestpractice.re +971 -0
  24. data/testdata/mybook/contents/91-compare.re +18 -0
  25. data/testdata/mybook/contents/92-filelist.re +119 -0
  26. data/testdata/mybook/contents/93-background.re +267 -0
  27. data/testdata/mybook/contents/99-postface.re +38 -0
  28. data/testdata/mybook/css/normalize.css +349 -0
  29. data/testdata/mybook/css/webstyle.css +514 -0
  30. data/testdata/mybook/images/03-syntax/favicon-16x16.png +0 -0
  31. data/testdata/mybook/images/03-syntax/figure_heretop.png +0 -0
  32. data/testdata/mybook/images/03-syntax/tw-icon1.jpg +0 -0
  33. data/testdata/mybook/images/03-syntax/tw-icon2.jpg +0 -0
  34. data/testdata/mybook/images/03-syntax/tw-icon3.jpg +0 -0
  35. data/testdata/mybook/images/03-syntax/tw-icon4.jpg +0 -0
  36. data/testdata/mybook/images/04-customize/caption_pagebreak.png +0 -0
  37. data/testdata/mybook/images/04-customize/chaptitlepage_sample.png +0 -0
  38. data/testdata/mybook/images/05-faq/codeblock_rpadding1.png +0 -0
  39. data/testdata/mybook/images/05-faq/codeblock_rpadding2.png +0 -0
  40. data/testdata/mybook/images/06-bestpractice/figure_heretop.png +0 -0
  41. data/testdata/mybook/images/06-bestpractice/font_beramono.png +0 -0
  42. data/testdata/mybook/images/06-bestpractice/heading_design1.png +0 -0
  43. data/testdata/mybook/images/06-bestpractice/heading_design2.png +0 -0
  44. data/testdata/mybook/images/06-bestpractice/margin_book.png +0 -0
  45. data/testdata/mybook/images/06-bestpractice/multiline-title.png +0 -0
  46. data/testdata/mybook/images/06-bestpractice/preface_numbered.png +0 -0
  47. data/testdata/mybook/images/06-bestpractice/program_border.png +0 -0
  48. data/testdata/mybook/images/06-bestpractice/sechead_design_4.png +0 -0
  49. data/testdata/mybook/images/06-bestpractice/titlepage-samples.png +0 -0
  50. data/testdata/mybook/images/93-background/bug913.png +0 -0
  51. data/testdata/mybook/images/93-background/slide2.png +0 -0
  52. data/testdata/mybook/images/cover_a5.pdf +0 -0
  53. data/testdata/mybook/images/cover_b5.pdf +0 -0
  54. data/testdata/mybook/images/tw-icon.jpg +0 -0
  55. data/testdata/mybook/layouts/layout.epub.erb +29 -0
  56. data/testdata/mybook/layouts/layout.html5.erb +106 -0
  57. data/testdata/mybook/layouts/layout.tex.erb +546 -0
  58. data/testdata/mybook/lib/hooks/beforetexcompile.rb +55 -0
  59. data/testdata/mybook/lib/ruby/review-builder.rb +503 -0
  60. data/testdata/mybook/lib/ruby/review-cli.rb +58 -0
  61. data/testdata/mybook/lib/ruby/review-compiler.rb +523 -0
  62. data/testdata/mybook/lib/ruby/review-epubmaker.rb +606 -0
  63. data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +661 -0
  64. data/testdata/mybook/lib/ruby/review-latexbuilder.rb +782 -0
  65. data/testdata/mybook/lib/ruby/review-maker.rb +235 -0
  66. data/testdata/mybook/lib/ruby/review-monkeypatch.rb +91 -0
  67. data/testdata/mybook/lib/ruby/review-pdfmaker.rb +468 -0
  68. data/testdata/mybook/lib/ruby/review-textbuilder.rb +36 -0
  69. data/testdata/mybook/lib/ruby/review-tocparser.rb +285 -0
  70. data/testdata/mybook/lib/ruby/review-webmaker.rb +433 -0
  71. data/testdata/mybook/lib/tasks/mytasks.rake +31 -0
  72. data/testdata/mybook/lib/tasks/review.rake +142 -0
  73. data/testdata/mybook/lib/tasks/review.rake.orig +72 -0
  74. data/testdata/mybook/lib/tasks/starter.rake +326 -0
  75. data/testdata/mybook/locale.yml +6 -0
  76. data/testdata/mybook/review-ext.rb +206 -0
  77. data/testdata/mybook/sty/jumoline.sty +310 -0
  78. data/testdata/mybook/sty/mycolophon.sty +81 -0
  79. data/testdata/mybook/sty/mystyle.sty +8 -0
  80. data/testdata/mybook/sty/mytextsize.sty +61 -0
  81. data/testdata/mybook/sty/mytitlepage.sty +103 -0
  82. data/testdata/mybook/sty/reviewmacro.sty +60 -0
  83. data/testdata/mybook/sty/starter-codeblock.sty +332 -0
  84. data/testdata/mybook/sty/starter-color.sty +79 -0
  85. data/testdata/mybook/sty/starter-font.sty +112 -0
  86. data/testdata/mybook/sty/starter-heading.sty +514 -0
  87. data/testdata/mybook/sty/starter-note.sty +127 -0
  88. data/testdata/mybook/sty/starter-section.sty +262 -0
  89. data/testdata/mybook/sty/starter-toc.sty +72 -0
  90. data/testdata/mybook/sty/starter.sty +554 -0
  91. data/testdata/mybook/style.css +597 -0
  92. metadata +100 -3
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+ ### ReVIEW::TEXTBuilderクラスを拡張する
5
+ ###
6
+
7
+ require 'review/textbuilder'
8
+
9
+
10
+ module ReVIEW
11
+
12
+ defined?(TEXTBuilder) or raise "internal error: TEXTBuilder not found."
13
+
14
+
15
+ class TEXTBuilder
16
+
17
+ ## ファイル名
18
+ def inline_file(str)
19
+ on_inline_file { escape(str) }
20
+ end
21
+ def on_inline_file
22
+ yield
23
+ end
24
+
25
+ ## ユーザ入力
26
+ def inline_userinput(str)
27
+ on_inline_input { escape(str) }
28
+ end
29
+ def on_inline_userinput
30
+ yield
31
+ end
32
+
33
+ end
34
+
35
+
36
+ end
@@ -0,0 +1,285 @@
1
+ #
2
+ # Copyright (c) 2008-2017 Minero Aoki, Kenshi Muto
3
+ # 2002-2007 Minero Aoki
4
+ #
5
+ # This program is free software.
6
+ # You can distribute or modify this program under the terms of
7
+ # the GNU LGPL, Lesser General Public License version 2.1.
8
+ # For details of the GNU LGPL, see the file "COPYING".
9
+ #
10
+
11
+ require 'review/preprocessor'
12
+ require 'review/book'
13
+ require 'review/textbuilder'
14
+
15
+ module ReVIEW
16
+
17
+
18
+ class TOCParser
19
+
20
+ def self.parse(chap)
21
+ f = StringIO.new(chap.content, 'r:BOM|utf-8')
22
+ stream = Preprocessor::Strip.new(f)
23
+ parser = self.new
24
+ return parser.parse(stream, chap).map {|root|
25
+ root.number = chap.number
26
+ root
27
+ }
28
+ end
29
+
30
+ def self.chapter_node(chap)
31
+ toc = self.parse(chap)
32
+ if toc.size != 1
33
+ $stderr.puts "warning: chapter #{toc.join} contains more than 1 chapter"
34
+ end
35
+ toc.first
36
+ end
37
+
38
+ def parse(stream, chap)
39
+ f = stream
40
+ roots = [] # list of chapters
41
+ node_stack = []
42
+ filename = chap.path
43
+ while (line = f.gets)
44
+ case line
45
+ when /\A\#@\+\+\+$/
46
+ beg = f.lineno
47
+ line = f.gets() while line && line !~ /\A\#@---$/
48
+ line or
49
+ error! filename, beg, 'unterminated list'
50
+ next
51
+ when /\A\#@/
52
+ # do nothing
53
+ next
54
+ when /\A\s*\z/
55
+ # do nothing
56
+ next
57
+ when /\A(={2,})[\[\s\{]/
58
+ lev = $1.size
59
+ lev <= 6 or
60
+ error! filename, f.lineno, "section level too deep: #{lev}"
61
+ label = get_label(line)
62
+ if node_stack.empty?
63
+ # missing chapter label
64
+ dummy_chapter = Chapter.new(label, chap)
65
+ node_stack.push dummy_chapter
66
+ roots.push dummy_chapter
67
+ end
68
+ next if label.start_with?('[/') # ex) "[/column]"
69
+ sec = Section.new(lev, label.gsub(/\A\{.*?\}\s?/, ''))
70
+ node_stack.pop until node_stack.last.level < sec.level
71
+ node_stack.last.add_child sec
72
+ node_stack.push sec
73
+
74
+ when /\A=[^=]/
75
+ label = get_label(line)
76
+ node_stack.clear
77
+ new_chapter = Chapter.new(label, chap)
78
+ node_stack.push new_chapter
79
+ roots.push new_chapter
80
+
81
+ when %r{\A//\w+(?:\[.*?\])*\{\s*\z}
82
+ ! node_stack.empty? or
83
+ error! filename, f.lineno, 'list found before section label'
84
+ node_stack.last.add_child(list = List.new)
85
+ beg = f.lineno
86
+ list.add line
87
+ while (line = f.gets) && ! line.start_with?('//}')
88
+ list.add line
89
+ end
90
+ line or
91
+ error! filename, beg, 'unterminated list'
92
+
93
+ when /\A\/\/\w/
94
+ # do nothing
95
+ next
96
+ else
97
+ # if node_stack.empty?
98
+ # error! filename, f.lineno, 'text found before section label'
99
+ # end
100
+ next if node_stack.empty?
101
+ node_stack.last.add_child(par = Paragraph.new(chap))
102
+ par.add line
103
+ while (line = f.gets) && line !~ /\A\s*\z/
104
+ par.add line
105
+ end
106
+ end
107
+ end
108
+
109
+ roots
110
+ end
111
+
112
+ def get_label(line)
113
+ line = line.strip.sub(/\A=+\s*/, '')
114
+ compile_label(line)
115
+ end
116
+
117
+ def compile_label(line)
118
+ b = ReVIEW::TEXTBuilder.new
119
+ dummy_book = ReVIEW::Book::Base.load
120
+ dummy_chapter = ReVIEW::Book::Chapter.new(dummy_book, 1, '-', nil, StringIO.new)
121
+ dummy_loc = Location.new('', StringIO.new)
122
+ b.bind(ReVIEW::Compiler.new(b), dummy_chapter, dummy_loc)
123
+ b.compile_inline(line)
124
+ end
125
+
126
+ def error!(filename, lineno, msg)
127
+ raise "#{filename}:#{lineno}: #{msg}"
128
+ end
129
+
130
+ # class Node
131
+ # def initialize(children = [])
132
+ # @children = children
133
+ # end
134
+ #
135
+ # attr_reader :children
136
+ #
137
+ # def add_child(c)
138
+ # @children.push c
139
+ # end
140
+ #
141
+ # def each_node(&block)
142
+ # @children.each do |c|
143
+ # yield c
144
+ # c.each(&block)
145
+ # end
146
+ # end
147
+ #
148
+ # def each_child(&block)
149
+ # @children.each(&block)
150
+ # end
151
+ #
152
+ # def chapter?
153
+ # false
154
+ # end
155
+ #
156
+ # def each_section(&block)
157
+ # @children.each { |n| n.yield_section(&block) }
158
+ # end
159
+ #
160
+ # def each_section_with_index
161
+ # i = 0
162
+ # each_section do |n|
163
+ # yield n, i
164
+ # i += 1
165
+ # end
166
+ # end
167
+ #
168
+ # def section_size
169
+ # cnt = 0
170
+ # @children.each { |n| n.yield_section { cnt += 1 } }
171
+ # cnt
172
+ # end
173
+ # end
174
+ #
175
+ # class Section < Node
176
+ # def initialize(level, label, path = nil)
177
+ # super()
178
+ # @level = level
179
+ # @label = label
180
+ # @filename = path ? real_filename(path) : nil
181
+ # end
182
+ #
183
+ # def real_filename(path)
184
+ # if FileTest.symlink?(path)
185
+ # File.basename(File.readlink(path))
186
+ # else
187
+ # File.basename(path)
188
+ # end
189
+ # end
190
+ # private :real_filename
191
+ #
192
+ # attr_reader :level
193
+ # attr_reader :label
194
+ #
195
+ # def estimated_lines
196
+ # @children.inject(0) { |sum, n| sum + n.estimated_lines }
197
+ # end
198
+ #
199
+ # def yield_section
200
+ # yield self
201
+ # end
202
+ #
203
+ # def inspect
204
+ # "#<#{self.class} level=#{@level} #{@label}>"
205
+ # end
206
+ # end
207
+ #
208
+ # class Chapter < Section
209
+ # def initialize(label, chap)
210
+ # super 1, label, chap.path
211
+ # @chapter = chap
212
+ # @chapter_id = chap.id
213
+ # @path = chap.path
214
+ # @page_metric = chap.book.page_metric
215
+ # @volume = nil
216
+ # @number = nil
217
+ # end
218
+ #
219
+ # attr_accessor :number
220
+ #
221
+ # def chapter?
222
+ # true
223
+ # end
224
+ #
225
+ # attr_reader :chapter_id
226
+ #
227
+ # def volume
228
+ # return @volume if @volume
229
+ # @volume = @chapter.volume
230
+ # @volume.lines = estimated_lines
231
+ # @volume
232
+ # end
233
+ #
234
+ # def inspect
235
+ # "#<#{self.class} #{@filename}>"
236
+ # end
237
+ # end
238
+ #
239
+ # class Paragraph < Node
240
+ # def initialize(chap)
241
+ # @bytes = 0
242
+ # @page_metric = chap.book.page_metric
243
+ # end
244
+ #
245
+ # def inspect
246
+ # "#<#{self.class}>"
247
+ # end
248
+ #
249
+ # def add(line)
250
+ # @bytes += line.strip.bytesize
251
+ # end
252
+ #
253
+ # def estimated_lines
254
+ # (@bytes + 2) / @page_metric.text.n_columns + 1
255
+ # end
256
+ #
257
+ # def yield_section
258
+ # end
259
+ # end
260
+ #
261
+ # class List < Node
262
+ # def initialize
263
+ # @lines = 0
264
+ # end
265
+ #
266
+ # def inspect
267
+ # "#<#{self.class}>"
268
+ # end
269
+ #
270
+ # def add(_line)
271
+ # @lines += 1
272
+ # end
273
+ #
274
+ # def estimated_lines
275
+ # @lines + 2
276
+ # end
277
+ #
278
+ # def yield_section
279
+ # end
280
+ # end
281
+
282
+ end
283
+
284
+
285
+ end
@@ -0,0 +1,433 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+ ### ReVIEW::WEBMakerクラスを書き直す
5
+ ### (でも元がひどすぎるので書き直すにも限界がある)
6
+ ###
7
+
8
+ require 'pathname'
9
+ require 'fileutils'
10
+ require 'erb'
11
+ require 'review/converter'
12
+ require 'review/htmlbuilder'
13
+ require 'review/template'
14
+ require 'review/webmaker'
15
+ require_relative './review-maker'
16
+
17
+
18
+ module ReVIEW
19
+
20
+ remove_const :WEBMaker
21
+
22
+
23
+ class WEBMaker < Maker
24
+
25
+ SCRIPT_NAME = "review-webmaker"
26
+
27
+ def initialize(*args)
28
+ super
29
+ @config['htmlext'] = 'html'
30
+ @docroot = @config['docroot'] || 'webroot'
31
+ end
32
+
33
+ def generate()
34
+ remove_old_files()
35
+ FileUtils.mkdir_p(@docroot)
36
+ #
37
+ @book = ReVIEW::Book.load(@basedir)
38
+ @book.config = @config
39
+ #
40
+ copy_stylesheet()
41
+ copy_frontmatter()
42
+ build_body()
43
+ copy_backmatter()
44
+ #
45
+ imagedir = @config['imagedir']
46
+ destdir = "#{@docroot}/#{imagedir}"
47
+ copy_images(imagedir, destdir)
48
+ #
49
+ copy_resources('covers', destdir)
50
+ copy_resources('adv', destdir)
51
+ copy_resources(@config['fontdir'], "#{@docroot}/fonts", @config['font_ext'])
52
+ end
53
+
54
+ def build_body()
55
+ base_path = Pathname.new(@basedir)
56
+ @converter = ReVIEW::Converter.new(@book, new_builder())
57
+ @book.parts.each do |part|
58
+ if part.name.present?
59
+ if part.file?
60
+ build_chap(part, base_path, true)
61
+ else
62
+ htmlfile = "part_#{part.number}.#{@config['htmlext']}"
63
+ build_part(part, htmlfile)
64
+ # title = ReVIEW::I18n.t('part', part.number)
65
+ # title += ReVIEW::I18n.t('chapter_postfix') + part.name.strip unless part.name.strip.empty?
66
+ end
67
+ end
68
+ part.chapters.each do |chap|
69
+ build_chap(chap, base_path, false)
70
+ end
71
+ end
72
+ end
73
+
74
+ def new_builder()
75
+ builder = ReVIEW::WEBBuilder.new()
76
+ builder.starter_config = @starter_config
77
+ return builder
78
+ end
79
+
80
+ def new_renderer()
81
+ return WEBRenderer.new(@config, @book, @basedir, @starter_config)
82
+ end
83
+
84
+ def build_part(part, htmlfile)
85
+ new_renderer().render_part(part, File.join(@docroot, htmlfile))
86
+ end
87
+
88
+ def build_chap(chap, base_path, ispart)
89
+ filename = \
90
+ if ispart.present?
91
+ chap.path
92
+ else
93
+ Pathname.new(chap.path).relative_path_from(base_path).to_s
94
+ end
95
+ chapter_id = filename.sub(/\.re\Z/, '')
96
+ htmlfile = "#{chapter_id}.#{@config['htmlext']}"
97
+ #
98
+ if @config['params'].present?
99
+ warn "'params:' in config.yml is obsoleted."
100
+ end
101
+ #
102
+ begin
103
+ @converter.convert(filename, File.join(@docroot, htmlfile))
104
+ rescue => ex
105
+ warn "compile error in #{filename} (#{ex.class})"
106
+ warn ex.message
107
+ generate_errorpage(ex, filename, htmlfile)
108
+ end
109
+ end
110
+
111
+ def remove_old_files()
112
+ math_dir = "./#{@config['imagedir']}/_review_math"
113
+ FileUtils.rm_rf(math_dir) if @config['imgmath'] && Dir.exist?(math_dir)
114
+ FileUtils.rm_rf(@docroot)
115
+ end
116
+
117
+ def copy_images(srcdir, destdir)
118
+ copy_resources(srcdir, destdir, nil)
119
+ end
120
+
121
+ def copy_resources(srcdir, destdir, allow_exts=nil)
122
+ if srcdir && File.exist?(srcdir)
123
+ FileUtils.mkdir_p(destdir)
124
+ allow_exts ||= @config['image_ext']
125
+ ok = allow_exts && ! allow_exts.empty?
126
+ ext_rexp = ok ? /\.(#{allow_exts.join('|')})\Z/i : nil
127
+ _recursive_copy_files(srcdir, destdir, ext_rexp)
128
+ end
129
+ end
130
+
131
+ def _recursive_copy_files(srcdir, destdir, ext_rexp)
132
+ Dir.open(srcdir) do |dir|
133
+ dir.each do |fname|
134
+ next if fname.start_with?('.')
135
+ srcpath = "#{srcdir}/#{fname}"
136
+ if File.directory?(srcpath)
137
+ destpath = "#{destdir}/#{fname}"
138
+ _recursive_copy_files(srcpath, destpath, ext_rexp)
139
+ elsif ext_rexp.nil? || fname =~ ext_rexp
140
+ FileUtils.mkdir_p(destdir)
141
+ FileUtils.cp(srcpath, destdir)
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def copy_stylesheet()
148
+ cssdir = File.join(@docroot, "css")
149
+ Dir.mkdir(cssdir) unless File.directory?(cssdir)
150
+ [@config['stylesheet']].flatten.compact.each do |x|
151
+ FileUtils.cp("css/#{x}", cssdir)
152
+ end
153
+ end
154
+
155
+ def copy_frontmatter()
156
+ generate_indexpage('index.html')
157
+ #
158
+ if @config['titlepage']
159
+ destfile = "titlepage.#{@config['htmlext']}"
160
+ if @config['titlefile']
161
+ FileUtils.cp(@config['titlefile'], "#{@docroot}/#{destfile}")
162
+ else
163
+ generate_titlepage(destfile)
164
+ end
165
+ end
166
+ #
167
+ _copy_file(@config['creditfile'])
168
+ _copy_file(@config['originaltitlefile'])
169
+ end
170
+
171
+ def generate_errorpage(ex, filename, htmlfile)
172
+ s = new_renderer().render_exception(ex, filename)
173
+ File.write(File.join(@docroot, htmlfile), s)
174
+ end
175
+
176
+ def generate_indexpage(htmlfile)
177
+ s = new_renderer().render_indexpage()
178
+ File.write(File.join(@docroot, htmlfile), s)
179
+ rescue => ex
180
+ generate_errorpage(ex, nil, htmlfile)
181
+ end
182
+
183
+ def generate_titlepage(htmlfile)
184
+ s = new_renderer().render_titlepage()
185
+ File.write(File.join(@docroot, htmlfile), s)
186
+ end
187
+
188
+ def copy_backmatter()
189
+ conf = @config
190
+ ext = conf['htmlext']
191
+ _copy_file(conf['profile'])
192
+ _copy_file(conf['advfile'])
193
+ _copy_file(conf['colophon'], "colophon.#{ext}") if conf['colophon'].is_a?(String)
194
+ _copy_file(conf['backcover'])
195
+ end
196
+
197
+ def _copy_file(srcfile, destfile=nil)
198
+ if srcfile && File.exist?(srcfile)
199
+ destfile ||= File.basename(srcfile)
200
+ FileUtils.cp(srcfile, File.join(@docroot, destfile))
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+
207
+ class WEBBuilder < HTMLBuilder
208
+
209
+ def layoutfile
210
+ "layouts/layout.html5.erb"
211
+ end
212
+
213
+ end
214
+
215
+
216
+ class WEBRenderer < BaseRenderer
217
+
218
+ def initialize(*args)
219
+ super
220
+ @language = @config['language']
221
+ @stylesheets = @config['stylesheet']
222
+ end
223
+
224
+ def layout_template_name()
225
+ #if @config['htmlversion'].to_i == 5
226
+ # 'web/html/layout-html5.html.erb'
227
+ #else
228
+ # 'web/html/layout-xhtml1.html.erb'
229
+ #end
230
+ "layout.html5.erb"
231
+ end
232
+
233
+ def render_exception(error, textfile)
234
+ @error = error
235
+ @textfile = textfile
236
+ #
237
+ return render()
238
+ end
239
+
240
+ def render_part(part)
241
+ part_name = part.name.strip
242
+ #
243
+ sb = ""
244
+ sb << "<div class=\"part\">\n"
245
+ sb << "<h1 class=\"part-number\">#{i18n('part', part.number)}</h1>\n"
246
+ sb << "<h2 class=\"part-title\">#{part_name}</h2>\n" if part_name.present?
247
+ sb << "</div>\n"
248
+ @body = sb
249
+ #
250
+ return render()
251
+ end
252
+
253
+ def render_indexpage()
254
+ if @config['coverimage']
255
+ imgfile = File.join(@config['imagedir'], @config['coverimage'])
256
+ else
257
+ imgfile = nil
258
+ end
259
+ #
260
+ sb = ""
261
+ if imgfile
262
+ sb << " <div id=\"cover-image\" class=\"cover-image\">\n"
263
+ sb << " <img src=\"#{imgfile}\" class=\"max\"/>\n"
264
+ sb << " </div>\n"
265
+ end
266
+ @body = sb
267
+ @toc = ReVIEW::WEBTOCPrinter.book_to_html(@book, nil)
268
+ @next = @book.chapters[0]
269
+ @next_title = @next ? @next.title : ''
270
+ #
271
+ return render()
272
+ end
273
+
274
+ def render_titlepage()
275
+ author = @config['aut'] ? _join_names(@config.names_of('aut')) : nil
276
+ publisher = @config['pbl'] ? _join_names(@config.names_of('pbl')) : nil
277
+ #
278
+ sb = ""
279
+ sb << "<div class=\"titlepage\">\n"
280
+ sb << "<h1 class=\"tp-title\">#{h @config.name_of('booktitle')}</h1>\n"
281
+ sb << "<h2 class=\"tp-author\">#{author}</h2>\n" if author
282
+ sb << "<h3 class=\"tp-publisher\">#{publisher}</h3>\n" if publisher
283
+ sb << "</div>\n"
284
+ @body = sb
285
+ #
286
+ return render()
287
+ end
288
+
289
+ private
290
+
291
+ def _join_names(names)
292
+ sep = i18n('names_splitter')
293
+ return [names].flatten.join(sep)
294
+ end
295
+
296
+ end
297
+
298
+
299
+ class WEBTOCPrinter
300
+
301
+ def self.book_to_html(book, current_chapter)
302
+ printer = self.new(nil, nil, nil)
303
+ arr = printer.handle_book(book, current_chapter)
304
+ html = printer.render_html(arr)
305
+ return html
306
+ end
307
+
308
+ def render_html(arr)
309
+ tag, attr, children = arr
310
+ tag == "book" or raise "internal error: tag=#{tag.inspect}"
311
+ buf = "<ul class=\"toc toc-1\">\n"
312
+ children.each do |child|
313
+ _render_li(child, buf, 1)
314
+ end
315
+ buf << "</ul>\n"
316
+ return buf
317
+ end
318
+
319
+ def parse_inline(str)
320
+ builder = HTMLBuilder.new
321
+ builder.instance_variable_set('@book', @_book)
322
+ @compiler ||= Compiler.new(builder)
323
+ return @compiler.text(str)
324
+ end
325
+
326
+ def _render_li(arr, buf, n)
327
+ tag, attr, children = arr
328
+ case tag
329
+ when "part"
330
+ buf << "<li class=\"toc-part\">#{parse_inline(attr[:label])}\n"
331
+ buf << " <ul class=\"toc toc-#{n+1}\">\n"
332
+ children.each {|child| _render_li(child, buf, n+1) }
333
+ buf << " </ul>\n"
334
+ buf << "</li>\n"
335
+ when "chapter"
336
+ buf << " <li class=\"toc-chapter\"><a href=\"#{h attr[:path]}\">#{parse_inline(attr[:label])}</a>"
337
+ if children && !children.empty?
338
+ buf << "\n <ul class=\"toc toc-#{n+1}\">\n"
339
+ children.each {|child| _render_li(child, buf, n+1) }
340
+ buf << " </ul>\n"
341
+ buf << " </li>\n"
342
+ else
343
+ buf << "</li>\n"
344
+ end
345
+ when "section"
346
+ buf << " <li class=\"toc-section\"><a href=\"##{attr[:anchor]}\">#{parse_inline(attr[:label])}</a></li>\n"
347
+ end
348
+ buf
349
+ end
350
+
351
+ def handle_book(book, current_chapter)
352
+ @_book = book
353
+ children = []
354
+ book.each_part do |part|
355
+ if part.number
356
+ children << handle_part(part, current_chapter)
357
+ else
358
+ part.each_chapter do |chap|
359
+ children << handle_chapter(chap, current_chapter)
360
+ end
361
+ end
362
+ end
363
+ #
364
+ attrs = {
365
+ title: book.config['booktitle'],
366
+ subtitle: book.config['subtitle'],
367
+ }
368
+ return ["book", attrs, children]
369
+ end
370
+
371
+ def handle_part(part, current_chapter)
372
+ children = []
373
+ part.each_chapter do |chap|
374
+ children << handle_chapter(chap, current_chapter)
375
+ end
376
+ #
377
+ attrs = {
378
+ number: part.number,
379
+ title: part.title,
380
+ #label: "#{I18n.t('part_short', part.number)} #{part.title}",
381
+ label: "#{I18n.t('part', part.number)} #{part.title}",
382
+ }
383
+ return ["part", attrs, children]
384
+ end
385
+
386
+ def handle_chapter(chap, current_chapter)
387
+ children = []
388
+ if current_chapter.nil? || chap == current_chapter
389
+ chap.headline_index.each do |sec|
390
+ next if sec.number.present? && sec.number.length >= 2
391
+ children << handle_section(sec, chap)
392
+ end
393
+ end
394
+ #
395
+ chap_node = TOCParser.chapter_node(chap)
396
+ ext = chap.book.config['htmlext'] || 'html'
397
+ path = chap.path.sub(/\.re\z/, ".#{ext}")
398
+ label = if chap_node.number && chap.on_chaps?
399
+ "#{I18n.t('chapter_short', chap.number)} #{chap.title}"
400
+ else
401
+ chap.title
402
+ end
403
+ #
404
+ attrs = {
405
+ number: chap_node.number,
406
+ title: chap.title,
407
+ label: label,
408
+ path: path,
409
+ }
410
+ return ["chapter", attrs, children]
411
+ end
412
+
413
+ def handle_section(sec, chap)
414
+ if chap.number && sec.number.length > 0
415
+ number = [chap.number] + sec.number
416
+ label = "#{number.join('.')} #{sec.caption}"
417
+ else
418
+ number = nil
419
+ label = sec.caption
420
+ end
421
+ attrs = {
422
+ number: number,
423
+ title: sec.caption,
424
+ label: label,
425
+ anchor: "h#{number ? number.join('-') : ''}",
426
+ }
427
+ return ["section", attrs, []]
428
+ end
429
+
430
+ end
431
+
432
+
433
+ end