lib/softcover/builders/epub.rb in softcover-1.1.22 vs lib/softcover/builders/epub.rb in softcover-1.1.23
- old
+ new
@@ -23,28 +23,42 @@
# should have not have a cover.)
def cover?(options={})
!options[:amazon] && cover_img
end
+ def cover_filename
+ xhtml("cover.#{html_extension}")
+ end
+
+ # Transforms foo.html to foo.xhtml
+ def xhtml(filename)
+ filename.sub('.html', '.xhtml')
+ end
+
def cover_img_path
path("#{images_dir}/#{cover_img}")
end
def images_dir
path('epub/OEBPS/images')
end
+ def nav_filename
+ xhtml("nav.#{html_extension}")
+ end
+
+
def escape(string)
CGI.escape_html(string)
end
# Returns a content.opf file based on a valid template.
def content_opf_template(title, copyright, author, uuid, cover_id,
toc_chapters, manifest_chapters, images)
if cover_id
cover_meta = %(<meta name="cover" content="#{cover_id}"/>)
- cover_html = '<item id="cover" href="cover.html" media-type="application/xhtml+xml"/>'
+ cover_html = %(<item id="cover" href="#{cover_filename}" media-type="application/xhtml+xml"/>)
cover_ref = '<itemref idref="cover" linear="no" />'
else
cover_meta = cover_html = cover_ref = ''
end
%(<?xml version="1.0" encoding="UTF-8"?>
@@ -59,11 +73,11 @@
<dc:identifier id="BookID">urn:uuid:#{uuid}</dc:identifier>
<meta property="dcterms:modified">#{Time.now.strftime('%Y-%m-%dT%H:%M:%S')}Z</meta>
#{cover_meta}
</metadata>
<manifest>
- <item href="nav.html" id="nav" media-type="application/xhtml+xml" properties="nav"/>
+ <item href="#{nav_filename}" id="nav" media-type="application/xhtml+xml" properties="nav"/>
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="page-template.xpgt" href="styles/page-template.xpgt" media-type="application/vnd.adobe-page-template+xml"/>
<item id="pygments.css" href="styles/pygments.css" media-type="text/css"/>
<item id="softcover.css" href="styles/softcover.css" media-type="text/css"/>
<item id="epub.css" href="styles/epub.css" media-type="text/css"/>
@@ -158,10 +172,11 @@
# Removes HTML.
# All the HTML is generated, so this clears out any unused files.
def remove_html
FileUtils.rm(Dir.glob(path('epub/OEBPS/*.html')))
+ FileUtils.rm(Dir.glob(path('epub/OEBPS/*.xhtml')))
end
# Removes images in case they are stale.
def remove_images
rm_r images_dir
@@ -213,18 +228,22 @@
def write_html(options={})
texmath_dir = File.join(images_dir, 'texmath')
mkdir images_dir
mkdir texmath_dir
- File.write(path('epub/OEBPS/cover.html'), cover_page) if cover?(options)
+ File.write(path("epub/OEBPS/#{cover_filename}"), cover_page) if cover?(options)
pngs = []
chapters.each_with_index do |chapter, i|
- target_filename = path("epub/OEBPS/#{chapter.fragment_name}")
+ target_filename = path("epub/OEBPS/#{xhtml(chapter.fragment_name)}")
File.open(target_filename, 'w') do |f|
content = File.read(path("html/#{chapter.fragment_name}"))
doc = strip_attributes(Nokogiri::HTML(content))
+ # Use xhtml in references.
+ doc.css('a.hyperref').each do |ref_node|
+ ref_node['href'] = ref_node['href'].sub('.html', xhtml('.html'))
+ end
body = doc.at_css('body')
if body.nil?
$stderr.puts "\nError: Document not built due to empty chapter"
$stderr.puts "Chapters must include a title using the Markdown"
$stderr.puts " # This is a chapter"
@@ -260,13 +279,14 @@
# for every math element. Since ereader support for SVGs is spotty,
# they are then converted to PNGs using Inkscape. The filenames are
# SHAs of their contents, which arranges both for unique filenames
# and for automatic disk caching.
def html_with_math(chapter, images_dir, texmath_dir, pngs, options={})
- content = File.read(File.join("html", "#{chapter.slug}.html"))
+ content = File.read(File.join("html",
+ "#{chapter.slug}.#{html_extension}"))
pagejs = "#{File.dirname(__FILE__)}/utils/page.js"
- url = "file://#{Dir.pwd}/html/#{chapter.slug}.html"
+ url = "file://#{Dir.pwd}/html/#{chapter.slug}.#{html_extension}"
cmd = "#{phantomjs} #{pagejs} #{url}"
silence { silence_stream(STDERR) { system cmd } }
# Sometimes in tests the phantomjs_source.html file is missing.
# It shouldn't ever happen, but it does no harm to skip it.
return nil unless File.exist?('phantomjs_source.html')
@@ -321,11 +341,12 @@
png['alt'] = png_filename.sub('.png', '')
svg.replace(png)
end
# Make references relative.
source.css('a.hyperref').each do |ref_node|
- ref_node['href'] = ref_node['href'].sub('.html', '_fragment.html')
+ ref_node['href'] = ref_node['href'].sub('.html',
+ xhtml('_fragment.html'))
end
source.at_css('div#book').children.to_xhtml
end
# Returns the PhantomJS executable (if available).
@@ -444,11 +465,11 @@
end
# Writes the navigation file.
# This is required by the EPUB standard.
def write_nav
- File.write('epub/OEBPS/nav.html', nav_html)
+ File.write("epub/OEBPS/#{nav_filename}", nav_html)
end
def container_xml
%(<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
@@ -468,11 +489,11 @@
end
# Returns the content configuration file.
def content_opf(options={})
man_ch = chapters.map do |chapter|
- %(<item id="#{chapter.slug}" href="#{chapter.fragment_name}" media-type="application/xhtml+xml"/>)
+ %(<item id="#{chapter.slug}" href="#{xhtml(chapter.fragment_name)}" media-type="application/xhtml+xml"/>)
end
toc_ch = chapters.map do |chapter|
%(<itemref idref="#{chapter.slug}"/>)
end
image_files = Dir['epub/OEBPS/images/**/*'].select { |f| File.file?(f) }
@@ -521,18 +542,18 @@
if article?
article = chapters.first
section_names_and_ids(article).each_with_index do |(name, id), n|
chapter_nav << %(<navPoint id="#{id}" playOrder="#{n+1}">)
chapter_nav << %( <navLabel><text>#{escape(name)}</text></navLabel>)
- chapter_nav << %( <content src="#{article.fragment_name}##{id}"/>)
+ chapter_nav << %( <content src="#{xhtml(article.fragment_name)}##{id}"/>)
chapter_nav << %(</navPoint>)
end
else
chapters.each_with_index do |chapter, n|
chapter_nav << %(<navPoint id="#{chapter.slug}" playOrder="#{n+1}">)
chapter_nav << %( <navLabel><text>#{chapter_name(n)}</text></navLabel>)
- chapter_nav << %( <content src="#{chapter.fragment_name}"/>)
+ chapter_nav << %( <content src="#{xhtml(chapter.fragment_name)}"/>)
chapter_nav << %(</navPoint>)
end
end
toc_ncx_template(manifest.title, manifest.uuid, chapter_nav)
end
@@ -545,11 +566,11 @@
# Returns the nav HTML content.
def nav_html
if article?
article = chapters.first
nav_list = section_names_and_ids(article).map do |name, id|
- %(<li> <a href="#{article.fragment_name}##{id}">#{name}</a></li>)
+ %(<li> <a href="#{xhtml(article.fragment_name)}##{id}">#{name}</a></li>)
end
else
nav_list = manifest.chapters.map do |chapter|
element = preview? ? chapter.title : nav_link(chapter)
%(<li>#{element}</li>)
@@ -558,17 +579,17 @@
nav_html_template(manifest.title, nav_list)
end
# Returns a navigation link for the chapter.
def nav_link(chapter)
- %(<a href="#{chapter.fragment_name}">#{chapter.html_title}</a>)
+ %(<a href="#{xhtml(chapter.fragment_name)}">#{chapter.html_title}</a>)
end
# Returns a list of the section names and CSS ids.
# Form is [['Beginning', 'sec-beginning'], ['Next', 'sec-next']]
def section_names_and_ids(article)
# Grab section names and ids from the article.
- filename = File.join('epub', 'OEBPS', article.fragment_name)
+ filename = File.join('epub', 'OEBPS', xhtml(article.fragment_name))
doc = Nokogiri::HTML(File.read(filename))
names = doc.css('div.section>h2').map do |s|
s.children.children.last.content
end
ids = doc.css('div.section').map { |s| s.attributes['id'].value }
\ No newline at end of file