opendoc-theme 2.0.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/_includes/directory.html +95 -0
- data/_includes/document-title.txt +58 -0
- data/_includes/toc.html +107 -0
- data/_includes/toolbar.html +53 -0
- data/_includes/welcome.html +5 -0
- data/_layouts/default.html +147 -0
- data/_layouts/home.html +4 -0
- data/_layouts/iframe.html +13 -0
- data/_layouts/page.html +4 -0
- data/_layouts/print.html +27 -0
- data/_sass/_base.scss +381 -0
- data/_sass/_constants.scss +87 -0
- data/_sass/_iframe.scss +7 -0
- data/_sass/_layout.scss +419 -0
- data/_sass/_nav.scss +592 -0
- data/_sass/_print.scss +43 -0
- data/_sass/_syntax-highlighting.scss +61 -0
- data/_sass/_toolbar.scss +372 -0
- data/_sass/_welcome.scss +41 -0
- data/assets/export.md +30 -0
- data/assets/images/chevron-up-white.svg +1 -0
- data/assets/images/chevron-up.svg +1 -0
- data/assets/images/close.svg +17 -0
- data/assets/images/favicon.ico +0 -0
- data/assets/images/feedback-hover.svg +3 -0
- data/assets/images/feedback-mobile.svg +1 -0
- data/assets/images/feedback.svg +1 -0
- data/assets/images/github-hover.svg +3 -0
- data/assets/images/github.svg +1 -0
- data/assets/images/home.svg +14 -0
- data/assets/images/index-img.png +0 -0
- data/assets/images/logo.png +0 -0
- data/assets/images/menu.svg +1 -0
- data/assets/images/opendoc-logo-full.svg +10 -0
- data/assets/images/pdf-hover.svg +11 -0
- data/assets/images/pdf.svg +9 -0
- data/assets/images/search-icon-dark.svg +19 -0
- data/assets/images/search-icon-white.svg +12 -0
- data/assets/images/share.svg +1 -0
- data/assets/images/sidebar-hover.svg +3 -0
- data/assets/images/sidebar.svg +1 -0
- data/assets/images/vertical-dots.svg +1 -0
- data/assets/images/x-mobile.svg +1 -0
- data/assets/index.html +5 -0
- data/assets/js/banner.js +20 -0
- data/assets/js/google_analytics.js +11 -0
- data/assets/js/header.js +31 -0
- data/assets/js/helpers.js +24 -0
- data/assets/js/lunr.min.js +6 -0
- data/assets/js/navigation.js +202 -0
- data/assets/js/page-index.js +57 -0
- data/assets/js/pqueue.js +373 -0
- data/assets/js/pre-loader.js +43 -0
- data/assets/js/search.js +580 -0
- data/assets/js/toolbar.js +130 -0
- data/assets/siteIndex.json +56 -0
- data/assets/startup/build.sh +18 -0
- data/assets/startup/docprint.html +20 -0
- data/assets/startup/pdf-gen.js +309 -0
- data/assets/startup/prebuild-lunr-index.js +52 -0
- data/assets/styles/main.scss +13 -0
- data/assets/styles/normalize.css +427 -0
- data/assets/vendor/babel-polyfill.min.js +3 -0
- data/assets/vendor/dom4.js +2 -0
- data/assets/vendor/fetch.umd.js +531 -0
- data/assets/vendor/headroom.min.js +7 -0
- data/assets/vendor/jump.min.js +2 -0
- data/assets/vendor/mark.min.js +7 -0
- data/assets/vendor/popper.min.js +5 -0
- data/assets/vendor/web-share-shim.bundle.min.js +2 -0
- metadata +158 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
---
|
2
|
+
---
|
3
|
+
(function () {
|
4
|
+
// Hard coded max-width for mobile view
|
5
|
+
window.isMobileView = function () {
|
6
|
+
return window.innerWidth < 992
|
7
|
+
}
|
8
|
+
|
9
|
+
// Documents - Section toggle
|
10
|
+
|
11
|
+
// Site-nav
|
12
|
+
// --------------------------
|
13
|
+
var menuToggle = document.getElementById('menu-toggle')
|
14
|
+
var showMenu = function showMenu() {
|
15
|
+
menuToggle.checked = true
|
16
|
+
document.body.classList.add('menu-toggled')
|
17
|
+
}
|
18
|
+
var hideMenu = function hideMenu() {
|
19
|
+
menuToggle.checked = false
|
20
|
+
document.body.classList.remove('menu-toggled')
|
21
|
+
}
|
22
|
+
menuToggle.addEventListener('change', function () {
|
23
|
+
if (menuToggle.checked) {
|
24
|
+
showMenu()
|
25
|
+
} else {
|
26
|
+
hideMenu()
|
27
|
+
}
|
28
|
+
})
|
29
|
+
|
30
|
+
var welcomeButton = document.getElementsByClassName('welcome-button')[0]
|
31
|
+
if (welcomeButton) {
|
32
|
+
welcomeButton.onclick = showMenu
|
33
|
+
}
|
34
|
+
|
35
|
+
// Hide site-nav on navigation
|
36
|
+
window.addEventListener('link-click', function () {
|
37
|
+
if (isMobileView()) {
|
38
|
+
hideMenu()
|
39
|
+
}
|
40
|
+
})
|
41
|
+
|
42
|
+
// Edit button
|
43
|
+
// --------------------------
|
44
|
+
var editButtons = document.querySelectorAll('.edit-btn')
|
45
|
+
editButtons.forEach(function (btn) {
|
46
|
+
btn.addEventListener('click', function () {
|
47
|
+
var repoUrl = '{{ site.github.repository_url }}' + '/blob/master/'
|
48
|
+
var page = pageIndex[window.location.pathname]
|
49
|
+
var pageUrl = page ? page.escapedPath : null
|
50
|
+
if (pageUrl) {
|
51
|
+
console.log('opening:', pageUrl)
|
52
|
+
repoUrl += pageUrl
|
53
|
+
}
|
54
|
+
window.open(repoUrl, '_blank')
|
55
|
+
})
|
56
|
+
})
|
57
|
+
|
58
|
+
// Print button
|
59
|
+
// --------------------------
|
60
|
+
var printButtons = document.querySelectorAll('.print-btn')
|
61
|
+
|
62
|
+
printButtons.forEach(function (btn) {
|
63
|
+
btn.addEventListener('click', function () {
|
64
|
+
window.open('./export.pdf', '_blank')
|
65
|
+
})
|
66
|
+
})
|
67
|
+
|
68
|
+
// Share button
|
69
|
+
// -------------------------
|
70
|
+
var shareButtons = document.querySelectorAll('.share-btn')
|
71
|
+
shareButtons.forEach(function(btn) {
|
72
|
+
btn.addEventListener('click', function() {
|
73
|
+
if (navigator.share) {
|
74
|
+
navigator.share({
|
75
|
+
title: {{ site.title | jsonify }},
|
76
|
+
text: document.title,
|
77
|
+
url: window.location.href
|
78
|
+
}).then()
|
79
|
+
}
|
80
|
+
})
|
81
|
+
})
|
82
|
+
|
83
|
+
// Floating Action Button
|
84
|
+
// -----------------------
|
85
|
+
var floatingActionButtonTrigger = document.getElementById('fab-trigger')
|
86
|
+
var floatingActionButton = document.getElementById('fab')
|
87
|
+
floatingActionButtonTrigger.addEventListener('click', function () {
|
88
|
+
floatingActionButton.classList.toggle('open')
|
89
|
+
});
|
90
|
+
|
91
|
+
var fabOverlay = document.getElementById('fab-overlay')
|
92
|
+
fabOverlay.addEventListener('click', function() {
|
93
|
+
floatingActionButton.classList.remove('open')
|
94
|
+
})
|
95
|
+
|
96
|
+
var backToTopButton = document.getElementById('back-to-top')
|
97
|
+
backToTopButton.addEventListener('click', function() {
|
98
|
+
// jump.js
|
99
|
+
Jump(-(window.pageYOffset || document.documentElement.scrollTop), {
|
100
|
+
duration: 300
|
101
|
+
})
|
102
|
+
})
|
103
|
+
|
104
|
+
// show/hide back-to-top button on scroll and on load
|
105
|
+
function scrollListener() {
|
106
|
+
var scrollTop = window.pageYOffset || document.documentElement.scrollTop
|
107
|
+
if (scrollTop > (window.innerHeight * 2)) {
|
108
|
+
backToTopButton.classList.remove('hidden')
|
109
|
+
} else {
|
110
|
+
backToTopButton.classList.add('hidden')
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
scrollListener()
|
115
|
+
|
116
|
+
window.addEventListener("scroll", scrollListener)
|
117
|
+
|
118
|
+
// Search Button for mobile
|
119
|
+
// --------------------------
|
120
|
+
var searchButtons = document.querySelectorAll('.search-btn')
|
121
|
+
var searchBoxElement = document.getElementById('search-box')
|
122
|
+
searchButtons.forEach(function(btn) {
|
123
|
+
btn.addEventListener('click', function() {
|
124
|
+
document.body.classList.toggle('search-toggled')
|
125
|
+
if (document.body.classList.contains('search-toggled')) {
|
126
|
+
searchBoxElement.focus()
|
127
|
+
}
|
128
|
+
})
|
129
|
+
})
|
130
|
+
})()
|
@@ -0,0 +1,56 @@
|
|
1
|
+
---
|
2
|
+
---
|
3
|
+
{% assign index_array = "" | split: ',' %}
|
4
|
+
{%- for page in site.html_pages -%}
|
5
|
+
{%- unless page.exclude -%}
|
6
|
+
{% unless page.name == 'index.html' or page.name == 'index.md' %}
|
7
|
+
{%- assign page_url = page.url -%}
|
8
|
+
{%- assign split_content = page.content | markdownify | split: '<h2' | splice: 1 -%}
|
9
|
+
|
10
|
+
{%- comment -%}Deal with h1 section{%- endcomment -%}
|
11
|
+
{%- assign page_header = split_content.first | split: '>' -%}
|
12
|
+
{%- assign page_header = page_header[1] | split: '</h1' -%}
|
13
|
+
{%- assign page_header = page_header[0] -%}
|
14
|
+
{%- assign header_section = '<h1' | append: split_content.first | strip_html | newline_to_br | strip_newlines | replace: '<br />', ' ' | replace: '\', '' | strip | smartify | normalize_whitespace -%}
|
15
|
+
{%- capture item -%}
|
16
|
+
{
|
17
|
+
"title": "{{ page_header}}",
|
18
|
+
"documentTitle": "{%- include_cached document-title.txt dir=page.dir info="title" -%}",
|
19
|
+
"url": "{{page_url | relative_url }}",
|
20
|
+
"text": "{{ header_section }}"
|
21
|
+
}
|
22
|
+
{% endcapture %}
|
23
|
+
{%- assign index_array = index_array | push: item -%}
|
24
|
+
|
25
|
+
{%- comment -%}Then deal with h2 sections {%- endcomment -%}
|
26
|
+
{%- for section in split_content offset:1 -%}
|
27
|
+
{%- assign section_header_html = section | split: 'id="' -%}
|
28
|
+
{%- assign section_header_html = section_header_html[1] | split: '">' -%}
|
29
|
+
|
30
|
+
{%- comment -%}Get section id{%- endcomment -%}
|
31
|
+
{%- assign section_id = section_header_html[0] -%}
|
32
|
+
{%- comment -%}Get section url{%- endcomment -%}
|
33
|
+
{%- assign section_url = page_url | append: '#' | append: section_id -%}
|
34
|
+
|
35
|
+
{%- comment -%}Get section header{%- endcomment -%}
|
36
|
+
{%- assign section_header = section_header_html | shift | join | split: '</h2' -%}
|
37
|
+
{%- assign section_header = section_header[0] | strip_html -%}
|
38
|
+
|
39
|
+
{%- comment -%}Get section body{%- endcomment -%}
|
40
|
+
{%- assign full_section = '<h2 ' | append:section | strip_html | newline_to_br | strip_newlines | replace: '<br />', ' ' | replace: '\', '' | strip | smartify | normalize_whitespace -%}
|
41
|
+
{%- capture item -%}
|
42
|
+
{
|
43
|
+
"title": "{{ section_header | smartify }}",
|
44
|
+
"documentTitle": "{%- include_cached document-title.txt dir=page.dir info="title" -%}",
|
45
|
+
"url": "{{ section_url | relative_url }}",
|
46
|
+
"text": "{{ full_section }}"
|
47
|
+
}
|
48
|
+
{% endcapture %}
|
49
|
+
{%- assign index_array = index_array | push: item -%}
|
50
|
+
|
51
|
+
{%- endfor -%}
|
52
|
+
{%- endunless -%}
|
53
|
+
{%- endunless -%}
|
54
|
+
{%- endfor -%}
|
55
|
+
|
56
|
+
[{{ index_array | join: ','}}]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
---
|
2
|
+
---
|
3
|
+
#!/bin/bash
|
4
|
+
|
5
|
+
echo 'Started script to generate PDFs'
|
6
|
+
echo 'Installing node dependencies'
|
7
|
+
npm i glob jsdom js-yaml p-all
|
8
|
+
if [[ (-z "${PDF_GEN_API_SERVER}") || (-z "${PDF_GEN_API_KEY}") ]]; then
|
9
|
+
npm i html-pdf
|
10
|
+
fi
|
11
|
+
node _site/assets/startup/pdf-gen.js
|
12
|
+
if [ "{{ site.offline_search_only }}" == "true" ]; then
|
13
|
+
node _site/assets/startup/prebuild-lunr-index.js
|
14
|
+
echo 'Generating Lunr Index complete'
|
15
|
+
else
|
16
|
+
echo 'Skipping Lunr Index'
|
17
|
+
fi
|
18
|
+
echo 'End script'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<!-- layout for printing individual documents-->
|
2
|
+
<!DOCTYPE html>
|
3
|
+
<html lang="en">
|
4
|
+
|
5
|
+
<head>
|
6
|
+
<meta charset="utf-8">
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
9
|
+
|
10
|
+
<link rel="icon" href="./assets/images/favicon.ico">
|
11
|
+
<link rel="stylesheet" href="./assets/styles/normalize.css">
|
12
|
+
<link rel="stylesheet" href="./assets/styles/main.css">
|
13
|
+
</head>
|
14
|
+
|
15
|
+
<body id=print-content>
|
16
|
+
<div id="main-content" class="site-main">
|
17
|
+
</div>
|
18
|
+
</body>
|
19
|
+
|
20
|
+
</html>
|
@@ -0,0 +1,309 @@
|
|
1
|
+
const fs = require('fs')
|
2
|
+
const fsp = require('fs').promises
|
3
|
+
const pAll = require('p-all')
|
4
|
+
const https = require('https')
|
5
|
+
const glob = require('glob')
|
6
|
+
const path = require('path')
|
7
|
+
const jsdom = require('jsdom')
|
8
|
+
const jsyaml = require('js-yaml')
|
9
|
+
const sitePath = __dirname + '/../..'
|
10
|
+
|
11
|
+
// Env vars to generate PDFs on AWS Lambda
|
12
|
+
let pdfGenVarsPresent = true
|
13
|
+
let pdf
|
14
|
+
let PDF_GEN_CONCURRENCY
|
15
|
+
|
16
|
+
if (process.env.PDF_GEN_API_KEY === undefined || process.env.PDF_GEN_API_SERVER === undefined) {
|
17
|
+
console.log('Env var PDF_GEN_API_KEY or PDF_GEN_API_SERVER for AWS Lambda not present: Generating PDFs locally instead.')
|
18
|
+
pdf = require('html-pdf')
|
19
|
+
pdfGenVarsPresent = false
|
20
|
+
PDF_GEN_CONCURRENCY = 1 // When generating locally make it synchronous
|
21
|
+
} else {
|
22
|
+
PDF_GEN_CONCURRENCY = process.env.PDF_GEN_CONCURRENCY !== undefined ?
|
23
|
+
parseInt(process.env.PDF_GEN_CONCURRENCY) :
|
24
|
+
50 // Tuned for Netlify
|
25
|
+
console.log(`Env vars detected: Generating PDFs on AWS Lambda with concurrency of ${PDF_GEN_CONCURRENCY}`)
|
26
|
+
}
|
27
|
+
|
28
|
+
// These options are only applied when PDFs are built locally
|
29
|
+
const localPdfOptions = {
|
30
|
+
height: '594mm', // allowed units: mm, cm, in, px
|
31
|
+
width: '420mm',
|
32
|
+
base: 'file://' + sitePath + '/',
|
33
|
+
border: {
|
34
|
+
right: '100px', // default is 0, units: mm, cm, in, px
|
35
|
+
left: '100px',
|
36
|
+
},
|
37
|
+
header: {
|
38
|
+
height: '80px',
|
39
|
+
},
|
40
|
+
footer: {
|
41
|
+
height: '80px',
|
42
|
+
},
|
43
|
+
}
|
44
|
+
|
45
|
+
// List of top-level folder names which may contain html but are not to be printed
|
46
|
+
const printIgnoreFolders = ['assets', 'files', 'iframes', 'images']
|
47
|
+
// List of top-level .html files which are not to be printed
|
48
|
+
const printIgnoreFiles = ['export.html', 'index.html']
|
49
|
+
|
50
|
+
// Tracking statistics
|
51
|
+
let numPdfsStarted = 0
|
52
|
+
let numPdfsError = 0
|
53
|
+
let numPdfsSuccess = 0
|
54
|
+
let numTotalPdfs = 0
|
55
|
+
const TIMER = 'Time to create PDFs'
|
56
|
+
|
57
|
+
const main = async () => {
|
58
|
+
|
59
|
+
// creating exports of individual documents
|
60
|
+
console.time(TIMER)
|
61
|
+
const docFolders = getDocumentFolders(sitePath, printIgnoreFolders)
|
62
|
+
await exportPdfTopLevelDocs(sitePath)
|
63
|
+
await exportPdfDocFolders(sitePath, docFolders)
|
64
|
+
console.log(`PDFs created with success:${numPdfsSuccess} error:${numPdfsError} total:${numTotalPdfs}`)
|
65
|
+
console.timeEnd(TIMER)
|
66
|
+
}
|
67
|
+
|
68
|
+
const exportPdfTopLevelDocs = async (sitePath) => {
|
69
|
+
let htmlFilePaths = glob.sync('*.html', { cwd: sitePath })
|
70
|
+
htmlFilePaths = htmlFilePaths.filter((filepath) => !printIgnoreFiles.includes(filepath))
|
71
|
+
htmlFilePaths = htmlFilePaths.map((filepath) => path.join(sitePath, filepath))
|
72
|
+
// Remove folders without HTML files (don't want empty pdfs)
|
73
|
+
if (htmlFilePaths.length === 0) return
|
74
|
+
numTotalPdfs++
|
75
|
+
const configFilepath = path.join(sitePath, '..', '_config.yml')
|
76
|
+
if (configFileHasValidOrdering(configFilepath)) {
|
77
|
+
const configYml = yamlToJs(configFilepath)
|
78
|
+
htmlFilePaths = reorderHtmlFilePaths(htmlFilePaths, configYml.order)
|
79
|
+
}
|
80
|
+
await createPdf(htmlFilePaths, sitePath)
|
81
|
+
}
|
82
|
+
|
83
|
+
const exportPdfDocFolders = (sitePath, docFolders) => {
|
84
|
+
const actions = []
|
85
|
+
for (let folder of docFolders) {
|
86
|
+
// find all the folders containing html files
|
87
|
+
const folderPath = path.join(sitePath, folder)
|
88
|
+
let htmlFilePaths = glob.sync('*.html', { cwd: folderPath })
|
89
|
+
htmlFilePaths = htmlFilePaths.filter((filepath) => !printIgnoreFiles.includes(filepath))
|
90
|
+
htmlFilePaths = htmlFilePaths.map((filepath) => path.join(folderPath, filepath))
|
91
|
+
|
92
|
+
// Remove folders without HTML files (don't want empty pdfs)
|
93
|
+
if (htmlFilePaths.length === 0) return
|
94
|
+
numTotalPdfs++
|
95
|
+
const indexFilepath = path.join(sitePath, '..', folder, 'index.md')
|
96
|
+
if (indexFileHasValidOrdering(indexFilepath)) {
|
97
|
+
const configMd = markdownToJs(indexFilepath)
|
98
|
+
const order = configMd.order
|
99
|
+
htmlFilePaths = reorderHtmlFilePaths(htmlFilePaths, order)
|
100
|
+
}
|
101
|
+
actions.push((() => createPdf(htmlFilePaths, folderPath)))
|
102
|
+
}
|
103
|
+
return pAll(actions, { concurrency: PDF_GEN_CONCURRENCY })
|
104
|
+
}
|
105
|
+
|
106
|
+
// Concatenates the contents in .html files, and outputs export.pdf in the specified output folder
|
107
|
+
const createPdf = (htmlFilePaths, outputFolderPath) => {
|
108
|
+
logStartedPdf(outputFolderPath)
|
109
|
+
// docprint.html is our template to build pdf up from.
|
110
|
+
const exportHtmlFile = fs.readFileSync(__dirname + '/docprint.html')
|
111
|
+
const exportDom = new jsdom.JSDOM(exportHtmlFile)
|
112
|
+
const exportDomBody = exportDom.window.document.body
|
113
|
+
const exportDomMain = exportDom.window.document.getElementById('main-content')
|
114
|
+
let addedTitle = false
|
115
|
+
let addedDocTitle = false
|
116
|
+
|
117
|
+
htmlFilePaths.forEach(function (filePath) {
|
118
|
+
const file = fs.readFileSync(filePath)
|
119
|
+
const dom = new jsdom.JSDOM(file, {
|
120
|
+
resources: 'usable' // to get JSDOM to load stylesheets
|
121
|
+
})
|
122
|
+
|
123
|
+
// html-pdf can't deal with these
|
124
|
+
removeTagsFromDom(dom, 'script')
|
125
|
+
removeTagsFromDom(dom, 'iframe')
|
126
|
+
|
127
|
+
// If a <img src=...> link src begins with '/', it is a relative link
|
128
|
+
// and needs to be prepended with '.' to show up in the pdf. Does not
|
129
|
+
// work for Lambda functions as the images are not available server side.
|
130
|
+
const imgsrcs = dom.window.document.getElementsByTagName('img')
|
131
|
+
for (let i = 0; i < imgsrcs.length; i++) {
|
132
|
+
const imgsrc = imgsrcs[i]
|
133
|
+
if (imgsrc.src.startsWith('/')) {
|
134
|
+
imgsrc.src = '.' + imgsrc.src
|
135
|
+
} else if (imgsrc.src.startsWith('.')) {
|
136
|
+
imgsrc.src = outputFolderPath + imgsrc.src.substr(1)
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
// Site titles needs only be added once
|
141
|
+
if (!addedTitle) {
|
142
|
+
try {
|
143
|
+
const oldTitle = dom.window.document.getElementsByClassName('site-header-text')[0]
|
144
|
+
exportDomBody.insertBefore(oldTitle, exportDomMain)
|
145
|
+
addedTitle = true
|
146
|
+
} catch (error) {
|
147
|
+
console.log('Failed to append Title, skipping: ' + error)
|
148
|
+
}
|
149
|
+
}
|
150
|
+
// Document titles too
|
151
|
+
if (!addedDocTitle) {
|
152
|
+
try {
|
153
|
+
const oldDocTitle = dom.window.document.getElementsByClassName('description-container')[0]
|
154
|
+
exportDomBody.insertBefore(oldDocTitle, exportDomMain)
|
155
|
+
const hr = dom.window.document.createElement('HR')
|
156
|
+
exportDomBody.insertBefore(hr, exportDomMain)
|
157
|
+
addedDocTitle = true
|
158
|
+
} catch (error) {
|
159
|
+
console.log('Failed to append Doc Title, skipping: ' + error)
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
// Concat all the id:main-content divs
|
164
|
+
try {
|
165
|
+
const oldNode = dom.window.document.getElementById('main-content')
|
166
|
+
exportDomMain.innerHTML += oldNode.innerHTML
|
167
|
+
} catch (error) {
|
168
|
+
console.log('Failed to append Node, skipping: ' + error)
|
169
|
+
}
|
170
|
+
dom.window.close()
|
171
|
+
})
|
172
|
+
|
173
|
+
if (!pdfGenVarsPresent) {
|
174
|
+
return new Promise((resolve, reject) => {
|
175
|
+
pdf.create(exportDom.serialize(), localPdfOptions).toFile(path.join(outputFolderPath, 'export.pdf'), (err, res) => {
|
176
|
+
if (err) {
|
177
|
+
logErrorPdf('Creating PDFs locally', err)
|
178
|
+
return reject()
|
179
|
+
}
|
180
|
+
logSuccessPdf(res.filename)
|
181
|
+
resolve()
|
182
|
+
})
|
183
|
+
exportDom.window.close()
|
184
|
+
})
|
185
|
+
} else {
|
186
|
+
// Code for this API lives at https://github.com/opendocsg/pdf-lambda
|
187
|
+
const requestOptions = {
|
188
|
+
method: 'POST',
|
189
|
+
responseType: 'arraybuffer',
|
190
|
+
headers: {
|
191
|
+
'x-api-key': process.env.PDF_GEN_API_KEY,
|
192
|
+
'content-type': 'application/json',
|
193
|
+
},
|
194
|
+
}
|
195
|
+
return new Promise(function(resolve, reject) {
|
196
|
+
const request = https.request(process.env.PDF_GEN_API_SERVER, requestOptions, function(res) {
|
197
|
+
if (res.statusCode < 200 || res.statusCode >= 300) {
|
198
|
+
logErrorPdf('Request status code', res.statusCode)
|
199
|
+
reject()
|
200
|
+
}
|
201
|
+
const chunks = []
|
202
|
+
res.on('data', function(d) {
|
203
|
+
chunks.push(d)
|
204
|
+
})
|
205
|
+
res.on('end', function() {
|
206
|
+
const buf = Buffer.concat(chunks)
|
207
|
+
resolve(buf)
|
208
|
+
})
|
209
|
+
})
|
210
|
+
request.on('error', (err) => {
|
211
|
+
logErrorPdf('Request encountered error', err)
|
212
|
+
reject()
|
213
|
+
})
|
214
|
+
// POST request body
|
215
|
+
request.write(JSON.stringify({
|
216
|
+
'serializedDom': exportDom.serialize()
|
217
|
+
}))
|
218
|
+
request.end()
|
219
|
+
exportDom.window.close()
|
220
|
+
}).then((buffer) => {
|
221
|
+
const outputPdfPath = path.join(outputFolderPath, 'export.pdf')
|
222
|
+
return fsp.writeFile(outputPdfPath, buffer)
|
223
|
+
.then(() => {
|
224
|
+
logSuccessPdf(outputPdfPath)
|
225
|
+
}).catch((err) => {
|
226
|
+
logErrorPdf('Writing out file', err)
|
227
|
+
})
|
228
|
+
}).catch((error) => {
|
229
|
+
logErrorPdf('Request promise', error)
|
230
|
+
})
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
const logStartedPdf = (outputFolderPath) => {
|
235
|
+
numPdfsStarted++
|
236
|
+
console.log(`createpdf started for:${outputFolderPath} (${numPdfsStarted}/${numTotalPdfs})`)
|
237
|
+
}
|
238
|
+
|
239
|
+
const logErrorPdf = (origin, error) => {
|
240
|
+
numPdfsError++
|
241
|
+
console.log(`createpdf error for: ${origin}: ${error}(${numPdfsError}/${numTotalPdfs})`)
|
242
|
+
}
|
243
|
+
|
244
|
+
const logSuccessPdf = (outputPdfPath) => {
|
245
|
+
numPdfsSuccess++
|
246
|
+
console.log(`createpdf success for:${outputPdfPath} (${numPdfsSuccess}/${numTotalPdfs})`)
|
247
|
+
}
|
248
|
+
|
249
|
+
// Returns a list of the valid document (i.e. folder) paths
|
250
|
+
const getDocumentFolders = (sitePath, printIgnoreFolders) => {
|
251
|
+
return fs.readdirSync(sitePath).filter(function (filePath) {
|
252
|
+
return fs.statSync(path.join(sitePath, filePath)).isDirectory() &&
|
253
|
+
!printIgnoreFolders.includes(filePath)
|
254
|
+
})
|
255
|
+
}
|
256
|
+
|
257
|
+
// Returns true if config file contains section_order field
|
258
|
+
const configFileHasValidOrdering = (configFilepath) => {
|
259
|
+
try {
|
260
|
+
const configYml = yamlToJs(configFilepath)
|
261
|
+
return 'order' in configYml
|
262
|
+
} catch (error) {
|
263
|
+
return false
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
// Returns true if index.md exists and contains order field
|
268
|
+
const indexFileHasValidOrdering = (indexFilepath) => {
|
269
|
+
try {
|
270
|
+
const configMd = markdownToJs(indexFilepath)
|
271
|
+
return 'order' in configMd
|
272
|
+
} catch (error) {
|
273
|
+
return false
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
// Mutates the htmlFilepath array to match order provided in order
|
278
|
+
const reorderHtmlFilePaths = (htmlFilePaths, order) => {
|
279
|
+
const orderedHtmlFilePaths = []
|
280
|
+
for (let i = 0; i < order.length; i++) {
|
281
|
+
const name = path.basename(order[i], '.md')
|
282
|
+
htmlFilePaths.some((filePath) => {
|
283
|
+
if (path.basename(filePath, '.html') === name) {
|
284
|
+
orderedHtmlFilePaths.push(filePath)
|
285
|
+
}
|
286
|
+
})
|
287
|
+
}
|
288
|
+
return orderedHtmlFilePaths
|
289
|
+
}
|
290
|
+
|
291
|
+
// Removes <tag></tag> from dom and everything in between them
|
292
|
+
const removeTagsFromDom = (dom, tagname) => {
|
293
|
+
const tags = dom.window.document.getElementsByTagName(tagname)
|
294
|
+
for (let i = tags.length - 1; i >= 0; i--) {
|
295
|
+
tags[i].parentNode.removeChild(tags[i])
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
// converts .md to JS Object
|
300
|
+
const markdownToJs = (filepath) => {
|
301
|
+
const configString = fs.readFileSync(filepath).toString().replace(/---/g, '')
|
302
|
+
return jsyaml.safeLoad(configString)
|
303
|
+
}
|
304
|
+
|
305
|
+
const yamlToJs = (filepath) => {
|
306
|
+
return jsyaml.safeLoad(fs.readFileSync(filepath))
|
307
|
+
}
|
308
|
+
|
309
|
+
main()
|