burr 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.md +30 -0
- data/README.md +180 -0
- data/Rakefile +118 -0
- data/bin/burr +9 -0
- data/burr.gemspec +36 -0
- data/generators/Gemfile.txt +3 -0
- data/generators/config.yml +55 -0
- data/generators/contents/chapter1.md +7 -0
- data/generators/contents/chapter2.md +7 -0
- data/generators/stylesheets/pdf.css +569 -0
- data/generators/stylesheets/site.css +1 -0
- data/lib/burr.rb +56 -0
- data/lib/burr/book.rb +289 -0
- data/lib/burr/cli.rb +64 -0
- data/lib/burr/converter.rb +19 -0
- data/lib/burr/core_ext/blank.rb +107 -0
- data/lib/burr/dependency.rb +28 -0
- data/lib/burr/eeepub_ext/maker.rb +131 -0
- data/lib/burr/exporter.rb +137 -0
- data/lib/burr/exporters/epub.rb +163 -0
- data/lib/burr/exporters/pdf.rb +95 -0
- data/lib/burr/exporters/site.rb +101 -0
- data/lib/burr/generator.rb +41 -0
- data/lib/burr/kramdown_ext/converter.rb +145 -0
- data/lib/burr/kramdown_ext/options.rb +38 -0
- data/lib/burr/kramdown_ext/parser.rb +65 -0
- data/lib/burr/liquid_ext/block.rb +58 -0
- data/lib/burr/liquid_ext/extends.rb +114 -0
- data/lib/burr/plugin.rb +70 -0
- data/lib/burr/plugins/aside.rb +44 -0
- data/lib/burr/plugins/codeblock.rb +42 -0
- data/lib/burr/plugins/figure.rb +62 -0
- data/lib/burr/plugins/link.rb +47 -0
- data/lib/burr/plugins/parser_plugin.rb +18 -0
- data/lib/burr/plugins/table.rb +42 -0
- data/lib/burr/plugins/toc.rb +105 -0
- data/lib/burr/ruby_version_check.rb +4 -0
- data/lib/burr/server.rb +27 -0
- data/lib/burr/ui.rb +46 -0
- data/lib/burr/version.rb +8 -0
- data/resources/locales/labels/en.yml +45 -0
- data/resources/locales/labels/zh_CN.yml +46 -0
- data/resources/locales/titles/en.yml +21 -0
- data/resources/locales/titles/zh_CN.yml +21 -0
- data/resources/templates/epub/_layout.liquid +17 -0
- data/resources/templates/epub/acknowledgement.liquid +10 -0
- data/resources/templates/epub/afterword.liquid +10 -0
- data/resources/templates/epub/appendix.liquid +10 -0
- data/resources/templates/epub/author.liquid +10 -0
- data/resources/templates/epub/chapter.liquid +10 -0
- data/resources/templates/epub/conclusion.liquid +10 -0
- data/resources/templates/epub/cover.liquid +9 -0
- data/resources/templates/epub/dedication.liquid +10 -0
- data/resources/templates/epub/edition.liquid +1 -0
- data/resources/templates/epub/epilogue.liquid +1 -0
- data/resources/templates/epub/foreword.liquid +10 -0
- data/resources/templates/epub/glossary.liquid +1 -0
- data/resources/templates/epub/introduction.liquid +1 -0
- data/resources/templates/epub/license.liquid +1 -0
- data/resources/templates/epub/lof.liquid +24 -0
- data/resources/templates/epub/lot.liquid +24 -0
- data/resources/templates/epub/part.liquid +4 -0
- data/resources/templates/epub/preface.liquid +10 -0
- data/resources/templates/epub/prologue.liquid +1 -0
- data/resources/templates/epub/table.liquid +7 -0
- data/resources/templates/epub/title.liquid +3 -0
- data/resources/templates/epub/toc.liquid +10 -0
- data/resources/templates/pdf/_item.liquid +6 -0
- data/resources/templates/pdf/acknowledgement.liquid +1 -0
- data/resources/templates/pdf/afterword.liquid +1 -0
- data/resources/templates/pdf/appendix.liquid +4 -0
- data/resources/templates/pdf/author.liquid +1 -0
- data/resources/templates/pdf/blank.liquid +3 -0
- data/resources/templates/pdf/book.liquid +42 -0
- data/resources/templates/pdf/chapter.liquid +4 -0
- data/resources/templates/pdf/code.liquid +3 -0
- data/resources/templates/pdf/conclusion.liquid +1 -0
- data/resources/templates/pdf/cover.liquid +6 -0
- data/resources/templates/pdf/dedication.liquid +3 -0
- data/resources/templates/pdf/edition.liquid +1 -0
- data/resources/templates/pdf/epilogue.liquid +1 -0
- data/resources/templates/pdf/foreword.liquid +1 -0
- data/resources/templates/pdf/glossary.liquid +1 -0
- data/resources/templates/pdf/introduction.liquid +1 -0
- data/resources/templates/pdf/license.liquid +1 -0
- data/resources/templates/pdf/lof.liquid +24 -0
- data/resources/templates/pdf/lot.liquid +24 -0
- data/resources/templates/pdf/part.liquid +4 -0
- data/resources/templates/pdf/preface.liquid +1 -0
- data/resources/templates/pdf/prologue.liquid +1 -0
- data/resources/templates/pdf/table.liquid +7 -0
- data/resources/templates/pdf/title.liquid +3 -0
- data/resources/templates/pdf/toc.liquid +4 -0
- data/resources/templates/site/_layout.liquid +27 -0
- data/resources/templates/site/author.liquid +13 -0
- data/resources/templates/site/chapter.liquid +13 -0
- data/resources/templates/site/foreword.liquid +13 -0
- data/resources/templates/site/preface.liquid +13 -0
- metadata +232 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Burr
|
|
2
|
+
module Dependency
|
|
3
|
+
|
|
4
|
+
# Checks if PrinceXML installed.
|
|
5
|
+
#
|
|
6
|
+
# Returns true if installed, otherwise false.
|
|
7
|
+
def self.prince_installed?
|
|
8
|
+
installed? 'prince'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.kindlegen_installed?
|
|
12
|
+
installed? 'kindlegen'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Checks if Dependent libx installed.
|
|
16
|
+
#
|
|
17
|
+
# Returns true if installed, otherwise false.
|
|
18
|
+
def self.installed?(cmd)
|
|
19
|
+
return true if which(cmd)
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Finds the executable.
|
|
24
|
+
def self.which(cmd)
|
|
25
|
+
system "which #{cmd} > /dev/null 2>&1"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Custom the eeepub maker.
|
|
2
|
+
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module Burr
|
|
7
|
+
class EpubMaker
|
|
8
|
+
[
|
|
9
|
+
:title,
|
|
10
|
+
:creator,
|
|
11
|
+
:publisher,
|
|
12
|
+
:date,
|
|
13
|
+
:language,
|
|
14
|
+
:subject,
|
|
15
|
+
:description,
|
|
16
|
+
:rights,
|
|
17
|
+
:relation
|
|
18
|
+
].each do |name|
|
|
19
|
+
class_eval <<-DELIM
|
|
20
|
+
def #{name}(value)
|
|
21
|
+
@#{name}s ||= []
|
|
22
|
+
@#{name}s << value
|
|
23
|
+
end
|
|
24
|
+
DELIM
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
[
|
|
28
|
+
:uid,
|
|
29
|
+
:files,
|
|
30
|
+
:nav,
|
|
31
|
+
:cover,
|
|
32
|
+
:ncx_file,
|
|
33
|
+
:opf_file,
|
|
34
|
+
:guide
|
|
35
|
+
].each do |name|
|
|
36
|
+
define_method(name) do |arg|
|
|
37
|
+
instance_variable_set("@#{name}", arg)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def identifier(id, options)
|
|
42
|
+
@identifiers ||= []
|
|
43
|
+
@identifiers << {:value => id, :scheme => options[:scheme], :id => options[:id]}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param [Proc] block the block for initialize
|
|
47
|
+
def initialize(&block)
|
|
48
|
+
@files ||= []
|
|
49
|
+
@nav ||= []
|
|
50
|
+
@ncx_file ||= 'toc.ncx'
|
|
51
|
+
@opf_file ||= 'content.opf'
|
|
52
|
+
|
|
53
|
+
instance_eval(&block) if block_given?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Save as ePub file
|
|
57
|
+
#
|
|
58
|
+
# @param [String] filename the ePub file name to save
|
|
59
|
+
def save(filename)
|
|
60
|
+
create_epub.save(filename)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# instead of saving to file, output the file contents.
|
|
64
|
+
# important for serving on-the-fly doc creation from
|
|
65
|
+
# web interface where we don't want to allow file system
|
|
66
|
+
# writes (Heroku, et al.)
|
|
67
|
+
def render
|
|
68
|
+
create_epub.render
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def create_epub
|
|
74
|
+
@uid ||= 'BookId'
|
|
75
|
+
unique_identifier = @identifiers.select{ |i| i[:id] == @uid }.first
|
|
76
|
+
unless unique_identifier
|
|
77
|
+
unique_identifier = @identifiers.first
|
|
78
|
+
unique_identifier[:id] = @uid
|
|
79
|
+
end
|
|
80
|
+
dir = Dir.mktmpdir
|
|
81
|
+
@files.each do |file|
|
|
82
|
+
case file
|
|
83
|
+
when String
|
|
84
|
+
FileUtils.cp(file, dir)
|
|
85
|
+
when Hash
|
|
86
|
+
file_path, dir_path = *file.first
|
|
87
|
+
dest_dir = File.join(dir, dir_path)
|
|
88
|
+
FileUtils.mkdir_p(dest_dir)
|
|
89
|
+
FileUtils.cp(file_path, dest_dir)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
::EeePub::NCX.new(
|
|
94
|
+
:uid => @identifiers.select{ |i| i[:id] == @uid }.first,
|
|
95
|
+
:title => @titles[0],
|
|
96
|
+
:nav => @nav
|
|
97
|
+
).save(File.join(dir, @ncx_file))
|
|
98
|
+
|
|
99
|
+
::EeePub::OPF.new(
|
|
100
|
+
:title => @titles,
|
|
101
|
+
:unique_identifier => @uid,
|
|
102
|
+
:identifier => @identifiers,
|
|
103
|
+
:creator => @creators,
|
|
104
|
+
:publisher => @publishers,
|
|
105
|
+
:date => @dates,
|
|
106
|
+
:language => @languages,
|
|
107
|
+
:subject => @subjects,
|
|
108
|
+
:description => @descriptions,
|
|
109
|
+
:rights => @rightss,
|
|
110
|
+
:cover => @cover,
|
|
111
|
+
:relation => @relations,
|
|
112
|
+
:manifest => @files.map{|file|
|
|
113
|
+
case file
|
|
114
|
+
when String
|
|
115
|
+
File.basename(file)
|
|
116
|
+
when Hash
|
|
117
|
+
file_path, dir_path = *file.first
|
|
118
|
+
File.join(dir_path, File.basename(file_path))
|
|
119
|
+
end
|
|
120
|
+
},
|
|
121
|
+
:ncx => @ncx_file,
|
|
122
|
+
:guide => @guide
|
|
123
|
+
).save(File.join(dir, @opf_file))
|
|
124
|
+
|
|
125
|
+
::EeePub::OCF.new(
|
|
126
|
+
:dir => dir,
|
|
127
|
+
:container => @opf_file
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module Burr
|
|
2
|
+
class Exporter
|
|
3
|
+
|
|
4
|
+
FRONTMATTER = %w(acknowledgement author cover dedication edition foreword
|
|
5
|
+
introduction license preface prologue title toc)
|
|
6
|
+
BODYMATTER = %w(appendix blank chapter conclusion part)
|
|
7
|
+
BACKMATTER = %w(afterword epilogue glossary lof lot)
|
|
8
|
+
|
|
9
|
+
attr_accessor :book, :config
|
|
10
|
+
attr_accessor :frontmatter, :bodymatter, :backmatter
|
|
11
|
+
|
|
12
|
+
def initialize(book)
|
|
13
|
+
@book = book
|
|
14
|
+
@config = book.config
|
|
15
|
+
|
|
16
|
+
@frontmatter = []
|
|
17
|
+
@bodymatter = []
|
|
18
|
+
@backmatter = []
|
|
19
|
+
|
|
20
|
+
prepare_output_dir
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Run all hooks of a type.
|
|
24
|
+
#
|
|
25
|
+
# type - The plugin name in Symbol, valid options are: :before_parse, :after_parse
|
|
26
|
+
# :before_decorate, :after_decorate.
|
|
27
|
+
#
|
|
28
|
+
# Returns nothing.
|
|
29
|
+
def run_plugins_of_type(type)
|
|
30
|
+
type = type.to_sym
|
|
31
|
+
|
|
32
|
+
Burr::Plugin.subclasses.each do |k|
|
|
33
|
+
k_obj = k.new(self.book)
|
|
34
|
+
Burr::Plugin::VALIDS.each do |h|
|
|
35
|
+
k_obj.send(type) if k_obj.respond_to?(h) && h == type
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Run exporter.
|
|
43
|
+
#
|
|
44
|
+
# The details should implement in subclass.
|
|
45
|
+
def run
|
|
46
|
+
self.load_contents
|
|
47
|
+
self.parse_contents
|
|
48
|
+
self.decorate_contents
|
|
49
|
+
self.assemble_book
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Load book contents
|
|
53
|
+
def load_contents
|
|
54
|
+
special_elements = %w(cover toc blank)
|
|
55
|
+
|
|
56
|
+
self.config['contents'].each do |content_config|
|
|
57
|
+
item = initialize_item(content_config)
|
|
58
|
+
|
|
59
|
+
# if the element defines its own content file (usually: `chapter`, `appendix`)
|
|
60
|
+
if !item['file'].blank?
|
|
61
|
+
content_file = File.join(self.book.contents_dir, item['file'])
|
|
62
|
+
|
|
63
|
+
# check that content file exists and is readable
|
|
64
|
+
if !File.readable? content_file
|
|
65
|
+
raise <<-MESSAGE % content_config['file'], item['element'], "outputs/#{content_config['file']}"
|
|
66
|
+
The '%s' content associated with '%s' element doesn't exist\n
|
|
67
|
+
or is not readable.\n\n
|
|
68
|
+
Check that '%s'\n
|
|
69
|
+
file exists and check its permissions.
|
|
70
|
+
MESSAGE
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
item['original'] = File.read(content_file)
|
|
74
|
+
elsif item['file'].blank? && special_elements.include?(item['element'])
|
|
75
|
+
item['skip'] = true
|
|
76
|
+
else
|
|
77
|
+
# look for a default content defined by burr for this element
|
|
78
|
+
# e.g. `cover.md`, `license.md`, `title.md`
|
|
79
|
+
default_content_file = File.join(self.book.contents_dir, "#{item['element']}.md")
|
|
80
|
+
if File.exist?(default_content_file)
|
|
81
|
+
item['original'] = File.read(default_content_file)
|
|
82
|
+
else
|
|
83
|
+
self.book.ui.error("Missing file for #{item['element']}")
|
|
84
|
+
exit 1
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
self.frontmatter << item if item['matter'] == 'frontmatter'
|
|
89
|
+
self.bodymatter << item if item['matter'] == 'bodymatter'
|
|
90
|
+
self.backmatter << item if item['matter'] == 'backmatter'
|
|
91
|
+
self.book.items << item
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def initialize_item(configs)
|
|
98
|
+
item = {
|
|
99
|
+
'element' => '', # the type of this content (`chapter', `appendix', `toc', `license', ...)
|
|
100
|
+
'number' => '', # the number/letter of the content (useful for `chapter', `part' and `appendix')
|
|
101
|
+
'c_title' => '', # the title of the content defined in `config.yml' (usually only `part' defines it)
|
|
102
|
+
'title' => '', # the `title' of this file, the first h1 in `content'
|
|
103
|
+
'original' => '', # original content as written by book author
|
|
104
|
+
'content' => '', # transformed content of the element (HTML usually)
|
|
105
|
+
'file' => '', # the name of this item contents file (it's a relative path from book's `contents/')
|
|
106
|
+
'toc' => [], # the table of contents of this element
|
|
107
|
+
'skip' => false, # some elements, like `toc', do not need to covert, so just skip
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
item.merge!(configs)
|
|
111
|
+
|
|
112
|
+
# set the matter
|
|
113
|
+
if FRONTMATTER.include?(item['element'])
|
|
114
|
+
item['matter'] = 'frontmatter'
|
|
115
|
+
elsif BODYMATTER.include?(item['element'])
|
|
116
|
+
item['matter'] = 'bodymatter'
|
|
117
|
+
elsif BACKMATTER.include?(item['element'])
|
|
118
|
+
item['matter'] = 'backmatter'
|
|
119
|
+
else
|
|
120
|
+
self.book.ui.error("Element #{ item['element'] } not defined!")
|
|
121
|
+
exit 1
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
item
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# If the outpus directory for current format not exists, create it!
|
|
128
|
+
#
|
|
129
|
+
def prepare_output_dir
|
|
130
|
+
dir = File.join(self.book.outputs_dir, self.book.format)
|
|
131
|
+
if !File.exist?(dir)
|
|
132
|
+
FileUtils.mkdir_p dir
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
module Burr
|
|
2
|
+
class Epub < Exporter
|
|
3
|
+
|
|
4
|
+
# Convert original contents into HTML
|
|
5
|
+
#
|
|
6
|
+
def parse_contents
|
|
7
|
+
parsed_items = []
|
|
8
|
+
self.book.items.each do |item|
|
|
9
|
+
self.book.current_item = item
|
|
10
|
+
|
|
11
|
+
# 'blank' element not include in epub
|
|
12
|
+
next if item['element'] == 'blank'
|
|
13
|
+
|
|
14
|
+
self.run_plugins_of_type(:before_parse)
|
|
15
|
+
|
|
16
|
+
unless item['skip']
|
|
17
|
+
item['content'] = Burr::Converter.new(self.book).convert(item['original'])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
self.run_plugins_of_type(:after_parse)
|
|
21
|
+
|
|
22
|
+
parsed_items << self.book.current_item
|
|
23
|
+
end
|
|
24
|
+
self.book.items = parsed_items
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Decorate the contents with template
|
|
28
|
+
#
|
|
29
|
+
def decorate_contents
|
|
30
|
+
decorated_items = []
|
|
31
|
+
self.book.items.each do |item|
|
|
32
|
+
self.book.current_item = item
|
|
33
|
+
self.run_plugins_of_type(:before_decorate)
|
|
34
|
+
self.run_plugins_of_type(:after_decorate)
|
|
35
|
+
decorated_items << self.book.current_item
|
|
36
|
+
end
|
|
37
|
+
self.book.items = decorated_items
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def assemble_book
|
|
41
|
+
# 1. create html files
|
|
42
|
+
special_elements = %w(blank)
|
|
43
|
+
base = File.join(self.book.outputs_dir, 'epub')
|
|
44
|
+
included_files = []
|
|
45
|
+
tmp_files = []
|
|
46
|
+
|
|
47
|
+
self.book.items.each do |item|
|
|
48
|
+
next if special_elements.include?(item['element'])
|
|
49
|
+
|
|
50
|
+
basename = if item['file'].blank?
|
|
51
|
+
item['element']
|
|
52
|
+
else
|
|
53
|
+
item['file'].split('.')[0..-2].join('.')
|
|
54
|
+
end
|
|
55
|
+
html_path = File.join(base, "#{ basename }.html")
|
|
56
|
+
included_files << html_path
|
|
57
|
+
tmp_files << html_path
|
|
58
|
+
|
|
59
|
+
File.open(html_path, 'w') do |f|
|
|
60
|
+
f.puts self.book.render(self.book.template_for(item['element']), { 'item' => item, 'toc' => html_toc })
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# 2. add other files
|
|
65
|
+
included_files << File.join(base, 'style.css')
|
|
66
|
+
Dir.glob(File.join(self.book.outputs_dir, 'site', 'figures', '*.*')) do |figure|
|
|
67
|
+
included_files << { figure => 'figures' }
|
|
68
|
+
end
|
|
69
|
+
included_files << File.join(base, 'cover.jpg')
|
|
70
|
+
|
|
71
|
+
# 3. build epub file
|
|
72
|
+
config = self.book.config
|
|
73
|
+
nav = ncx_toc
|
|
74
|
+
guide = build_guide
|
|
75
|
+
|
|
76
|
+
epub = Burr::EpubMaker.new do
|
|
77
|
+
title config['title']
|
|
78
|
+
creator config['translator'].blank? ? config['author'] : config['translator']
|
|
79
|
+
publisher config['publisher']
|
|
80
|
+
date config['pubdate']
|
|
81
|
+
identifier config['identifier'], :scheme => config['id_scheme'], :id => config['slug']
|
|
82
|
+
uid config['slug']
|
|
83
|
+
language config['language']
|
|
84
|
+
cover 'cover.jpg'
|
|
85
|
+
|
|
86
|
+
files included_files
|
|
87
|
+
nav nav
|
|
88
|
+
guide guide
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
epub.save(File.join(base, "#{self.book.config['slug']}-#{Time.new.strftime('%Y%m%d')}.epub"))
|
|
92
|
+
|
|
93
|
+
# 4. remove useless files
|
|
94
|
+
tmp_files.each do |file|
|
|
95
|
+
FileUtils.remove_entry(file)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def ncx_toc
|
|
102
|
+
nav = []
|
|
103
|
+
self.book.items.each do |item|
|
|
104
|
+
special_elements = %w(cover toc blank)
|
|
105
|
+
next if special_elements.include?(item['element'])
|
|
106
|
+
level_1 = item['toc'].first
|
|
107
|
+
next unless level_1['level'] == 1
|
|
108
|
+
basename = if item['file'].blank?
|
|
109
|
+
item['element']
|
|
110
|
+
else
|
|
111
|
+
item['file'].split('.')[0..-2].join('.')
|
|
112
|
+
end
|
|
113
|
+
html_path = "#{ basename }.html"
|
|
114
|
+
nav_label = if level_1['label'].blank?
|
|
115
|
+
"#{level_1['title']}"
|
|
116
|
+
else
|
|
117
|
+
"#{level_1['label']} #{level_1['title']}"
|
|
118
|
+
end
|
|
119
|
+
nav << { :label => nav_label, :content => html_path }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
nav
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def html_toc
|
|
126
|
+
html = '<ol class="toc-list">'
|
|
127
|
+
self.book.items.each do |item|
|
|
128
|
+
# editions define the *tocable* items
|
|
129
|
+
if self.book.config['formats']['epub']['toc']['elements'].include?(item['element'])
|
|
130
|
+
# item has several elements in its toc
|
|
131
|
+
if item['toc'].size > 0
|
|
132
|
+
item['toc'].each do |entry|
|
|
133
|
+
if entry['level'] <= self.book.config['formats'][self.book.format]['toc']['deep']
|
|
134
|
+
anchor = "#{item['element']}#{entry['id'].split('-')[1]}.html"
|
|
135
|
+
html << <<-LI1
|
|
136
|
+
<li class="#{ item['matter'] } #{ item['element'] } level-#{ entry['level'] }">
|
|
137
|
+
<a href="#{ anchor }##{ entry['id']}">#{ entry['label'] } #{ entry['title'] }</a>
|
|
138
|
+
</li>
|
|
139
|
+
LI1
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# empty or special item (anything different from 'chapter' and 'appendix')
|
|
145
|
+
elsif !%w(cover blank toc).include?(item['element'])
|
|
146
|
+
html << <<-LI2
|
|
147
|
+
<li class="#{ item['matter'] } #{ item['element'] } level-1">
|
|
148
|
+
<a href="#{ item['id'] }.html">#{ item['title'] }</a>
|
|
149
|
+
</li>
|
|
150
|
+
LI2
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
html << '</ol>'
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def build_guide
|
|
157
|
+
o = []
|
|
158
|
+
o << { :type => 'toc', :href => "toc.html", :title => 'Table of Contents' }
|
|
159
|
+
o << { :type => 'cover', :href => "cover.html", :title => 'Cover' }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
end
|