kitabu 2.0.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +61 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +17 -0
- data/CHANGELOG.md +34 -1
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +2 -0
- data/LICENSE.md +20 -0
- data/README.md +121 -85
- data/Rakefile +7 -0
- data/bin/kitabu +4 -0
- data/kitabu.gemspec +20 -14
- data/lib/kitabu/cli.rb +54 -39
- data/lib/kitabu/dependency.rb +11 -5
- data/lib/kitabu/errors.rb +2 -0
- data/lib/kitabu/exporter/base.rb +13 -11
- data/lib/kitabu/exporter/css.rb +6 -14
- data/lib/kitabu/exporter/epub.rb +24 -18
- data/lib/kitabu/exporter/html.rb +33 -20
- data/lib/kitabu/exporter/mobi.rb +7 -1
- data/lib/kitabu/exporter/pdf.rb +9 -3
- data/lib/kitabu/exporter.rb +15 -16
- data/lib/kitabu/extensions/rouge.rb +7 -1
- data/lib/kitabu/extensions/string.rb +5 -3
- data/lib/kitabu/footnotes/base.rb +2 -0
- data/lib/kitabu/footnotes/html.rb +19 -12
- data/lib/kitabu/footnotes/pdf.rb +17 -11
- data/lib/kitabu/generator.rb +16 -8
- data/lib/kitabu/helpers.rb +12 -9
- data/lib/kitabu/markdown.rb +12 -10
- data/lib/kitabu/source_list.rb +15 -12
- data/lib/kitabu/stats.rb +3 -1
- data/lib/kitabu/syntax/highlight.rb +4 -11
- data/lib/kitabu/toc/epub.rb +5 -2
- data/lib/kitabu/toc/html/stream.rb +33 -0
- data/lib/kitabu/toc/html.rb +19 -9
- data/lib/kitabu/version.rb +4 -2
- data/lib/kitabu.rb +11 -12
- data/spec/kitabu/cli/export_spec.rb +6 -4
- data/spec/kitabu/cli/new_spec.rb +6 -4
- data/spec/kitabu/cli/permalinks_spec.rb +4 -2
- data/spec/kitabu/cli/stats_spec.rb +19 -15
- data/spec/kitabu/cli/version_spec.rb +3 -1
- data/spec/kitabu/exporter/css_spec.rb +3 -1
- data/spec/kitabu/exporter/epub_spec.rb +2 -0
- data/spec/kitabu/exporter/html_spec.rb +17 -4
- data/spec/kitabu/exporter/mobi_spec.rb +5 -5
- data/spec/kitabu/exporter/pdf_spec.rb +8 -4
- data/spec/kitabu/extensions/string_spec.rb +14 -9
- data/spec/kitabu/footnotes/html_spec.rb +38 -28
- data/spec/kitabu/generator_spec.rb +3 -1
- data/spec/kitabu/markdown_spec.rb +15 -3
- data/spec/kitabu/source_list_spec.rb +8 -2
- data/spec/kitabu/stats_spec.rb +10 -6
- data/spec/kitabu/toc/html_spec.rb +55 -35
- data/spec/spec_helper.rb +23 -8
- data/spec/support/exit_with_code.rb +7 -5
- data/spec/support/have_tag.rb +44 -32
- data/spec/support/helper.rb +5 -3
- data/spec/support/mybook/code/code.rb +2 -0
- data/spec/support/mybook/config/helper.rb +2 -0
- data/spec/support/mybook/fonts/OpenSans-CondBold.ttf +0 -0
- data/spec/support/shared.rb +12 -6
- data/templates/Gemfile +5 -3
- data/templates/Guardfile +3 -1
- data/templates/helper.rb +8 -6
- data/templates/templates/styles/epub.css +1 -0
- data/templates/templates/styles/files/normalize.css +351 -0
- data/templates/templates/styles/{html.scss → html.css} +28 -26
- data/templates/templates/styles/{pdf.scss → pdf.css} +49 -47
- data/templates/templates/styles/print.css +2 -0
- data/templates/text/01_Getting_Started.md +27 -9
- data/templates/text/02_Creating_Chapters.md +9 -3
- data/templates/text/{03_Syntax_Highlighting.erb → 03_Syntax_Highlighting.md.erb} +12 -7
- data/templates/text/04_Dynamic_Content.md.erb +48 -0
- data/templates/text/05_Exporting_Files.md +17 -8
- metadata +42 -50
- data/.gitmodules +0 -3
- data/.travis.yml +0 -18
- data/Gemfile.lock +0 -108
- data/lib/kitabu/exporter/txt.rb +0 -18
- data/lib/kitabu/stream.rb +0 -27
- data/lib/kitabu/toc.rb +0 -6
- data/spec/kitabu/exporter/txt_spec.rb +0 -14
- data/templates/ebook.png +0 -0
- data/templates/templates/styles/epub.scss +0 -1
- data/templates/templates/styles/files/_normalize.scss +0 -427
- data/templates/templates/styles/print.scss +0 -2
- data/templates/text/04_Dynamic_Content.erb +0 -64
data/lib/kitabu/exporter/epub.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
class Exporter
|
3
5
|
class Epub < Base
|
4
6
|
def sections
|
5
|
-
@sections ||=
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
@sections ||=
|
8
|
+
html.css("div.chapter").each_with_index.map do |chapter, index|
|
9
|
+
OpenStruct.new(
|
10
|
+
index: index,
|
11
|
+
filename: "section_#{index}.html",
|
12
|
+
filepath: tmp_dir.join("section_#{index}.html").to_s,
|
13
|
+
html: Nokogiri::HTML(chapter.inner_html)
|
14
|
+
)
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def epub
|
@@ -34,7 +37,7 @@ module Kitabu
|
|
34
37
|
epub.save(epub_path)
|
35
38
|
|
36
39
|
true
|
37
|
-
rescue
|
40
|
+
rescue StandardError => error
|
38
41
|
handle_error(error)
|
39
42
|
false
|
40
43
|
end
|
@@ -54,7 +57,8 @@ module Kitabu
|
|
54
57
|
epub.publisher config[:publisher]
|
55
58
|
epub.date config[:published_at]
|
56
59
|
epub.uid config[:uid]
|
57
|
-
epub.identifier config[:identifier][:id],
|
60
|
+
epub.identifier config[:identifier][:id],
|
61
|
+
scheme: config[:identifier][:type]
|
58
62
|
epub.cover_page cover_image if cover_image && File.exist?(cover_image)
|
59
63
|
end
|
60
64
|
|
@@ -70,13 +74,11 @@ module Kitabu
|
|
70
74
|
# First we need to get all ids, which are used as
|
71
75
|
# the anchor target.
|
72
76
|
#
|
73
|
-
links = sections.
|
77
|
+
links = sections.each_with_object({}) do |section, buffer|
|
74
78
|
section.html.css("[id]").each do |element|
|
75
|
-
anchor = "##{element[
|
79
|
+
anchor = "##{element['id']}"
|
76
80
|
buffer[anchor] = "#{section.filename}#{anchor}"
|
77
81
|
end
|
78
|
-
|
79
|
-
buffer
|
80
82
|
end
|
81
83
|
|
82
84
|
# Then we can normalize all links and
|
@@ -102,14 +104,16 @@ module Kitabu
|
|
102
104
|
# Save file to disk.
|
103
105
|
#
|
104
106
|
File.open(section.filepath, "w") do |file|
|
105
|
-
body = section.html.css("body").to_xhtml.gsub(
|
107
|
+
body = section.html.css("body").to_xhtml.gsub(
|
108
|
+
%r{<body>(.*?)</body>}m, "\\1"
|
109
|
+
)
|
106
110
|
file << render_chapter(body)
|
107
111
|
end
|
108
112
|
end
|
109
113
|
end
|
110
114
|
|
111
115
|
def render_chapter(content)
|
112
|
-
locals = config.merge(:
|
116
|
+
locals = config.merge(content: content)
|
113
117
|
render_template(template_path, locals)
|
114
118
|
end
|
115
119
|
|
@@ -122,14 +126,16 @@ module Kitabu
|
|
122
126
|
end
|
123
127
|
|
124
128
|
def cover_image
|
125
|
-
path =
|
129
|
+
path =
|
130
|
+
Dir[root_dir.join("templates/epub/cover.{jpg,png,gif}").to_s].first
|
131
|
+
|
126
132
|
return path if path && File.exist?(path)
|
127
133
|
end
|
128
134
|
|
129
135
|
def navigation
|
130
136
|
sections.map do |section|
|
131
137
|
{
|
132
|
-
label: section.html.css("
|
138
|
+
label: section.html.css(":first-child").text,
|
133
139
|
content: section.filename
|
134
140
|
}
|
135
141
|
end
|
data/lib/kitabu/exporter/html.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
class Exporter
|
3
5
|
class HTML < Base
|
@@ -13,6 +15,7 @@ module Kitabu
|
|
13
15
|
#
|
14
16
|
def export
|
15
17
|
copy_images!
|
18
|
+
copy_fonts!
|
16
19
|
export_stylesheets!
|
17
20
|
|
18
21
|
File.open(root_dir.join("output/#{name}.html"), "w") do |file|
|
@@ -20,7 +23,7 @@ module Kitabu
|
|
20
23
|
end
|
21
24
|
|
22
25
|
true
|
23
|
-
rescue
|
26
|
+
rescue StandardError => error
|
24
27
|
handle_error(error)
|
25
28
|
false
|
26
29
|
end
|
@@ -32,28 +35,29 @@ module Kitabu
|
|
32
35
|
# Return all chapters wrapped in a <tt>div.chapter</tt> tag.
|
33
36
|
#
|
34
37
|
def content
|
35
|
-
|
38
|
+
buffer = [].tap do |content|
|
36
39
|
source_list.each_chapter do |files|
|
37
40
|
content << %[<div class="chapter">#{render_chapter(files)}</div>]
|
38
41
|
end
|
39
42
|
end
|
43
|
+
|
44
|
+
buffer.join
|
40
45
|
end
|
41
46
|
|
42
|
-
private
|
43
47
|
# Render +file+ considering its extension.
|
44
48
|
#
|
45
|
-
def render_file(
|
46
|
-
if
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
private def render_file(file_path)
|
50
|
+
content = if file_format(file_path) == :erb
|
51
|
+
render_template(file_path, config)
|
52
|
+
else
|
53
|
+
File.read(file_path)
|
54
|
+
end
|
51
55
|
|
52
56
|
Kitabu::Markdown.render(content)
|
53
57
|
end
|
54
58
|
|
55
|
-
def
|
56
|
-
if File.extname(
|
59
|
+
private def file_format(file_path)
|
60
|
+
if File.extname(file_path) == ".erb"
|
57
61
|
:erb
|
58
62
|
else
|
59
63
|
:markdown
|
@@ -62,15 +66,16 @@ module Kitabu
|
|
62
66
|
|
63
67
|
# Parse layout file, making available all configuration entries.
|
64
68
|
#
|
65
|
-
def parse_layout(html)
|
69
|
+
private def parse_layout(html)
|
66
70
|
toc = TOC::HTML.generate(html)
|
67
|
-
content =
|
71
|
+
content =
|
72
|
+
Footnotes::HTML.process(toc.content).html.css("body").first.inner_html
|
68
73
|
|
69
|
-
locals = config.merge(
|
74
|
+
locals = config.merge(
|
70
75
|
content: content,
|
71
76
|
toc: toc.to_html,
|
72
77
|
changelog: render_changelog
|
73
|
-
|
78
|
+
)
|
74
79
|
|
75
80
|
render_template(root_dir.join("templates/html/layout.erb"), locals)
|
76
81
|
end
|
@@ -78,30 +83,38 @@ module Kitabu
|
|
78
83
|
# Render changelog file.
|
79
84
|
# This file can be used to inform any book change.
|
80
85
|
#
|
81
|
-
def render_changelog
|
86
|
+
private def render_changelog
|
82
87
|
changelog = Dir[root_dir.join("text/CHANGELOG.*")].first
|
83
88
|
render_file(changelog) if changelog
|
84
89
|
end
|
85
90
|
|
86
91
|
# Render all +files+ from a given chapter.
|
87
92
|
#
|
88
|
-
def render_chapter(files)
|
89
|
-
|
93
|
+
private def render_chapter(files)
|
94
|
+
buffer = [].tap do |chapter|
|
90
95
|
files.each do |file|
|
91
96
|
chapter << render_file(file) << "\n\n"
|
92
97
|
end
|
93
98
|
end
|
99
|
+
|
100
|
+
buffer.join
|
94
101
|
end
|
95
102
|
|
96
103
|
# Copy images
|
97
104
|
#
|
98
|
-
def copy_images!
|
105
|
+
private def copy_images!
|
99
106
|
copy_directory("images", "output/images")
|
100
107
|
end
|
101
108
|
|
109
|
+
# Copy font files
|
110
|
+
#
|
111
|
+
private def copy_fonts!
|
112
|
+
copy_directory("fonts", "output/fonts")
|
113
|
+
end
|
114
|
+
|
102
115
|
# Export all root stylesheets.
|
103
116
|
#
|
104
|
-
def export_stylesheets!
|
117
|
+
private def export_stylesheets!
|
105
118
|
Exporter::CSS.new(root_dir).export
|
106
119
|
end
|
107
120
|
end
|
data/lib/kitabu/exporter/mobi.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
class Exporter
|
3
5
|
class Mobi < Base
|
4
6
|
def export
|
5
|
-
spawn_command ["
|
7
|
+
spawn_command ["ebook-convert", epub_file.to_s, mobi_file.to_s]
|
6
8
|
true
|
7
9
|
end
|
8
10
|
|
11
|
+
def mobi_file
|
12
|
+
root_dir.join("output/#{name}.mobi")
|
13
|
+
end
|
14
|
+
|
9
15
|
def epub_file
|
10
16
|
root_dir.join("output/#{name}.epub")
|
11
17
|
end
|
data/lib/kitabu/exporter/pdf.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
class Exporter
|
3
5
|
class PDF < Base
|
@@ -9,13 +11,17 @@ module Kitabu
|
|
9
11
|
|
10
12
|
def apply_footnotes!
|
11
13
|
html = Footnotes::PDF.process(html_file.read).html
|
12
|
-
create_html_file(html_for_print, html,
|
13
|
-
create_html_file(html_for_pdf, html,
|
14
|
+
create_html_file(html_for_print, html, "print")
|
15
|
+
create_html_file(html_for_pdf, html, "pdf")
|
14
16
|
end
|
15
17
|
|
16
18
|
def create_html_file(target, html, class_name)
|
17
19
|
html.css("html").first.set_attribute "class", class_name
|
18
|
-
html
|
20
|
+
html
|
21
|
+
.css("link[name=stylesheet]")
|
22
|
+
.first
|
23
|
+
.set_attribute "href", "styles/#{class_name}.css"
|
24
|
+
|
19
25
|
File.open(target, "w") {|f| f << html.to_html }
|
20
26
|
end
|
21
27
|
|
data/lib/kitabu/exporter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
class Exporter
|
3
5
|
def self.run(root_dir, options)
|
@@ -5,8 +7,7 @@ module Kitabu
|
|
5
7
|
exporter.export!
|
6
8
|
end
|
7
9
|
|
8
|
-
attr_accessor :root_dir
|
9
|
-
attr_accessor :options
|
10
|
+
attr_accessor :root_dir, :options
|
10
11
|
|
11
12
|
def initialize(root_dir, options)
|
12
13
|
@root_dir = root_dir
|
@@ -26,37 +27,35 @@ module Kitabu
|
|
26
27
|
export_pdf = [nil, "pdf"].include?(options[:only])
|
27
28
|
export_epub = [nil, "mobi", "epub"].include?(options[:only])
|
28
29
|
export_mobi = [nil, "mobi"].include?(options[:only])
|
29
|
-
export_txt = [nil, "txt"].include?(options[:only])
|
30
30
|
|
31
31
|
exported = []
|
32
32
|
exported << HTML.export(root_dir)
|
33
33
|
exported << PDF.export(root_dir) if export_pdf && Dependency.prince?
|
34
34
|
exported << Epub.export(root_dir) if export_epub
|
35
|
-
exported << Mobi.export(root_dir) if export_mobi && Dependency.
|
36
|
-
exported << Txt.export(root_dir) if export_txt && Dependency.html2text?
|
35
|
+
exported << Mobi.export(root_dir) if export_mobi && Dependency.calibre?
|
37
36
|
|
38
37
|
if exported.all?
|
39
38
|
color = :green
|
40
|
-
message = options[:auto] ? "exported!" : "
|
39
|
+
message = options[:auto] ? "exported!" : "=> e-book has been exported"
|
41
40
|
|
42
41
|
if options[:open] && export_pdf
|
43
42
|
filepath = root_dir.join("output/#{File.basename(root_dir)}.pdf")
|
44
43
|
|
45
|
-
|
44
|
+
case RUBY_PLATFORM
|
45
|
+
when /darwin/
|
46
46
|
IO.popen("open -a Preview.app '#{filepath}'").close
|
47
|
-
|
48
|
-
Process.detach(Process.spawn("xdg-open '#{filepath}'",
|
47
|
+
when /linux/
|
48
|
+
Process.detach(Process.spawn("xdg-open '#{filepath}'",
|
49
|
+
out: "/dev/null"))
|
49
50
|
end
|
50
51
|
end
|
51
|
-
|
52
|
-
Notifier.notify(
|
53
|
-
:image => Kitabu::ROOT.join("templates/ebook.png"),
|
54
|
-
:title => "Kitabu",
|
55
|
-
:message => "Your \"#{config[:title]}\" e-book has been exported!"
|
56
|
-
)
|
57
52
|
else
|
58
53
|
color = :red
|
59
|
-
message = options[:auto]
|
54
|
+
message = if options[:auto]
|
55
|
+
"could not be exported!"
|
56
|
+
else
|
57
|
+
"=> e-book couldn't be exported"
|
58
|
+
end
|
60
59
|
end
|
61
60
|
|
62
61
|
ui.say message, color
|
@@ -1,8 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rouge
|
2
4
|
module Plugins
|
3
5
|
module Redcarpet
|
4
6
|
def rouge_formatter(lexer)
|
5
|
-
|
7
|
+
options = lexer.respond_to?(:options) ? lexer.options : {}
|
8
|
+
|
9
|
+
Formatters::HTMLLegacy.new(
|
10
|
+
{css_class: "highlight #{lexer.tag}"}.merge(options)
|
11
|
+
)
|
6
12
|
end
|
7
13
|
end
|
8
14
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class String
|
2
4
|
def to_permalink
|
3
|
-
str =
|
4
|
-
str = str.
|
5
|
-
str.gsub!(/[^-\w
|
5
|
+
str = dup.unicode_normalize(:nfkd)
|
6
|
+
str = str.gsub(/[^\x00-\x7F]/, "").to_s
|
7
|
+
str.gsub!(/[^-\w]+/xim, "-")
|
6
8
|
str.gsub!(/-+/xm, "-")
|
7
9
|
str.gsub!(/^-?(.*?)-?$/, '\1')
|
8
10
|
str.downcase!
|
@@ -1,25 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
module Footnotes
|
3
5
|
class HTML < Base
|
4
6
|
def process
|
5
|
-
html.css(
|
7
|
+
html.css(".chapter").each(&method(:process_chapter))
|
6
8
|
end
|
7
9
|
|
8
10
|
def process_chapter(chapter)
|
9
|
-
footnotes = chapter.css(
|
11
|
+
footnotes = chapter.css(".footnotes").first
|
10
12
|
return unless footnotes
|
11
|
-
list = footnotes.css('ol').first
|
12
|
-
list.set_attribute 'start', footnote_index
|
13
13
|
|
14
|
-
|
14
|
+
list = footnotes.css("ol").first
|
15
|
+
list.set_attribute "start", footnote_index
|
16
|
+
|
17
|
+
chapter.css(".footnotes li").each do |footnote|
|
15
18
|
process_footnote(chapter, footnote)
|
16
19
|
increment_footnote_index!
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
20
23
|
def process_footnote(chapter, footnote)
|
21
|
-
current_index = footnote.get_attribute(
|
22
|
-
footnote.set_attribute
|
24
|
+
current_index = footnote.get_attribute("id").gsub(/[^\d]/m, "")
|
25
|
+
footnote.set_attribute "id", "fn#{footnote_index}"
|
23
26
|
|
24
27
|
process_links_to_footnote(chapter, current_index)
|
25
28
|
process_rev_links(chapter, current_index)
|
@@ -28,23 +31,27 @@ module Kitabu
|
|
28
31
|
|
29
32
|
def process_links_to_footnote(chapter, current_index)
|
30
33
|
chapter.css("a[href='#fn#{current_index}']").each do |link|
|
31
|
-
link.set_attribute
|
34
|
+
link.set_attribute "href", "#fn#{footnote_index}"
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
38
|
def process_rev_links(chapter, current_index)
|
36
39
|
chapter.css("a[href='#fnref#{current_index}']").each do |link|
|
37
|
-
link.set_attribute
|
40
|
+
link.set_attribute "href", "#fnref#{footnote_index}"
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
44
|
def process_ref_elements(chapter, current_index)
|
42
|
-
|
45
|
+
selector = "sup[id=fnref#{current_index}]"
|
46
|
+
|
47
|
+
chapter.css(selector).each_with_index do |sup, index|
|
43
48
|
if index.zero?
|
44
|
-
sup.set_attribute
|
49
|
+
sup.set_attribute "id", "fnref#{footnote_index}"
|
45
50
|
else
|
46
|
-
sup.remove_attribute
|
51
|
+
sup.remove_attribute "id"
|
47
52
|
end
|
53
|
+
|
54
|
+
sup.css("a").first.content = footnote_index
|
48
55
|
end
|
49
56
|
end
|
50
57
|
end
|
data/lib/kitabu/footnotes/pdf.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
module Footnotes
|
3
5
|
class PDF < Base
|
@@ -8,35 +10,39 @@ module Kitabu
|
|
8
10
|
|
9
11
|
def remove_duplicated_attributes
|
10
12
|
# https://github.com/sparklemotion/nokogiri/issues/339
|
11
|
-
html.css(
|
13
|
+
html.css("html").first.tap do |element|
|
12
14
|
next unless element
|
13
|
-
|
14
|
-
element.delete(
|
15
|
+
|
16
|
+
element.delete("xmlns")
|
17
|
+
element.delete("xml:lang")
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
def process_chapter(chapter)
|
19
|
-
chapter.css(
|
22
|
+
chapter.css(".footnotes li").each do |footnote|
|
20
23
|
process_footnote(chapter, footnote)
|
21
24
|
increment_footnote_index!
|
22
25
|
end
|
23
26
|
|
24
|
-
chapter.css(
|
27
|
+
chapter.css(".footnotes").each(&:remove)
|
25
28
|
end
|
26
29
|
|
27
30
|
def process_footnote(chapter, footnote)
|
28
31
|
# Remove rev links
|
29
|
-
footnote.css(
|
32
|
+
footnote.css("[rev=footnote]").map(&:remove)
|
30
33
|
|
31
34
|
# Create an element for storing the footnote description
|
32
|
-
description = Nokogiri::XML::Node.new(
|
33
|
-
|
34
|
-
|
35
|
+
description = Nokogiri::XML::Node.new(
|
36
|
+
"span",
|
37
|
+
Nokogiri::HTML::DocumentFragment.parse("")
|
38
|
+
)
|
39
|
+
description.set_attribute "class", "footnote"
|
40
|
+
description.inner_html = footnote.css("p").map(&:inner_html).join("\n")
|
35
41
|
|
36
42
|
# Find ref based on footnote's id
|
37
|
-
fn_id = footnote.get_attribute(
|
43
|
+
fn_id = footnote.get_attribute("id")
|
38
44
|
|
39
|
-
|
45
|
+
chapter.css("a[href='##{fn_id}']").each do |ref|
|
40
46
|
sup = ref.parent
|
41
47
|
sup.after(description)
|
42
48
|
sup.remove
|
data/lib/kitabu/generator.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
# The Kitabu::Generator class will create a new book structure.
|
3
5
|
#
|
@@ -11,7 +13,7 @@ module Kitabu
|
|
11
13
|
desc "Generate a new e-Book structure"
|
12
14
|
|
13
15
|
def self.source_root
|
14
|
-
File.dirname(__FILE__)
|
16
|
+
"#{File.dirname(__FILE__)}/../../templates"
|
15
17
|
end
|
16
18
|
|
17
19
|
def copy_templates
|
@@ -43,12 +45,15 @@ module Kitabu
|
|
43
45
|
|
44
46
|
def create_directories
|
45
47
|
empty_directory "output"
|
48
|
+
empty_directory "fonts"
|
46
49
|
end
|
47
50
|
|
48
51
|
def create_git_files
|
49
52
|
create_file ".gitignore" do
|
50
53
|
"/output"
|
51
54
|
end
|
55
|
+
|
56
|
+
create_file "fonts/.keep"
|
52
57
|
end
|
53
58
|
|
54
59
|
def copy_guardfile
|
@@ -61,13 +66,16 @@ module Kitabu
|
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
no_commands do
|
70
|
+
# Retrieve user's name using finger.
|
71
|
+
# Defaults to <tt>John Doe</tt>.
|
72
|
+
#
|
73
|
+
def full_name
|
74
|
+
name =
|
75
|
+
`finger $USER 2> /dev/null | grep Login | colrm 1 46 2> /dev/null`
|
76
|
+
.chomp
|
77
|
+
name.present? ? name.squish : "John Doe"
|
78
|
+
end
|
71
79
|
end
|
72
80
|
end
|
73
81
|
end
|
data/lib/kitabu/helpers.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
module Helpers
|
3
5
|
def highlight_theme(name = theme)
|
4
6
|
html = '<style type="text/css">'
|
5
|
-
html << Rouge::Theme.find(name).render(scope:
|
6
|
-
html <<
|
7
|
+
html << Rouge::Theme.find(name).render(scope: ".highlight")
|
8
|
+
html << "</style>"
|
7
9
|
html
|
8
10
|
end
|
9
11
|
|
10
|
-
def image_tag(path,
|
11
|
-
|
12
|
+
def image_tag(path, _attributes = {})
|
13
|
+
%[<img src="images/#{path}" />]
|
12
14
|
end
|
13
15
|
|
14
16
|
def escape_html(content)
|
@@ -17,19 +19,20 @@ module Kitabu
|
|
17
19
|
|
18
20
|
def note(class_name = :info, &block)
|
19
21
|
content = block_content(block)
|
20
|
-
output << '<div class="note %s">' % escape_html(class_name)
|
22
|
+
output << ('<div class="note %s">' % escape_html(class_name)) # rubocop:disable Style/FormatString
|
21
23
|
output << markdown(content)
|
22
|
-
output <<
|
24
|
+
output << "</div>"
|
23
25
|
end
|
24
26
|
|
25
27
|
def block_content(block)
|
26
|
-
output
|
28
|
+
output = @_output.dup
|
29
|
+
@_output = ""
|
27
30
|
content = block.call
|
28
31
|
@_output = output
|
29
32
|
content
|
30
33
|
end
|
31
34
|
|
32
|
-
def markdown(content, deindent_content
|
35
|
+
def markdown(content, deindent_content: true)
|
33
36
|
content = deindent(content) if deindent_content
|
34
37
|
Markdown.render(content)
|
35
38
|
end
|
@@ -37,7 +40,7 @@ module Kitabu
|
|
37
40
|
def deindent(content)
|
38
41
|
content = content.to_s
|
39
42
|
indent = (content.scan(/^[ \t]*(?=\S)/) || []).size
|
40
|
-
content.gsub(/^[ \t]{#{indent}}/,
|
43
|
+
content.gsub(/^[ \t]{#{indent}}/, "")
|
41
44
|
end
|
42
45
|
|
43
46
|
def output
|
data/lib/kitabu/markdown.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kitabu
|
2
4
|
module Markdown
|
3
5
|
class Renderer < Redcarpet::Render::HTML
|
@@ -13,16 +15,16 @@ module Kitabu
|
|
13
15
|
renderer = Renderer.new(hard_wrap: true, safe_links_only: true)
|
14
16
|
|
15
17
|
self.processor = Redcarpet::Markdown.new(renderer, {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
tables: true,
|
19
|
+
footnotes: true,
|
20
|
+
space_after_headers: true,
|
21
|
+
superscript: true,
|
22
|
+
highlight: true,
|
23
|
+
strikethrough: true,
|
24
|
+
autolink: true,
|
25
|
+
fenced_code_blocks: true,
|
26
|
+
no_intra_emphasis: true
|
27
|
+
})
|
26
28
|
|
27
29
|
def self.render(text)
|
28
30
|
processor.render(text)
|