review-retrovert 0.9.10 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +1 -1
  3. data/.gitignore +0 -1
  4. data/.pinact.yaml +12 -0
  5. data/.ruby-version +1 -1
  6. data/Dockerfile +2 -1
  7. data/Dockerfile.local +13 -0
  8. data/Gemfile.lock +62 -35
  9. data/Makefile +7 -0
  10. data/README.md +2 -1
  11. data/Rakefile +9 -0
  12. data/aqua.yaml +20 -0
  13. data/hooks/post_push +14 -1
  14. data/lib/review/retrovert/cli.rb +10 -2
  15. data/lib/review/retrovert/converter.rb +106 -20
  16. data/lib/review/retrovert/reviewdef.rb +29 -0
  17. data/lib/review/retrovert/sty/review-utbook.cls +7 -0
  18. data/lib/review/retrovert/version.rb +1 -1
  19. data/lib/review/retrovert/yamlconfig.rb +38 -1
  20. data/review-retrovert.gemspec +18 -4
  21. data/zizmor.yml +5 -0
  22. metadata +54 -121
  23. data/.github/FUNDING.yml +0 -4
  24. data/.github/workflows/release.yml +0 -26
  25. data/.github/workflows/retrovert.yml +0 -76
  26. data/testdata/mybook/.gitignore +0 -9
  27. data/testdata/mybook/.textlintrc +0 -11
  28. data/testdata/mybook/README.md +0 -43
  29. data/testdata/mybook/Rakefile +0 -24
  30. data/testdata/mybook/catalog.yml +0 -60
  31. data/testdata/mybook/config-noretrovert.yml +0 -404
  32. data/testdata/mybook/config-retrovert.yml +0 -16
  33. data/testdata/mybook/config-starter.yml +0 -264
  34. data/testdata/mybook/config.yml +0 -404
  35. data/testdata/mybook/contents/00-preface.re +0 -129
  36. data/testdata/mybook/contents/01-install.re +0 -305
  37. data/testdata/mybook/contents/02-tutorial.re +0 -1228
  38. data/testdata/mybook/contents/03-syntax.re +0 -4610
  39. data/testdata/mybook/contents/04-customize.re +0 -1064
  40. data/testdata/mybook/contents/05-faq.re +0 -606
  41. data/testdata/mybook/contents/06-bestpractice.re +0 -1343
  42. data/testdata/mybook/contents/91-compare.re +0 -418
  43. data/testdata/mybook/contents/92-filelist.re +0 -125
  44. data/testdata/mybook/contents/93-background.re +0 -267
  45. data/testdata/mybook/contents/99-postface.re +0 -39
  46. data/testdata/mybook/contents/r0-inner.re +0 -2
  47. data/testdata/mybook/contents/r0-root.re +0 -31
  48. data/testdata/mybook/contents/table.csv +0 -4
  49. data/testdata/mybook/contents/test.txt +0 -1
  50. data/testdata/mybook/css/normalize.css +0 -349
  51. data/testdata/mybook/css/webstyle.css +0 -692
  52. data/testdata/mybook/data/terms.txt +0 -3
  53. data/testdata/mybook/data/words.txt +0 -15
  54. data/testdata/mybook/images/03-syntax/favicon-16x16.png +0 -0
  55. data/testdata/mybook/images/03-syntax/figure_heretop.png +0 -0
  56. data/testdata/mybook/images/03-syntax/index-page.png +0 -0
  57. data/testdata/mybook/images/03-syntax/order-detail.png +0 -0
  58. data/testdata/mybook/images/03-syntax/tw-icon1.jpg +0 -0
  59. data/testdata/mybook/images/03-syntax/tw-icon2.jpg +0 -0
  60. data/testdata/mybook/images/03-syntax/tw-icon3.jpg +0 -0
  61. data/testdata/mybook/images/03-syntax/tw-icon4.jpg +0 -0
  62. data/testdata/mybook/images/04-customize/caption_pagebreak.png +0 -0
  63. data/testdata/mybook/images/04-customize/chaptitlepage_sample.png +0 -0
  64. data/testdata/mybook/images/04-customize/section_decoration_samples.png +0 -0
  65. data/testdata/mybook/images/05-faq/codeblock_rpadding1.png +0 -0
  66. data/testdata/mybook/images/05-faq/codeblock_rpadding2.png +0 -0
  67. data/testdata/mybook/images/05-faq/dummy-image.png +0 -0
  68. data/testdata/mybook/images/06-bestpractice/figure_heretop.png +0 -0
  69. data/testdata/mybook/images/06-bestpractice/font_beramono.png +0 -0
  70. data/testdata/mybook/images/06-bestpractice/heading_design1.png +0 -0
  71. data/testdata/mybook/images/06-bestpractice/heading_design2.png +0 -0
  72. data/testdata/mybook/images/06-bestpractice/margin_book.png +0 -0
  73. data/testdata/mybook/images/06-bestpractice/multiline-title.png +0 -0
  74. data/testdata/mybook/images/06-bestpractice/preface_numbered.png +0 -0
  75. data/testdata/mybook/images/06-bestpractice/program_border.png +0 -0
  76. data/testdata/mybook/images/06-bestpractice/sechead_design_4.png +0 -0
  77. data/testdata/mybook/images/06-bestpractice/section_title_wlines.png +0 -0
  78. data/testdata/mybook/images/06-bestpractice/titlepage-samples.png +0 -0
  79. data/testdata/mybook/images/93-background/bug913.png +0 -0
  80. data/testdata/mybook/images/93-background/slide2.png +0 -0
  81. data/testdata/mybook/images/avatar-b.png +0 -0
  82. data/testdata/mybook/images/avatar-g.png +0 -0
  83. data/testdata/mybook/images/avatar-r.png +0 -0
  84. data/testdata/mybook/images/caution-icon.png +0 -0
  85. data/testdata/mybook/images/cover_a5.pdf +0 -0
  86. data/testdata/mybook/images/cover_b5.pdf +0 -0
  87. data/testdata/mybook/images/info-icon.png +0 -0
  88. data/testdata/mybook/images/tw-icon.jpg +0 -0
  89. data/testdata/mybook/images/warning-icon.png +0 -0
  90. data/testdata/mybook/layouts/layout.epub.erb +0 -29
  91. data/testdata/mybook/layouts/layout.html5.erb +0 -108
  92. data/testdata/mybook/layouts/layout.tex.erb +0 -432
  93. data/testdata/mybook/layouts/layout.tex.erb.orig +0 -386
  94. data/testdata/mybook/lib/hooks/beforetexcompile.rb +0 -55
  95. data/testdata/mybook/lib/ruby/review-book.rb +0 -64
  96. data/testdata/mybook/lib/ruby/review-builder.rb +0 -1342
  97. data/testdata/mybook/lib/ruby/review-cli.rb +0 -58
  98. data/testdata/mybook/lib/ruby/review-compiler.rb +0 -1176
  99. data/testdata/mybook/lib/ruby/review-epubbuilder.rb +0 -33
  100. data/testdata/mybook/lib/ruby/review-epubmaker.rb +0 -609
  101. data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +0 -949
  102. data/testdata/mybook/lib/ruby/review-latexbuilder.rb +0 -1065
  103. data/testdata/mybook/lib/ruby/review-maker.rb +0 -346
  104. data/testdata/mybook/lib/ruby/review-markdownbuilder.rb +0 -945
  105. data/testdata/mybook/lib/ruby/review-markdownmaker.rb +0 -91
  106. data/testdata/mybook/lib/ruby/review-monkeypatch.rb +0 -93
  107. data/testdata/mybook/lib/ruby/review-pdfmaker.rb +0 -546
  108. data/testdata/mybook/lib/ruby/review-textbuilder.rb +0 -36
  109. data/testdata/mybook/lib/ruby/review-tocparser.rb +0 -285
  110. data/testdata/mybook/lib/ruby/review-webmaker.rb +0 -448
  111. data/testdata/mybook/lib/tasks/mytasks.rake +0 -31
  112. data/testdata/mybook/lib/tasks/review.rake +0 -156
  113. data/testdata/mybook/lib/tasks/review.rake.orig +0 -72
  114. data/testdata/mybook/lib/tasks/starter.rake +0 -470
  115. data/testdata/mybook/locale.yml +0 -6
  116. data/testdata/mybook/review-ext.rb +0 -206
  117. data/testdata/mybook/sty/indexstyle.ist +0 -25
  118. data/testdata/mybook/sty/jumoline.sty +0 -310
  119. data/testdata/mybook/sty/mycolophon.sty +0 -81
  120. data/testdata/mybook/sty/mystyle.sty +0 -8
  121. data/testdata/mybook/sty/mytextsize.sty +0 -90
  122. data/testdata/mybook/sty/mytitlepage.sty +0 -126
  123. data/testdata/mybook/sty/review-base.sty +0 -276
  124. data/testdata/mybook/sty/reviewmacro.sty +0 -60
  125. data/testdata/mybook/sty/starter-codeblock.sty +0 -463
  126. data/testdata/mybook/sty/starter-color.sty +0 -134
  127. data/testdata/mybook/sty/starter-font.sty +0 -112
  128. data/testdata/mybook/sty/starter-heading.sty +0 -561
  129. data/testdata/mybook/sty/starter-misc.sty +0 -894
  130. data/testdata/mybook/sty/starter-note.sty +0 -180
  131. data/testdata/mybook/sty/starter-section.sty +0 -262
  132. data/testdata/mybook/sty/starter-talklist.sty +0 -105
  133. data/testdata/mybook/sty/starter-toc.sty +0 -72
  134. data/testdata/mybook/sty/starter-util.sty +0 -35
  135. data/testdata/mybook/sty/starter.sty +0 -36
  136. data/testdata/mybook/style.css +0 -597
