// GitHub
diff --git a/src/distill-transforms/distill-appendix.js b/src/distill-transforms/distill-appendix.js
index 2fb639b..1dd3584 100644
--- a/src/distill-transforms/distill-appendix.js
+++ b/src/distill-transforms/distill-appendix.js
@@ -1,4 +1,6 @@
-export default function(dom) {
+import { appendixTemplate } from '../distill-components/distill-appendix';
+
+export default function(dom, data) {
const appendixTag = dom.querySelector('d-appendix');
if (!appendixTag) {
@@ -9,6 +11,7 @@ export default function(dom) {
if (!distillAppendixTag) {
const distillAppendix = dom.createElement('distill-appendix');
appendixTag.appendChild(distillAppendix);
+ distillAppendix.innerHTML = appendixTemplate(data);
}
}
diff --git a/src/extractors/bibliography.js b/src/extractors/bibliography.js
index 89a0fc7..2fb18cd 100644
--- a/src/extractors/bibliography.js
+++ b/src/extractors/bibliography.js
@@ -1,3 +1,5 @@
+import { parseBibtex } from '../helpers/bibtex';
+import fs from 'fs';
import { parseBibliography } from '../components/d-bibliography';
export default function(dom, data) {
@@ -6,5 +8,18 @@ export default function(dom, data) {
console.warn('No bibliography tag found!');
return;
}
+
+ const src = bibliographyTag.getAttribute('src');
+ if (src) {
+ const path = data.inputDirectory + '/' + src;
+ const text = fs.readFileSync(path, 'utf-8');
+ const bibliography = parseBibtex(text);
+ const scriptTag = dom.createElement('script');
+ scriptTag.type = 'text/json';
+ scriptTag.textContent = JSON.stringify([...bibliography]);
+ bibliographyTag.appendChild(scriptTag);
+ bibliographyTag.removeAttribute('src');
+ }
+
data.bibliography = parseBibliography(bibliographyTag);
}
diff --git a/src/front-matter.js b/src/front-matter.js
index 81766fa..f247974 100644
--- a/src/front-matter.js
+++ b/src/front-matter.js
@@ -13,6 +13,23 @@ const RFC = function(date) {
return `${day}, ${paddedDate} ${month} ${year} ${hours}:${minutes}:${seconds} Z`;
};
+const objectFromMap = function(map) {
+ const object = Array.from(map).reduce((object, [key, value]) => (
+ Object.assign(object, { [key]: value }) // Be careful! Maps can have non-String keys; object literals can't.
+ ), {});
+ return object;
+};
+
+const mapFromObject = function(object) {
+ const map = new Map();
+ for (var property in object) {
+ if (object.hasOwnProperty(property)) {
+ map.set(property, object[property]);
+ }
+ }
+ return map;
+};
+
class Author {
// constructor(name='', personalURL='', affiliation='', affiliationURL='') {
@@ -44,7 +61,20 @@ class Author {
export function mergeFromYMLFrontmatter(target, source) {
target.title = source.title;
- target.publishedDate = new Date(source.published);
+ if (source.published) {
+ if (source.published instanceof Date) {
+ target.publishedDate = source.published;
+ } else if (source.published.constructor === String) {
+ target.publishedDate = new Date(source.published);
+ }
+ }
+ if (source.publishedDate) {
+ if (source.publishedDate instanceof Date) {
+ target.publishedDate = source.publishedDate;
+ } else if (source.publishedDate.constructor === String) {
+ target.publishedDate = new Date(source.publishedDate);
+ }
+ }
target.description = source.description;
target.authors = source.authors.map( (authorObject) => new Author(authorObject));
target.katex = source.katex;
@@ -103,7 +133,6 @@ export class FrontMatter {
// }
// volume: 1,
// issue: 9,
- this.publishedDate = new Date();
this.katex = {};
@@ -114,7 +143,7 @@ export class FrontMatter {
// githubCompareUpdatesUrl: 'https://github.com/distillpub/post--augmented-rnns/compare/1596e094d8943d2dc0ea445d92071129c6419c59...3bd9209e0c24d020f87cf6152dcecc6017cbc193',
// updatedDate: 2017-03-21T07:13:16.000Z,
// doi: '10.23915/distill.00001',
-
+ this.publishedDate = undefined;
}
// Example:
@@ -147,7 +176,11 @@ export class FrontMatter {
// 'https://github.com/distillpub/post--augmented-rnns',
get githubUrl() {
- return 'https://github.com/' + this.githubPath;
+ if (this.githubPath) {
+ return 'https://github.com/' + this.githubPath;
+ } else {
+ return undefined;
+ }
}
// TODO resolve differences in naming of URL/Url/url.
@@ -230,4 +263,42 @@ export class FrontMatter {
}));
}
+ set bibliography(bibliography) {
+ if (bibliography instanceof Map) {
+ this._bibliography = bibliography;
+ } else if (typeof bibliography === 'object') {
+ this._bibliography = mapFromObject(bibliography);
+ }
+ }
+
+ get bibliography() {
+ return this._bibliography;
+ }
+
+ static fromObject(source) {
+ const frontMatter = new FrontMatter();
+ Object.assign(frontMatter, source);
+ return frontMatter;
+ }
+
+ assignToObject(target) {
+ Object.assign(target, this);
+ target.bibliography = objectFromMap(this.bibliographyEntries);
+ target.url = this.url;
+ target.githubUrl = this.githubUrl;
+ target.previewURL = this.previewURL;
+ target.volume = this.volume;
+ target.issue = this.issue;
+ target.publishedDateRFC = this.publishedDateRFC;
+ target.publishedYear = this.publishedYear;
+ target.publishedMonth = this.publishedMonth;
+ target.publishedDay = this.publishedDay;
+ target.publishedMonthPadded = this.publishedMonthPadded;
+ target.publishedDayPadded = this.publishedDayPadded;
+ target.updatedDateRFC = this.updatedDateRFC;
+ target.concatenatedAuthors = this.concatenatedAuthors;
+ target.bibtexAuthors = this.bibtexAuthors;
+ target.slug = this.slug;
+ }
+
}
diff --git a/src/helpers/hover-box.js b/src/helpers/hover-box.js
index d59d5f3..4efa6e9 100644
--- a/src/helpers/hover-box.js
+++ b/src/helpers/hover-box.js
@@ -41,7 +41,7 @@ export class HoverBox {
this.stopTimeout();
});
this.div.addEventListener('mouseout', () => {
- this.extendTimeout(250);
+ this.extendTimeout(500);
});
// Don't trigger body touchstart event when touching within box
this.div.addEventListener('touchstart', (event) => {
@@ -62,7 +62,7 @@ export class HoverBox {
});
node.addEventListener('mouseout', () => {
- this.extendTimeout(250);
+ this.extendTimeout(500);
});
node.addEventListener('touchstart', (event) => {
diff --git a/src/helpers/polyfills.js b/src/helpers/polyfills.js
new file mode 100644
index 0000000..aec59d8
--- /dev/null
+++ b/src/helpers/polyfills.js
@@ -0,0 +1,68 @@
+export function addPolyfill(polyfill, polyfillLoadedCallback) {
+ console.info('Runlevel 0: Polyfill required: ' + polyfill.name);
+ const script = document.createElement('script');
+ script.src = polyfill.url;
+ script.async = false;
+ if (polyfillLoadedCallback) {
+ script.onload = function() { polyfillLoadedCallback(polyfill); };
+ }
+ script.onerror = function() {
+ new Error('Runlevel 0: Polyfills failed to load script ' + polyfill.name);
+ };
+ document.head.appendChild(script);
+}
+
+export const polyfills = [
+ {
+ name: 'WebComponents',
+ support: function() {
+ return 'customElements' in window &&
+ 'attachShadow' in Element.prototype &&
+ 'getRootNode' in Element.prototype &&
+ 'content' in document.createElement('template') &&
+ 'Promise' in window &&
+ 'from' in Array;
+ },
+ url: 'https://distill.pub/third-party/polyfills/webcomponents-lite.js'
+ }, {
+ name: 'IntersectionObserver',
+ support: function() {
+ return 'IntersectionObserver' in window &&
+ 'IntersectionObserverEntry' in window;
+ },
+ url: 'https://distill.pub/third-party/polyfills/intersection-observer.js'
+ },
+];
+
+export class Polyfills {
+
+ static browserSupportsAllFeatures() {
+ return polyfills.every((poly) => poly.support());
+ }
+
+ static load(callback) {
+ // Define an intermediate callback that checks if all is loaded.
+ const polyfillLoaded = function(polyfill) {
+ polyfill.loaded = true;
+ console.info('Runlevel 0: Polyfill has finished loading: ' + polyfill.name);
+ // console.info(window[polyfill.name]);
+ if (Polyfills.neededPolyfills.every((poly) => poly.loaded)) {
+ console.info('Runlevel 0: All required polyfills have finished loading.');
+ console.info('Runlevel 0->1.');
+ window.distillRunlevel = 1;
+ callback();
+ }
+ };
+ // Add polyfill script tags
+ for (const polyfill of Polyfills.neededPolyfills) {
+ addPolyfill(polyfill, polyfillLoaded);
+ }
+ }
+
+ static get neededPolyfills() {
+ if (!Polyfills._neededPolyfills) {
+ Polyfills._neededPolyfills = polyfills.filter((poly) => !poly.support());
+ }
+ return Polyfills._neededPolyfills;
+ }
+}
diff --git a/src/styles/d-article.css b/src/styles/d-article.css
index 397fcbe..050b4e3 100644
--- a/src/styles/d-article.css
+++ b/src/styles/d-article.css
@@ -71,8 +71,8 @@ d-article h3 {
font-weight: 700;
font-size: 18px;
line-height: 1.4em;
- margin-bottom: 24px;
- margin-top: 0;
+ margin-bottom: 1em;
+ margin-top: 2em;
}
@media(min-width: 1024px) {
@@ -146,7 +146,7 @@ d-article hr {
grid-column: screen;
width: 100%;
border: none;
- border-bottom: 1px solid rgba(0, 0, 0, 0.2);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin-top: 60px;
margin-bottom: 60px;
}
diff --git a/src/styles/d-byline.css b/src/styles/d-byline.css
index 89307e7..c1602ee 100644
--- a/src/styles/d-byline.css
+++ b/src/styles/d-byline.css
@@ -41,9 +41,10 @@ d-article d-byline a:hover {
border-bottom: none;
}
-d-byline .authors p {
- font-weight: 600;
+d-byline p.author {
+ font-weight: 500;
}
+
d-byline .affiliations {
}
diff --git a/src/styles/d-math.css b/src/styles/d-math.css
index e02be30..2703bd2 100644
--- a/src/styles/d-math.css
+++ b/src/styles/d-math.css
@@ -1,7 +1,7 @@
span.katex-display {
text-align: left;
padding: 8px 0 8px 0;
- margin: 0 0 1.7em 1em;
+ margin: 0.5em 0 0.5em 1em;
}
span.katex {
diff --git a/src/styles/styles-base.css b/src/styles/styles-base.css
index baa87ba..b92cbd9 100644
--- a/src/styles/styles-base.css
+++ b/src/styles/styles-base.css
@@ -52,6 +52,17 @@ p {
margin-bottom: 1em;
}
+sup, sub {
+ vertical-align: baseline;
+ position: relative;
+ top: -0.4em;
+ line-height: 1em;
+}
+
+sub {
+ top: 0.4em;
+}
+
.kicker,
.marker {
font-size: 15px;
@@ -72,7 +83,12 @@ p {
figure {
position: relative;
- margin-bottom: 1.5rem;
+ margin-bottom: 2.5em;
+ margin-top: 2.5em;
+}
+
+figcaption+figure {
+
}
figure img {
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 5206d46..c883308 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -17,7 +17,8 @@ export function makeStyleTag(dom) {
styleTag.type = 'text/css';
const cssTextTag = dom.createTextNode(styles);
styleTag.appendChild(cssTextTag);
- dom.head.insertBefore(styleTag, dom.head.firstChild);
+ const firstScriptTag = dom.head.querySelector('script');
+ dom.head.insertBefore(styleTag, firstScriptTag);
}
}
diff --git a/src/transforms.js b/src/transforms.js
index 8de90bc..9286ffa 100644
--- a/src/transforms.js
+++ b/src/transforms.js
@@ -16,26 +16,26 @@ const extractors = new Map([
/* Transforms */
import HTML from './transforms/html';
import Byline from './transforms/byline';
-import Polyfills from './transforms/polyfills';
import OptionalComponents from './transforms/optional-components';
import Mathematics from './transforms/mathematics';
import Meta from './transforms/meta';
import { makeStyleTag } from './styles/styles';
import TOC from './transforms/toc';
import Typeset from './transforms/typeset';
-import Bibliography from './transforms/bibliography';
+import Polyfills from './transforms/polyfills';
+import CitationList from './transforms/citation-list';
const transforms = new Map([
['HTML', HTML],
['makeStyleTag', makeStyleTag],
- ['Polyfills', Polyfills],
['OptionalComponents', OptionalComponents],
['TOC', TOC],
['Byline', Byline],
['Mathematics', Mathematics],
['Meta', Meta],
['Typeset', Typeset],
- ['Bibliography', Bibliography],
+ ['Polyfills', Polyfills],
+ ['CitationList', CitationList],
]);
/* Distill Transforms */
@@ -52,19 +52,30 @@ const distillTransforms = new Map([
/* Exported functions */
export function render(dom, data, verbose=true) {
+ let frontMatter;
+ if (data instanceof FrontMatter) {
+ frontMatter = data;
+ } else {
+ frontMatter = FrontMatter.fromObject(data);
+ }
// first, we collect static data from the dom
for (const [name, extract] of extractors.entries()) {
if (verbose) console.warn('Running extractor: ' + name);
- extract(dom, data, verbose);
+ extract(dom, frontMatter, verbose);
}
// secondly we use it to transform parts of the dom
for (const [name, transform] of transforms.entries()) {
if (verbose) console.warn('Running transform: ' + name);
// console.warn('Running transform: ', transform);
- transform(dom, data, verbose);
+ transform(dom, frontMatter, verbose);
}
dom.body.setAttribute('distill-prerendered', '');
// the function calling us can now use the transformed dom and filled data object
+ if (data instanceof FrontMatter) {
+ // frontMatter will already have needed properties
+ } else {
+ frontMatter.assignToObject(data);
+ }
}
export function distillify(dom, data, verbose=true) {
diff --git a/src/transforms/bibliography.js b/src/transforms/bibliography.js
deleted file mode 100644
index a72e48b..0000000
--- a/src/transforms/bibliography.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// import { renderBibliography, templateString } from '../components/d-bibliography';
-import { parseBibtex } from '../helpers/bibtex';
-import fs from 'fs';
-
-export default function(dom, data) {
- const bibliographyTag = dom.querySelector('d-bibliography');
- if (!bibliographyTag) {
- console.warn('No bibliography tag present!');
- return;
- }
-
- const src = bibliographyTag.getAttribute('src');
- if (src) {
- const path = data.inputDirectory + '/' + src;
- const text = fs.readFileSync(path, 'utf-8');
- const bibliography = parseBibtex(text);
- const scriptTag = dom.createElement('script');
- scriptTag.type = 'text/json';
- scriptTag.textContent = JSON.stringify([...bibliography]);
- bibliographyTag.appendChild(scriptTag);
- bibliographyTag.removeAttribute('src');
- }
- // const bibliographyEntries = new Map(data.citations.map( citationKey => {
- // const entry = data.bibliography.get(citationKey);
- // return [citationKey, entry];
- // }));
- //
- // const prerenderedBibliography = dom.createElement('d-bibliography-prerendered');
- //
- // const template = dom.createElement('template');
- // template.innerHTML = templateString;
- // const clone = dom.importNode(template.content, true);
- // prerenderedBibliography.innerHTML = template.content;
- // renderBibliography(prerenderedBibliography, bibliographyEntries, dom);
- //
- // bibliographyTag.parentElement.insertBefore(bibliographyTag, prerenderedBibliography);
- // bibliographyTag.parentElement.removeChild(bibliographyTag);
-
-}
diff --git a/src/transforms/citation-list.js b/src/transforms/citation-list.js
new file mode 100644
index 0000000..373fe1b
--- /dev/null
+++ b/src/transforms/citation-list.js
@@ -0,0 +1,11 @@
+import { renderCitationList } from '../components/d-citation-list'; // (element, entries)
+
+export default function(dom, data) {
+ const citationListTag = dom.querySelector('d-citation-list');
+ if (citationListTag) {
+ const entries = new Map(data.citations.map( citationKey => {
+ return [citationKey, data.bibliography.get(citationKey)];
+ }));
+ renderCitationList(citationListTag, entries, dom);
+ }
+}
diff --git a/src/transforms/meta.js b/src/transforms/meta.js
index d4ffb81..b8e03f6 100644
--- a/src/transforms/meta.js
+++ b/src/transforms/meta.js
@@ -14,16 +14,28 @@ export default function(dom, data) {
-
- ${data.title}
`);
- appendHead(`
+ if (data.url) {
+ appendHead(`
+
+ `);
+ }
+
+ if (data.title) {
+ appendHead(`
+ ${data.title}
+ `);
+ }
+
+ if (data.publishedDate){
+ appendHead(`
- `);
+ `);
+ }
(data.authors || []).forEach((a) => {
appendHtml(head, `
diff --git a/src/transforms/optional-components.js b/src/transforms/optional-components.js
index 410dfbc..9409c67 100644
--- a/src/transforms/optional-components.js
+++ b/src/transforms/optional-components.js
@@ -9,17 +9,21 @@
export default function(dom, data) {
const article = dom.querySelector('d-article');
-
if (!article) {
- console.warn('No d-article tag found!');
+ console.warn('No d-article tag found; skipping adding optional components!');
return;
}
+ const hasPassword = typeof data.password !== 'undefined';
let interstitial = dom.querySelector('d-interstitial');
- if (!interstitial && data.password) {
- interstitial = dom.createElement('d-interstitial');
- interstitial.password = data.password;
- dom.body.insertBefore(interstitial, dom.body.firstChild);
+ if (hasPassword && !interstitial) {
+ const inBrowser = typeof window !== 'undefined';
+ const onLocalhost = inBrowser && window.location.hostname.includes('localhost');
+ if (!inBrowser || !onLocalhost) {
+ interstitial = dom.createElement('d-interstitial');
+ interstitial.password = data.password;
+ dom.body.insertBefore(interstitial, dom.body.firstChild);
+ }
}
// let h1 = dom.querySelector('h1');
diff --git a/src/transforms/polyfills.js b/src/transforms/polyfills.js
index 8fbbdaf..34ded4d 100644
--- a/src/transforms/polyfills.js
+++ b/src/transforms/polyfills.js
@@ -42,5 +42,6 @@ export default function render(dom) {
polyfillScriptTag.id = 'polyfills';
// insert at appropriate position--before any other script tag
- dom.head.insertBefore(polyfillScriptTag, dom.head.firstChild);
+ const firstScriptTag = dom.head.querySelector('script');
+ dom.head.insertBefore(polyfillScriptTag, firstScriptTag);
}
diff --git a/test/transforms.js b/test/transforms.js
index 7d568b3..73c67a0 100644
--- a/test/transforms.js
+++ b/test/transforms.js
@@ -196,7 +196,7 @@ describe('Distill V2 (transforms)', function() {
expect(content).to.not.include('journal');
});
- it('given only a DOM, it should add Google scholar references information', function() {
+ it('given only a DOM (and publish data), it should add Google scholar references information', function() {
const dom = new JSDOM(`
sth
@@ -215,7 +215,7 @@ describe('Distill V2 (transforms)', function() {
`, options);
- const data = {};
+ const data = { publishedDate: new Date(), updatedDate: new Date() };
distill.render(dom.window.document, data, false);
const metaTags = [].slice.call(dom.window.document.querySelectorAll('meta[name="citation_reference"]'));
expect(metaTags).to.not.be.empty;