wp-epub-gen 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +142 -84
- package/build/index.js +142 -84
- package/build/templates.d.ts +1 -1
- package/build/types.d.ts +1 -0
- package/package.json +1 -1
- package/templates/template.css +106 -27
package/build/index.cjs
CHANGED
|
@@ -363,20 +363,24 @@ function loadAndProcessHtml(data) {
|
|
|
363
363
|
}
|
|
364
364
|
try {
|
|
365
365
|
let $ = cheerio__namespace.load(trimmedData, {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
366
|
+
xmlMode: true,
|
|
367
|
+
// @ts-ignore
|
|
368
|
+
decodeEntities: false,
|
|
369
|
+
lowerCaseTags: true,
|
|
370
|
+
recognizeSelfClosing: true,
|
|
371
|
+
lowerCaseAttributeNames: true
|
|
370
372
|
});
|
|
371
373
|
const body = $("body");
|
|
372
374
|
if (body.length) {
|
|
373
375
|
const html = body.html();
|
|
374
376
|
if (html) {
|
|
375
377
|
$ = cheerio__namespace.load(html, {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
378
|
+
xmlMode: true,
|
|
379
|
+
// @ts-ignore
|
|
380
|
+
decodeEntities: false,
|
|
381
|
+
lowerCaseTags: true,
|
|
382
|
+
recognizeSelfClosing: true,
|
|
383
|
+
lowerCaseAttributeNames: true
|
|
380
384
|
});
|
|
381
385
|
}
|
|
382
386
|
}
|
|
@@ -436,7 +440,7 @@ function processImages($, chapter, epubConfigs) {
|
|
|
436
440
|
}
|
|
437
441
|
const trimmedUrl = url2.trim();
|
|
438
442
|
try {
|
|
439
|
-
if (!trimmedUrl.match(/^(https?:\/\/|data:|\.\/|\/)/)) {
|
|
443
|
+
if (!trimmedUrl.match(/^(https?:\/\/|file:\/\/|data:|\.\/|\/)/)) {
|
|
440
444
|
logger.warn(`Image URL "${trimmedUrl}" appears to be invalid, but processing anyway`);
|
|
441
445
|
}
|
|
442
446
|
} catch (error) {
|
|
@@ -493,54 +497,20 @@ function processImages($, chapter, epubConfigs) {
|
|
|
493
497
|
}
|
|
494
498
|
});
|
|
495
499
|
}
|
|
496
|
-
function extractAndCleanHtmlContent(
|
|
500
|
+
function extractAndCleanHtmlContent($) {
|
|
497
501
|
let data;
|
|
498
502
|
if ($("body").length) {
|
|
499
503
|
data = $("body").html() || "";
|
|
500
504
|
} else {
|
|
501
505
|
data = $.root().html() || "";
|
|
502
506
|
}
|
|
503
|
-
|
|
504
|
-
return data.replace(
|
|
505
|
-
/<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)><\/\1>/gi,
|
|
506
|
-
"<$1$2/>"
|
|
507
|
-
).replace(
|
|
508
|
-
new RegExp("<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)(?<!\\/)>", "gi"),
|
|
509
|
-
"<$1$2/>"
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
const entityMap = /* @__PURE__ */ new Map();
|
|
513
|
-
const entityRegex = /&[a-zA-Z][a-zA-Z0-9]*;|&#[0-9]+;|&#x[0-9a-fA-F]+;/g;
|
|
514
|
-
const matches = Array.from(originalData.matchAll(entityRegex));
|
|
515
|
-
let processedOriginal = originalData;
|
|
516
|
-
const timestamp = Date.now();
|
|
517
|
-
const randomId = Math.random().toString(36).substring(2, 8);
|
|
518
|
-
const placeholderPrefix = `__ENTITY_${timestamp}_${randomId}_`;
|
|
519
|
-
for (let i = matches.length - 1; i >= 0; i--) {
|
|
520
|
-
const match = matches[i];
|
|
521
|
-
const placeholder = `${placeholderPrefix}${i}__`;
|
|
522
|
-
entityMap.set(placeholder, match[0]);
|
|
523
|
-
processedOriginal = processedOriginal.substring(0, match.index) + placeholder + processedOriginal.substring(match.index + match[0].length);
|
|
524
|
-
}
|
|
525
|
-
const $temp = cheerio__namespace.load(processedOriginal, {
|
|
526
|
-
xmlMode: false
|
|
527
|
-
});
|
|
528
|
-
let tempData;
|
|
529
|
-
if ($temp("body").length) {
|
|
530
|
-
tempData = $temp("body").html() || "";
|
|
531
|
-
} else {
|
|
532
|
-
tempData = $temp.root().html() || "";
|
|
533
|
-
}
|
|
534
|
-
for (const [placeholder, entity] of entityMap) {
|
|
535
|
-
tempData = tempData.replace(new RegExp(placeholder, "g"), entity);
|
|
536
|
-
}
|
|
537
|
-
return tempData.replace(
|
|
507
|
+
return data.replace(
|
|
538
508
|
/<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)><\/\1>/gi,
|
|
539
509
|
"<$1$2/>"
|
|
540
510
|
).replace(
|
|
541
511
|
new RegExp("<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)(?<!\\/)>", "gi"),
|
|
542
512
|
"<$1$2/>"
|
|
543
|
-
);
|
|
513
|
+
).replace(/<\/img\s*>/gi, "");
|
|
544
514
|
}
|
|
545
515
|
function processChildrenChapters(chapter, index2, epubConfigs) {
|
|
546
516
|
if (Array.isArray(chapter.children)) {
|
|
@@ -574,7 +544,7 @@ function parseContent(content, index2, epubConfigs) {
|
|
|
574
544
|
}
|
|
575
545
|
processHtmlElements($, allowedAttributes, allowedXhtml11Tags, epubConfigs, index2);
|
|
576
546
|
processImages($, chapter, epubConfigs);
|
|
577
|
-
chapter.data = extractAndCleanHtmlContent(
|
|
547
|
+
chapter.data = extractAndCleanHtmlContent($);
|
|
578
548
|
}
|
|
579
549
|
processChildrenChapters(chapter, index2, epubConfigs);
|
|
580
550
|
return chapter;
|
|
@@ -870,52 +840,131 @@ const epub3_toc_xhtml_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
|
870
840
|
</body>
|
|
871
841
|
</html>
|
|
872
842
|
`;
|
|
873
|
-
const template_css =
|
|
874
|
-
|
|
843
|
+
const template_css = `/* =========================
|
|
844
|
+
EPUB 3 Base Stylesheet
|
|
845
|
+
========================= */
|
|
846
|
+
|
|
847
|
+
/* 全局基础设置 */
|
|
848
|
+
html {
|
|
849
|
+
font-size: 100%;
|
|
875
850
|
}
|
|
876
851
|
|
|
877
|
-
|
|
878
|
-
margin
|
|
852
|
+
body {
|
|
853
|
+
margin: 0;
|
|
854
|
+
padding: 0;
|
|
855
|
+
line-height: 1.6;
|
|
856
|
+
font-family: serif;
|
|
857
|
+
color: #000;
|
|
858
|
+
background-color: transparent;
|
|
879
859
|
}
|
|
880
860
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
861
|
+
/* 段落 */
|
|
862
|
+
p {
|
|
863
|
+
margin: 0;
|
|
864
|
+
padding: 0;
|
|
865
|
+
/*text-indent: 2em;*/
|
|
866
|
+
orphans: 2;
|
|
867
|
+
widows: 2;
|
|
884
868
|
}
|
|
885
869
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
870
|
+
/* 标题 */
|
|
871
|
+
h1,
|
|
872
|
+
h2,
|
|
873
|
+
h3,
|
|
874
|
+
h4,
|
|
875
|
+
h5,
|
|
876
|
+
h6 {
|
|
877
|
+
font-weight: bold;
|
|
878
|
+
line-height: 1.3;
|
|
879
|
+
margin: 1.2em 0 0.6em 0;
|
|
880
|
+
text-indent: 0;
|
|
881
|
+
page-break-after: avoid;
|
|
889
882
|
}
|
|
890
883
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
font-size: 85%;
|
|
894
|
-
display: block;
|
|
884
|
+
h1 {
|
|
885
|
+
font-size: 1.6em;
|
|
895
886
|
}
|
|
896
887
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
border-bottom: 1px solid #dedede;
|
|
900
|
-
margin: 60px 10%;
|
|
888
|
+
h2 {
|
|
889
|
+
font-size: 1.4em;
|
|
901
890
|
}
|
|
902
891
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
892
|
+
h3 {
|
|
893
|
+
font-size: 1.2em;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/* 章节标题常用居中 */
|
|
897
|
+
.chapter-title {
|
|
898
|
+
text-align: center;
|
|
899
|
+
margin-top: 2em;
|
|
900
|
+
margin-bottom: 1.5em;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/* 首段不缩进(常用于章节开头) */
|
|
904
|
+
.no-indent {
|
|
905
|
+
text-indent: 0;
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
-
|
|
908
|
+
/* 强调 */
|
|
909
|
+
em {
|
|
910
|
+
font-style: italic;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
strong {
|
|
914
|
+
font-weight: bold;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/* 引用 */
|
|
918
|
+
blockquote {
|
|
919
|
+
margin: 1em 1.5em;
|
|
909
920
|
padding: 0;
|
|
910
|
-
margin-left: 2em;
|
|
911
921
|
}
|
|
912
922
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
923
|
+
/* 分隔符(如 ***) */
|
|
924
|
+
hr {
|
|
925
|
+
border: none;
|
|
926
|
+
text-align: center;
|
|
927
|
+
margin: 1.5em 0;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* 图片 */
|
|
931
|
+
img {
|
|
932
|
+
max-width: 100%;
|
|
933
|
+
height: auto;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/* 图片居中 */
|
|
937
|
+
.figure {
|
|
938
|
+
text-align: center;
|
|
939
|
+
margin: 1em 0;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/* 列表 */
|
|
943
|
+
ul,
|
|
944
|
+
ol {
|
|
945
|
+
margin: 1em 0 1em 1.5em;
|
|
917
946
|
padding: 0;
|
|
918
947
|
}
|
|
948
|
+
|
|
949
|
+
li {
|
|
950
|
+
margin: 0.3em 0;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/* 表格(谨慎使用) */
|
|
954
|
+
table {
|
|
955
|
+
border-collapse: collapse;
|
|
956
|
+
margin: 1em 0;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
td,
|
|
960
|
+
th {
|
|
961
|
+
padding: 0.3em 0.5em;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/* 分页控制(EPUB 安全用法) */
|
|
965
|
+
.page-break {
|
|
966
|
+
page-break-before: always;
|
|
967
|
+
}
|
|
919
968
|
`;
|
|
920
969
|
const toc_ncx_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
921
970
|
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
|
@@ -965,12 +1014,20 @@ const toc_ncx_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
|
965
1014
|
`;
|
|
966
1015
|
const generateTempFile = async (epubData) => {
|
|
967
1016
|
const { log } = epubData;
|
|
968
|
-
const
|
|
969
|
-
await fs$1.ensureDir(
|
|
970
|
-
|
|
971
|
-
|
|
1017
|
+
const oebpsDir = path.join(epubData.dir, "OEBPS");
|
|
1018
|
+
await fs$1.ensureDir(oebpsDir);
|
|
1019
|
+
const customCss = epubData.css || "";
|
|
1020
|
+
if (!epubData.noDefaultCss) {
|
|
1021
|
+
epubData.css = template_css;
|
|
1022
|
+
if (customCss) {
|
|
1023
|
+
epubData.css += "\n\n" + customCss;
|
|
1024
|
+
}
|
|
1025
|
+
} else {
|
|
1026
|
+
epubData.css = customCss;
|
|
1027
|
+
}
|
|
1028
|
+
await writeFile(path.join(oebpsDir, "style.css"), epubData.css, "utf-8");
|
|
972
1029
|
if (epubData.fonts?.length) {
|
|
973
|
-
const fonts_dir = path.join(
|
|
1030
|
+
const fonts_dir = path.join(oebpsDir, "fonts");
|
|
974
1031
|
await fs$1.ensureDir(fonts_dir);
|
|
975
1032
|
epubData.fonts = epubData.fonts.map((font) => {
|
|
976
1033
|
const filename = path.basename(font);
|
|
@@ -1056,14 +1113,14 @@ const generateTempFile = async (epubData) => {
|
|
|
1056
1113
|
htmlTocTemplate = epubData.version === 2 ? epub2_toc_xhtml_ejs : epub3_toc_xhtml_ejs;
|
|
1057
1114
|
}
|
|
1058
1115
|
const toc_depth = 1;
|
|
1059
|
-
fs$1.writeFileSync(path.join(
|
|
1116
|
+
fs$1.writeFileSync(path.join(oebpsDir, "content.opf"), ejs.render(opfTemplate, epubData), "utf-8");
|
|
1060
1117
|
fs$1.writeFileSync(
|
|
1061
|
-
path.join(
|
|
1118
|
+
path.join(oebpsDir, "toc.ncx"),
|
|
1062
1119
|
ejs.render(ncxTocTemplate, { ...epubData, toc_depth }),
|
|
1063
1120
|
"utf-8"
|
|
1064
1121
|
);
|
|
1065
1122
|
fs$1.writeFileSync(
|
|
1066
|
-
path.join(
|
|
1123
|
+
path.join(oebpsDir, "toc.xhtml"),
|
|
1067
1124
|
simpleMinifier(ejs.render(htmlTocTemplate, epubData)),
|
|
1068
1125
|
"utf-8"
|
|
1069
1126
|
);
|
|
@@ -1220,12 +1277,12 @@ function parseOptions(options) {
|
|
|
1220
1277
|
if (data.version === 2) {
|
|
1221
1278
|
data.docHeader = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1222
1279
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
1223
|
-
<html xmlns="http://www.w3.org/1999/xhtml" lang="
|
|
1280
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${data.lang}" lang="${data.lang}">
|
|
1224
1281
|
`;
|
|
1225
1282
|
} else {
|
|
1226
1283
|
data.docHeader = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1227
1284
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
1228
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="
|
|
1285
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="${data.lang}" lang="${data.lang}">
|
|
1229
1286
|
`;
|
|
1230
1287
|
}
|
|
1231
1288
|
if (Array.isArray(data.author) && data.author.length === 0) {
|
|
@@ -1245,6 +1302,7 @@ async function epubGen(options, configs) {
|
|
|
1245
1302
|
if (configs?.logger) {
|
|
1246
1303
|
logger.setLogger(configs.logger);
|
|
1247
1304
|
}
|
|
1305
|
+
logger.info("EpubGen started 101...");
|
|
1248
1306
|
options = { ...options };
|
|
1249
1307
|
const o = check(options);
|
|
1250
1308
|
const verbose = options.verbose !== false;
|
package/build/index.js
CHANGED
|
@@ -342,20 +342,24 @@ function loadAndProcessHtml(data) {
|
|
|
342
342
|
}
|
|
343
343
|
try {
|
|
344
344
|
let $ = cheerio.load(trimmedData, {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
345
|
+
xmlMode: true,
|
|
346
|
+
// @ts-ignore
|
|
347
|
+
decodeEntities: false,
|
|
348
|
+
lowerCaseTags: true,
|
|
349
|
+
recognizeSelfClosing: true,
|
|
350
|
+
lowerCaseAttributeNames: true
|
|
349
351
|
});
|
|
350
352
|
const body = $("body");
|
|
351
353
|
if (body.length) {
|
|
352
354
|
const html = body.html();
|
|
353
355
|
if (html) {
|
|
354
356
|
$ = cheerio.load(html, {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
xmlMode: true,
|
|
358
|
+
// @ts-ignore
|
|
359
|
+
decodeEntities: false,
|
|
360
|
+
lowerCaseTags: true,
|
|
361
|
+
recognizeSelfClosing: true,
|
|
362
|
+
lowerCaseAttributeNames: true
|
|
359
363
|
});
|
|
360
364
|
}
|
|
361
365
|
}
|
|
@@ -415,7 +419,7 @@ function processImages($, chapter, epubConfigs) {
|
|
|
415
419
|
}
|
|
416
420
|
const trimmedUrl = url.trim();
|
|
417
421
|
try {
|
|
418
|
-
if (!trimmedUrl.match(/^(https?:\/\/|data:|\.\/|\/)/)) {
|
|
422
|
+
if (!trimmedUrl.match(/^(https?:\/\/|file:\/\/|data:|\.\/|\/)/)) {
|
|
419
423
|
logger.warn(`Image URL "${trimmedUrl}" appears to be invalid, but processing anyway`);
|
|
420
424
|
}
|
|
421
425
|
} catch (error) {
|
|
@@ -472,54 +476,20 @@ function processImages($, chapter, epubConfigs) {
|
|
|
472
476
|
}
|
|
473
477
|
});
|
|
474
478
|
}
|
|
475
|
-
function extractAndCleanHtmlContent(
|
|
479
|
+
function extractAndCleanHtmlContent($) {
|
|
476
480
|
let data;
|
|
477
481
|
if ($("body").length) {
|
|
478
482
|
data = $("body").html() || "";
|
|
479
483
|
} else {
|
|
480
484
|
data = $.root().html() || "";
|
|
481
485
|
}
|
|
482
|
-
|
|
483
|
-
return data.replace(
|
|
484
|
-
/<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)><\/\1>/gi,
|
|
485
|
-
"<$1$2/>"
|
|
486
|
-
).replace(
|
|
487
|
-
new RegExp("<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)(?<!\\/)>", "gi"),
|
|
488
|
-
"<$1$2/>"
|
|
489
|
-
);
|
|
490
|
-
}
|
|
491
|
-
const entityMap = /* @__PURE__ */ new Map();
|
|
492
|
-
const entityRegex = /&[a-zA-Z][a-zA-Z0-9]*;|&#[0-9]+;|&#x[0-9a-fA-F]+;/g;
|
|
493
|
-
const matches = Array.from(originalData.matchAll(entityRegex));
|
|
494
|
-
let processedOriginal = originalData;
|
|
495
|
-
const timestamp = Date.now();
|
|
496
|
-
const randomId = Math.random().toString(36).substring(2, 8);
|
|
497
|
-
const placeholderPrefix = `__ENTITY_${timestamp}_${randomId}_`;
|
|
498
|
-
for (let i = matches.length - 1; i >= 0; i--) {
|
|
499
|
-
const match = matches[i];
|
|
500
|
-
const placeholder = `${placeholderPrefix}${i}__`;
|
|
501
|
-
entityMap.set(placeholder, match[0]);
|
|
502
|
-
processedOriginal = processedOriginal.substring(0, match.index) + placeholder + processedOriginal.substring(match.index + match[0].length);
|
|
503
|
-
}
|
|
504
|
-
const $temp = cheerio.load(processedOriginal, {
|
|
505
|
-
xmlMode: false
|
|
506
|
-
});
|
|
507
|
-
let tempData;
|
|
508
|
-
if ($temp("body").length) {
|
|
509
|
-
tempData = $temp("body").html() || "";
|
|
510
|
-
} else {
|
|
511
|
-
tempData = $temp.root().html() || "";
|
|
512
|
-
}
|
|
513
|
-
for (const [placeholder, entity] of entityMap) {
|
|
514
|
-
tempData = tempData.replace(new RegExp(placeholder, "g"), entity);
|
|
515
|
-
}
|
|
516
|
-
return tempData.replace(
|
|
486
|
+
return data.replace(
|
|
517
487
|
/<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)><\/\1>/gi,
|
|
518
488
|
"<$1$2/>"
|
|
519
489
|
).replace(
|
|
520
490
|
new RegExp("<(br|hr|img|input|meta|area|base|col|embed|link|source|track|wbr)([^>]*?)(?<!\\/)>", "gi"),
|
|
521
491
|
"<$1$2/>"
|
|
522
|
-
);
|
|
492
|
+
).replace(/<\/img\s*>/gi, "");
|
|
523
493
|
}
|
|
524
494
|
function processChildrenChapters(chapter, index2, epubConfigs) {
|
|
525
495
|
if (Array.isArray(chapter.children)) {
|
|
@@ -553,7 +523,7 @@ function parseContent(content, index2, epubConfigs) {
|
|
|
553
523
|
}
|
|
554
524
|
processHtmlElements($, allowedAttributes, allowedXhtml11Tags, epubConfigs, index2);
|
|
555
525
|
processImages($, chapter, epubConfigs);
|
|
556
|
-
chapter.data = extractAndCleanHtmlContent(
|
|
526
|
+
chapter.data = extractAndCleanHtmlContent($);
|
|
557
527
|
}
|
|
558
528
|
processChildrenChapters(chapter, index2, epubConfigs);
|
|
559
529
|
return chapter;
|
|
@@ -849,52 +819,131 @@ const epub3_toc_xhtml_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
|
849
819
|
</body>
|
|
850
820
|
</html>
|
|
851
821
|
`;
|
|
852
|
-
const template_css =
|
|
853
|
-
|
|
822
|
+
const template_css = `/* =========================
|
|
823
|
+
EPUB 3 Base Stylesheet
|
|
824
|
+
========================= */
|
|
825
|
+
|
|
826
|
+
/* 全局基础设置 */
|
|
827
|
+
html {
|
|
828
|
+
font-size: 100%;
|
|
854
829
|
}
|
|
855
830
|
|
|
856
|
-
|
|
857
|
-
margin
|
|
831
|
+
body {
|
|
832
|
+
margin: 0;
|
|
833
|
+
padding: 0;
|
|
834
|
+
line-height: 1.6;
|
|
835
|
+
font-family: serif;
|
|
836
|
+
color: #000;
|
|
837
|
+
background-color: transparent;
|
|
858
838
|
}
|
|
859
839
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
840
|
+
/* 段落 */
|
|
841
|
+
p {
|
|
842
|
+
margin: 0;
|
|
843
|
+
padding: 0;
|
|
844
|
+
/*text-indent: 2em;*/
|
|
845
|
+
orphans: 2;
|
|
846
|
+
widows: 2;
|
|
863
847
|
}
|
|
864
848
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
849
|
+
/* 标题 */
|
|
850
|
+
h1,
|
|
851
|
+
h2,
|
|
852
|
+
h3,
|
|
853
|
+
h4,
|
|
854
|
+
h5,
|
|
855
|
+
h6 {
|
|
856
|
+
font-weight: bold;
|
|
857
|
+
line-height: 1.3;
|
|
858
|
+
margin: 1.2em 0 0.6em 0;
|
|
859
|
+
text-indent: 0;
|
|
860
|
+
page-break-after: avoid;
|
|
868
861
|
}
|
|
869
862
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
font-size: 85%;
|
|
873
|
-
display: block;
|
|
863
|
+
h1 {
|
|
864
|
+
font-size: 1.6em;
|
|
874
865
|
}
|
|
875
866
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
border-bottom: 1px solid #dedede;
|
|
879
|
-
margin: 60px 10%;
|
|
867
|
+
h2 {
|
|
868
|
+
font-size: 1.4em;
|
|
880
869
|
}
|
|
881
870
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
871
|
+
h3 {
|
|
872
|
+
font-size: 1.2em;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/* 章节标题常用居中 */
|
|
876
|
+
.chapter-title {
|
|
877
|
+
text-align: center;
|
|
878
|
+
margin-top: 2em;
|
|
879
|
+
margin-bottom: 1.5em;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/* 首段不缩进(常用于章节开头) */
|
|
883
|
+
.no-indent {
|
|
884
|
+
text-indent: 0;
|
|
885
885
|
}
|
|
886
886
|
|
|
887
|
-
|
|
887
|
+
/* 强调 */
|
|
888
|
+
em {
|
|
889
|
+
font-style: italic;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
strong {
|
|
893
|
+
font-weight: bold;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/* 引用 */
|
|
897
|
+
blockquote {
|
|
898
|
+
margin: 1em 1.5em;
|
|
888
899
|
padding: 0;
|
|
889
|
-
margin-left: 2em;
|
|
890
900
|
}
|
|
891
901
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
902
|
+
/* 分隔符(如 ***) */
|
|
903
|
+
hr {
|
|
904
|
+
border: none;
|
|
905
|
+
text-align: center;
|
|
906
|
+
margin: 1.5em 0;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* 图片 */
|
|
910
|
+
img {
|
|
911
|
+
max-width: 100%;
|
|
912
|
+
height: auto;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/* 图片居中 */
|
|
916
|
+
.figure {
|
|
917
|
+
text-align: center;
|
|
918
|
+
margin: 1em 0;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/* 列表 */
|
|
922
|
+
ul,
|
|
923
|
+
ol {
|
|
924
|
+
margin: 1em 0 1em 1.5em;
|
|
896
925
|
padding: 0;
|
|
897
926
|
}
|
|
927
|
+
|
|
928
|
+
li {
|
|
929
|
+
margin: 0.3em 0;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/* 表格(谨慎使用) */
|
|
933
|
+
table {
|
|
934
|
+
border-collapse: collapse;
|
|
935
|
+
margin: 1em 0;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
td,
|
|
939
|
+
th {
|
|
940
|
+
padding: 0.3em 0.5em;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/* 分页控制(EPUB 安全用法) */
|
|
944
|
+
.page-break {
|
|
945
|
+
page-break-before: always;
|
|
946
|
+
}
|
|
898
947
|
`;
|
|
899
948
|
const toc_ncx_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
900
949
|
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
|
@@ -944,12 +993,20 @@ const toc_ncx_ejs = `<?xml version="1.0" encoding="UTF-8"?>
|
|
|
944
993
|
`;
|
|
945
994
|
const generateTempFile = async (epubData) => {
|
|
946
995
|
const { log } = epubData;
|
|
947
|
-
const
|
|
948
|
-
await fs$1.ensureDir(
|
|
949
|
-
|
|
950
|
-
|
|
996
|
+
const oebpsDir = path.join(epubData.dir, "OEBPS");
|
|
997
|
+
await fs$1.ensureDir(oebpsDir);
|
|
998
|
+
const customCss = epubData.css || "";
|
|
999
|
+
if (!epubData.noDefaultCss) {
|
|
1000
|
+
epubData.css = template_css;
|
|
1001
|
+
if (customCss) {
|
|
1002
|
+
epubData.css += "\n\n" + customCss;
|
|
1003
|
+
}
|
|
1004
|
+
} else {
|
|
1005
|
+
epubData.css = customCss;
|
|
1006
|
+
}
|
|
1007
|
+
await writeFile(path.join(oebpsDir, "style.css"), epubData.css, "utf-8");
|
|
951
1008
|
if (epubData.fonts?.length) {
|
|
952
|
-
const fonts_dir = path.join(
|
|
1009
|
+
const fonts_dir = path.join(oebpsDir, "fonts");
|
|
953
1010
|
await fs$1.ensureDir(fonts_dir);
|
|
954
1011
|
epubData.fonts = epubData.fonts.map((font) => {
|
|
955
1012
|
const filename = path.basename(font);
|
|
@@ -1035,14 +1092,14 @@ const generateTempFile = async (epubData) => {
|
|
|
1035
1092
|
htmlTocTemplate = epubData.version === 2 ? epub2_toc_xhtml_ejs : epub3_toc_xhtml_ejs;
|
|
1036
1093
|
}
|
|
1037
1094
|
const toc_depth = 1;
|
|
1038
|
-
fs$1.writeFileSync(path.join(
|
|
1095
|
+
fs$1.writeFileSync(path.join(oebpsDir, "content.opf"), ejs.render(opfTemplate, epubData), "utf-8");
|
|
1039
1096
|
fs$1.writeFileSync(
|
|
1040
|
-
path.join(
|
|
1097
|
+
path.join(oebpsDir, "toc.ncx"),
|
|
1041
1098
|
ejs.render(ncxTocTemplate, { ...epubData, toc_depth }),
|
|
1042
1099
|
"utf-8"
|
|
1043
1100
|
);
|
|
1044
1101
|
fs$1.writeFileSync(
|
|
1045
|
-
path.join(
|
|
1102
|
+
path.join(oebpsDir, "toc.xhtml"),
|
|
1046
1103
|
simpleMinifier(ejs.render(htmlTocTemplate, epubData)),
|
|
1047
1104
|
"utf-8"
|
|
1048
1105
|
);
|
|
@@ -1199,12 +1256,12 @@ function parseOptions(options) {
|
|
|
1199
1256
|
if (data.version === 2) {
|
|
1200
1257
|
data.docHeader = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1201
1258
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
1202
|
-
<html xmlns="http://www.w3.org/1999/xhtml" lang="
|
|
1259
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${data.lang}" lang="${data.lang}">
|
|
1203
1260
|
`;
|
|
1204
1261
|
} else {
|
|
1205
1262
|
data.docHeader = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1206
1263
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
1207
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="
|
|
1264
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="${data.lang}" lang="${data.lang}">
|
|
1208
1265
|
`;
|
|
1209
1266
|
}
|
|
1210
1267
|
if (Array.isArray(data.author) && data.author.length === 0) {
|
|
@@ -1224,6 +1281,7 @@ async function epubGen(options, configs) {
|
|
|
1224
1281
|
if (configs?.logger) {
|
|
1225
1282
|
logger.setLogger(configs.logger);
|
|
1226
1283
|
}
|
|
1284
|
+
logger.info("EpubGen started 101...");
|
|
1227
1285
|
options = { ...options };
|
|
1228
1286
|
const o = check(options);
|
|
1229
1287
|
const verbose = options.verbose !== false;
|
package/build/templates.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export declare const epub2_content_opf_ejs = "<?xml version=\"1.0\" encoding=\"U
|
|
|
7
7
|
export declare const epub2_toc_xhtml_ejs = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xml:lang=\"<%- lang %>\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <title><%= title %></title>\n <meta charset=\"UTF-8\"/>\n <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/>\n</head>\n<body>\n<h1 class=\"h1\"><%= tocTitle %></h1>\n<% content.forEach(function(content, index){ %>\n <% if(!content.excludeFromToc){ %>\n <p class=\"table-of-content\">\n <a href=\"<%= content.href %>\"><%= (1 + index) + \". \" + (content.title || \"Chapter \" + (1 + index)) %>\n <% if(content.author.length){ %>\n - <small class=\"toc-author\"><%= content.author.join(\",\") %></small>\n <% } %>\n <% if(content.url){ %><span class=\"toc-link\"><%= content.url %></span>\n <% }else{ %><span class=\"toc-link\"></span>\n <% } %>\n </a>\n </p>\n <% } %>\n<% }) %>\n</body>\n</html>\n";
|
|
8
8
|
export declare const epub3_content_opf_ejs = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<package xmlns=\"http://www.idpf.org/2007/opf\"\n version=\"3.0\"\n unique-identifier=\"BookId\"\n xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n xmlns:dcterms=\"http://purl.org/dc/terms/\"\n xml:lang=\"en\"\n xmlns:media=\"http://www.idpf.org/epub/vocab/overlays/#\"\n prefix=\"ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/\">\n\n <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf\">\n\n <dc:identifier id=\"BookId\"><%= id %></dc:identifier>\n <meta refines=\"#BookId\" property=\"identifier-type\" scheme=\"onix:codelist5\">22</meta>\n <meta property=\"dcterms:identifier\" id=\"meta-identifier\">BookId</meta>\n <dc:title><%= title %></dc:title>\n <meta property=\"dcterms:title\" id=\"meta-title\"><%= title %></meta>\n <dc:language><%= lang || \"en\" %></dc:language>\n <meta property=\"dcterms:language\" id=\"meta-language\"><%= lang || \"en\" %></meta>\n <meta property=\"dcterms:modified\"><%= (new Date()).toISOString().split(\".\")[0] + \"Z\" %></meta>\n <dc:creator id=\"creator\"><%= author.length ? author.join(\",\") : author %></dc:creator>\n <meta refines=\"#creator\" property=\"file-as\"><%= author.length ? author.join(\",\") : author %></meta>\n <meta property=\"dcterms:publisher\"><%= publisher || \"anonymous\" %></meta>\n <dc:publisher><%= publisher || \"anonymous\" %></dc:publisher>\n <% var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var stringDate = \"\" + year + \"-\" + month + \"-\" + day; %>\n <meta property=\"dcterms:date\"><%= stringDate %></meta>\n <dc:date><%= stringDate %></dc:date>\n <meta property=\"dcterms:rights\">All rights reserved</meta>\n <dc:rights>Copyright © <%= (new Date()).getFullYear() %> by <%= publisher || \"anonymous\" %></dc:rights>\n <% if(locals.cover) { %>\n <meta name=\"cover\" content=\"image_cover\" />\n <% } %>\n <meta name=\"generator\" content=\"epub-gen\" />\n <meta property=\"ibooks:specified-fonts\">true</meta>\n </metadata>\n\n <manifest>\n <item id=\"ncx\" href=\"toc.ncx\" media-type=\"application/x-dtbncx+xml\" />\n <item id=\"toc\" href=\"toc.xhtml\" media-type=\"application/xhtml+xml\" properties=\"nav\" />\n <item id=\"css\" href=\"style.css\" media-type=\"text/css\" />\n\n <% if(locals.cover) { %>\n <item id=\"image_cover\" href=\"cover.<%= _coverExtension %>\" media-type=\"<%= _coverMediaType %>\" />\n <% } %>\n\n <% images.forEach(function(image, index){ %>\n <item id=\"image_<%= index %>\" href=\"images/<%= image.id %>.<%= image.extension %>\" media-type=\"<%= image.mediaType %>\" />\n <% }) %>\n\n <% function renderContentItem(content) { %>\n <% content.forEach(function(content){ %>\n <item id=\"content_<%= content.id %>\" href=\"<%= content.href %>\" media-type=\"application/xhtml+xml\" />\n <% if (Array.isArray(content.children)) { %>\n <% renderContentItem(content.children) %>\n <% } %>\n <% }) %>\n <% } %>\n <% renderContentItem(content) %>\n\n <% fonts.forEach(function(font, index){ %>\n <item id=\"font_<%= index %>\" href=\"fonts/<%= font %>\" media-type=\"application/x-font-ttf\" />\n <% }) %>\n </manifest>\n\n <spine toc=\"ncx\">\n <% var nodes_1 = content.filter(item => !item.excludeFromToc && item.beforeToc) %>\n <% var nodes_2 = content.filter(item => !item.excludeFromToc && !item.beforeToc) %>\n <% function renderToc(nodes) { %>\n <% nodes.forEach(function(content){ %>\n <itemref idref=\"content_<%= content.id %>\" />\n <% if (Array.isArray(content.children)) { %>\n <% renderToc(content.children) %>\n <% } %>\n <% }) %>\n <% } %>\n <% renderToc(nodes_1) %>\n <itemref idref=\"toc\" />\n <% renderToc(nodes_2) %>\n </spine>\n <guide>\n <reference type=\"text\" title=\"Table of Content\" href=\"toc.xhtml\" />\n </guide>\n</package>\n";
|
|
9
9
|
export declare const epub3_toc_xhtml_ejs = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" xml:lang=\"<%- lang %>\"\n lang=\"<%- lang %>\">\n<head>\n <title><%= title %></title>\n <meta charset=\"UTF-8\" />\n <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n</head>\n<body>\n<h1 class=\"h1\"><%= tocTitle %></h1>\n<nav id=\"toc\" class=\"TOC\" epub:type=\"toc\">\n <% var nodes_1 = content.filter(item => !item.excludeFromToc && item.beforeToc) %>\n <% var nodes_2 = content.filter(item => !item.excludeFromToc && !item.beforeToc) %>\n <% function renderToc(nodes, indent = 0) { %>\n <ol>\n <% nodes.forEach(function(content, index){ %>\n <li class=\"table-of-content\">\n <a href=\"<%= content.href %>\"><%= (content.title || \"Chapter \" + (1 + index)) %>\n <% if(content.author.length){ %> - <small\n class=\"toc-author\"><%= content.author.join(\",\") %></small>\n <% } %>\n <% if(content.url){ %><span class=\"toc-link\"><%= content.url %></span>\n <% } %>\n </a>\n <% if (Array.isArray(content.children) && content.children.length > 0) { %>\n <% renderToc(content.children, indent + 1) %>\n <% } %>\n </li>\n <% }) %>\n </ol>\n <% } %>\n <% renderToc(nodes_1) %>\n <% renderToc(nodes_2) %>\n</nav>\n\n</body>\n</html>\n";
|
|
10
|
-
export declare const template_css = "
|
|
10
|
+
export declare const template_css = "/* =========================\n EPUB 3 Base Stylesheet\n ========================= */\n\n/* \u5168\u5C40\u57FA\u7840\u8BBE\u7F6E */\nhtml {\n font-size: 100%;\n}\n\nbody {\n margin: 0;\n padding: 0;\n line-height: 1.6;\n font-family: serif;\n color: #000;\n background-color: transparent;\n}\n\n/* \u6BB5\u843D */\np {\n margin: 0;\n padding: 0;\n /*text-indent: 2em;*/\n orphans: 2;\n widows: 2;\n}\n\n/* \u6807\u9898 */\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-weight: bold;\n line-height: 1.3;\n margin: 1.2em 0 0.6em 0;\n text-indent: 0;\n page-break-after: avoid;\n}\n\nh1 {\n font-size: 1.6em;\n}\n\nh2 {\n font-size: 1.4em;\n}\n\nh3 {\n font-size: 1.2em;\n}\n\n/* \u7AE0\u8282\u6807\u9898\u5E38\u7528\u5C45\u4E2D */\n.chapter-title {\n text-align: center;\n margin-top: 2em;\n margin-bottom: 1.5em;\n}\n\n/* \u9996\u6BB5\u4E0D\u7F29\u8FDB\uFF08\u5E38\u7528\u4E8E\u7AE0\u8282\u5F00\u5934\uFF09 */\n.no-indent {\n text-indent: 0;\n}\n\n/* \u5F3A\u8C03 */\nem {\n font-style: italic;\n}\n\nstrong {\n font-weight: bold;\n}\n\n/* \u5F15\u7528 */\nblockquote {\n margin: 1em 1.5em;\n padding: 0;\n}\n\n/* \u5206\u9694\u7B26\uFF08\u5982 ***\uFF09 */\nhr {\n border: none;\n text-align: center;\n margin: 1.5em 0;\n}\n\n/* \u56FE\u7247 */\nimg {\n max-width: 100%;\n height: auto;\n}\n\n/* \u56FE\u7247\u5C45\u4E2D */\n.figure {\n text-align: center;\n margin: 1em 0;\n}\n\n/* \u5217\u8868 */\nul,\nol {\n margin: 1em 0 1em 1.5em;\n padding: 0;\n}\n\nli {\n margin: 0.3em 0;\n}\n\n/* \u8868\u683C\uFF08\u8C28\u614E\u4F7F\u7528\uFF09 */\ntable {\n border-collapse: collapse;\n margin: 1em 0;\n}\n\ntd,\nth {\n padding: 0.3em 0.5em;\n}\n\n/* \u5206\u9875\u63A7\u5236\uFF08EPUB \u5B89\u5168\u7528\u6CD5\uFF09 */\n.page-break {\n page-break-before: always;\n}\n";
|
|
11
11
|
export declare const toc_ncx_ejs = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\">\n <head>\n <meta name=\"dtb:uid\" content=\"<%= id %>\"/>\n <meta name=\"dtb:generator\" content=\"epub-gen\"/>\n <meta name=\"dtb:depth\" content=\"<%= (toc_depth || 1)%>\"/>\n <meta name=\"dtb:totalPageCount\" content=\"0\"/>\n <meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n </head>\n <docTitle>\n <text><%= title %></text>\n </docTitle>\n <docAuthor>\n <text><%= author %></text>\n </docAuthor>\n <navMap>\n <% var _index = 1; %>\n <% var nodes_1 = content.filter(c => !c.excludeFromToc && c.beforeToc) %>\n <% var nodes_2 = content.filter(c => !c.excludeFromToc && !c.beforeToc) %>\n <% function renderToc(nodes) { %>\n <% nodes.forEach(function(content, index){ %>\n <navPoint id=\"content_<%= content.id %>\" playOrder=\"<%= _index++ %>\" class=\"chapter\">\n <navLabel>\n <text><%= (tocAutoNumber ? ((1 + index) + \". \") : \"\") + (content.title || \"Chapter \" + (1 + index)) %></text>\n </navLabel>\n <content src=\"<%= content.href %>\"/>\n <% if (Array.isArray(content.children)) { %>\n <% renderToc(content.children) %>\n <% } %>\n </navPoint>\n <% }) %>\n <% } %>\n\n <% renderToc(nodes_1) %>\n\n <navPoint id=\"toc\" playOrder=\"<%= _index++ %>\" class=\"chapter\">\n <navLabel>\n <text><%= tocTitle %></text>\n </navLabel>\n <content src=\"toc.xhtml\"/>\n </navPoint>\n\n <% renderToc(nodes_2) %>\n </navMap>\n</ncx>\n";
|
package/build/types.d.ts
CHANGED
package/package.json
CHANGED
package/templates/template.css
CHANGED
|
@@ -1,46 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/* =========================
|
|
2
|
+
EPUB 3 Base Stylesheet
|
|
3
|
+
========================= */
|
|
4
|
+
|
|
5
|
+
/* 全局基础设置 */
|
|
6
|
+
html {
|
|
7
|
+
font-size: 100%;
|
|
3
8
|
}
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
margin
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
line-height: 1.6;
|
|
14
|
+
font-family: serif;
|
|
15
|
+
color: #000;
|
|
16
|
+
background-color: transparent;
|
|
7
17
|
}
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
/* 段落 */
|
|
20
|
+
p {
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
/*text-indent: 2em;*/
|
|
24
|
+
orphans: 2;
|
|
25
|
+
widows: 2;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
/* 标题 */
|
|
29
|
+
h1,
|
|
30
|
+
h2,
|
|
31
|
+
h3,
|
|
32
|
+
h4,
|
|
33
|
+
h5,
|
|
34
|
+
h6 {
|
|
35
|
+
font-weight: bold;
|
|
36
|
+
line-height: 1.3;
|
|
37
|
+
margin: 1.2em 0 0.6em 0;
|
|
38
|
+
text-indent: 0;
|
|
39
|
+
page-break-after: avoid;
|
|
17
40
|
}
|
|
18
41
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
font-size: 85%;
|
|
22
|
-
display: block;
|
|
42
|
+
h1 {
|
|
43
|
+
font-size: 1.6em;
|
|
23
44
|
}
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
border-bottom: 1px solid #dedede;
|
|
28
|
-
margin: 60px 10%;
|
|
46
|
+
h2 {
|
|
47
|
+
font-size: 1.4em;
|
|
29
48
|
}
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
h3 {
|
|
51
|
+
font-size: 1.2em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* 章节标题常用居中 */
|
|
55
|
+
.chapter-title {
|
|
56
|
+
text-align: center;
|
|
57
|
+
margin-top: 2em;
|
|
58
|
+
margin-bottom: 1.5em;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 首段不缩进(常用于章节开头) */
|
|
62
|
+
.no-indent {
|
|
63
|
+
text-indent: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* 强调 */
|
|
67
|
+
em {
|
|
68
|
+
font-style: italic;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
strong {
|
|
72
|
+
font-weight: bold;
|
|
34
73
|
}
|
|
35
74
|
|
|
36
|
-
|
|
75
|
+
/* 引用 */
|
|
76
|
+
blockquote {
|
|
77
|
+
margin: 1em 1.5em;
|
|
37
78
|
padding: 0;
|
|
38
|
-
margin-left: 2em;
|
|
39
79
|
}
|
|
40
80
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
81
|
+
/* 分隔符(如 ***) */
|
|
82
|
+
hr {
|
|
83
|
+
border: none;
|
|
84
|
+
text-align: center;
|
|
85
|
+
margin: 1.5em 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* 图片 */
|
|
89
|
+
img {
|
|
90
|
+
max-width: 100%;
|
|
91
|
+
height: auto;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* 图片居中 */
|
|
95
|
+
.figure {
|
|
96
|
+
text-align: center;
|
|
97
|
+
margin: 1em 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* 列表 */
|
|
101
|
+
ul,
|
|
102
|
+
ol {
|
|
103
|
+
margin: 1em 0 1em 1.5em;
|
|
45
104
|
padding: 0;
|
|
46
105
|
}
|
|
106
|
+
|
|
107
|
+
li {
|
|
108
|
+
margin: 0.3em 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* 表格(谨慎使用) */
|
|
112
|
+
table {
|
|
113
|
+
border-collapse: collapse;
|
|
114
|
+
margin: 1em 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
td,
|
|
118
|
+
th {
|
|
119
|
+
padding: 0.3em 0.5em;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* 分页控制(EPUB 安全用法) */
|
|
123
|
+
.page-break {
|
|
124
|
+
page-break-before: always;
|
|
125
|
+
}
|