diff --git a/modules/lib/api.json b/modules/lib/api.json index 409e2af4b..08bd55404 100644 --- a/modules/lib/api.json +++ b/modules/lib/api.json @@ -1034,6 +1034,14 @@ "example": "docbook.odd" } }, + { + "name": "nav-root", + "in": "query", + "schema": { + "type": "string", + "example": "1.4" + } + }, { "name": "images-collection", "in": "query", diff --git a/modules/lib/api/document.xql b/modules/lib/api/document.xql index 2fe953eb8..e0de28df9 100644 --- a/modules/lib/api/document.xql +++ b/modules/lib/api/document.xql @@ -373,12 +373,15 @@ declare function dapi:epub($request as map(*)) { }; declare %private function dapi:work2epub($request as map(*), $id as xs:string, $work as document-node(), $lang as xs:string?) { + let $navRootParam := $request?parameters?nav-root + let $navRoot := if ($navRootParam) then util:node-by-id($work, $navRootParam) else () let $imagesCollection := $request?parameters?images-collection let $coverImage := $request?parameters?cover-image let $config := map:merge(($config:epub-config($work, $lang), map { 'imagesCollection': $imagesCollection, 'skipTitle': $request?parameters?skip-title, - 'coverImage': $coverImage + 'coverImage': $coverImage, + 'navRoot': $navRoot })) let $odd := head(($request?parameters?odd, $config:default-odd)) let $oddName := replace($odd, "^([^/\.]+).*$", "$1") diff --git a/modules/lib/epub.xql b/modules/lib/epub.xql index 629d999cb..9a4daae61 100644 --- a/modules/lib/epub.xql +++ b/modules/lib/epub.xql @@ -260,7 +260,7 @@ declare function epub:nav-entry($config, $text) { diff --git a/test/navigation.test.js b/test/navigation.test.js new file mode 100644 index 000000000..54ad95b16 --- /dev/null +++ b/test/navigation.test.js @@ -0,0 +1,94 @@ +const util = require('./util.js'); +const path = require('path'); +const FormData = require('form-data'); +const chai = require('chai'); +const chaiXML = require('chai-xml'); +const expect = chai.expect; +const chaiResponseValidator = require('chai-openapi-response-validator'); +const jsdom = require("jsdom"); +const zip = require('adm-zip'); +const { JSDOM } = jsdom; + +const spec = path.resolve("./modules/lib/api.json"); +chai.use(chaiResponseValidator(spec)); +chai.use(chaiXML); + +const testXml = ` + + + + EPUB Navigation Test + + +

+ + +

+ + + + + +

+ Pre-Document 1 +

Pre-Document 1 body

+
+
+ Pre-Document 2 +

Pre-Document 2 body

+
+
+ Pre-Document 3 +

Pre-Document 3 body

+
+ + +
+ Document 4 +

Document 4 body

+
+
+ Document 5 +

Document 5 body

+
+
+ Document 6 +

Document 6 body

+
+ + +
`; + +function getNav(data) { + return new zip(Buffer.from(data)).getEntries().find(({ entryName }) => entryName === 'OEBPS/nav.xhtml')?.getData().toString('utf-8'); +} + +describe('/api/document/{document}}/epub?nav-root=', function() { + before(async () => { + await util.login(); + const formData = new FormData() + formData.append('files[]', testXml, "nav.xml"); + const res = await util.axios.post('upload/playground', formData, { + headers: formData.getHeaders() + }); + expect(res.data).to.have.length(1); + expect(res.data[0].name).to.equal('/db/apps/tei-publisher/data/playground/nav.xml'); + expect(res).to.satisfyApiSpec; + }); + + it('let tei-publisher determine the navigation root', async () => { + const res = await util.axios.get('document/playground%2Fnav.xml/epub', { responseType: 'arraybuffer' }); + expect(res.status).to.equal(200); + const document = new JSDOM(getNav(res.data), { contentType: "application/xml" }).window.document; + expect(document.querySelectorAll('li').length).to.equal(3); + }); + + it('define navigation root', async () => { + const res = await util.axios.get('document/playground%2Fnav.xml/epub?nav-root=1.4', { responseType: 'arraybuffer' }); + expect(res.status).to.equal(200); + const document = new JSDOM(getNav(res.data), { contentType: "application/xml" }).window.document; + expect(document.querySelectorAll('li').length).to.equal(6); + }); + + after(util.logout); +}); \ No newline at end of file