epub-maker2
Version:
Easily create epub files with javascript
348 lines (288 loc) • 8.4 kB
text/typescript
import zipLib, { JSZip } from '../../epubtpl-lib/zip';
import { compileTpl, Handlebars } from '../../epubtpl-lib/handlebar-helpers';
import { fetchFile } from '../../epubtpl-lib/ajax';
import { compileCss } from '../../epubtpl-lib/postcss';
import path from 'upath2';
import { IBuilder } from '../../var';
import { EpubMaker } from '../../index';
import { BPromise, shortid } from '../../lib/util';
import { EnumEpubConfigVertical } from '../../config';
export const EPUB_TEMPLATES_PATH = path.join(__dirname) as string;
export const EPUB_TEMPLATES_TPL = path.join(EPUB_TEMPLATES_PATH, 'tpl') as string;
declare module '../../index'
{
namespace EpubMaker
{
interface Section
{
needPage: boolean;
name: string;
rank: number | string;
}
}
}
export namespace Builder
{
export let templates = {
//mimetype: 'mimetype',
//container: 'META-INF/container.xml',
opf: 'EPUB/content.opf',
ncx: 'EPUB/toc.ncx',
nav: 'EPUB/nav.xhtml',
css: 'EPUB/css/main.css',
content: 'EPUB/content.xhtml',
autoToc: 'EPUB/auto-toc.xhtml',
sectionsNavTemplate: 'EPUB/sections-nav-template.html',
sectionsNCXTemplate: 'EPUB/sections-ncx-template.xml',
sectionsOPFManifestTemplate: 'EPUB/sections-opf-manifest-template.xml',
sectionsOPFSpineTemplate: 'EPUB/sections-opf-spine-template.xml',
coverPage: 'EPUB/CoverPage.xhtml',
tableOfContents: 'EPUB/TableOfContents.xhtml',
sectionsInfo: 'EPUB/sections-info.html',
sectionsScript: 'EPUB/sections-script.html',
contents: 'EPUB/contents.xhtml',
};
for (let i in templates)
{
templates[i] = `\{\{import \'${path.join(EPUB_TEMPLATES_TPL, templates[i])}'\}\}`;
}
let playOrder = 0;
export let staticFiles = {
'mimetype': 'mimetype',
'META-INF/container.xml': 'META-INF/container.xml',
};
for (let i in staticFiles)
{
staticFiles[i] = path.join(EPUB_TEMPLATES_TPL, staticFiles[i]);
}
export function make(epub: EpubMaker, options?): BPromise<JSZip>
{
//let epubConfig = epub.epubConfig;
options = Object.assign({}, {
templates: templates,
}, options);
//console.debug('[building epub]', epub.epubConfig);
//console.debug('[building epub]', options);
let zip = new JSZip();
//await addAditionalInfo(zip, epub, options);
Handlebars.registerPartial('sectionsInfo', options.templates.sectionsInfo);
Handlebars.registerPartial('sectionsScript', options.templates.sectionsScript);
return BPromise
.mapSeries([
addStaticFiles,
addAditionalInfo,
//zipLib.addMimetype,
//zipLib.addContainerInfo,
addCover,
zipLib.addFiles,
addStylesheets,
addManifestOpf,
addEpub2Nav,
addEpub3Nav,
addContent,
tableOfContents,
], async function (fn, index)
{
if (fn === zipLib.addFiles)
{
return (fn as typeof zipLib.addFiles)(zip, epub, options)
.then(function (ls)
{
return ls;
})
;
}
return fn(zip, epub, options);
})
.tap(function ()
{
//console.log(epub.epubConfig.cover);
})
.then(function ()
{
return zip;
})
//.catch(err => console.log(err))
;
}
export function addStaticFiles(zip, epub: EpubMaker, options)
{
let ls = Object.keys(staticFiles).reduce(function (a, key)
{
let b = {
name: key,
ext: '',
file: staticFiles[key],
};
a.push(b);
return a;
}, []);
return zipLib.addStaticFiles(zip, ls);
}
export async function tableOfContents(zip, epub: EpubMaker, options)
{
zip
.folder('EPUB')
.file('TableOfContents.xhtml', compileTpl(options.templates.tableOfContents, epub.epubConfig))
;
zip
.folder('EPUB')
.file('contents.xhtml', compileTpl(options.templates.contents, epub.epubConfig))
;
}
export async function addCover(zip, epub: EpubMaker, options)
{
let bool = await zipLib.addCover(zip, epub, options);
if (bool)
{
zip
.folder('EPUB')
.file('CoverPage.xhtml', compileTpl(options.templates.coverPage, epub.epubConfig))
;
}
else
{
epub.epubConfig.cover = null;
}
}
export function addInfoSection(section, titlePrefix?, namePrefix?)
{
let c = '_';
if (!section.content)
{
section.content = {};
}
if (titlePrefix)
{
titlePrefix = section.content.fullTitle = titlePrefix + ' - ' + section.content.title;
namePrefix = section.name = namePrefix + c + section.rank;
}
else
{
titlePrefix = section.content.fullTitle = section.content.title;
namePrefix = section.name = section.rank;
}
if (section.content.content || section.content.renderTitle || section.epubType == 'auto-toc')
{
section.needPage = true;
}
section.playOrder = playOrder++;
if (!section.id)
{
section.id = (section.epubType || '').toString().replace('/\W/g', '') + shortid();
}
for (let i = 0; i < section.subSections.length; i++)
{
section.subSections[i].rank = i.toString().padStart(3, '0');
addInfoSection(section.subSections[i], titlePrefix, namePrefix);
}
}
export function addAditionalInfo(zip, epub: EpubMaker, options)
{
//Default options
// @ts-ignore
epub.epubConfig.options.tocName = epub.epubConfig.options.tocName || 'Menu';
//Generate name and full title for each section/subsection
for (let i = 0; i < epub.epubConfig.sections.length; i++)
{
epub.epubConfig.sections[i].rank = i.toString().padStart(3, '0');
addInfoSection(epub.epubConfig.sections[i]);
}
}
export function addManifestOpf(zip, epub: EpubMaker, options)
{
Handlebars.registerPartial('sectionsOPFManifestTemplate', options.templates.sectionsOPFManifestTemplate);
Handlebars.registerPartial('sectionsOPFSpineTemplate', options.templates.sectionsOPFSpineTemplate);
zip.folder('EPUB').file('content.opf', compileTpl(options.templates.opf, epub.epubConfig));
}
export function addEpub2Nav(zip, epub: EpubMaker, options)
{
Handlebars.registerPartial('sectionsNCXTemplate', options.templates.sectionsNCXTemplate);
zip.folder('EPUB').file('toc.ncx', compileTpl(options.templates.ncx, epub.epubConfig));
}
export function addEpub3Nav(zip, epub: EpubMaker, options)
{
Handlebars.registerPartial('sectionsNavTemplate', options.templates.sectionsNavTemplate);
zip.folder('EPUB').file('nav.xhtml', compileTpl(options.templates.nav, epub.epubConfig));
}
export async function addStylesheets(zip, epub: EpubMaker, options)
{
if (epub.epubConfig.vertical === EnumEpubConfigVertical.VERTICAL_RL)
{
try
{
const fs = require('fs') as typeof import('fs');
let data = fs.readFileSync(path.join(__dirname, './tpl/EPUB/css/vertical-rl.css'));
let file = await fetchFile({
data,
});
epub.epubConfig.stylesheet.styles += "\n" + file.data.toString();
}
catch (e)
{
console.error(e);
}
}
if (epub.epubConfig.stylesheet.url || epub.epubConfig.stylesheet.file)
{
let file = await fetchFile(epub.epubConfig.stylesheet);
epub.epubConfig.stylesheet.styles += "\n" + file.data.toString();
}
return compileAndAddCss();
async function compileAndAddCss()
{
let styles = {
original: epub.epubConfig.stylesheet.replaceOriginal ? '' : options.templates.css,
custom: epub.epubConfig.stylesheet.styles || '',
};
let css = await compileTpl(`${styles.original}\n${styles.custom}`, styles, true);
css = await compileCss(css);
return zip.folder('EPUB')
.folder('css')
.file('main.css', css)
;
}
}
export function addSection(zip: JSZip, section: EpubMaker.Section, epub: EpubMaker, options)
{
return zipLib.addSubSections(zip, section, function (zip, section, epubConfig, options)
{
if (section.needPage)
{
let name = section.name + '.xhtml';
if (section.epubType == 'auto-toc')
{
return zip
.folder('EPUB')
.file(name, compileTpl(options.templates.autoToc, section))
;
}
else
{
return zip
.folder('EPUB')
.file(name, compileTpl(options.templates.content, section))
;
}
}
return false;
}, epub, options);
}
export function addContent(zip, epub: EpubMaker, options)
{
return BPromise.mapSeries(epub.epubConfig.sections, function (section)
{
return addSection(zip, section, epub, options);
});
}
}
// @ts-ignore
export const builder = Builder as IBuilder;
export default builder as IBuilder;
/*
if (typeof window !== 'undefined')
{
// @ts-ignore
window.epubMaker = builder;
}
*/