@@ -1,33 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
-
4
- require 'review/epubbuilder'
5
-
6
-
7
- module ReVIEW
8
-
9
- defined?(EPUBBuilder) or
10
- raise "ReVIEW::EPUBBuilder class not found."
11
-
12
-
13
- class EPUBBuilder
14
-
15
- def target_name
16
- "epub"
17
- end
18
-
19
- def inline_par(arg)
20
- case arg
21
- when 'i'
22
- #"<p class=\"indent\">"
23
- "<p class=\"indent\"></p>" # TODO: (workaround)
24
- else
25
- #"<p>"
26
- "<p></p>" # TODO: (workaround)
27
- end
28
- end
29
-
30
- end
31
-
32
-
33
- end
@@ -1,609 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- #
4
- # Copyright (c) 2010-2017 Kenshi Muto and Masayoshi Takahashi
5
- #
6
- # This program is free software.
7
- # You can distribute or modify this program under the terms of
8
- # the GNU LGPL, Lesser General Public License version 2.1.
9
- # For details of the GNU LGPL, see the file "COPYING".
10
- #
11
-
12
- require 'review/epubmaker'
13
-
14
- require_relative './review-maker'
15
-
16
-
17
- module ReVIEW
18
-
19
-
20
- class EpubMaker < Maker
21
-
22
- SCRIPT_NAME = "review-epubmaker"
23
-
24
- def initialize(config_filename, optional_values={})
25
- super
26
- @htmltoc = nil
27
- @buildlogtxt = 'build-log.txt'
28
- @producer = ::EPUBMaker::Producer.new(@config)
29
- @producer.load(config_filename)
30
- @config = @producer.config
31
- @config.maker = 'epubmaker'
32
- end
33
-
34
- def log(s)
35
- puts s if debug?()
36
- end
37
-
38
- def prepare_build_dir()
39
- dir = "#{@config['bookname']}-epub"
40
- if debug?()
41
- builddir = File.expand_path(dir, Dir.pwd)
42
- FileUtils.rm_rf(builddir, secure: true) if File.exist?(builddir)
43
- FileUtils.mkdir_p(builddir)
44
- else
45
- builddir = Dir.mktmpdir("#{dir}-")
46
- end
47
- #
48
- if @config['imgmath']
49
- math_dir = "./#{@config['imagedir']}/_review_math"
50
- FileUtils.rm_rf(math_dir) if Dir.exist?(math_dir)
51
- end
52
- #
53
- return builddir
54
- end
55
-
56
- def generate()
57
- bookname = @config['bookname']
58
- epubname = "#{bookname}.epub"
59
- booktmpname = "#{bookname}-epub"
60
-
61
- begin
62
- @config.check_version(ReVIEW::VERSION)
63
- rescue ReVIEW::ConfigError => e
64
- warn e.message
65
- end
66
- log("I will produce #{epubname}.")
67
-
68
- FileUtils.rm_f(epubname)
69
-
70
- builddir = prepare_build_dir()
71
- @builddir = builddir
72
- begin
73
- log("Created first temporary directory as #{builddir}.")
74
-
75
- call_hook('hook_beforeprocess')
76
-
77
- @htmltoc = ReVIEW::HTMLToc.new(builddir)
78
- ## copy all files into builddir
79
- copy_stylesheet()
80
-
81
- copy_frontmatter()
82
- call_hook('hook_afterfrontmatter')
83
-
84
- build_body()
85
- call_hook('hook_afterbody')
86
-
87
- copy_backmatter()
88
- call_hook('hook_afterbackmatter')
89
-
90
- ## push contents in builddir into @producer
91
- push_contents()
92
-
93
- imagedir = @config['imagedir']
94
- imagedir_dest = File.join(builddir, imagedir)
95
- if @config['epubmaker']['verify_target_images'].present?
96
- verify_target_images()
97
- copy_images(imagedir, builddir)
98
- else
99
- copy_images(imagedir, imagedir_dest)
100
- end
101
-
102
- copy_resources('covers', imagedir_dest)
103
- copy_resources('adv', imagedir_dest)
104
- copy_resources(@config['fontdir'], "#{builddir}/fonts", @config['font_ext'])
105
-
106
- call_hook('hook_aftercopyimage')
107
-
108
- @producer.import_imageinfo(imagedir_dest, builddir)
109
- @producer.import_imageinfo("#{builddir}/fonts", builddir, @config['font_ext'])
110
-
111
- check_image_size(@config['image_maxpixels'], @config['image_ext'])
112
-
113
- if debug?()
114
- epubtmpdir = File.join(builddir, booktmpname)
115
- FileUtils.mkdir(epubtmpdir)
116
- else
117
- epubtmpdir = nil
118
- end
119
- log('Call ePUB producer.')
120
- @producer.produce(epubname, builddir, epubtmpdir)
121
- log('Finished.')
122
- rescue ApplicationError => ex
123
- raise if debug?()
124
- #error(ex.message)
125
- error(colored_errmsg(ex.message))
126
- ensure
127
- FileUtils.remove_entry_secure(builddir) unless debug?()
128
- end
129
- end
130
-
131
- def call_hook(hook_name)
132
- filename = @config['epubmaker'][hook_name]
133
- log("Call #{hook_name}. (#{filename})")
134
- return unless filename.present?
135
- return unless File.exist?(filename)
136
- return unless FileTest.executable?(filename)
137
- if ENV['REVIEW_SAFE_MODE'].to_i & 0x1 != 0
138
- warn 'hook is prohibited in safe mode. ignored.'
139
- else
140
- system(filename, @builddir)
141
- end
142
- end
143
-
144
- def verify_target_images()
145
- ## なんでメソッド名が「verify_xxx」なのに副作用があるの?アホ?
146
- items = @config['epubmaker']['force_include_images']
147
- @producer.contents.each do |content|
148
- File.open("#{@builddir}/#{content.file}") do |f|
149
- if content.media == 'application/xhtml+xml'
150
- REXML::Document.new(File.new(f)).each_element('//img') do |e|
151
- items << e.attributes['src']
152
- content.properties << 'svg' if e.attributes['src'] =~ /svg\Z/i
153
- end
154
- elsif content.media == 'text/css'
155
- f.each_line do |l|
156
- l.scan(/url\((.+?)\)/) { items << $1.strip }
157
- end
158
- else
159
- end
160
- end
161
- end
162
- @config['epubmaker']['force_include_images'] = items.compact.sort.uniq
163
- end
164
-
165
- def copy_images(resdir, destdir, allow_exts=nil)
166
- return nil unless File.exist?(resdir)
167
- allow_exts ||= @config['image_ext']
168
- FileUtils.mkdir_p(destdir)
169
- if @config['epubmaker']['verify_target_images'].present?
170
- @config['epubmaker']['force_include_images'].each do |file|
171
- unless File.exist?(file)
172
- warn "#{file} is not found, skip." if file !~ /\Ahttp[s]?:/
173
- next
174
- end
175
- basedir = File.dirname(file)
176
- dirpath = "#{destdir}/#{basedir}"
177
- FileUtils.mkdir_p(dirpath)
178
- log("Copy #{file} to the temporary directory.")
179
- FileUtils.cp(file, dirpath)
180
- end
181
- else
182
- recursive_copy_files(resdir, destdir, allow_exts)
183
- end
184
- end
185
-
186
- def copy_resources(resdir, destdir, allow_exts=nil)
187
- return nil unless File.exist?(resdir)
188
- allow_exts ||= @config['image_ext']
189
- FileUtils.mkdir_p(destdir)
190
- recursive_copy_files(resdir, destdir, allow_exts)
191
- end
192
-
193
- def recursive_copy_files(resdir, destdir, allow_exts)
194
- allow_exts_rexp = /\.(#{allow_exts.join('|')})\Z/i
195
- Dir.open(resdir) do |dir|
196
- dir.each do |fname|
197
- srcfile = "#{resdir}/#{fname}"
198
- next if fname.start_with?('.')
199
- if File.directory?(srcfile)
200
- recursive_copy_files(srcfile, "#{destdir}/#{fname}", allow_exts)
201
- elsif fname =~ allow_exts_rexp
202
- FileUtils.mkdir_p(destdir)
203
- log("Copy #{srcfile} to the temporary directory.")
204
- FileUtils.cp(srcfile, destdir)
205
- end
206
- end
207
- end
208
- end
209
-
210
- def check_compile_status
211
- return unless @compile_errors
212
-
213
- $stderr.puts 'compile error, No EPUB file output.'
214
- exit 1
215
- end
216
-
217
- def new_builder()
218
- builder = ReVIEW::EPUBBuilder.new()
219
- builder.starter_config = @starter_config
220
- return builder
221
- end
222
-
223
- def build_body()
224
- @precount = 0
225
- @bodycount = 0
226
- @postcount = 0
227
-
228
- @manifeststr = ''
229
- @ncxstr = ''
230
- @tocdesc = []
231
-
232
- basedir = @basedir
233
- base_path = Pathname.new(basedir)
234
- book = ReVIEW::Book.load(basedir)
235
- book.config = @config
236
- @book = book
237
- @converter = ReVIEW::Converter.new(book, new_builder())
238
- @compile_errors = nil
239
- book.parts.each do |part|
240
- if part.name.present?
241
- if part.file?
242
- build_chap(part, base_path, 'part')
243
- else
244
- htmlfile = "part_#{part.number}.#{@config['htmlext']}"
245
- build_part(part, htmlfile)
246
- title = ReVIEW::I18n.t('part', part.number)
247
- title += ReVIEW::I18n.t('chapter_postfix') + part.name.strip if part.name.strip.present?
248
- @htmltoc.add_item(0, htmlfile, title, chaptype: 'part')
249
- write_buildlogtxt(htmlfile, '')
250
- end
251
- end
252
- #
253
- part.chapters.each do |chap|
254
- build_chap(chap, base_path, nil)
255
- end
256
- end
257
- check_compile_status()
258
- end
259
-
260
- def new_renderer()
261
- return EPUBRenderer.new(@config, @book, @basedir, @starter_config)
262
- end
263
-
264
- def build_part(part, htmlfile)
265
- log("Create #{htmlfile} from a template.")
266
- new_renderer().generate_part_page(part, File.join(@builddir, htmlfile))
267
- end
268
-
269
- def build_chap(chap, base_path, chaptype)
270
- chaptype ||= _chapter_type(chap)
271
- filename = chaptype == 'part' ? chap.path : \
272
- Pathname.new(chap.path).relative_path_from(base_path).to_s
273
- chap_id = _chapter_id(chap, chaptype)
274
- #
275
- htmlfile = "#{chap_id}.#{@config['htmlext']}"
276
- write_buildlogtxt(htmlfile, filename)
277
- log("Create #{htmlfile} from #{filename}.")
278
- #
279
- if (params_str = @config['params']).present?
280
- warn "'params:' in config.yml is obsoleted."
281
- if params_str =~ /stylesheet=/
282
- warn "stylesheets should be defined in 'stylesheet:', not in 'params:'"
283
- end
284
- end
285
- #
286
- begin
287
- @converter.convert(filename, File.join(@builddir, htmlfile))
288
- write_info_body(htmlfile, chaptype)
289
- remove_hidden_title(htmlfile)
290
- ## 文法エラーだけキャッチし、それ以外のエラーはキャッチしないよう変更
291
- #rescue => ex
292
- rescue ApplicationError => ex
293
- @compile_errors = true
294
- warn "compile error in #{filename} (#{ex.class})"
295
- warn colored_errmsg(ex.message)
296
- end
297
- end
298
-
299
- def _chapter_type(chap)
300
- return 'pre' if chap.on_predef?
301
- return 'post' if chap.on_appendix?
302
- return 'body'
303
- end
304
-
305
- def _chapter_id(chap, chaptype)
306
- id = File.basename(chap.path).sub(/\.re\z/, '')
307
- if @config['epubmaker']['rename_for_legacy']
308
- if chaptype == 'part';
309
- elsif chap.on_predef? ; id = 'pre%02d' % (@precount += 1)
310
- elsif chap.on_appendix? ; id = 'post%02d' % (@postcount += 1)
311
- else ; id = 'chap%02d' % (@bodycount += 1)
312
- end
313
- end
314
- return id
315
- end
316
-
317
- def remove_hidden_title(htmlfile)
318
- File.open("#{@builddir}/#{htmlfile}", 'r+') do |f|
319
- html = _remove_hidden_title(f.read())
320
- f.rewind()
321
- f.print(html)
322
- f.truncate(f.tell)
323
- end
324
- end
325
-
326
- def _remove_hidden_title(html)
327
- html = html.gsub(/<h\d .*?hidden=['"]true['"].*?>.*?<\/h\d>\n/, '')
328
- html = html.gsub(/(<h\d .*?)\s*notoc=['"]true['"]\s*(.*?>.*?<\/h\d>\n)/, '\1\2')
329
- return html
330
- end
331
-
332
- def detect_properties(path)
333
- doc = File.open(path, encoding: 'utf-8') {|f| REXML::Document.new(f) }
334
- has_math = REXML::XPath.first(doc, '//m:math', 'm' => 'http://www.w3.org/1998/Math/MathML')
335
- has_svg = REXML::XPath.first(doc, '//s:svg', 's' => 'http://www.w3.org/2000/svg')
336
- properties = []
337
- properties << 'mathml' if has_math
338
- properties << 'svg' if has_svg
339
- return properties
340
- end
341
-
342
- def write_info_body(filename, chaptype)
343
- headlines = []
344
- path = File.join(@builddir, filename)
345
- File.open(path) do |htmlio|
346
- REXML::Document.parse_stream(htmlio, ReVIEWHeaderListener.new(headlines))
347
- end
348
- properties = detect_properties(path)
349
- prop_str = ''
350
- prop_str = ',properties=' + properties.join(' ') if properties.present?
351
- headlines.each_with_index do |headline, i|
352
- headline['level'] = 0 if chaptype == 'part' && headline['level'] == 1
353
- if i == 0
354
- opts = {chaptype: chaptype + prop_str, force_include: true}
355
- _add_headline_item(headline, filename, nil, opts)
356
- else
357
- opts = {chaptype: chaptype}
358
- _add_headline_item(headline, filename, headline['id'], opts)
359
- end
360
- end
361
- end
362
-
363
- def _add_headline_item(headline, filename, id, opts)
364
- opts[:notoc] = headline['notoc']
365
- entry = id ? "#{filename}\##{id}" : filename
366
- @htmltoc.add_item(headline['level'], entry, headline['title'], opts)
367
- end
368
- private :_add_headline_item
369
-
370
- def push_contents()
371
- toclevel = @config['toclevel']
372
- @htmltoc.each_item do |level, file, title, args|
373
- if level.to_i <= toclevel || args[:force_include]
374
- log("Push #{file} to ePUB contents.")
375
- x = nil
376
- hash = {'file'=>file, 'level'=>level.to_i, 'title'=>title, 'chaptype'=>args[:chaptype]}
377
- hash['id'] = x if (x = args[:id]).present?
378
- hash['properties'] = x.split(' ') if (x = args[:properties]).present?
379
- hash['notoc'] = x if (x = args[:notoc]).present?
380
- @producer.contents.push(::EPUBMaker::Content.new(hash))
381
- end
382
- end
383
- end
384
-
385
- def copy_stylesheet()
386
- return if @config['stylesheet'].empty?
387
- @config['stylesheet'].each do |sfile|
388
- FileUtils.cp(sfile, @builddir)
389
- @producer.contents.push(::EPUBMaker::Content.new('file' => sfile))
390
- end
391
- end
392
-
393
- def copy_frontmatter()
394
- cover = @config['cover']
395
- if cover.present?
396
- FileUtils.cp(cover, @builddir) if File.exist?(cover)
397
- end
398
- #
399
- if @config['titlepage']
400
- titlepage = "titlepage.#{@config['htmlext']}"
401
- titlefile = @config['titlefile']
402
- FileUtils.cp(titlefile, @builddir) if titlefile.present?
403
- build_titlepage(titlepage) unless titlefile.present?
404
- _add_pre_item(titlepage, 'titlepagetitle')
405
- end
406
- #
407
- original_titlefile = @config['originaltitlefile']
408
- if original_titlefile.present? && File.exist?(original_titlefile)
409
- FileUtils.cp(original_titlefile, @builddir)
410
- _add_pre_item(original_titlefile, 'originaltitle')
411
- end
412
- #
413
- creditfile = @config['creditfile']
414
- if creditfile.present? && File.exist?(creditfile)
415
- FileUtils.cp(creditfile, @builddir)
416
- _add_pre_item(creditfile, 'credittitle')
417
- end
418
- #
419
- true
420
- end
421
-
422
- def _add_pre_item(filename, key)
423
- @htmltoc.add_item(1, File.basename(filename), @producer.res.v(key), chaptype: 'pre')
424
- end
425
-
426
- def build_titlepage(htmlfile)
427
- # TODO: should be created via epubcommon
428
- new_renderer().generate_title_page("#{@builddir}/#{htmlfile}")
429
- end
430
-
431
- def _join_names(names)
432
- sep = ReVIEW::I18n.t('names_splitter')
433
- return [names].flatten.join(sep)
434
- end
435
-
436
- def copy_backmatter()
437
- if (profile = @config['profile'])
438
- FileUtils.cp(profile, @builddir)
439
- _add_post_item(profile, 'profiletitle')
440
- end
441
- #
442
- if (advfile = @config['advfile'])
443
- FileUtils.cp(advfile, @builddir)
444
- _add_post_item(advfile, 'advtitle')
445
- end
446
- #
447
- if (colophon = @config['colophon'])
448
- colophon_page = File.join(@builddir, "colophon.#{@config['htmlext']}")
449
- if colophon.is_a?(String) # FIXME: should let obsolete this style?
450
- FileUtils.cp(colophon, colophon_page)
451
- else
452
- File.open(colophon_page, 'w') {|f| @producer.colophon(f) }
453
- end
454
- _add_post_item(colophon_page, 'colophontitle')
455
- end
456
- #
457
- if (backcover = @config['backcover'])
458
- FileUtils.cp(backcover, @builddir)
459
- _add_post_item(backcover, 'backcovertitle')
460
- end
461
- #
462
- true
463
- end
464
-
465
- def _add_post_item(filename, key)
466
- @htmltoc.add_item(1, File.basename(filename), @producer.res.v(key), chaptype: 'post')
467
- end
468
-
469
- def write_buildlogtxt(htmlfile, reviewfile)
470
- File.open("#{@builddir}/#{@buildlogtxt}", 'a') { |f| f.puts "#{htmlfile},#{reviewfile}" }
471
- end
472
-
473
- def check_image_size(maxpixels, allow_exts = nil)
474
- begin
475
- require 'image_size'
476
- rescue LoadError
477
- return nil
478
- end
479
- require 'find'
480
- allow_exts ||= @config['image_ext']
481
-
482
- extre = Regexp.new('\\.(' + allow_exts.delete_if { |t| %w[ttf woff otf].include?(t) }.join('|') + ')', Regexp::IGNORECASE)
483
- Find.find(@builddir) do |fname|
484
- next unless fname.match(extre)
485
- img = ImageSize.path(fname)
486
- next if img.width.nil? || img.width * img.height <= maxpixels
487
- h = Math.sqrt(img.height * maxpixels / img.width)
488
- w = maxpixels / h
489
- fname.sub!("#{@builddir}/", '')
490
- warn "#{fname}: #{img.width}x#{img.height} exceeds a limit. suggeted value is #{w.to_i}x#{h.to_i}"
491
- end
492
-
493
- true
494
- end
495
-
496
-
497
- class EPUBRenderer < BaseRenderer
498
-
499
- def initialize(config, book, basedir, starter_config)
500
- super
501
- @language = @config['language']
502
- @stylesheets = @config['stylesheet']
503
- end
504
-
505
- protected
506
-
507
- def layout_template_name()
508
- #if @config['htmlversion'].to_i == 5
509
- # './html/layout-html5.html.erb'
510
- #else
511
- # './html/layout-xhtml1.html.erb'
512
- #end
513
- "layout.epub.erb"
514
- end
515
-
516
- def escape(s)
517
- return CGI.escapeHTML(s)
518
- end
519
-
520
- public
521
-
522
- def generate_title_page(filepath)
523
- c = @config
524
- title = escape(c.name_of('booktitle'))
525
- body = []
526
- body << "<div class=\"titlepage\">\n"
527
- body << "<h1 class=\"tp-title\">#{escape c.name_of('booktitle')}</h1>\n"
528
- body << "<h2 class=\"tp-subtitle\">#{escape c.name_of('subtitle')}</h2>\n" if c['subtitle']
529
- body << "<h2 class=\"tp-author\">#{escape _join_names(c.names_of('aut'))}</h2>\n" if c['aut']
530
- body << "<h3 class=\"tp-publisher\">#{escape _join_names(c.names_of('pbl'))}</h3>\n" if c['pbl']
531
- body << "</div>"
532
- generate_file(filepath, {title: title, body: body.join()})
533
- end
534
-
535
- def generate_part_page(part, filepath)
536
- part_number = i18n('part', part.number)
537
- part_name = part.name.strip()
538
- body = []
539
- body << "<div class=\"part\">\n"
540
- body << "<h1 class=\"part-number\">#{escape part_number}</h1>\n"
541
- body << "<h2 class=\"part-title\">#{escape part_name}</h2>\n" if part_name.present?
542
- body << "</div>\n"
543
- generate_file(filepath, {body: body.join()})
544
- end
545
-
546
- private
547
-
548
- def _join_names(names)
549
- sep = i18n('names_splitter')
550
- return [names].flatten.join(sep)
551
- end
552
-
553
- end
554
-
555
-
556
- class ReVIEWHeaderListener
557
- include REXML::StreamListener
558
-
559
- def initialize(headlines)
560
- @headlines = headlines
561
- _clear()
562
- end
563
-
564
- def _clear()
565
- @content = ''
566
- @level = nil
567
- @id = nil
568
- @notoc = nil
569
- end
570
- private :_clear
571
-
572
- HEADING_REXP = /\Ah(\d+)\z/
573
-
574
- def tag_start(name, attrs)
575
- v = nil
576
- if name =~ HEADING_REXP
577
- raise "#{name}, #{attrs}" if @level.present?
578
- @level = $1.to_i
579
- @id = v if (v = attrs['id']).present?
580
- @notoc = v if (v = attrs['notoc']).present?
581
- elsif @level
582
- if name == 'img'
583
- @content << v if (v = attrs['alt']).present?
584
- elsif name == 'a'
585
- @id = v if (v = attrs['id']).present?
586
- end
587
- end
588
- end
589
-
590
- def tag_end(name)
591
- if name =~ HEADING_REXP
592
- if @id
593
- attrs = {'level'=>@level, 'id'=>@id, 'title'=>@content, 'notoc'=>@notoc}
594
- @headlines.push(attrs)
595
- end
596
- _clear()
597
- end
598
- true
599
- end
600
-
601
- def text(text)
602
- @content << text.gsub("\t", ' ') if @level
603
- end
604
-
605
- end
606
-
607
- end
608
-
609
- end