kitabu 2.1.0 → 3.0.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.
- 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/.rubocop.yml +17 -0
- data/CHANGELOG.md +13 -2
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +2 -0
- data/LICENSE.md +20 -0
- data/README.md +103 -88
- data/Rakefile +7 -0
- data/bin/kitabu +4 -0
- data/kitabu.gemspec +21 -15
- 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 +11 -11
- data/lib/kitabu/exporter/css.rb +6 -15
- data/lib/kitabu/exporter/epub.rb +23 -17
- data/lib/kitabu/exporter/html.rb +27 -21
- 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 +6 -1
- data/lib/kitabu/extensions/string.rb +5 -3
- data/lib/kitabu/footnotes/base.rb +2 -0
- data/lib/kitabu/footnotes/html.rb +18 -13
- data/lib/kitabu/footnotes/pdf.rb +17 -11
- data/lib/kitabu/generator.rb +13 -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 +3 -1
- data/lib/kitabu/toc/html.rb +12 -8
- data/lib/kitabu/version.rb +4 -2
- data/lib/kitabu.rb +8 -10
- 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 +11 -9
- 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 +35 -33
- data/spec/kitabu/generator_spec.rb +3 -1
- data/spec/kitabu/markdown_spec.rb +8 -6
- data/spec/kitabu/source_list_spec.rb +8 -2
- data/spec/kitabu/stats_spec.rb +10 -6
- data/spec/kitabu/toc/html_spec.rb +37 -21
- 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/shared.rb +8 -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 +40 -48
- data/.gitmodules +0 -3
- data/.travis.yml +0 -18
- data/lib/kitabu/exporter/txt.rb +0 -18
- 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,7 +126,9 @@ 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
|
|
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
|
|
@@ -21,7 +23,7 @@ module Kitabu
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
true
|
|
24
|
-
rescue
|
|
26
|
+
rescue StandardError => error
|
|
25
27
|
handle_error(error)
|
|
26
28
|
false
|
|
27
29
|
end
|
|
@@ -33,28 +35,29 @@ module Kitabu
|
|
|
33
35
|
# Return all chapters wrapped in a <tt>div.chapter</tt> tag.
|
|
34
36
|
#
|
|
35
37
|
def content
|
|
36
|
-
|
|
38
|
+
buffer = [].tap do |content|
|
|
37
39
|
source_list.each_chapter do |files|
|
|
38
40
|
content << %[<div class="chapter">#{render_chapter(files)}</div>]
|
|
39
41
|
end
|
|
40
42
|
end
|
|
43
|
+
|
|
44
|
+
buffer.join
|
|
41
45
|
end
|
|
42
46
|
|
|
43
|
-
private
|
|
44
47
|
# Render +file+ considering its extension.
|
|
45
48
|
#
|
|
46
|
-
def render_file(
|
|
47
|
-
if
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
52
55
|
|
|
53
56
|
Kitabu::Markdown.render(content)
|
|
54
57
|
end
|
|
55
58
|
|
|
56
|
-
def
|
|
57
|
-
if File.extname(
|
|
59
|
+
private def file_format(file_path)
|
|
60
|
+
if File.extname(file_path) == ".erb"
|
|
58
61
|
:erb
|
|
59
62
|
else
|
|
60
63
|
:markdown
|
|
@@ -63,15 +66,16 @@ module Kitabu
|
|
|
63
66
|
|
|
64
67
|
# Parse layout file, making available all configuration entries.
|
|
65
68
|
#
|
|
66
|
-
def parse_layout(html)
|
|
69
|
+
private def parse_layout(html)
|
|
67
70
|
toc = TOC::HTML.generate(html)
|
|
68
|
-
content =
|
|
71
|
+
content =
|
|
72
|
+
Footnotes::HTML.process(toc.content).html.css("body").first.inner_html
|
|
69
73
|
|
|
70
|
-
locals = config.merge(
|
|
74
|
+
locals = config.merge(
|
|
71
75
|
content: content,
|
|
72
76
|
toc: toc.to_html,
|
|
73
77
|
changelog: render_changelog
|
|
74
|
-
|
|
78
|
+
)
|
|
75
79
|
|
|
76
80
|
render_template(root_dir.join("templates/html/layout.erb"), locals)
|
|
77
81
|
end
|
|
@@ -79,36 +83,38 @@ module Kitabu
|
|
|
79
83
|
# Render changelog file.
|
|
80
84
|
# This file can be used to inform any book change.
|
|
81
85
|
#
|
|
82
|
-
def render_changelog
|
|
86
|
+
private def render_changelog
|
|
83
87
|
changelog = Dir[root_dir.join("text/CHANGELOG.*")].first
|
|
84
88
|
render_file(changelog) if changelog
|
|
85
89
|
end
|
|
86
90
|
|
|
87
91
|
# Render all +files+ from a given chapter.
|
|
88
92
|
#
|
|
89
|
-
def render_chapter(files)
|
|
90
|
-
|
|
93
|
+
private def render_chapter(files)
|
|
94
|
+
buffer = [].tap do |chapter|
|
|
91
95
|
files.each do |file|
|
|
92
96
|
chapter << render_file(file) << "\n\n"
|
|
93
97
|
end
|
|
94
98
|
end
|
|
99
|
+
|
|
100
|
+
buffer.join
|
|
95
101
|
end
|
|
96
102
|
|
|
97
103
|
# Copy images
|
|
98
104
|
#
|
|
99
|
-
def copy_images!
|
|
105
|
+
private def copy_images!
|
|
100
106
|
copy_directory("images", "output/images")
|
|
101
107
|
end
|
|
102
108
|
|
|
103
109
|
# Copy font files
|
|
104
110
|
#
|
|
105
|
-
def copy_fonts!
|
|
111
|
+
private def copy_fonts!
|
|
106
112
|
copy_directory("fonts", "output/fonts")
|
|
107
113
|
end
|
|
108
114
|
|
|
109
115
|
# Export all root stylesheets.
|
|
110
116
|
#
|
|
111
|
-
def export_stylesheets!
|
|
117
|
+
private def export_stylesheets!
|
|
112
118
|
Exporter::CSS.new(root_dir).export
|
|
113
119
|
end
|
|
114
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").to_s,
|
|
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,9 +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 : {}
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
Formatters::HTMLLegacy.new(
|
|
10
|
+
{css_class: "highlight #{lexer.tag}"}.merge(options)
|
|
11
|
+
)
|
|
7
12
|
end
|
|
8
13
|
end
|
|
9
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,25 +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
|
|
48
53
|
|
|
49
|
-
sup.css(
|
|
54
|
+
sup.css("a").first.content = footnote_index
|
|
50
55
|
end
|
|
51
56
|
end
|
|
52
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
|
|
@@ -64,13 +66,16 @@ module Kitabu
|
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
74
79
|
end
|
|
75
80
|
end
|
|
76
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)
|