Skip to content
Snippets Groups Projects
Commit 2d710cf1 authored by Yannis Barlas's avatar Yannis Barlas
Browse files

Merge branch 'vivliostyle-converter' into 'master'

Vivliostyle converter

See merge request !103
parents 5e7b29c3 3f52bad3
No related branches found
No related tags found
1 merge request!103Vivliostyle converter
Pipeline #3123 passed with stage
in 11 minutes and 28 seconds
const HTMLEPUB = require('html-epub')
const fs = require('fs')
const indexOf = require('lodash/indexOf')
const sorter = require('./sorter')
const converters = require('./converters')
const processFragment = require('./process')
const output = require('./output')
const config = require('config')
const EpubBackend = function (app) {
app.use('/api/collections/:id/epub', async function (req, res, next) {
......@@ -35,19 +37,37 @@ const EpubBackend = function (app) {
stylesRoot = `${__dirname}/themes`
}
let fontsRoot = config.epub && config.epub.fontsPath
? process.cwd() + config.epub.fontsPath
: null
if (!fs.existsSync(fontsRoot)) fontsRoot = ''
// converters
const activeConverters = [req.query.converter]
.filter(name => name && converters[name])
.map(name => converters[name])
const parts = fragments.sort(sorter).map(
processFragment({ styles, activeConverters })
const sortedFragments = fragments.sort(sorter)
const partsIds = sortedFragments
.filter(fragment => fragment.division === 'body' && fragment.subCategory === 'part') // HACK -- to remove
.map(fragment => fragment.id)
sortedFragments.forEach(fragment => {
let found = indexOf(partsIds, fragment.id)
if (found !== -1) {
fragment.number = found + 1
}
})
const parts = sortedFragments.map(
processFragment({ styles, activeConverters, book })
)
// TODO: read the path to the uploads folder from config
const resourceRoot = process.cwd() + '/uploads'
const epub = new HTMLEPUB(book, {resourceRoot, stylesRoot})
const epub = new HTMLEPUB(book, {resourceRoot, stylesRoot, fontsRoot})
await epub.load(parts)
......
module.exports = $ => {
module.exports = ($, fragmentTitle, bookTitle, fragmentDivision, fragmentSubcategory, fragmentNumber) => {
const body = $('body')
const replaceWithBlockquote = (i, elem) => {
let outerContainer = $('<div/>').attr('class', fragmentDivision)
let innerContainer
if (fragmentDivision === 'front') {
innerContainer = $('<section/>').attr('data-type', 'fm-body')
} else if (fragmentDivision === 'back') {
innerContainer = $('<section/>').attr('data-type', 'bm-body')
} else {
innerContainer = $('<section/>').attr('data-type', fragmentSubcategory)
}
$('<p/>').attr('class', 'ch-start').html('beginning').appendTo(innerContainer)
$('<div/>').attr('class', 'folio').appendTo(innerContainer)
$('<div/>').attr('class', 'booktitle').html(bookTitle).appendTo(innerContainer)
$('<div/>').attr('class', 'dup').html(fragmentTitle).appendTo(innerContainer)
if (fragmentSubcategory === 'part') {
$('<p/>').attr('class', 'part-number').html(fragmentNumber).appendTo(innerContainer)
} else if (fragmentSubcategory === 'chapter') {
$('<p/>').attr('class', 'chapter-number').html(fragmentNumber).appendTo(innerContainer)
}
$('<h1/>').attr('class', 'ct').html(fragmentTitle).appendTo(innerContainer)
const replaceWithBlockquote = className => (i, elem) => {
const $elem = $(elem)
const blockquote = $('<blockquote class="sc-blockquote"/>')
const blockquote = $(`<blockquote class="${className}"/>`)
.append($elem.contents())
$elem.replaceWith(blockquote)
......@@ -43,14 +65,19 @@ module.exports = $ => {
})
// replace custom HTML elements
$('extract-prose, extract-poetry, epigraph-poetry, epigraph-prose').each(replaceWithBlockquote)
$('extract').each(replaceWithBlockquote('ex')) // delete when xsweet is updated
$('extract-prose').each(replaceWithBlockquote('ex'))
$('extract-poetry').each(replaceWithBlockquote('px'))
$('epigraph-poetry').each(replaceWithBlockquote('sepo'))
$('epigraph-prose').each(replaceWithBlockquote('sep'))
$('bibliography-entry').each(replaceWithParagraph('bibliography-entry'))
$('comment').each(replaceWithText)
$('chapter-number').each(replaceWithParagraph('sc-chapter-number'))
$('chapter-title').each(replaceWithParagraph('sc-chapter-title'))
$('chapter-subtitle').each(replaceWithParagraph('sc-chapter-subtitle'))
$('source-note').each(replaceWithParagraph('source-note'))
$('ol[styling="qa"]').each(replaceWithList('sc-list-ol-qa'))
$('ol[styling="unstyled"]').each(replaceWithList('sc-list-ol-unstyled'))
// $('chapter-number').each(replaceWithParagraph('sc-chapter-number'))
$('chapter-title').each(replaceWithParagraph('ct'))
$('chapter-subtitle').each(replaceWithParagraph('cst'))
$('source-note').each(replaceWithParagraph('exsn'))
$('ol[styling="qa"]').each(replaceWithList('di'))
$('ol[styling="unstyled"]').each(replaceWithList('none'))
// remove "uploads" from the start of each src attribute
$('[src]').each((i, elem) => {
......@@ -77,17 +104,24 @@ module.exports = $ => {
const $elem = $(elem)
const id = $elem.attr('data-id')
const content = `${i + 1}. ${$elem.attr('note-content')}`
$('<aside epub:type="footnote" class="footnote"/>')
.attr('id', id)
.html(content)
.appendTo(body)
const callout = $('<a epub:type="noteref" class="note-callout"/>')
.attr('href', '#' + id)
.text(`[${i + 1}]`)
const noteNumber = `${i + 1}.`
const content = `${$elem.attr('note-content')}`
const callout = $(`
<a class="inline-note-callout" href="#${id}">
<sup>${i + 1}</sup>
</a>
<span class="inline-note-footer" data-note-num="${id}">
<span class="inline-note-number"> ${noteNumber} </span>
<span class="inline-note-content"> ${content} </span>
</span>
`)
$elem.replaceWith(callout)
})
let bodyContent = body.contents()
innerContainer.append(bodyContent)
outerContainer.append(innerContainer)
body.replaceWith(outerContainer)
}
source diff could not be displayed: it is too large. Options to address this: view the blob.
......@@ -11,7 +11,7 @@
"dependencies": {
"@pubsweet/logger": "^0.0.1",
"cheerio": "^1.0.0-rc.2",
"html-epub": "^0.5.0",
"html-epub": "^0.5.1",
"mkdirp": "^0.5.1",
"unzipper": "^0.8.9"
},
......
const cheerio = require('cheerio')
module.exports = ({ styles, activeConverters }) => fragment => {
module.exports = ({ styles, activeConverters, book }) => fragment => {
const $ = cheerio.load(fragment.source)
const fragmentTitle = fragment.title
const bookTitle = book.title
const fragmentDivision = fragment.division
const fragmentSubcategory = fragment.subCategory
const fragmentNumber = fragment.hasOwnProperty('number') ? fragment.number : -1
activeConverters.forEach(converter => converter($))
activeConverters.forEach(converter => converter($, fragmentTitle, bookTitle, fragmentDivision, fragmentSubcategory, fragmentNumber))
styles.forEach(uri => {
$('<link rel="stylesheet"/>').attr('href', uri).appendTo('head')
......
......@@ -5,18 +5,27 @@ const processFragment = require('./process')
test('converts source to html', () => {
const fragment = {
title: 'A Test',
division: 'body',
subCategory: 'part',
number: 3,
source: `
<div>
<h1>A Test</h1>
<p>Test</p>
</div>
`
`,
id: '1'
}
const book = {
title: 'Test Book',
identifier: '65ac5abe353ef4d32f1ce55abfe665185d58d811883b1715032b8ed70a8cc1e1'
}
const styles = ['test.css']
const activeConverters = [converters['wax']]
const { title, content } = processFragment({styles, activeConverters})(fragment)
const { title, content } = processFragment({styles, activeConverters, book})(fragment)
expect(title).toBe('A Test')
......
This diff is collapsed.
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment