From 43dbb363c1af1e4a1a1cd79b8b8fdd262169338c Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 22 Jun 2022 19:08:53 +0300
Subject: [PATCH 1/6] added epub3 support
---
ebook-batch.xq | 16 +-
modules/epub3.xql | 878 +++++++++++++++++++++++
resources/boilerplate/frus-about.tei.xml | 45 ++
resources/css/epub3.css | 356 +++++++++
4 files changed, 1291 insertions(+), 4 deletions(-)
create mode 100644 modules/epub3.xql
create mode 100644 resources/boilerplate/frus-about.tei.xml
create mode 100644 resources/css/epub3.css
diff --git a/ebook-batch.xq b/ebook-batch.xq
index 6ea902b..d1aa7fa 100644
--- a/ebook-batch.xq
+++ b/ebook-batch.xq
@@ -3,6 +3,7 @@ xquery version "3.0";
import module namespace release = "http://history.state.gov/ns/xquery/release" at "modules/release.xql";
import module namespace epub = "http://history.state.gov/ns/xquery/epub" at "modules/epub.xql";
import module namespace frus = "http://history.state.gov/ns/xquery/frus" at "modules/frus.xql";
+import module namespace epub3 = "http://history.state.gov/ns/xquery/epub3/epub" at "modules/epub3.xql";
import module namespace console="http://exist-db.org/xquery/console";
import module namespace process="http://exist-db.org/xquery/process" at "java:org.exist.xquery.modules.process.ProcessModule";
@@ -13,9 +14,10 @@ declare option output:method "html";
declare option output:media-type "text/html";
declare function local:output-directory() {
- let $username := environment-variable('USER')
- return
- concat('/Users/', $username, '/Downloads/frus-ebooks-', substring(xs:string(current-date()), 1, 10), '/')
+ '/tmp/'
+(: let $username := environment-variable('USER'):)
+(: return:)
+(: concat('/Users/', $username, '/Downloads/frus-ebooks-', substring(xs:string(current-date()), 1, 10), '/'):)
};
declare function local:generate-mobis() {
@@ -95,6 +97,8 @@ declare function local:generate-ebooks($vol-ids, $format) {
let $operation :=
if ($f = 'epub') then
epub:save-frus-epub-to-disk($tei-content-data-path, (), $file-system-output-dir)
+ else if ($f = 'epub3') then
+ epub3:save-frus-epub-to-disk($tei-content-data-path, (), $file-system-output-dir)
else (: if ($f = 'mobi') then :)
epub:save-frus-epub-to-disk($tei-content-data-path, 'mobi', $file-system-output-dir)
let $end-time := util:system-time()
@@ -125,7 +129,7 @@ declare variable $local:ebook-format-options :=
epub
-
+
mobi-bound
@@ -135,6 +139,10 @@ declare variable $local:ebook-format-options :=
all
+
+ epub3
+
+
;
diff --git a/modules/epub3.xql b/modules/epub3.xql
new file mode 100644
index 0000000..e7144fe
--- /dev/null
+++ b/modules/epub3.xql
@@ -0,0 +1,878 @@
+xquery version "3.0";
+
+module namespace epub3 = "http://history.state.gov/ns/xquery/epub3/epub";
+
+import module namespace pm-config="http://www.tei-c.org/tei-simple/config" at "/db/apps/tei-publisher/modules/config.xqm";
+import module namespace epub2 = "http://history.state.gov/ns/xquery/epub" at "epub.xql";
+import module namespace epub = "http://exist-db.org/xquery/epub" at "/db/apps/tei-publisher/modules/lib/epub.xql";
+import module namespace nav="http://www.tei-c.org/tei-simple/navigation" at "/db/apps/tei-publisher/modules/navigation.xql";
+import module namespace compression = "http://exist-db.org/xquery/compression";
+import module namespace frus="http://history.state.gov/ns/xquery/frus" at "frus.xql";
+import module namespace tpu="http://www.tei-c.org/tei-publisher/util" at "/db/apps/tei-publisher/modules/lib/util.xql";
+
+import module namespace xmldb = "http://exist-db.org/xquery/xmldb";
+
+declare namespace tei="http://www.tei-c.org/ns/1.0";
+declare namespace xhtml = "http://www.w3.org/1999/xhtml";
+declare namespace opf = "http://www.idpf.org/2007/opf";
+declare namespace ncx = "http://www.daisy.org/z3986/2005/ncx/";
+
+declare variable $epub3:cache-collection := '/db/apps/release/epub-cache';
+declare variable $epub3:abs-site-uri := 'historicaldocuments/';
+
+declare function local:generate-epub($id, $doc, $title, $creator, $text, $urn, $db-path-to-resources, $cover, $filename, $options) {
+ (: $title : volume (series, sub-series, volume-number) :)
+ (: $creator : Constant :)
+ (: $text : /text node :)
+ (: $urn : id+timestamp :)
+ (: $db-path-to-resources : resources path (css, images, and about.xml) :)
+ (: $cover : get cover image path, if not found download it, if not found use default cover :)
+ (: $filename : output epub filename :)
+ (: $options : () :)
+
+ let $default-config := $pm-config:epub-config($doc, ())
+ let $config := map:merge((
+ $default-config,
+ map {
+ "options": $options,
+ (:"fonts": (),:)
+ "metadata": map:merge(
+ ($default-config?metadata,
+ map {
+ "id": $id,
+ "title": $title,
+ "creator": $creator,
+ "urn": $urn
+ })
+ )
+ }
+ ))
+ let $odd := head($pm-config:default-odd)
+ let $oddName := replace($odd, "^([^/\.]+).*$", "$1")
+ let $css-default := util:binary-to-string(util:binary-doc($pm-config:output-root || "/" || $oddName || ".css"))
+ let $css-epub := util:binary-to-string(util:binary-doc("/db/apps/release/resources/css/epub.css"))
+ let $css-epub3 := util:binary-to-string(util:binary-doc("/db/apps/release/resources/css/epub3.css"))
+ let $css := concat($css-default, $css-epub, $css-epub3)
+ let $updated := local:update-document($config, $doc)/node()
+ let $stored := xmldb:store($epub3:cache-collection, concat('/', $id, ".xml"), $updated)
+ let $stored := doc(concat($epub3:cache-collection, '/', $id, ".xml"))
+ return
+ let $raw-epub := epub:generate-epub($config, $stored/*, $css, $id)
+ let $epub := document { ($raw-epub) }
+ return local:post-process-document($epub/node())
+};
+
+declare function local:frus-toc-to-li($node, $suppress-documents as xs:boolean, $options) {
+ typeswitch($node)
+ case element(tei:div) return local:frus-div-to-li($node, $suppress-documents, $options)
+ default return local:recurse-li($node, $suppress-documents, $options)
+};
+
+declare function local:recurse-li($node, $suppress-documents, $options) {
+ for $child in $node/node()
+ return local:frus-toc-to-li($child, $suppress-documents, $options)
+};
+
+declare function local:frus-div-to-li($div as element(tei:div), $suppress-documents as xs:boolean, $options) {
+ let $id := $div/@xml:id
+ return
+ if (not($id)) then
+ local:recurse-li($div, $suppress-documents, $options)
+ else if ($id = $epub2:frus-div-xmlids-to-suppress) then
+ ()
+ else if ($div/@type = ('document', 'introduction')) then
+ if ($suppress-documents) then
+ ()
+ else
+
+ {
+ normalize-space(frus:head-sans-note($div))
+ }
+
+ else
+
+ {
+ normalize-space(frus:head-sans-note($div))
+ }
+ {
+ if ($div[tei:div/@type eq 'document']) then
+ if ($suppress-documents) then
+ concat(' (Documents ', $div/tei:div[@n][1]/@n, '-', $div/tei:div[@n][last()]/@n, ')')
+ else ()
+ else
+ ()
+ ,
+ if ($div//tei:div[@xml:id][not(@type = ('document', 'introduction'))] or not($suppress-documents)) then
+ { local:recurse-li($div, $suppress-documents, $options) }
+ else ()
+ }
+
+};
+
+declare function local:cache-graphic-image($node) {
+ let $graphic-basename := $node/@url
+ return
+ if (contains($graphic-basename, '.')) then
+ $graphic-basename
+ else
+ let $vol-id := substring-before(util:document-name($node), '.xml')
+ let $file := concat($graphic-basename, '.png')
+ let $rel-images-path := "images"
+ let $s3-path := concat('frus/', $vol-id)
+ let $ensure-collections-exist := (
+ xmldb:create-collection($epub3:cache-collection, $rel-images-path)
+ )
+ let $images-path := concat($epub3:cache-collection, '/', $rel-images-path)
+ let $rel-file-path := concat($rel-images-path, '/', $file)
+ let $file-path := concat($images-path, '/', $file)
+ let $graphic-binary-uri :=
+ if (util:binary-doc-available($file-path)) then
+ $file-path
+ else
+ let $uri := concat('https://static.history.state.gov/', $s3-path, '/', encode-for-uri($file))
+ return
+ local:cache-image($uri, $images-path, $file)
+ return
+ $rel-file-path
+};
+
+declare function local:cache-image($href, $target-collection, $filename) {
+ let $request :=
+ let $response := hc:send-request($request)
+ return
+ if ($response/@status eq '200') then
+ let $request :=
+ let $response := hc:send-request($request)
+ let $response-body := $response[2]
+ let $store := xmldb:store($target-collection, xmldb:encode($filename), $response-body, 'image/png')
+ return
+ concat($target-collection, '/', $filename)
+ else
+ error(xs:QName('epub-error'), concat('Unable to fetch image ', $href, ' for volume ', $filename, ' from S3'))
+};
+
+declare function local:generate-target($id, $node) {
+ let $node := root($node)//node()[@xml:id=$id]
+ let $parent := if ($node) then
+ typeswitch ($node)
+ case element(tei:div)return false()
+ default return $node/ancestor::tei:div[1]
+ else ()
+ return if ($node) then
+ concat(
+ epub:generate-id(if ($parent) then $parent else $node), '.xhtml',
+ if ($parent) then concat('#', typeswitch ($node)
+ case element(tei:note) return 'fn'
+ default return '',
+ epub:generate-id($node)) else ()
+ ) else ''
+};
+
+declare function local:pb-to-document-links($vol as document-node(), $pb-id as xs:string) {
+ local:pb-range-to-document-links($vol, $pb-id, $pb-id)
+};
+
+declare function local:pb-range-to-document-links($vol as document-node(), $pb1-id as xs:string, $pb2-id as xs:string) {
+ let $pb1 := $vol/id($pb1-id)
+ let $pb2 := $vol/id($pb2-id)
+ let $range-start := $pb1
+ let $range-end := subsequence($pb2/following::tei:pb, 1, 1)
+ let $divs := $vol//tei:div[@type=('document', 'section') and @xml:id]
+ let $divs-within-range := $divs[. >> $range-start and . << $range-end]/@xml:id
+ let $ancestor-document := subsequence($range-start/ancestor::tei:div[@type=('document', 'section') and @xml:id], 1, 1)/@xml:id
+ let $doc-ids := distinct-values(($ancestor-document, $divs-within-range)[. ne ''])
+ let $doc-ids := if (empty($doc-ids)) then ($pb1/ancestor::tei:div[@xml:id][1]/@xml:id, $pb1/following::tei:div[@xml:id][1]/@xml:id)[1] else $doc-ids
+ let $docs-in-frag := for $doc-id in $doc-ids return $vol/id($doc-id)
+ let $link :=
+ [{
+ let $docs-count := count($docs-in-frag)
+ return
+ if ($docs-count = 0) then
+ ()
+ else if ($docs-count = 1) then
+ (
+ if ($pb1 = $pb2) then
+ concat('Pg. ', $pb1/@n, ' is part of ')
+ else
+ concat('Pgs. ', $pb1/@n, '–', $pb2/@n, ' are part of ')
+ ,
+ {
+ for $doc in $docs-in-frag
+ return
+ if ($doc/@type='document') then
+ concat('Doc. ', $doc/@n)
+ else
+ frus:head-sans-note($doc)
+ }
+ )
+ else
+ (
+ if ($pb1-id = $pb2-id) then
+ concat('Pg. ', $pb1/@n, ' includes portions of ')
+ else
+ concat('Pgs. ', $pb1/@n, '–', $pb2/@n, ' include portions of ')
+ ,
+ for $doc at $count in $docs-in-frag
+ return
+ (
+ {if ($doc/@n ne '') then concat('Doc. ', $doc/@n) else frus:head-sans-note($doc)},
+ if ($count lt $docs-count - 1 and $docs-count gt 2) then
+ ', '
+ else if ($count lt $docs-count) then
+ if ($docs-count = 2) then
+ ' and '
+ else
+ ', and '
+ else ()
+ )
+ )
+ }]
+ return
+ $link
+};
+
+declare function local:remove-title($node, $title) {
+ if (fn:deep-equal($node, $title)) then () else
+ typeswitch ($node)
+ case text() return $node
+ default return element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:remove-title($child, $title)
+ )}
+};
+
+declare function local:update-content($nodes) {
+ for $node in $nodes
+ return typeswitch ($node)
+ case text() return $node
+ case element(opf:manifest)
+ return element {node-name($node)} {(
+ $node/@*,
+ for $sub-node in $node/node()
+ return if ($sub-node[@id="title"] or $sub-node/preceding-sibling::*[1][@id="title"]) then () else $sub-node
+ )}
+ case element(opf:spine) return
+ element {node-name($node)} {(
+ $node/@*,
+ for $sub-node in $node/node()
+ return if ($sub-node[@idref="title"] or $sub-node/preceding-sibling::*[1][@idref="title"]) then () else $sub-node
+ )}
+ default return element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-content($child)
+ )}
+};
+
+declare function local:update-nav($nodes) {
+ for $node in $nodes
+ return typeswitch ($node)
+ case text() return $node
+ case element(xhtml:li)
+ return if(ends-with($node/xhtml:a/@href, '-generated-document')) then () else element {node-name($node)} {(
+ $node/@*,
+ local:update-nav($node/node())
+ )}
+ default return element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-nav($child)
+ )}
+};
+
+declare function local:update-toc($nodes) {
+ for $node in $nodes
+ return typeswitch ($node)
+ case text() return $node
+ case element(ncx:navMap) return
+ element {node-name($node)} {(
+ $node/@*,
+ $node/node()[not(@id="navpoint-title")][not(./text()="Title")]
+ )}
+ default return element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-toc($child)
+ )}
+};
+declare function local:post-process-entry-contents($node) {
+ typeswitch ($node)
+ case text() return $node
+ case element(xhtml:aside) return
+ element {node-name($node)} {
+ $node/@*,
+ for $child in $node/node()
+ return typeswitch ($child)
+ case text() return $child
+ default return
+ let $child := local:post-process-entry-contents($child)
+ let $class := concat($child/@class, ' ')
+ let $child := if (contains($class, 'bold ')) then
+ {$child}
+ else $child
+ let $child := if (contains($class, 'italic ')) then
+ {$child}
+ else $child
+ let $child := if (contains($class, 'underline ')) then
+ {$child}
+ else $child
+ return $child
+ }
+ case element(xhtml:a) return
+ if (contains(concat($node/@class, ' '), 'tei-ref3 ')) then
+ element {node-name($node)} {(
+ ($node/@* except $node/@href, attribute href {
+ $node/@href ! (
+ let $nodes :=
+ if (starts-with(., '#')) then
+ if (starts-with(., '#in')) then
+ (concat('index.xhtml', .))
+ else if (matches(., '^#d\d+$')) then
+ (substring-after(., '#'))
+ else if (matches(., '^#d\d+fn\d+$')) then
+ let $document-id := substring-after(substring-before(., 'fn'), '#')
+ let $footnote-n := number(substring-after(., 'fn'))
+ let $document := root($node)//xhtml:div[@id=$document-id]
+ let $node-id := if ($document) then
+ $document/..//xhtml:aside[position()=$footnote-n]/@id
+ else ()
+ return ($document-id, $node-id, 'fn')
+ else if (matches(., '^#d\d+.+$')) then
+ (replace(., '^#(d\d+).+$', '$1'), substring-after(., '#'))
+ else
+ let $document := substring-after(., '#')
+ return if (contains($document, '#')) then
+ let $node := substring-after($document, '#')
+ let $document := substring-before($document, '#')
+ return ($document, $node, 'a#b')
+ else
+ ($document, (), 'doc')
+ else
+ ()
+ return
+ (:($nodes[3], ': ', $nodes[1], '/', $nodes[2], ' ::: ',:)
+ if ($nodes[1]) then
+ let $document := root($node)//xhtml:div[@id=$nodes[1]]/ancestor::entry/@name
+ let $document := if (starts-with($document, 'chapter-')) then
+ concat('ch-', substring-after($document, 'chapter-'))
+ else if (starts-with($document, 'compilation-')) then
+ concat('comp-', substring-after($document, 'compilation-'))
+ else if (starts-with($document, 'appendix-')) then
+ concat('app', substring-after($document, 'appendix-'))
+ else if (starts-with($document, 'conclusion')) then
+ 'conclusion'
+ else if (starts-with($document, 'introduction')) then
+ 'introduction'
+ else
+ $document
+ return if ($document) then
+ let $node := $document/id($nodes[2])
+ return concat(substring-after($document, 'OEBPS/'), if ($nodes[2]) then concat('#', $nodes[2]) else '')
+ else
+ if (contains($nodes[1], ('.xhtml', '::/'))) then
+ $nodes[1]
+ else
+ .
+ else
+ .)
+ (:):)
+ }),
+ for $child-node in $node/node()
+ return local:post-process-entry-contents($child-node)
+ )}
+ else $node
+ default return
+ if (count($node/node()) > 0) then
+ element {node-name($node)} {(
+ $node/@*,
+ for $child-node in $node/node()
+ return local:post-process-entry-contents($child-node)
+ )}
+ else
+ $node
+};
+declare function local:post-process-document($entries) {
+ let $result := for $entry in $entries
+ let $type := data($entry/@type)
+ return if ($type = ("text", "binary")) then
+ $entry
+ else
+ let $entry := local:post-process-entry-contents($entry)
+ let $ext := replace(data($entry/@name), "^.*\.([^.]*)", "$1")
+ let $entry := if ($ext = ("xhtml")) then
+ if ($entry[@name="OEBPS/nav.xhtml"]) then local:update-nav(($entry)) else
+ if ($entry[@name="OEBPS/title.xhtml"]) then () else
+ if ($entry[.//xhtml:body/xhtml:div/xhtml:p/text()="::delete::"][.//xhtml:head/xhtml:title/text()="--no title---"]) then
+ ()
+ else if ($entry/xhtml:html/xhtml:body/node()[1]/@id = ('cover', 'table-of-contents', 'title')) then
+ local:remove-title($entry, $entry/xhtml:html/xhtml:body/node()[1]/node()[1])
+ else
+ $entry
+ else if ($ext = "opf") then
+ local:update-content(($entry))
+ else if ($ext = "ncx") then
+ local:update-toc(($entry))
+ else
+ $entry
+ return $entry
+ return $result
+};
+
+declare function local:update-document($config, $doc) {
+ let $root := $doc/node()
+ return (document { element {node-name($root)} {(
+ $root/@*,
+ for $node in $root/*
+ return typeswitch ($node)
+ case element(tei:text) return
::delete::
{local:update-text($config, $node)}
+ default return $node
+ )} })
+};
+declare function local:update-text($config, $text) {
+ for $node in $text/node()
+ return typeswitch ($node)
+ case element(tei:front) return {(
+ local:cover-xhtml($config, $node),
+ local:title-xhtml($config),
+ (: for now, we don't need to update the contents of the about page
+ however we should recheck if its content changes in the future :)
+ (:local:update-text-node($config, local:about-xhtml($config)),:)
+ local:about-xhtml($config),
+ local:toc-xhtml($config, $text, true()),
+ for $sub-node in $node/tei:div[not(@xml:id = $epub2:frus-div-xmlids-to-suppress)]
+ return local:update-text-node($config, $sub-node, true())
+ )}
+ default return (
+ if (count($node/*) > 0) then
+ local:update-text-node($config, $node)
+ else
+ $node
+ )
+};
+declare function local:update-text-node($config, $node) {
+ local:update-text-node($config, $node, false())
+};
+declare function local:update-text-node($config, $node, $skip-nesting) {
+ typeswitch ($node)
+ case text() return $node
+ case element(tei:graphic) return element {node-name($node)} {(
+ ($node/@*[not(name()="url")], attribute url { local:cache-graphic-image($node) }),
+ $node/node()
+ )}
+ case element(tei:date) return element {node-name($node)} {(
+ $node/@*[not(name()="when")],
+ $node/node()
+ )}
+ case element(tei:head) return
+ let $attr := if ($node/parent::tei:div[./*[1] = $node][./parent::tei:front]) then
+ attribute rend { "front-title" }
+ else
+ ()
+ return element {node-name($node)} {(
+ ($node/@*, $attr),
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(xhtml:span) return
+ if ($node/@class eq 'ho:generate-month-year') then
+ format-date(current-date(), "[MNn] [Y0001]")
+ else
+ element {node-name($node)} {(
+ $node/@*,
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(tei:note) return
+ if ($node[@rend='inline']) then
+ {(
+ $node/@*[not(name()="when")],
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ else if ($node/@rend and empty(root($node)//*[xml:id=@rend])) then
+ ()
+ else
+ element {node-name($node)} {(
+ $node/@*[not(name()="when")],
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(frus:attachment) return
+ {(
+ if ($node/@xml:id) then else (),
+ $node/@*,
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(tei:ref) return
+ let $target := $node/@target
+ let $result :=
+ if (starts-with($target, '#')) then
+ if (starts-with($target, '#pg')) then
+ if (
+ let $first-node := $node/preceding-sibling::node()[1]
+ let $second-node := $node/preceding-sibling::node()[2]
+ return
+ $first-node eq '–' and $second-node instance of element(tei:ref) and $second-node[starts-with(@target, '#pg')]
+ ) then (
+ $target,
+ local:pb-range-to-document-links(
+ root($node),
+ substring-after($node/preceding-sibling::tei:ref[1]/@target, '#'),
+ substring-after($target, '#')
+ )
+ ) else if (subsequence($node/following-sibling::node(), 1, 1) eq '–' and subsequence($node/following-sibling::node(), 2, 1)/./self::tei:ref[starts-with(@target, '#pg')]) then
+ ($target, render:recurse($node, $options))
+ else (
+ ($target, (' ', local:pb-to-document-links(root($node), substring-after($target, '#'))))
+ )
+ else
+ ($target)
+ else if (contains($target, '#') and contains($target, 'fn')) then
+ (concat('http://history.state.gov/', $epub3:abs-site-uri, substring-before($target, '#'), '/',
+ concat(substring-before(substring-after($target, '#'), 'fn'), '#fn',
+ substring-after($target, 'fn')), (:$persistent-view:) false()))
+ else if (contains($target, '#')) then
+ (concat('http://history.state.gov/', $epub3:abs-site-uri, substring-before($target, '#'), '/', substring-after($target, '#')))
+ else if (starts-with($target, 'frus')) then
+ (concat('http://history.state.gov/', $epub3:abs-site-uri, $target))
+ else
+ ($target)
+ return
+ (
+ element { node-name($node) } {
+ $node/@*[local-name() != 'target'],
+ attribute target { $result[1] },
+ (:attribute target { concat($target, ' :: ', $result[1]) },:)
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ },
+ $result[2]
+ )
+ case element(tei:item) return element {node-name($node)} {(
+ $node/@*, if ($node/parent::tei:list/*[1][local-name()!="head"] and $node/parent::tei:list/@type = ('participants', 'subject', 'from', 'references', 'to') ) then
+ attribute rend { "subjectallcaps" }
+ else (),
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(tei:list) return
+ let $list-rend := if ($node/@type) then switch ($node/@type)
+ case 'index' return "index"
+ case 'indexentry' return "indexentry"
+ case 'ordered' return "customorder"
+ case 'bulleted' return "bulleted"
+ default return if ($node/@type = ('participants', 'subject', 'from', 'references', 'to')) then "subject" else ()
+ else ()
+ let $item-rend := if (($node/@type, $node/ancestor::tei:list/@type) = ('participants', 'subject', 'from', 'references', 'to')) then "subjectallcaps" else ()
+ let $list-attr := (
+ $node/@*[local-name() != 'rend'][local-name() != 'type'],
+ attribute rend { if ($list-rend) then ($node/@rend, $list-rend) else $node/@rend }
+ )
+ let $item-attr := if ($item-rend) then (attribute rend { $item-rend }) else ()
+ return if ($node/*[1][local-name()="head"]) then element {node-name($node)} {(
+ $list-attr, $node/@type,
+ {$item-attr[local-name() != 'rend'], attribute rend { ($item-attr[local-name() = 'rend'], "sub-list") },
+ $node/tei:head/node()},
+ for $child-node in $node/node()[./tei:list] return
+ local:update-text-node($config, $child-node)
+ ,
+
+ {$list-attr[local-name() != 'rend'], attribute rend { ($list-attr[local-name() = 'rend'], "sub-list") }}
+ {for $child-node in $node/node()[not(local-name()="head")][not(./tei:list)] return
+ local:update-text-node($config, $child-node)
+ }
+
+
+ )}
+ else element {node-name($node)} {(
+ $node/@*,
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ case element(tei:div) return
+ if ($skip-nesting) then
+ element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-text-node($config, $child)
+ )}
+ else if ($node/@type = ("document")) then
+ let $head := $node/tei:head
+ let $is-document := starts-with($head, concat($node/@n, '.')) or starts-with($head, concat('No. ', $node/@n))
+ return element {node-name($node)} {
+ $node/@*,
+ for $child in $node/node()[not(local-name()="headsss")]
+ return local:update-text-node($config, $child)
+ }
+ else if ($node/@type = ("chapter", "compilation", "section")) then (
+ let $notes := $node/tei:head/tei:note
+ let $content := if ($notes) then
+ for $note at $i in $notes
+ return
+
+
+ {($note/@n/string(), '*')[1]}
+
+
+
+ else ()
+ return element {node-name($node)} {(
+ $node/@*,
+ (
+ element {node-name($node/tei:head)} {(
+ (
+ $node/tei:head/@*,
+ attribute rend { if ($node/parent::tei:body) then "compilation-title" else "chapter-title" }
+ ),
+ $node/tei:head/node()
+ )}
+ ,
+
+ {(
+ $content,
+ if ($node/tei:div[@type!='document']) then
+ (
+ ,
+ Contents,
+
+
{
+ for $document in $node/tei:div[@type='chapter']
+ let $docnumber := frus:document-number($document)
+ let $docid := frus:document-id($document)
+ let $doctitle := frus:document-head-sans-number($document)
+ let $docsource := frus:source-note($document)/string()
+ let $docdateline := local:update-text-node($config, frus:dateline($document))
+ let $docsummary := $document//tei:note[@type='summary']/string()
+ return (
+ ,
+ {if (not(starts-with($document/tei:head, concat($document/@n, '.')))) then concat('[', $docnumber, ']') else concat($docnumber, '. '), $doctitle},
+
{$docdateline}
,
+ if (exists($docsummary)) then
{$docsummary}
else (),
+
{$docsource}
+ )
+ }
+
+ )
+ else (
+ for $document in $node/tei:div[@type='document']
+ let $docnumber := frus:document-number($document)
+ let $docid := frus:document-id($document)
+ let $doctitle := frus:document-head-sans-number($document)
+ let $docsource := frus:source-note($document)/string()
+ let $docdateline := local:update-text-node($config, frus:dateline($document))
+ let $docsummary := $document//tei:note[@type='summary']/string()
+ return (
+ ,
+ {if (not(starts-with($document/tei:head, concat($document/@n, '.')))) then concat('[', $docnumber, ']') else concat($docnumber, '. '), $doctitle},
+
{$docdateline}
,
+ if (exists($docsummary)) then
{$docsummary}
else (),
+
{$docsource}
+ )
+ )
+ )
+ }
+ ,
+ for $child in $node/node()[not(local-name()="head")]
+ return local:update-text-node($config, $child)
+ )
+ )})
+ else element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-text-node($config, $child)
+ )}
+ default return if (local-name($node)='attachment') then
+ (
+ if ($node/@xml:id) then else (),
+ $node/@*,
+ for $child-node in $node/node()
+ return if (local-name($child-node)='head') then
+ {(
+ $child-node/@*[not(name()="rend")],
+ attribute rend {($child-node/@rend, 'xhtml-h5')},
+ for $child-child-node in $child-node/node()
+ return local:update-text-node($config, $child-child-node)
+ )}
+ else local:update-text-node($config, $child-node)
+ )
+ else if (count($node/node()) > 0) then
+ element {node-name($node)} {(
+ $node/@*,
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ else
+ $node
+};
+declare function local:update-list-items($config, $node) {
+ typeswitch ($node)
+ case element(tei:graphic) return element {node-name($node)} {(
+ ($node/@*[not(name()="url")], attribute url { local:cache-graphic-image($node) }),
+ $node/node()
+ )}
+ case element(tei:list) return local:update-list($config, $node)
+ default return element {node-name($node)} {(
+ $node/@*,
+ for $child-node in $node/*
+ return local:update-list-items($config, $child-node)
+ )}
+};
+declare function local:update-list($config, $node) {
+ if ($node/*[1][local-name()="head"]) then
+ element {node-name($node)} {(
+ $node/@*,
+ $node/node(),
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ )}
+ else ({node-name($node/*[1])}, $node)
+};
+declare function local:about-xhtml($config) {
+ doc('/db/apps/release/resources/boilerplate/frus-about.tei.xml')//tei:text/tei:body/tei:div
+};
+
+declare function local:title-xhtml($config) {
+ let $volume-id := $config?metadata?id
+ let $volume := collection('/db/apps/frus/bibiliography')/volume[@id eq $volume-id]
+ let $editor-roles-to-display := ('primary', 'general')
+ let $editors := $volume/editor[@role = $editor-roles-to-display and . ne '']
+ let $published-year := $volume/published-year/string()
+ let $office-name := $volume/office-name/string()
+ let $office-parent := $volume/office-parent/string()
+ let $body :=
+
+ {concat(frus:volume-title($volume-id, 'series'), ', ', frus:volume-title($volume-id, 'sub-series'))}
+
+ H3:{frus:volume-title($volume-id, 'volume-number')}
+ {frus:volume-title($volume-id, 'volume')}
+ {
+ if ($editors) then
+
+ {
+ for $role in frus:editor-roles()[. = $editors/@role]
+ let $editors-in-role := $editors[@role = $role]
+ let $label :=
+ if (count($editors-in-role) gt 1) then
+ frus:editor-role-to-label($role, 'plural')
+ else
+ frus:editor-role-to-label($role, 'singular')
+ return
+ (
+ {$label}:
+ ,
+ for $ed in $editors-in-role
+ return
+ {$ed/string()}
+ )
+ }
+
+ else ()
+ }
+
+
+ United States Government Publishing Office
+ Washington
+ {$published-year}
+
+
+ U.S. Department of State
+ {$office-name}
+ {$office-parent}
+
+
+
+ This ebook was generated on {format-date(current-date(), "[MNn] [D1], [Y0001]")}.
+ Please visit the Office of the Historian ebooks web page to access updates.
+
+
+ let $title := 'Title page'
+ return local:topic($config, $body, "title", "Title", "section", "title")
+};
+
+declare function local:toc-xhtml($config, $text, $suppress-documents) {
+ local:topic($config,
+ Contents
+ {
+ local:frus-toc-to-li($text, $suppress-documents, $config?options)
+ }
+ , "table-of-contents", "Table of Contents", "section", "table-of-contents")
+};
+
+declare function local:topic($config, $doc, $id, $title, $type) {
+ local:topic($config, $doc, $id, $type, "")
+};
+
+declare function local:topic($config, $doc, $id, $title, $type, $subtype) {
+ (: TODO: tell tei-publisher to not render the title instead of removing the title from the content :)
+ let $content := for $node in $doc/node() return local:update-text-node($config, $node)
+ return {if ($subtype != "") then attribute subtype { $subtype } else ()}
+ {$title}
+ {$content}
+
+};
+
+declare function local:cover-xhtml($config, $node) {
+ local:topic($config,
+
+ , "cover", "Cover", "section", "cover")
+};
+
+declare function epub3:save-frus-epub-to-disk($path-to-tei-document as xs:string, $option as xs:string*, $file-system-output-dir as xs:string) {
+ (: volume id extracted from filename :)
+ let $vol-id := substring-after(substring-before($path-to-tei-document, '.xml'), 'volumes/')
+ (: images dir path specific to this volume :)
+ let $images-collection := concat($epub3:cache-collection, '/', $vol-id, '/images')
+ (: xml data of volume :)
+ let $item := doc($path-to-tei-document)
+ (: /teiHeader/fileDesc/titleStmt/title(5) :)
+ let $titles := $item//tei:titleStmt/tei:title
+ (: from the above titles, generate the following string: :)
+ (: volume (series, sub-series, volume-number) :)
+ let $title := normalize-space(concat($titles[@type eq 'volume'], ' (', string-join(($titles[@type eq 'series'], $titles[@type eq 'sub-series'], $titles[@type eq 'volume-number'])[. ne ''], ', '), ')'))
+ (: Constant :)
+ let $creator := 'Office of the Historian, Foreign Service Institute, United States Department of State'
+ (: /text node :)
+ let $text := $item//tei:text
+ (: id+timestamp :)
+ let $urn := concat($vol-id, '-', current-dateTime())
+ (: resources dir (css, images, and about.xml) :)
+ let $db-path-to-resources := '/db/apps/release/resources'
+ (: get cover image path, if not found download it, if not found use default cover :)
+ let $cover-uri :=
+ if (util:binary-doc-available(concat($images-collection, '/', $vol-id, '.jpg'))) then
+ concat($images-collection, '/', $vol-id, '.jpg')
+ else
+ let $href := concat('https://static.history.state.gov/frus/', $vol-id, '/covers/', $vol-id, '.jpg')
+ let $request :=
+ let $response := hc:send-request($request)
+ return
+ if ($response/@status eq '200') then
+ let $check-collection :=
+ if (xmldb:collection-available($images-collection)) then
+ ()
+ else
+ (
+ xmldb:create-collection($epub3:cache-collection, $vol-id),
+ xmldb:create-collection(concat($epub3:cache-collection, '/', $vol-id), 'images')
+ )
+ let $request :=
+ let $response := hc:send-request($request)
+ let $response-body := $response[2]
+ let $store := xmldb:store($images-collection, 'cover.jpg', $response-body, 'image/jpeg')
+ return
+ concat($images-collection, '/cover.jpg')
+ else
+ (concat($db-path-to-resources, '/images/epub-cover.jpg'))
+ return
+ let $epub-dir := concat($file-system-output-dir, 'epub')
+ let $mobi-dir := concat($file-system-output-dir, 'mobi-bound')
+ let $filename := concat($file-system-output-dir, if ($option = 'mobi') then 'mobi-bound/' else 'epub/', $vol-id, '.3.epub')
+ let $epub-zip := local:generate-epub($vol-id, $item, $title, $creator, $text, $urn, $db-path-to-resources, $cover-uri, $filename, $option)
+ return
+
+};
diff --git a/resources/boilerplate/frus-about.tei.xml b/resources/boilerplate/frus-about.tei.xml
new file mode 100644
index 0000000..6909376
--- /dev/null
+++ b/resources/boilerplate/frus-about.tei.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ About the Electronic Edition
+
+
+ United States Government Publishing Office
+
+
+
+
+
+
+
+ About the Electronic Edition
+
The Office of the Historian at the U.S. Department of State has embarked on a program to
+ release an ebook edition of the Foreign Relations of the United States
+ (FRUS) series, which was established in 1861. Far lighter and more portable
+ than printed editions of FRUS, the ebook edition offers the full content of each
+ volume and makes use of the full-text search and other reading features of most ebook
+ devices and applications, including bookmarking and note-taking. Unlike the web-based
+ edition of FRUS, the ebook edition, once downloaded, can be accessed even without
+ internet connectivity.
+
In creating the FRUS ebook edition, we endeavored to maintain fidelity with the
+ original printed edition. One challenge in this respect is representing original page
+ numbers from printed editions in ebooks. For readers who need to cite material in this
+ ebook, we recommend citing document numbers instead of page numbers, since document numbers
+ are persistent, media-neutral identifiers. In older FRUS volumes (before the
+ subseries covering the Johnson administration), where cross references use page numbers
+ rather than document numbers, we append to each page number a bracketed list of the document
+ numbers that correspond to it.
+
The Office of the Historian has worked to ensure that this ebook is error-free and works on a
+ broad range of devices. Please email history_ebooks@state.gov with any feedback.
+
To learn about updates to this ebook, other ebooks, and the ebook initiative in general,
+ visit our ebooks homepage,
+ and follow us on Twitter at @HistoryAtState
+ and Tumblr at HistoryAtState.
+
Office of the Historian Foreign Service
+ Institute U.S. Department of State
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/css/epub3.css b/resources/css/epub3.css
new file mode 100644
index 0000000..633c71a
--- /dev/null
+++ b/resources/css/epub3.css
@@ -0,0 +1,356 @@
+/* ====Updated CSS==== */
+body {
+ font-family: Palatino, Georgia, "Times New Roman", Times, serif;
+}
+
+/* ====Table of Contents==== */
+/* ====0. additional tei Styles==== */
+/* ====1. FRUS Document div Styles==== */
+/* ====2. FRUS Paragraph Styles==== */
+/* ====3. FRUS Footnote Styles ==== */
+/* ====4. FRUS List & Index Styles ==== */
+/* ====5. Bibliography Styles ==== */
+/* ====6. Tables ==== */
+/* ====7. Links ==== */
+
+/* ====0. additional tei Styles==== */
+p.h1 {
+ display: block;
+ font-size: 2em;
+ margin-block-start: 0.67em;
+ margin-block-end: 0.67em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+p.h2 {
+ display: block;
+ font-size: 1.5em;
+ margin-block-start: 0.83em;
+ margin-block-end: 0.83em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+p.h3 {
+ display: block;
+ font-size: 1.17em;
+ margin-block-start: 1em;
+ margin-block-end: 1em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+p.h4 {
+ display: block;
+ margin-block-start: 1.33em;
+ margin-block-end: 1.33em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+p.h5 {
+ display: block;
+ font-size: 0.83em;
+ margin-block-start: 1.67em;
+ margin-block-end: 1.67em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+p.h6 {
+ display: block;
+ font-size: 0.67em;
+ margin-block-start: 2.33em;
+ margin-block-end: 2.33em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+}
+/* additional styles for tei specific classes */
+.strong {
+ font-weight: bold;
+}to
+section[epub\:type="footnotes"], /*TODO: not working!!*/
+body > section:last-of-type {
+ margin-top: 1em;
+ padding-top: 1em;
+ counter-reset: footnotes;
+}
+section[epub\:type="footnotes"] > aside, /*TODO: not working!!*/
+body > section:last-of-type > aside {
+ display: list-item;
+ counter-increment: footnotes;
+}
+section[epub\:type="footnotes"] > aside:before, /*TODO: not working!!*/
+body > section:last-of-type > aside:before {
+ content: counter(footnotes) " ";
+ display: inline;
+ vertical-align: super;
+ font-size: smaller;
+ line-height: 0em;
+}
+.pagebreak.tei-pb {
+ display: none;
+ page-break-after: always;
+}
+div.tei-opener {
+ text-align: end;
+}
+a.noteref {
+ vertical-align: top;
+ font-size: 80%;
+ position: relative;
+ top: -0.3em;
+}
+div.tei-dateline {
+ float: right;
+}
+div.tei-opener div.tei-dateline {
+ float: none;
+}
+span.tei-milestone {
+ display: block;
+ background: #ddd;
+ color: #ddd;
+ clear: both;
+ float: none;
+ width: 100%;
+ height: .1em;
+ margin: 0 0 1.45em;
+ border: none;
+}
+span[class^="tei-figure"] {
+ display: block;
+}
+h1.compilation-title {
+ margin-block-start: 0.83em;
+ margin-block-end: 0.83em;
+ font-size: 3em;
+}
+h1.chapter-title {
+ margin-block-start: 1em;
+ margin-block-end: 1em;
+ font-size: 2.34em;
+}
+h1.front-title {
+ font-size: 1.5em;
+ margin-block-start: 0.83em;
+ margin-block-end: 0.83em;
+}
+p.xhtml-h5 {
+ font-size: 0.83em;
+ font-weight: bold;
+}
+a.ref-title {
+ font-weight: bold;
+}
+.italic {
+ font-style: italic;
+}
+/* ====1. FRUS Document div Styles==== */
+/* For ePubs, we use each device's default for divs */
+
+/* ====2. FRUS Paragraph Styles==== */
+/* Approximate print volume styles */
+p.sourceheadcenterboldbig {
+ text-align: center;
+ font-weight: bold;
+ font-size: 1.5em;
+ padding: 2px;
+}
+p.sourcearchiveboldbig {
+ font-weight: bold;
+ font-size:1.12em;
+}
+p.sourceparagraphspaceafter {
+ padding: 4px 0 0 0;
+}
+p.sourceparagraphfullindent {
+ margin-left: 20px;
+}
+p.sourceparagraphtightspacing {
+ line-height: 1em;
+}
+p.sourceparagraphbibliography {
+ padding-left: 4em;
+}
+ul.sourceparagraphbibliography {
+ padding-left: 10em;
+}
+div.tei-dateline {
+ text-align: right;
+}
+p.center {
+ text-align:center
+}
+p.right {
+ text-align: right
+}
+p.flushleft {
+ text-align: left;
+}
+div.tei-closer {
+ text-align: right;
+}
+div.tei-closer div[class^="tei-signed"],
+div.tei-closer div[class*=" tei-signed"] {
+ font-weight: bold
+}
+div.tei-closer div[class^="tei-signed"] em
+div.tei-closer div[class*=" tei-signed"] em {
+ font-weight: normal;
+ font-style: italic;
+}
+p.sectiontitleital {
+ font-style: italic;
+ margin-top: 2em;
+}
+p.sectiontitlebold {
+ font-weight: bold;
+ margin-top: 2em;
+}
+span.strikethrough {
+ text-decoration:line-through
+}
+
+/* ====3. FRUS Footnote Styles ==== */
+small {
+ font-size: smaller;
+}
+/* sup is used for footnote reference numbers */
+sup {
+ vertical-align: super;
+ font-size: smaller;
+ line-height: 0em;
+}
+/* prevents sourcenotes from inheriting bold styling of document titles */
+div.footnotes, div.footnotes p {
+ font-weight: normal;
+ font-size: .973em;
+}
+hr {
+ background: #ddd;
+ color: transparent;
+ clear: both;
+ float: none;
+ width: 100%;
+ height: 0.1em;
+ margin: 0 0 1.45em;
+ border:none;
+}
+hr.space {
+ background: #fff;
+ color: transparent;
+}
+
+/* ====4. FRUS List & Index Styles ==== */
+/* FRUS lists by default have no bullets.
+ Whereas HTML typically asserts list indentation as a ul property, we do it as a li property.
+ This allows us to move some lists leftward help with tei:list/tei:head */
+blockquote {
+ padding-left: 2em;
+ margin-left: 0
+}
+ul {
+ list-style-type: none;
+ padding-left: 0;
+ margin-left: 0;
+}
+li {
+ padding-left: 1em;
+ text-indent: -1em;
+}
+ul.bulleted {
+ list-style-type: disc;
+ margin-left: 2em;
+}
+ul.bulleted li {
+ padding-left: 0em;
+ margin-left: 0em;
+ text-indent: 0em;
+ padding-bottom: .75em;
+}
+/* Persons, Terms, and Index lists are flush left, and hanging lines are indented */
+#sources li, #persons li, #terms li, #index li, #table-of-contents li {
+ padding-left: 1em;
+ text-indent: -1em;
+}
+ul {
+ list-style-type: none;
+}
+/* give TOC a little extra vertical space*/
+#table-of-contents li{
+ padding-top: .2em;
+ padding-bottom: .2em;
+}
+/* "Subject" lists are small caps with space below */
+ul.subject {
+ font-size: .9em;
+ margin-left: 0;
+}
+ul.sub-list {
+ font-size: 1em;
+}
+li > ul {
+/* margin-inline-start: -2em;*/
+}
+ul.subject li {
+ text-indent: -4em;
+ padding-left: 4em;
+}
+ul.subject li.subjectallcaps {
+ text-indent: 0;
+ padding-left: 0;
+ font-variant: small-caps;
+ /*margin-inline-start: -2em;*/
+}
+/* for 1952-54 subjects - TODO: test once 1st volume is received */
+li.subjectflushleft {
+ padding-bottom: 1em;
+}
+ul.flushleft li.subjectallcaps,
+ul.subject li ul.sub-list {
+ padding-bottom: 1em;
+}
+li.sub-list ul {
+ padding-bottom: 1em;
+}
+p.subjectallcaps {
+ font-size: smaller;
+ font-variant: small-caps;
+}
+p.subjectentry {
+ padding: 0 0 0 30px;
+ font-size: smaller;
+ margin: 0
+}
+.bulleted {
+ list-style-type: disc;
+ padding-left: 1em;
+}
+
+/* ====5. Bibliographies ==== */
+ul.bibl {
+ list-style-type: none;
+ padding-left: 0;
+ margin-left: 0;
+}
+ul.bibl li {
+ padding-left: 2em;
+ text-indent: -2em;
+}
+/* ====6. Tables ==== */
+td.label {
+ font-weight: bold;
+}
+tr.label {
+ font-weight: bold;
+}
+
+/* ====7. Links ==== */
+/* show icon for external links */
+a[href ^='http://'] {
+ padding-right: 13px;
+ background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAFZJREFUeF59z4EJADEIQ1F36k7u5E7ZKXeUQPACJ3wK7UNokVxVk9kHnQH7bY9hbDyDhNXgjpRLqFlo4M2GgfyJHhjq8V4agfrgPQX3JtJQGbofmCHgA/nAKks+JAjFAAAAAElFTkSuQmCC") no-repeat scroll right center transparent;
+}
\ No newline at end of file
From f9c6298e9a34b43f8d1f1025943b9a2125a99c53 Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 29 Jun 2022 17:05:09 +0300
Subject: [PATCH 2/6] minor fixes
---
modules/epub3.xql | 10 +++++-----
resources/boilerplate/frus-about.tei.xml | 2 +-
resources/css/epub3.css | 6 ++++++
3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/modules/epub3.xql b/modules/epub3.xql
index e7144fe..0e642fe 100644
--- a/modules/epub3.xql
+++ b/modules/epub3.xql
@@ -772,18 +772,18 @@ declare function local:title-xhtml($config) {
}
- United States Government Publishing Office
- Washington
+ United States Government Publishing Office
+ Washington
{$published-year}
- U.S. Department of State
- {$office-name}
+ U.S. Department of State
+ {$office-name}
{$office-parent}
- This ebook was generated on {format-date(current-date(), "[MNn] [D1], [Y0001]")}.
+ This ebook was generated on {format-date(current-date(), "[MNn] [D1], [Y0001]")}.
Please visit the Office of the Historian ebooks web page to access updates.
diff --git a/resources/boilerplate/frus-about.tei.xml b/resources/boilerplate/frus-about.tei.xml
index 6909376..86431ee 100644
--- a/resources/boilerplate/frus-about.tei.xml
+++ b/resources/boilerplate/frus-about.tei.xml
@@ -36,7 +36,7 @@
visit our ebooks homepage,
and follow us on Twitter at @HistoryAtState
and Tumblr at HistoryAtState.
-
Office of the Historian Foreign Service
+
Office of the Historian Foreign Service
Institute U.S. Department of State
diff --git a/resources/css/epub3.css b/resources/css/epub3.css
index 633c71a..f65b0fd 100644
--- a/resources/css/epub3.css
+++ b/resources/css/epub3.css
@@ -148,6 +148,12 @@ a.ref-title {
.italic {
font-style: italic;
}
+.bold {
+ font-weight: bold;
+}
+.underline {
+ text-decoration: underline;
+}
/* ====1. FRUS Document div Styles==== */
/* For ePubs, we use each device's default for divs */
From 170050d9de798546aa7a36c62ba4ff4ad1cc8946 Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 29 Jun 2022 17:07:15 +0300
Subject: [PATCH 3/6] [fix] lists styles
---
modules/epub3.xql | 65 +++++++++++++++++++++++------------------
resources/css/epub3.css | 22 +-------------
2 files changed, 38 insertions(+), 49 deletions(-)
diff --git a/modules/epub3.xql b/modules/epub3.xql
index 0e642fe..6364803 100644
--- a/modules/epub3.xql
+++ b/modules/epub3.xql
@@ -465,6 +465,21 @@ declare function local:update-text-node($config, $node, $skip-nesting) {
$node/node()
)}
case element(tei:head) return
+ if ($node/parent::tei:list) then
+ (: tei-publisher-lib does not render head in list for now :)
+ {
+ $node/@* except $node/@rend,
+ attribute rend {
+ $node/@rend,
+ if ($node/ancestor::tei:list/@type = ('participants', 'subject', 'from', 'references', 'to') ) then
+ "subjectallcaps"
+ else
+ ()
+ },
+ for $child-node in $node/node()
+ return local:update-text-node($config, $child-node)
+ }
+ else
let $attr := if ($node/parent::tei:div[./*[1] = $node][./parent::tei:front]) then
attribute rend { "front-title" }
else
@@ -550,44 +565,38 @@ declare function local:update-text-node($config, $node, $skip-nesting) {
},
$result[2]
)
- case element(tei:item) return element {node-name($node)} {(
- $node/@*, if ($node/parent::tei:list/*[1][local-name()!="head"] and $node/parent::tei:list/@type = ('participants', 'subject', 'from', 'references', 'to') ) then
- attribute rend { "subjectallcaps" }
- else (),
+ case element(tei:item) return
+ let $rend := attribute rend {
+ $node/@rend,
+ if ($node/parent::tei:list/@type = 'subject' and $node/parent::tei:list/@rend = 'flushleft') then
+ "subjectflushleft" else ()
+ }
+ return element {node-name($node)} {(
+ $node/@* except $node/@rend, $rend,
for $child-node in $node/node()
return local:update-text-node($config, $child-node)
)}
case element(tei:list) return
- let $list-rend := if ($node/@type) then switch ($node/@type)
+ let $list-rend := if ($node/@type) then
+ switch ($node/@type)
case 'index' return "index"
case 'indexentry' return "indexentry"
case 'ordered' return "customorder"
case 'bulleted' return "bulleted"
- default return if ($node/@type = ('participants', 'subject', 'from', 'references', 'to')) then "subject" else ()
- else ()
- let $item-rend := if (($node/@type, $node/ancestor::tei:list/@type) = ('participants', 'subject', 'from', 'references', 'to')) then "subjectallcaps" else ()
+ default return
+ if ($node/@type = ('participants', 'subject', 'from', 'references', 'to')) then
+ "subject"
+ else
+ ()
+ else
+ ()
let $list-attr := (
- $node/@*[local-name() != 'rend'][local-name() != 'type'],
- attribute rend { if ($list-rend) then ($node/@rend, $list-rend) else $node/@rend }
+ $node/@* except $node/@rend,
+ attribute rend { $node/@rend, if ($list-rend) then $list-rend else () }
)
- let $item-attr := if ($item-rend) then (attribute rend { $item-rend }) else ()
- return if ($node/*[1][local-name()="head"]) then element {node-name($node)} {(
- $list-attr, $node/@type,
- {$item-attr[local-name() != 'rend'], attribute rend { ($item-attr[local-name() = 'rend'], "sub-list") },
- $node/tei:head/node()},
- for $child-node in $node/node()[./tei:list] return
- local:update-text-node($config, $child-node)
- ,
-
- {$list-attr[local-name() != 'rend'], attribute rend { ($list-attr[local-name() = 'rend'], "sub-list") }}
- {for $child-node in $node/node()[not(local-name()="head")][not(./tei:list)] return
- local:update-text-node($config, $child-node)
- }
-
-
- )}
- else element {node-name($node)} {(
- $node/@*,
+ return
+ element {node-name($node)} {(
+ $list-attr,
for $child-node in $node/node()
return local:update-text-node($config, $child-node)
)}
diff --git a/resources/css/epub3.css b/resources/css/epub3.css
index f65b0fd..44adeb5 100644
--- a/resources/css/epub3.css
+++ b/resources/css/epub3.css
@@ -290,27 +290,7 @@ ul {
padding-top: .2em;
padding-bottom: .2em;
}
-/* "Subject" lists are small caps with space below */
-ul.subject {
- font-size: .9em;
- margin-left: 0;
-}
-ul.sub-list {
- font-size: 1em;
-}
-li > ul {
-/* margin-inline-start: -2em;*/
-}
-ul.subject li {
- text-indent: -4em;
- padding-left: 4em;
-}
-ul.subject li.subjectallcaps {
- text-indent: 0;
- padding-left: 0;
- font-variant: small-caps;
- /*margin-inline-start: -2em;*/
-}
+
/* for 1952-54 subjects - TODO: test once 1st volume is received */
li.subjectflushleft {
padding-bottom: 1em;
From e97bc383155110d22632d5a35b693968803c5294 Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 29 Jun 2022 18:18:17 +0300
Subject: [PATCH 4/6] [fix] output-directory
---
ebook-batch.xq | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/ebook-batch.xq b/ebook-batch.xq
index d1aa7fa..8184be8 100644
--- a/ebook-batch.xq
+++ b/ebook-batch.xq
@@ -14,10 +14,9 @@ declare option output:method "html";
declare option output:media-type "text/html";
declare function local:output-directory() {
- '/tmp/'
-(: let $username := environment-variable('USER'):)
-(: return:)
-(: concat('/Users/', $username, '/Downloads/frus-ebooks-', substring(xs:string(current-date()), 1, 10), '/'):)
+ let $username := environment-variable('USER')
+ return
+ concat('/Users/', $username, '/Downloads/frus-ebooks-', substring(xs:string(current-date()), 1, 10), '/')
};
declare function local:generate-mobis() {
From d7225c7da583456be6f28fb54d689fef2845d5e1 Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 28 Sep 2022 19:57:44 +0300
Subject: [PATCH 5/6] [fix] failing to create chapter entries
---
modules/epub3.xql | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/modules/epub3.xql b/modules/epub3.xql
index 6364803..bff25f8 100644
--- a/modules/epub3.xql
+++ b/modules/epub3.xql
@@ -648,7 +648,6 @@ declare function local:update-text-node($config, $node, $skip-nesting) {
{
for $document in $node/tei:div[@type='chapter']
- let $docnumber := frus:document-number($document)
let $docid := frus:document-id($document)
let $doctitle := frus:document-head-sans-number($document)
let $docsource := frus:source-note($document)/string()
@@ -656,7 +655,7 @@ declare function local:update-text-node($config, $node, $skip-nesting) {
let $docsummary := $document//tei:note[@type='summary']/string()
return (
,
- {if (not(starts-with($document/tei:head, concat($document/@n, '.')))) then concat('[', $docnumber, ']') else concat($docnumber, '. '), $doctitle},
+ {$doctitle},
{$docdateline}
,
if (exists($docsummary)) then
{$docsummary}
else (),
{$docsource}
From aaaf88e7b1bfa45d091083a263175c0a9d214eb5 Mon Sep 17 00:00:00 2001
From: Charafeddine Cheraa
Date: Wed, 28 Sep 2022 19:57:49 +0300
Subject: [PATCH 6/6] [fix] missing document numbers in reader's TOC
---
modules/epub3.xql | 47 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 4 deletions(-)
diff --git a/modules/epub3.xql b/modules/epub3.xql
index bff25f8..bf7cf54 100644
--- a/modules/epub3.xql
+++ b/modules/epub3.xql
@@ -274,6 +274,12 @@ declare function local:update-nav($nodes) {
$node/@*,
local:update-nav($node/node())
)}
+ case element(xhtml:a) return
+ let $id := substring-after($node/@href/string(), '#')
+ return if (matches($id, "^d\d+$")) then element {node-name($node)} {(
+ $node/@*,
+ concat('[', substring-after($id, 'd'), '] ', $node/text())
+ )} else $node
default return element {node-name($node)} {(
$node/@*,
for $child in $node/node()
@@ -281,14 +287,47 @@ declare function local:update-nav($nodes) {
)}
};
+declare function local:update-navmap($nodes) {
+ for $node in $nodes
+ return typeswitch ($node)
+ case text() return $node
+ default return
+ if (name($node)='navPoint') then
+ element {node-name($node)} {
+ $node/@*,
+ for $child-node in $node/node() return
+ if (name($child-node)='navLabel') then
+ let $id := $node/@id/string()
+ return if (matches($id, "^navpoint-d\d+$")) then
+ element {node-name($child-node)} {
+ $child-node/@*,
+ let $text := $child-node/node()[name()='text']
+ return element {node-name($text)} {
+ $text/@*,
+ concat('[', substring-after($id, 'navpoint-d'), '] ', $text/text())
+ }
+ }
+ else
+ $child-node
+ else
+ local:update-navmap($child-node)
+ }
+ else
+ element {node-name($node)} {(
+ $node/@*,
+ for $child in $node/node()
+ return local:update-navmap($child)
+ )}
+};
+
declare function local:update-toc($nodes) {
for $node in $nodes
return typeswitch ($node)
case text() return $node
- case element(ncx:navMap) return
+ case element(ncx:navMap) return
element {node-name($node)} {(
$node/@*,
- $node/node()[not(@id="navpoint-title")][not(./text()="Title")]
+ local:update-navmap($node/node())
)}
default return element {node-name($node)} {(
$node/@*,
@@ -632,8 +671,8 @@ declare function local:update-text-node($config, $node, $skip-nesting) {
(
element {node-name($node/tei:head)} {(
(
- $node/tei:head/@*,
- attribute rend { if ($node/parent::tei:body) then "compilation-title" else "chapter-title" }
+ $node/tei:head/@*,
+ attribute rend { if ($node/parent::tei:body) then "compilation-title" else "chapter-title" }
),
$node/tei:head/node()
)}