Switch to central controller for distributed control flow

This commit is contained in:
Ludwig Schubert
2017-08-01 16:54:46 -07:00
parent 929b159aaa
commit 9fe826447b
37 changed files with 5358 additions and 4778 deletions
+5
View File
@@ -34,3 +34,8 @@ jspm_packages
# Yarn Integrity file
.yarn-integrity
# Copied fonts
examples/fonts
dist/examples/fonts
dist/fonts
+37 -27
View File
@@ -1,32 +1,42 @@
// load `webcomponent` polyfills asynchronously
// import "webcomponents.js/webcomponents-loader.js";
/* Static styles and other modules */
import * as Styles from './components/styles';
import * as frontMatter from "./components/d-front-matter";
import * as title from "./components/d-title";
import * as byline from "./components/d-byline";
import * as article from "./components/d-article";
import * as abstract from "./components/d-abstract";
import * as toc from "./components/d-toc";
import * as styles from "./components/styles";
import * as appendix from "./components/d-appendix";
import * as distillAppendix from "./components/distill-appendix";
import * as bibliography from "./components/d-bibliography";
import * as references from "./components/d-references";
import * as code from "./components/d-code";
import * as math from "./components/d-math";
import * as footnote from "./components/d-footnote";
import * as footnoteList from "./components/d-footnote-list";
import * as acknowledgements from "./components/d-acknowledgements";
import * as cite from "./components/d-cite";
/* Components */
import { Abstract } from './components/d-abstract';
import { Acknowledgements } from './components/d-acknowledgements';
import { Appendix } from './components/d-appendix';
import { Article } from './components/d-article';
import { Bibliography } from './components/d-bibliography';
import { Byline } from './components/d-byline';
import { Cite } from './components/d-cite';
import { Code } from './components/d-code';
import { Footnote } from './components/d-footnote';
import { FootnoteList } from './components/d-footnote-list';
import { FrontMatter } from './components/d-front-matter';
import { DMath } from './components/d-math';
import { References } from './components/d-references';
import { Title } from './components/d-title';
import { TOC } from './components/d-toc';
// let codeStyle = document.createElement("style");
// codeStyle.textContent = codeCss;
// document.querySelector("head").appendChild(codeStyle);
const components = [
Abstract, Acknowledgements, Appendix, Article, Bibliography,
Byline, Cite, Code, Footnote, FootnoteList, FrontMatter, DMath,
References, Title, TOC,
];
document.addEventListener("DOMContentLoaded", function() {
// Render byline with authors list.
/* Distill website specific components */
import { DistillHeader } from "./distill-components/distill-header";
import { DistillAppendix } from "./distill-components/distill-appendix";
// Render distill appendix with distill journal data.
// document.querySelector("distill-appendix").render([]);
const distillComponents = [
DistillHeader, DistillAppendix,
];
})
function defineComponents() {
const allComponents = components.concat(distillComponents);
for (const component of allComponents) {
customElements.define(component.is, component);
}
}
defineComponents();
+145
View File
@@ -0,0 +1,145 @@
import { FrontMatter } from '../transforms/data';
import { collectCitations } from './d-cite';
const frontMatter = new FrontMatter();
// set up global controller object
/* functions whose names start with 'on' will be registered as listeners on d-article */
export const Controller = {
frontMatter: frontMatter,
waitingOn: {
bibliography: [],
citations: [],
},
listeners: {
onCiteKeyCreated(event) {
const [citeTag, keys] = event.detail;
// ensure we have citations
if (frontMatter.citations.length === 0) {
console.debug('onCiteKeyCreated, but unresolved dependency ("citations"). Enqueing.');
Controller.waitingOn.citations.push(() => Controller.listeners.onCiteKeyCreated(event));
return;
}
// ensure we have a loaded bibliography
if (frontMatter.bibliography.size === 0) {
console.debug('onCiteKeyCreated, but unresolved dependency ("bibliography"). Enqueing.');
Controller.waitingOn.bibliography.push(() => Controller.listeners.onCiteKeyCreated(event));
return;
}
const numbers = keys.map( key => frontMatter.citations.indexOf(key) );
citeTag.numbers = numbers;
const entries = keys.map( key => frontMatter.bibliography.get(key) );
citeTag.entries = entries;
},
onCiteKeyChanged(event) {
const [citeTag, keys] = event.detail;
// update citations
frontMatter.citations = collectCitations();
for (const waitingCallback of Controller.waitingOn.citations) {
waitingCallback();
}
// update bibliography
const bibliographyTag = document.querySelector('d-bibliography');
const bibliographyEntries = new Map(frontMatter.citations.map( citationKey => {
return [citationKey, frontMatter.bibliography.get(citationKey)];
}));
bibliographyTag.entries = bibliographyEntries;
const citeTags = document.querySelectorAll('d-cite');
for (const citeTag of citeTags) {
const keys = citeTag.keys;
const numbers = keys.map( key => frontMatter.citations.indexOf(key) );
citeTag.numbers = numbers;
const entries = keys.map( key => frontMatter.bibliography.get(key) );
citeTag.entries = entries;
}
const numbers = keys.map( key => frontMatter.citations.indexOf(key) );
citeTag.numbers = numbers;
const entries = keys.map( key => frontMatter.bibliography.get(key) );
citeTag.entries = entries;
},
onBibliographyChanged(event) {
const bibliographyTag = event.target;
const bibliography = event.detail;
frontMatter.bibliography = bibliography;
for (const waitingCallback of Controller.waitingOn.bibliography) {
waitingCallback();
}
// ensure we have citations
if (frontMatter.citations.length === 0) {
console.debug('onBibliographyChanged, but unresolved dependency ("citations"). Enqueing.');
Controller.waitingOn.citations.push(() => Controller.listeners.onBibliographyChanged(event));
return;
}
const entries = new Map(frontMatter.citations.map( citationKey => {
return [citationKey, frontMatter.bibliography.get(citationKey)];
}));
bibliographyTag.entries = entries;
},
onFootnoteChanged(event) {
const footnote = event.detail;
//TODO: optimize to only update current footnote
const footnotesList = document.querySelector('d-footnote-list');
if (footnotesList) {
const footnotes = document.querySelectorAll('d-footnote');
footnotesList.footnotes = footnotes;
}
},
onFrontMatterChanged(event) {
const data = event.detail;
frontMatter.mergeFromYMLFrontmatter(data);
const appendix = document.querySelector('distill-appendix');
appendix.frontMatter = frontMatter;
},
DOMContentLoaded(event) {
console.debug('DOMContentLoaded.');
const frontMatterTag = document.querySelector('d-front-matter');
const data = frontMatterTag.parse();
frontMatter.mergeFromYMLFrontmatter(data);
const appendix = document.querySelector('distill-appendix');
appendix.frontMatter = frontMatter;
console.debug('Resolving "citations" dependency due to initial DOM load.');
frontMatter.citations = collectCitations();
for (const waitingCallback of Controller.waitingOn.citations) {
waitingCallback();
}
const footnotesList = document.querySelector('d-footnote-list');
if (footnotesList) {
const footnotes = document.querySelectorAll('d-footnote');
footnotesList.footnotes = footnotes;
}
}
}, // listeners
update: {
cite(element) {
},
footnoteList(element) {
}
}
} // Controller
+4 -6
View File
@@ -1,5 +1,5 @@
import {Template} from "../mixins/template";
import {body} from "./layout";
import { Template } from "../mixins/template";
import { body } from "./layout";
const T = Template("d-abstract", `
<style>
@@ -13,8 +13,6 @@ const T = Template("d-abstract", `
</style>
`, false);
export default class Abstract extends T(HTMLElement) {
static get is() { return "d-abstract"; }
}
export class Abstract extends T(HTMLElement) {
customElements.define(Abstract.is, Abstract);
}
+2 -8
View File
@@ -1,8 +1,6 @@
import { Template } from "../mixins/template";
const name = 'd-acknowledgements';
const T = Template(name, `
const T = Template('d-acknowledgements', `
<style>
::slotted(h3) {
font-size: 15px;
@@ -20,10 +18,6 @@ const T = Template(name, `
<slot></slot>
`);
export default class Acknowledgements extends T(HTMLElement) {
static get is() { return name; }
export class Acknowledgements extends T(HTMLElement) {
}
customElements.define(name, Acknowledgements);
+1 -5
View File
@@ -25,10 +25,6 @@ ${page(".l-body")}
</div>
`);
export default class Appendix extends T(HTMLElement) {
static get is() { return "d-appendix"; }
export class Appendix extends T(HTMLElement) {
}
customElements.define(Appendix.is, Appendix);
+22 -205
View File
@@ -1,209 +1,26 @@
import {Template} from "../mixins/template";
import { Template } from '../mixins/template';
import { Controller } from './controller';
const T = Template("d-article", `
<style>
d-article {
display: block;
color: rgba(0, 0, 0, 0.8);
padding-top: 36px;
padding-bottom: 72px;
overflow: hidden;
font-size: 16px;
line-height: 1.6em;
border-top: 1px solid rgba(0, 0, 0, 0.2);
}
@media(min-width: 1024px) {
d-article {
font-size: 18px;
}
}
/* H2 */
d-article h2 {
font-weight: 400;
font-size: 26px;
line-height: 1.25em;
margin-top: 36px;
margin-bottom: 24px;
padding-bottom: 24px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
@media(min-width: 1024px) {
d-article h2 {
margin-top: 2em;
font-size: 32px;
}
}
d-article h1 + h2 {
font-weight: 300;
font-size: 20px;
line-height: 1.4em;
margin-top: 8px;
font-style: normal;
}
@media(min-width: 1080px) {
.centered h1 + h2 {
text-align: center;
}
d-article h1 + h2 {
margin-top: 12px;
font-size: 32px;
}
}
/* H3 */
d-article h3 {
font-weight: 400;
font-size: 20px;
line-height: 1.4em;
margin-top: 36px;
margin-bottom: 18px;
font-style: italic;
}
d-article h1 + h3 {
margin-top: 48px;
}
@media(min-width: 1024px) {
d-article h3 {
font-size: 26px;
}
}
/* H4 */
d-article h4 {
font-weight: 600;
text-transform: uppercase;
font-size: 14px;
line-height: 1.4em;
}
d-article a {
color: inherit;
}
d-article p,
d-article ul,
d-article ol {
margin-bottom: 24px;
}
d-article p b,
d-article ul b,
d-article ol b {
-webkit-font-smoothing: antialiased;
}
d-article a {
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
text-decoration: none;
}
d-article a:hover {
border-bottom: 1px solid rgba(0, 0, 0, 0.8);
}
d-article .link {
text-decoration: underline;
cursor: pointer;
}
d-article ul,
d-article ol {
padding-left: 24px;
}
d-article li {
margin-bottom: 24px;
margin-left: 0;
padding-left: 0;
}
d-article pre {
font-size: 14px;
margin-bottom: 20px;
}
d-article hr {
border: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
margin-top: 60px;
margin-bottom: 60px;
}
d-article section {
margin-top: 60px;
margin-bottom: 60px;
}
/* Figure */
d-article figure {
position: relative;
margin-top: 30px;
margin-bottom: 30px;
}
@media(min-width: 1024px) {
d-article figure {
margin-top: 48px;
margin-bottom: 48px;
}
}
d-article figure img {
width: 100%;
}
d-article figure svg text,
d-article figure svg tspan {
}
d-article figure figcaption {
color: rgba(0, 0, 0, 0.6);
font-size: 12px;
line-height: 1.5em;
}
@media(min-width: 1024px) {
d-article figure figcaption {
font-size: 13px;
}
}
d-article figure.external img {
background: white;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
padding: 18px;
box-sizing: border-box;
}
d-article figure figcaption a {
color: rgba(0, 0, 0, 0.6);
}
/*d-article figure figcaption::before {
position: relative;
display: block;
top: -20px;
content: "";
width: 25px;
border-top: 1px solid rgba(0, 0, 0, 0.3);
}*/
d-article span.equation-mimic {
font-family: georgia;
font-size: 115%;
font-style: italic;
}
d-article figure figcaption b {
font-weight: 600;
color: rgba(0, 0, 0, 1.0);
}
d-article > d-code,
d-article section > d-code {
display: block;
}
d-article > d-math[block],
d-article section > d-math[block] {
display: block;
}
d-article .citation {
color: #668;
cursor: pointer;
}
d-include {
width: auto;
display: block;
}
</style>
const T = Template('d-article', `
<style></style>
`, false);
export default class Article extends T(HTMLElement) {
static get is() { return "d-article"; }
}
customElements.define(Article.is, Article);
export class Article extends T(HTMLElement) {
// constructor() {
// super();
// }
connectedCallback() {
for (const [functionName, callback] of Object.entries(Controller.listeners)) {
if (typeof callback === 'function') {
document.addEventListener(functionName, callback);
} else {
console.error('Controller listeners need to be functions!')
}
}
}
}
+66 -51
View File
@@ -1,9 +1,10 @@
import bibtexParse from "bibtex-parse-js";
import { Template } from "../mixins/template";
import { Mutating } from "../mixins/mutating";
import { collectCitations } from './d-cite'
import bibtexParse from "bibtex-parse-js";
import { bibliography_cite } from "./citation";
const name = 'd-bibliography';
const T = Template(name, `
const T = Template('d-bibliography', `
<style>
.references {
font-size: 12px;
@@ -35,7 +36,7 @@ const T = Template(name, `
<ol></ol>
`);
function parseBibtex(bibtex) {
export function parseBibtex(bibtex) {
const bibliography = new Map();
const parsedEntries = bibtexParse.toJSON(bibtex);
for (const entry of parsedEntries) {
@@ -56,66 +57,80 @@ function parseBibtex(bibtex) {
return bibliography;
}
export default class Bibliography extends T(HTMLElement) {
export class Bibliography extends T(HTMLElement) {
constructor() {
super()
this.citations = new Array();
this.finishedLoading = false;
// set up mutation observer
const options = {childList: true, subtree: true};
const observer = new MutationObserver( (mutations) => {
observer.disconnect();
this.parseIfPossible();
observer.observe(this, options);
});
// ...and listen for changes
observer.observe(this, options);
}
parseIfPossible() {
if (this.firstElementChild && this.firstElementChild.tagName === 'SCRIPT') {
const newBibtex = this.firstElementChild.textContent;
if (this.bibtex !== newBibtex) {
this.bibtex = newBibtex;
const bibliography = parseBibtex(this.bibtex);
this.notify(bibliography);
}
}
};
connectedCallback() {
this.list = this.root.querySelector('ol');
// bibliography is initially hidden
this.root.host.style.display = 'none';
// parse bibliography
const scriptTag = this.querySelector("script");
if (scriptTag) {
this.bibliography = parseBibtex(scriptTag.textContent);
this.finishedLoading = true;
// look through document and register existing citations
document.querySelectorAll('d-cite')
.forEach(citation => this.registerCitation(citation));
} else {
console.error("No script tag with bibtex found in d-bibliography tag!")
// this.parseIfPossible();
// Store.subscribeTo('citations', (citations) => {
// // ensure citations list is visible
// this.root.host.style.display = 'initial';
// this.list.innerHTML = '';
// for (const key of citations) {
// const bibliography = Store.get('bibliography');
// const entry = bibliography.get(key);
// // construct and append list item to show citation
// const listItem = document.createElement('li');
// listItem.id = key;
// listItem.innerHTML = bibliography_cite(entry);
// this.list.appendChild(listItem);
// }
// });
}
notify(bibliography) {
const options = { detail: bibliography, bubbles: true };
const event = new CustomEvent('onBibliographyChanged', options);
this.dispatchEvent(event);
}
set entries(newEntries) {
this.root.host.style.display = 'initial';
this.list.innerHTML = '';
for (const [key, entry] of newEntries) {
const listItem = document.createElement('li');
listItem.id = key;
listItem.innerHTML = bibliography_cite(entry);
this.list.appendChild(listItem);
}
}
getEntry(key) {
return this.bibliography.get(key);
}
hasEntry(key) {
return this.bibliography.has(key);
}
getIndex(key) {
return this.citations.indexOf(key);
}
registerCitation(citation) {
// a d-cite element may cite multiple sources
const keyString = citation.getAttribute("key");
const keys = keyString ? keyString.split(",") : [];
for (const key of keys) {
if (!this.bibliography.has(key)) {
console.error("Citation key '" + key + "' is not present in bibliography!")
} else if (this.citations.indexOf(key) === -1) {
this.citations.push(key);
const entry = this.getEntry(key);
// ensure citations list is visible
this.root.host.style.display = 'initial';
// construct and append list item to show citation
const listItem = document.createElement('li');
listItem.id = key;
listItem.innerHTML = bibliography_cite(entry);
this.list.appendChild(listItem);
}
}
renderContent() {
// compute and store bibliography
// FrontMatter.bibliography = parseBibtex(this.bibtex);
// this.notify();
// Store.set('bibliography', bibliography);
// compute and store citations
// const citations = collectCitations();
// Store.set('citations', citations);
}
}
customElements.define(Bibliography.is, Bibliography);
+6 -15
View File
@@ -55,13 +55,8 @@ const T = Template("d-byline", `
display: inline;
}
@media(min-width: 768px) {
{
}
}
@media(min-width: 1080px) {
{
:host {
border-bottom: none;
}
@@ -152,17 +147,13 @@ const mustacheTemplate = `
{{/citation}}
`;
export default class Byline extends T(HTMLElement) {
static get is() { return "d-byline"; }
export class Byline extends T(HTMLElement) {
connectedCallback() {
const frontmatter = document.querySelector('d-front-matter');
const container = this.root.querySelector('.byline');
container.innerHTML = mustache.render(mustacheTemplate, frontmatter.data);
console.log(frontmatter.data)
// const frontmatter = document.querySelector('d-front-matter');
// const container = this.root.querySelector('.byline');
// container.innerHTML = mustache.render(mustacheTemplate, frontmatter.data);
// // console.log(frontmatter.data)
}
}
customElements.define(Byline.is, Byline);
+94 -50
View File
@@ -28,7 +28,7 @@ const T = Template('d-cite', `
}
</style>
<div style="display: none;" class="dt-hover-box">
<div style="display: none;" id="hover-box" class="dt-hover-box">
</div>
<span id="citation-" class="citation">
@@ -37,76 +37,120 @@ const T = Template('d-cite', `
</span>
`);
function inline_cite_short(keys, bibliography) {
function cite_string(key) {
if (bibliography.hasEntry(key)){
return (bibliography.getIndex(key)+1).toString();
} else {
return "?";
export function collectCitations() {
const citations = new Set();
const citeTags = document.querySelectorAll('d-cite');
for (const tag of citeTags) {
const keys = tag.getAttribute('key').split(',');
for (const key of keys) {
citations.add(key);
}
}
return "[" + keys.map(cite_string).join(", ") + "]";
return [...citations];
}
export class Cite extends T(HTMLElement) {
export default class Cite extends T(HTMLElement) {
/* Lifecycle */
constructor() {
super()
this._key = null;
Cite.currentId += 1;
this.citeId = Cite.currentId;
// Cite.currentId += 1;
// this.citeId = Cite.currentId;
}
connectedCallback() {
// this.notify();
this.hoverDiv = this.root.querySelector('.dt-hover-box');
this.outerSpan = this.root.querySelector('#citation-');
this.innerSpan = this.root.querySelector('.citation-number');
// this.outerSpan.id = `citation-${this.citeId}`;
// this.hoverDiv.id = `dt-cite-hover-box-${this.citeId}`;
HoverBox.get_box(this.hoverDiv).bind(this.outerSpan);
}
/* Observed Attributes */
// renderCitationNumbers(citations) {
// const numbers = this._keys.map( (key) => {
// const index = citations.indexOf(key);
// return index == -1 ? '?' : index + 1 + '';
// });
// const text = "[" + numbers.join(", ") + "]";
// this.innerSpan.textContent = text;
// }
/* observe 'key' attribute */
static get observedAttributes() {
return ['key'];
}
attributeChangedCallback(name, oldValue, newValue) {
// name will always be "key" due to observedAttributes
this._key = newValue;
this.renderContent();
}
get key() {
return this._key;
const eventName = oldValue ? 'onCiteKeyChanged' : 'onCiteKeyCreated';
const keys = newValue.split(',');
const options = { detail: [this, keys], bubbles: true };
const event = new CustomEvent(eventName, options);
document.dispatchEvent(event);
}
set key(value) {
this.setAttribute('key', value);
}
renderContent() {
const bibliography = document.querySelector('d-bibliography');
if (bibliography && bibliography.finishedLoading) {
customElements.whenDefined('d-bibliography').then( () => {
const keys = this.key.split(",");
// set up hidden hover box
const div = this.root.querySelector('.dt-hover-box');
div.innerHTML = keys.map( (key) => {
return bibliography.getEntry(key);
}).map(hover_cite).join('<br><br>');
div.id ='dt-cite-hover-box-' + this.citeId;
// set up visible citation marker
const outerSpan = this.root.querySelector('#citation-');
outerSpan.id = `citation-${this.citeId}`;
// outerSpan.setAttribute('data-hover', dataHoverString); // directly tell HoverBox instead?
const innerSpan = this.root.querySelector('.citation-number');
innerSpan.textContent = inline_cite_short(keys, bibliography);
HoverBox.get_box(div).bind(outerSpan);
});
} else {
console.error(`You used a d-cite tag (${key}) without including a d-bibliography tag in your article. We can't lookup your citation this way.`)
}
get key() {
return this.getAttribute('key');
}
get keys() {
return this.getAttribute('key').split(',');
}
/* Setters & Rendering */
set numbers(numbers) {
const numberStrings = numbers.map( index => {
return index == -1 ? '?' : index + 1 + '';
});
const textContent = "[" + numberStrings.join(", ") + "]";
const innerSpan = this.root.querySelector('.citation-number');
innerSpan.textContent = textContent;
}
set entries(entries) {
const div = this.root.querySelector('#hover-box');
div.innerHTML = entries.map(hover_cite).join('<br><br>');
}
// renderContent() {
// const bibliography = document.querySelector('d-bibliography');
// if (bibliography && bibliography.finishedLoading) {
// customElements.whenDefined('d-bibliography').then( () => {
// const keys = this.key.split(",");
//
// // set up hidden hover box
// const div = this.root.querySelector('.dt-hover-box');
// div.innerHTML = keys.map( (key) => {
// return bibliography.getEntry(key);
// }).map(hover_cite).join('<br><br>');
// div.id ='dt-cite-hover-box-' + this.citeId;
//
// // set up visible citation marker
// const outerSpan = this.root.querySelector('#citation-');
// outerSpan.id = `citation-${this.citeId}`;
// // outerSpan.setAttribute('data-hover', dataHoverString); // directly tell HoverBox instead?
// const innerSpan = this.root.querySelector('.citation-number');
// innerSpan.textContent = inline_cite_short(keys, bibliography);
//
// HoverBox.get_box(div).bind(outerSpan);
// });
// } else {
// console.error(`You used a d-cite tag (${key}) without including a d-bibliography tag in your article. We can't lookup your citation this way.`)
// }
// }
}
Cite.currentId = 0;
customElements.define(Cite.is, Cite);
+3 -9
View File
@@ -6,9 +6,7 @@ import css from "prismjs/themes/prism.css";
import { Template } from "../mixins/template.js"
import { Mutating } from "../mixins/mutating.js"
const templateString = `
const T = Template("d-code", `
<style>
code {
@@ -32,11 +30,9 @@ ${css}
<code id="code-container"></code>
`
`);
const Templated = Template("d-code", templateString);
export class Code extends Mutating(Templated(HTMLElement)) {
export class Code extends Mutating(T(HTMLElement)) {
renderContent() {
@@ -76,5 +72,3 @@ export class Code extends Mutating(Templated(HTMLElement)) {
}
}
customElements.define("d-code", Code);
+33 -26
View File
@@ -1,7 +1,7 @@
import { Template } from "../mixins/template";
// import { Store } from './store';
const name = 'd-footnote-list';
const T = Template(name, `
const T = Template('d-footnote-list', `
<style>
ol {
padding: 0 0 0 18px;
@@ -33,40 +33,47 @@ a.footnote-backlink {
<ol></ol>
`);
export default class FootnoteList extends T(HTMLElement) {
static get is() { return name; }
export class FootnoteList extends T(HTMLElement) {
connectedCallback() {
this.list = this.root.querySelector('ol');
this.footnotes = new Map();
// footnotes list is initially hidden
this.root.host.style.display = 'none';
// look through document and register existing footnotes
document.querySelectorAll('d-footnote')
.forEach(footnote => this.registerFootnote(footnote));
// Store.subscribeTo('footnotes', (footnote) => {
// this.renderFootnote(footnote);
// });
}
registerFootnote(element) {
// check if we already know about this footnote
if (!this.footnotes.has(element.id)) {
this.footnotes.set(element.id, element);
// TODO: could optimize this to accept individual footnotes?
set footnotes(footnotes) {
this.list.innerHTML = '';
if (footnotes.length) {
// ensure footnote list is visible
this.root.host.style.display = 'initial'
// construct and append list item to show footnote
const listItem = document.createElement('li');
listItem.innerHTML = element.innerHTML;
const backlink = document.createElement('a');
backlink.setAttribute('class', 'footnote-backlink');
backlink.textContent = '[↩]';
backlink.href = `#${element.id}`;
listItem.appendChild(backlink);
this.list.appendChild(listItem);
} /*else {
console.debug('Had already registered footnote ' + element.id + '!')
}*/
for (const footnote of footnotes) {
// construct and append list item to show footnote
const listItem = document.createElement('li');
listItem.id = footnote.id + '-listing';
listItem.innerHTML = footnote.innerHTML;
const backlink = document.createElement('a');
backlink.setAttribute('class', 'footnote-backlink');
backlink.textContent = '[↩]';
backlink.href = `#${footnote.id}`;
listItem.appendChild(backlink);
this.list.appendChild(listItem);
}
} else {
// ensure footnote list is invisible
this.shadowRoot.host.style.display = 'none';
}
}
renderFootnote(element) {
}
}
customElements.define(name, FootnoteList);
+23 -16
View File
@@ -1,7 +1,8 @@
import { Template } from "../mixins/template.js"
import { HoverBox } from "./hover-box.js"
// import { Store } from './store';
const templateString = `
const T = Template("d-footnote", `
<style>
d-math[block] {
@@ -11,18 +12,34 @@ d-math[block] {
</style>
<div style="display: none;" class="dt-hover-box">
<slot></slot>
<slot id='slot'></slot>
</div>
<sup><span id="fn-" data-hover-ref="" style="cursor:pointer"></span></sup>
`;
`);
const TemplatedFootnote = Template("d-footnote", templateString);
export class Footnote extends T(HTMLElement) {
export class Footnote extends TemplatedFootnote(HTMLElement) {
constructor() {
super();
const options = {childList: true, characterData: true, subtree: true};
const observer = new MutationObserver(this.notify);
observer.observe(this, options);
}
notify() {
const options = { detail: this, bubbles: true };
const event = new CustomEvent('onFootnoteChanged', options);
document.dispatchEvent(event);
}
connectedCallback() {
// listen and notify about changes to slotted content
// const slot = this.shadowRoot.querySelector('#slot');
// slot.addEventListener('slotchange', this.notify);
// create numeric ID
Footnote.currentFootnoteId += 1;
const IdString = Footnote.currentFootnoteId.toString();
@@ -37,20 +54,10 @@ export class Footnote extends TemplatedFootnote(HTMLElement) {
span.setAttribute('id', 'fn-' + IdString);
span.setAttribute('data-hover-ref', div.id);
span.textContent = IdString;
HoverBox.get_box(div).bind(span);
// register with footnote list should there be one
const footnoteList = document.querySelector('d-footnote-list');
if (footnoteList) {
customElements.whenDefined('d-footnote-list').then(() => {
footnoteList.registerFootnote(this);
});
}
HoverBox.get_box(div).bind(span);
}
}
Footnote.currentFootnoteId = 0;
customElements.define("d-footnote", Footnote);
+25 -41
View File
@@ -1,52 +1,36 @@
import ymlParse from "js-yaml";
import expandData from "../transforms/expand-data"
export default class FrontMatter extends HTMLElement {
export class FrontMatter extends HTMLElement {
static get is() { return "d-front-matter"; }
constructor() {
super();
this.data = {};
const options = {childList: true, characterData: true, subtree: true};
const observer = new MutationObserver( (mutation) => {
const data = this.parse();
this.notify(data);
});
observer.observe(this, options);
}
connectedCallback() {
const el = this.querySelector("script");
if (el) {
const text = el.textContent;
this.parse(ymlParse.safeLoad(text));
parse(){
const scriptTag = this.querySelector("script");
if (scriptTag) {
const yml = scriptTag.textContent;
const data = ymlParse.safeLoad(yml);
return data;
} else {
console.error('You added a frontmatter tag but did not provide a script tag with front matter data in it. Please take a look at our templates.')
return {};
}
}
parse(localData) {
this.data.title = localData.title ? localData.title : "Untitled";
this.data.description = localData.description ? localData.description : "No description.";
this.data.publishedDate = localData.published ? new Date(localData.published) : false;
this.data.authors = localData.authors ? localData.authors : [];
this.data.authors = this.data.authors.map((author, i) =>{
let a = {};
let name = Object.keys(author)[0];
if ((typeof author) === "string") {
name = author;
} else {
a.personalURL = author[name];
}
let names = name.split(" ");
a.name = name;
a.firstName = names.slice(0, names.length - 1).join(" ");
a.lastName = names[names.length -1];
if (localData.affiliations[i]) {
let affiliation = Object.keys(localData.affiliations[i])[0];
if ((typeof localData.affiliations[i]) === "string") {
affiliation = localData.affiliations[i]
} else {
a.affiliationURL = localData.affiliations[i][affiliation];
}
a.affiliation = affiliation;
}
return a;
});
expandData(null, this.data);
notify(data) {
const options = { detail: data, bubbles: true };
const event = new CustomEvent('onFrontMatterChanged', options);
document.dispatchEvent(event);
}
}
customElements.define(FrontMatter.is, FrontMatter);
}
+8 -10
View File
@@ -1,30 +1,28 @@
import katex from "katex";
import { Mutating } from "../mixins/mutating.js"
import { Template } from "../mixins/template.js"
import katexCSS from "../node_modules/katex/dist/katex.min.css"
const templateString = `
const T = Template("d-math", `
<style>
d-math[block] {
display: block;
}
${katexCSS}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css">
<span id="katex-container"></span>
`;
`);
const TemplatedMath = Template("d-math", templateString);
export class Math extends Mutating(TemplatedMath(HTMLElement)) {
export class DMath extends Mutating(T(HTMLElement)) {
renderContent() {
const options = { displayMode: this.hasAttribute("block") };
const container = this.shadowRoot.querySelector("#katex-container")
const container = this.root.querySelector("#katex-container");
katex.render(this.textContent, container, options);
}
}
customElements.define("d-math", Math);
}
+5 -6
View File
@@ -1,5 +1,5 @@
import {Template} from "../mixins/template";
import {body} from "./layout";
import { Template } from "../mixins/template";
import { body } from "./layout";
const T = Template("d-references", `
<style>
@@ -9,11 +9,10 @@ d-references {
</style>
`, false);
export default class References extends T(HTMLElement) {
static get is() { return "d-references"; }
export class References extends T(HTMLElement) {
connectedCallback() {
super.connectedCallback();
}
}
customElements.define(References.is, References);
}
+3 -7
View File
@@ -1,5 +1,5 @@
import {Template} from "../mixins/template";
import {page} from "./layout";
import { Template } from "../mixins/template";
import { page } from "./layout";
const T = Template("d-title", `
<style>
@@ -32,9 +32,7 @@ ${page("::slotted(h1), ::slotted(h2)")}
<d-byline></d-byline>
`);
export default class Title extends T(HTMLElement) {
static get is() { return "d-title"; }
export class Title extends T(HTMLElement) {
connectedCallback() {
super.connectedCallback();
@@ -44,5 +42,3 @@ export default class Title extends T(HTMLElement) {
}
}
customElements.define(Title.is, Title);
+2 -6
View File
@@ -8,10 +8,6 @@ d-toc {
</style>
`, false);
export default class Toc extends T(HTMLElement) {
static get is() {
return "d-toc";
}
}
export class TOC extends T(HTMLElement) {
customElements.define(Toc.is, Toc);
}
-62
View File
@@ -1,62 +0,0 @@
import {page} from "./layout";
import mustache from "mustache";
let mustacheTemplate = `
<style>
distill-appendix h3 {
font-size: 15px;
font-weight: 500;
margin-top: 20px;
margin-bottom: 0;
color: rgba(0,0,0,0.65);
line-height: 1em;
}
distill-appendix a {
color: rgba(0, 0, 0, 0.6);
}
distill-appendix ol,
distill-appendix ul {
padding-left: 24px;
}
distill-appendix .citation {
font-size: 11px;
line-height: 15px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: 18px;
border: 1px solid rgba(0,0,0,0.1);
background: rgba(0, 0, 0, 0.02);
padding: 10px 18px;
border-radius: 3px;
color: rgba(150, 150, 150, 1);
overflow: hidden;
margin-top: -12px;
}
</style>
<h3>Updates and Corrections</h3>
<p><a href="">View all changes</a> to this article since it was first published. If you see mistakes or want to suggest changes, please <a href="">create an issue on GitHub</a>. </p>
<h3>Reuse</h3>
<p>Diagrams and text are licensed under Creative Commons Attribution <a href="https://creativecommons.org/licenses/by/2.0/">CC-BY 2.0</a> with the <a class="github" href="https://github.com/distillpub/post--augmented-rnns">source available on GitHub</a>, unless noted otherwise. The figures that have been reused from other sources dont fall under this license and can be recognized by a note in their caption: “Figure from …”.</p>
<h3>Citation</h3>
<p>For attribution in academic contexts, please cite this work as</p>
<pre class="citation short">Olah &amp; Carter, "Attention and Augmented Recurrent Neural Networks", Distill, 2016.</pre>
<p>BibTeX citation</p>
<pre class="citation long">@article{olah2016attention,
author = {Olah, Chris and Carter, Shan},
title = {Attention and Augmented Recurrent Neural Networks},
journal = {Distill},
year = {2016},
note = {http://distill.pub/2016/augmented-rnns}
}</pre>
`;
export default class DistillAppendix extends HTMLElement {
static get is() { return "distill-appendix"; }
connectedCallback(data) {
this.innerHTML = mustache.render(mustacheTemplate, data);
}
}
customElements.define(DistillAppendix.is, DistillAppendix);
+3 -3
View File
@@ -94,7 +94,7 @@ HoverBox.prototype.bind = function bind(node) {
}
// Don't trigger body touchstart event when touching link
e.stopPropagation();
}.bind(this));
}.bind(this), {passive: true});
}
HoverBox.prototype.bindDivEvents = function bindDivEvents(node){
@@ -106,7 +106,7 @@ HoverBox.prototype.bindDivEvents = function bindDivEvents(node){
this.div.addEventListener("mouseout", function(){this.extendTimeout(250);}.bind(this));
// Don't trigger body touchstart event when touching within box
this.div.addEventListener("touchstart", function(e){e.stopPropagation();});
this.div.addEventListener("touchstart", function(e){e.stopPropagation();}, {passive: true});
// Close box when touching outside box
document.body.addEventListener("touchstart", function(){this.hide();}.bind(this));
document.body.addEventListener("touchstart", function(){this.hide();}.bind(this), {passive: true});
}
-23
View File
@@ -44,29 +44,6 @@ export function page(selector) {
`;
}
export function pagePadding(selector) {
return `${selector} {
width: auto;
padding-left: 24px;
padding-right: 24px;
box-sizing: border-box;
}
@media(min-width: 768px) {
${selector} {
padding-left: 72px;
padding-right: 72px;
}
}
@media(min-width: 1080px) {
${selector} {
width: 984px;
padding-left: auto;
padding-right: auto;
}
}
`;
}
export function screen(selector) {
return `${selector} {
width: auto;
+60
View File
@@ -0,0 +1,60 @@
class DataStore {
constructor() {
this.collections = new Map();
this.subscribers = new Map();
}
get(collectionName) {
return this.collections.get(collectionName);
}
set(collectionName, collection) {
this.collections.set(collectionName, collection);
// notify subscribers
if (this.subscribers.has(collectionName)) {
const subscribers = this.subscribers.get(collectionName);
for (const subscriber of subscribers) {
subscriber(collection);
}
}
}
register(collectionName, element) {
// create collection if it doesn't yet exist
if (!this.collections.has(collectionName)) {
this.collections.set(collectionName, []);
}
// add new element to collection
const collection = this.collections.get(collectionName);
collection.push(element);
// notify subscribers
if (this.subscribers.has(collectionName)) {
const subscribers = this.subscribers.get(collectionName);
for (const subscriber of subscribers) {
subscriber(element, collection);
}
}
}
subscribeTo(collectionName, callback) {
// create subscriber collection if it doesn't yet exist
if (!this.subscribers.has(collectionName)) {
this.subscribers.set(collectionName, []);
}
// add new callback to list of subscribers
const subscribers = this.subscribers.get(collectionName);
subscribers.push(callback);
// notify subscriber about existing collection entries
if (this.collections.has(collectionName)) {
const collection = this.collections.get(collectionName);
for (const entry of collection) {
callback(entry, collection);
}
}
}
}
// set up store
// export const Store = new DataStore();
+197
View File
@@ -0,0 +1,197 @@
d-article {
display: block;
color: rgba(0, 0, 0, 0.8);
padding-top: 36px;
padding-bottom: 72px;
overflow: hidden;
font-size: 16px;
line-height: 1.6em;
border-top: 1px solid rgba(0, 0, 0, 0.2);
}
@media(min-width: 1024px) {
d-article {
font-size: 18px;
}
}
/* H2 */
d-article h2 {
font-weight: 400;
font-size: 26px;
line-height: 1.25em;
margin-top: 36px;
margin-bottom: 24px;
padding-bottom: 24px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
@media(min-width: 1024px) {
d-article h2 {
margin-top: 2em;
font-size: 32px;
}
}
d-article h1 + h2 {
font-weight: 300;
font-size: 20px;
line-height: 1.4em;
margin-top: 8px;
font-style: normal;
}
@media(min-width: 1080px) {
.centered h1 + h2 {
text-align: center;
}
d-article h1 + h2 {
margin-top: 12px;
font-size: 32px;
}
}
/* H3 */
d-article h3 {
font-weight: 400;
font-size: 20px;
line-height: 1.4em;
margin-top: 36px;
margin-bottom: 18px;
font-style: italic;
}
d-article h1 + h3 {
margin-top: 48px;
}
@media(min-width: 1024px) {
d-article h3 {
font-size: 26px;
}
}
/* H4 */
d-article h4 {
font-weight: 600;
text-transform: uppercase;
font-size: 14px;
line-height: 1.4em;
}
d-article a {
color: inherit;
}
d-article p,
d-article ul,
d-article ol {
margin-bottom: 24px;
}
d-article p b,
d-article ul b,
d-article ol b {
-webkit-font-smoothing: antialiased;
}
d-article a {
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
text-decoration: none;
}
d-article a:hover {
border-bottom: 1px solid rgba(0, 0, 0, 0.8);
}
d-article .link {
text-decoration: underline;
cursor: pointer;
}
d-article ul,
d-article ol {
padding-left: 24px;
}
d-article li {
margin-bottom: 24px;
margin-left: 0;
padding-left: 0;
}
d-article pre {
font-size: 14px;
margin-bottom: 20px;
}
d-article hr {
border: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
margin-top: 60px;
margin-bottom: 60px;
}
d-article section {
margin-top: 60px;
margin-bottom: 60px;
}
/* Figure */
d-article figure {
position: relative;
margin-top: 30px;
margin-bottom: 30px;
}
@media(min-width: 1024px) {
d-article figure {
margin-top: 48px;
margin-bottom: 48px;
}
}
d-article figure img {
width: 100%;
}
d-article figure svg text,
d-article figure svg tspan {
}
d-article figure figcaption {
color: rgba(0, 0, 0, 0.6);
font-size: 12px;
line-height: 1.5em;
}
@media(min-width: 1024px) {
d-article figure figcaption {
font-size: 13px;
}
}
d-article figure.external img {
background: white;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
padding: 18px;
box-sizing: border-box;
}
d-article figure figcaption a {
color: rgba(0, 0, 0, 0.6);
}
/*d-article figure figcaption::before {
position: relative;
display: block;
top: -20px;
content: "";
width: 25px;
border-top: 1px solid rgba(0, 0, 0, 0.3);
}*/
d-article span.equation-mimic {
font-family: georgia;
font-size: 115%;
font-style: italic;
}
d-article figure figcaption b {
font-weight: 600;
color: rgba(0, 0, 0, 1.0);
}
d-article > d-code,
d-article section > d-code {
display: block;
}
d-article > d-math[block],
d-article section > d-math[block] {
display: block;
}
d-article .citation {
color: #668;
cursor: pointer;
}
d-include {
width: auto;
display: block;
}
+2 -1
View File
@@ -2,8 +2,9 @@ import base from "./styles-base.css";
import layout from "./styles-layout.css";
import article from "./styles-article.css";
import print from "./styles-print.css";
import katex from '../node_modules/katex/dist/katex.min.css'
let s = document.createElement("style");
s.textContent = base + layout + print + article;
s.textContent = base + layout + print + article + katex;
document.querySelector("head").appendChild(s);
export default s;
+4344 -4129
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+66
View File
@@ -0,0 +1,66 @@
const styles = `
<style>
distill-appendix h3 {
font-size: 15px;
font-weight: 500;
margin-top: 20px;
margin-bottom: 0;
color: rgba(0,0,0,0.65);
line-height: 1em;
}
distill-appendix a {
color: rgba(0, 0, 0, 0.6);
}
distill-appendix ol,
distill-appendix ul {
padding-left: 24px;
}
distill-appendix .citation {
font-size: 11px;
line-height: 15px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: 18px;
border: 1px solid rgba(0,0,0,0.1);
background: rgba(0, 0, 0, 0.02);
padding: 10px 18px;
border-radius: 3px;
color: rgba(150, 150, 150, 1);
overflow: hidden;
margin-top: -12px;
}
</style>
`
export function appendixTemplate(frontMatter) {
return `
${styles}
<h3>Updates and Corrections</h3>
<p><a href="">View all changes</a> to this article since it was first published. If you see mistakes or want to suggest changes, please <a href="${frontMatter.githubUrl + '/issues/new'}">create an issue on GitHub</a>. </p>
<h3>Reuse</h3>
<p>Diagrams and text are licensed under Creative Commons Attribution <a href="https://creativecommons.org/licenses/by/2.0/">CC-BY 2.0</a> with the <a class="github" href="${frontMatter.githubUrl}">source available on GitHub</a>, unless noted otherwise. The figures that have been reused from other sources dont fall under this license and can be recognized by a note in their caption: “Figure from …”.</p>
<h3>Citation</h3>
<p>For attribution in academic contexts, please cite this work as</p>
<pre class="citation short">${frontMatter.concatenatedAuthors}, "${frontMatter.title}", Distill, ${frontMatter.publishedYear}.</pre>
<p>BibTeX citation</p>
<pre class="citation long">@article{${frontMatter.slug},
author = {${frontMatter.bibtexAuthors}},
title = {${frontMatter.title}},
journal = {Distill},
year = {${frontMatter.publishedYear}},
note = {${frontMatter.url}}
}</pre>
`;
}
export class DistillAppendix extends HTMLElement {
static get is() { return "distill-appendix"; }
set frontMatter(frontMatter) {
this.innerHTML = appendixTemplate(frontMatter);
}
}
+2 -4
View File
@@ -1,4 +1,4 @@
import {Template} from "./mixins/template";
import {Template} from "../mixins/template";
// import logo from "./distill-logo.svg";
var logo = "";
@@ -84,10 +84,8 @@ svg path {
</div>
`);
export default class DistillHeader extends T(HTMLElement) {
export class DistillHeader extends T(HTMLElement) {
static get is() {
return "distill-header";
}
}
customElements.define(DistillHeader.is, DistillHeader);
+35 -17
View File
@@ -1,23 +1,40 @@
<!doctype html>
<meta charset="utf8">
<script src="../dist/components.js" async></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css">
<head>
<meta charset="utf8">
<d-front-matter>
<script type="text/yml">
title: Demo Title Attention and Augmented Recurrent Neural Networks
published: Jan 10, 2017
authors:
- Chris Olah:
- Shan Carter: http://shancarter.com
affiliations:
- Google Brain:
- Google Brain: http://g.co/brain
<script>
// checks for webcomponents compatibility
if ('registerElement' in document &&
'import' in document.createElement('link') &&
'content' in document.createElement('template')) {
// Platform supports webcomponents natively! :-)
} else {
// Platform does not support webcomponents--loading polyfills.
const scriptTag = document.createElement('script');
scriptTag.src = '../node_modules/webcomponents.js/webcomponents-lite.js';
scriptTag.src = '../node_modules/webcomponents.js/webcomponents-lite.js';
scriptTag.async = false;
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
}
</script>
</d-front-matter>
<script src="../dist/components.js"></script>
<d-front-matter>
<script type="text/yml">
title: Demo Title Attention and Augmented Recurrent Neural Networks
published: Jan 10, 2017
authors:
- Chris Olah:
- Shan Carter: http://shancarter.com
affiliations:
- Google Brain:
- Google Brain: http://g.co/brain
</script>
</d-front-matter>
</head>
<body>
<d-article>
<d-title>
<h1>Attention and Augmented Recurrent Neural Networks</h1>
@@ -31,8 +48,8 @@
<d-math block>
c = \pm \sqrt{ \sum_{i=0}^{n}{a^{222} + b^2}}
</d-math>
<p>We can also cite <d-cite key="gregor2015draw,mercier2011humans"></d-cite> external publications. <d-cite key="dong2014image,dumoulin2016guide,mordvintsev2015inceptionism"></d-cite></p>
<p>We should also be testing footnotes<d-footnote>This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote.</d-footnote>. There are multiple footnotes, and they appear in the appendix<d-footnote>Given I have coded them right. Also, here's math in a footnote: <d-math>c = \sum_0^i{x}<d-math>.</d-footnote> as well.</p>
<p>We can<d-cite key="mercier2011humans"></d-cite> also cite <d-cite key="gregor2015draw,mercier2011humans"></d-cite> external publications. <d-cite key="dong2014image,dumoulin2016guide,mordvintsev2015inceptionism"></d-cite></p>
<p>We should also be testing footnotes<d-footnote>This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote.</d-footnote>. There are multiple footnotes, and they appear in the appendix<d-footnote>Given I have coded them right. Also, here's math in a footnote: <d-math>c = \sum_0^i{x}</d-math>. Also, a citation. Box-ception<d-cite key='gregor2015draw'></d-cite>!</d-footnote> as well.</p>
<table>
<thead>
<tr><th>First</th><th>Second</th><th>Third</th></tr>
@@ -182,3 +199,4 @@
<distill-appendix> </distill-appendix>
</d-appendix>
</body>
+6 -13
View File
@@ -1,16 +1,7 @@
export const Mutating = (superclass) => {
return class extends superclass {
static get observedAttributes() {
return ['textContent'];
}
attributeChangedCallback(name, oldValue, newValue) {
console.warn(name, oldValue, newValue);
}
constructor() {
super();
@@ -22,20 +13,22 @@ export const Mutating = (superclass) => {
observer.observe(this, options);
});
this.renderIfPossible();
// ...and listen for changes afterwards
// ...and listen for changes
observer.observe(this, options);
}
connectedCallback() {
super.connectedCallback();
this.renderIfPossible();
}
// potential TODO: check if this is enough for all our usecases
// maybe provide a custom function to tell if we have enough information to render
renderIfPossible() {
if (this.textContent && this.shadowRoot) { this.renderContent(); }
if (this.textContent && this.root) {
this.renderContent();
}
};
renderContent() {
+9 -6
View File
@@ -1,11 +1,11 @@
// import '@webcomponents/shadycss/scoping-shim';
export const Template = (name, templateString, useShadow = true) => {
const template = document.createElement('template');
template.innerHTML = templateString;
// ShadyCSS.prepareTemplate(template, name);
if (useShadow && 'ShadyCSS' in window) {
ShadyCSS.prepareTemplate(template, name);
}
return (superclass) => {
return class extends superclass {
@@ -17,19 +17,21 @@ export const Template = (name, templateString, useShadow = true) => {
this.clone = document.importNode(template.content, true);
if (useShadow) {
// ShadyCSS.applyStyle(this);
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(this.clone);
}
}
connectedCallback() {
if (!useShadow) {
if (useShadow) {
if ('ShadyCSS' in window) {
ShadyCSS.styleElement(this);
}
} else {
this.insertBefore(this.clone, this.firstChild);
}
}
/* TODO: Are we using these? Should we even? */
get root() {
if (useShadow) {
return this.shadowRoot;
@@ -38,6 +40,7 @@ export const Template = (name, templateString, useShadow = true) => {
}
}
/* TODO: Are we using these? Should we even? */
$(query) {
return this.root.querySelector(query);
}
+9 -7
View File
@@ -3,21 +3,21 @@
"version": "0.0.21",
"description": "Template for creating Distill articles.",
"main": "dist/template.js",
"author": "Shan Carter",
"homepage": "https://github.com/distillpub/distill-template#readme",
"bugs": {
"url": "https://github.com/distillpub/distill-template/issues"
},
"scripts": {
"start": "rollup -c rollup.config.components.js -w",
"serve": "python3 -m http.server",
"serve": "python3 -m http.server --bind 127.0.0.1",
"test": "mocha",
"build": "rollup -c rollup.config.components.js && rollup -c rollup.config.transforms.js"
"build": "rollup -c rollup.config.components.js"
},
"author": "Shan Carter",
"repository": {
"url": "git+https://github.com/distillpub/distill-template.git",
"type": "git"
},
"bugs": {
"url": "https://github.com/distillpub/distill-template/issues"
},
"homepage": "https://github.com/distillpub/distill-template#readme",
"devDependencies": {
"bibtex-parse-js": "^0.0.23",
"chai": "^3.5.0",
@@ -36,12 +36,14 @@
"rollup-watch": "^2.5.0"
},
"dependencies": {
"@webcomponents/webcomponentsjs": "webcomponents/webcomponentsjs",
"commander": "^2.9.0",
"d3-time-format": "^2.0.3",
"handlebars": "^4.0.6",
"katex": "^0.7.1",
"mustache": "^2.3.0",
"rollup-plugin-babili": "^3.1.0",
"rollup-plugin-copy": "^0.2.3",
"rollup-plugin-gzip": "^1.2.0",
"webcomponents.js": "webcomponents/webcomponentsjs",
"webpack": "^2.2.1"
+12 -8
View File
@@ -1,8 +1,9 @@
import copy from 'rollup-plugin-copy';
import resolve from 'rollup-plugin-node-resolve';
import string from 'rollup-plugin-string';
import commonjs from 'rollup-plugin-commonjs';
import babili from 'rollup-plugin-babili';
import gzip from 'rollup-plugin-gzip';
// import babili from 'rollup-plugin-babili';
// import gzip from 'rollup-plugin-gzip';
import serve from 'rollup-plugin-serve';
const PORT = 8080;
@@ -13,7 +14,7 @@ export default {
sourceMap: true,
targets: [
{
format: 'umd',
format: 'iife',
moduleName: 'dl',
dest: `dist/components.js`,
}
@@ -28,13 +29,16 @@ export default {
}),
commonjs(),
// babili({
// comments: false, // means: *don't* preserve comments
// comments: false, // means: *remove comments
// sourceMap: true,
// }),
// gzip(), // just for testing -- firebase CDN gzips automatically
serve({
port: PORT,
open: true,
})
// serve({
// port: PORT,
// open: true,
// })
copy({
'node_modules/katex/dist/fonts': 'examples/fonts',
}),
]
};
+40
View File
@@ -0,0 +1,40 @@
import resolve from 'rollup-plugin-node-resolve';
import string from 'rollup-plugin-string';
import commonjs from 'rollup-plugin-commonjs';
import babili from 'rollup-plugin-babili';
import gzip from 'rollup-plugin-gzip';
import serve from 'rollup-plugin-serve';
const PORT = 8080;
console.log(`opening http://localhost:${PORT} .../`);
export default {
entry: 'template.v2.js',
sourceMap: true,
targets: [
{
format: 'umd',
moduleName: 'dl',
dest: `dist/template.v2.js`,
}
],
plugins: [
resolve({
jsnext: true,
browser: true,
}),
string({
include: ["**/*.txt", "**/*.svg", "**/*.html", "**/*.css", "**/*.base64"]
}),
commonjs(),
// babili({
// comments: false, // means: *remove* comments
// sourceMap: true,
// }),
// gzip(), // just for testing -- firebase CDN gzips automatically
serve({
port: PORT,
open: true,
})
]
};
+1 -1
View File
@@ -16,7 +16,7 @@ export default {
{
format: 'umd',
moduleName: 'dl',
dest: `dist/template.js`,
dest: `dist/transforms.js`,
}
],
plugins: [
+53 -14
View File
@@ -1,26 +1,27 @@
import {timeFormat} from "d3-time-format";
const zeroPad = n => n < 10 ? "0" + n : n;
const zeroPad = n => n < 10 ? "0" + n : n;
const RFC = timeFormat("%a, %d %b %Y %H:%M:%S %Z");
const months = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"];
class Author {
constructor() {
this.personalURL = ""; // "https://colah.github.io"
this.name = ""; // "Chris Olah"
this.affiliationURL = ""; // "https://g.co/brain"
this.affiliation = ""; // "Google Brain"
constructor(name='', personalURL='', affiliation='', affiliationURL='') {
this.name = name; // "Chris Olah"
this.personalURL = personalURL; // "https://colah.github.io"
this.affiliation = affiliation; // "Google Brain"
this.affiliationURL = affiliationURL; // "https://g.co/brain"
}
// "Chris"
get firstName() {
let names = this.name.split(" ");
const names = this.name.split(" ");
return names.slice(0, names.length - 1).join(" ");
}
// "Olah"
get lastName() {
let names = this.name.split(" ");
const names = this.name.split(" ");
return names[names.length -1];
}
}
@@ -31,7 +32,7 @@ export class FrontMatter {
this.description = ""; // "A visual overview of neural attention..."
this.authors = []; // Array of Author(s)
this.bibliography = {};
this.bibliography = new Map();
// {
// "gregor2015draw": {
// "title": "DRAW: A recurrent neural network for image generation",
@@ -61,7 +62,7 @@ export class FrontMatter {
//
// Assigned from journal
//
this.journal = {};
// journal: {
// "title": "Distill",
// "full_title": "Distill",
@@ -87,6 +88,34 @@ export class FrontMatter {
}
// Example:
// title: Demo Title Attention and Augmented Recurrent Neural Networks
// published: Jan 10, 2017
// authors:
// - Chris Olah:
// - Shan Carter: http://shancarter.com
// affiliations:
// - Google Brain:
// - Google Brain: http://g.co/brain
mergeFromYMLFrontmatter(data) {
this.title = data.title;
this.publishedDate = new Date(data.published);
this.description = data.description;
const zipped = data.authors.map( (author, index) => [author, data.affiliations[index]]);
this.authors = zipped.map( ([authorEntry, affiliationEntry]) => {
const name = Object.keys(authorEntry)[0];
const author = new Author(name);
if (typeof authorEntry === 'object') {
author.personalURL = authorEntry[name];
}
author.affiliation = Object.keys(affiliationEntry)[0];
if (typeof affiliationEntry === 'object') {
author.affiliationURL = affiliationEntry[author.affiliation]
}
return author;
});
}
//
// Computed Properties
//
@@ -102,6 +131,8 @@ export class FrontMatter {
return this.journal.url + "/" + this.distillPath;
} else if (this.journal.url) {
return this.journal.url;
} else {
return
}
}
@@ -160,23 +191,31 @@ export class FrontMatter {
// 'Olah & Carter',
get concatenatedAuthors() {
if (this.authors.length > 2) {
if (this.authors.length > 2) {
return this.authors[0].lastName + ", et al.";
} else if (this.authors.length === 2) {
return this.authors[0].lastName + " & " + this.authors[1].lastName;
} else if (this.authors.length === 1) {
return this.authors[0].lastName
return this.authors[0].lastName;
}
}
// 'Olah, Chris and Carter, Shan',
get bibtexAuthors() {
return this.authors.map(author => author.lastName + ", " + author.firstName }).join(" and ");
return this.authors.map(author => {
return author.lastName + ", " + author.firstName
}).join(" and ");
}
// 'olah2016attention'
get slug() {
return this.authors.length ? this.authors[0].lastName.toLowerCase() + this.publishedYear + this.title.split(" ")[0].toLowerCase() : "Untitled";
let slug = '';
if (this.authors.length) {
slug += this.authors[0].lastName.toLowerCase();
slug += this.publishedYear;
slug += this.title.split(' ')[0].toLowerCase();
}
return slug || 'Untitled';
}
}
+34 -1
View File
@@ -6,6 +6,10 @@
version "1.0.0"
resolved "https://registry.yarnpkg.com/@comandeer/babel-plugin-banner/-/babel-plugin-banner-1.0.0.tgz#40bcce0bbee084b5b02545a33635d053c248356f"
"@webcomponents/webcomponentsjs@webcomponents/webcomponentsjs":
version "1.0.3"
resolved "https://codeload.github.com/webcomponents/webcomponentsjs/tar.gz/f01672c05cca9ec5839b064d2f5e1da73f01ea10"
abab@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
@@ -728,6 +732,10 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
colors@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
@@ -1084,6 +1092,14 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
fs-extra@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^3.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1202,7 +1218,7 @@ good-listener@^1.2.0:
dependencies:
delegate "^3.1.1"
graceful-fs@^4.1.2:
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@@ -1539,6 +1555,12 @@ json5@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
jsonfile@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
optionalDependencies:
graceful-fs "^4.1.6"
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@@ -2365,6 +2387,13 @@ rollup-plugin-commonjs@^7.0.0:
resolve "^1.1.7"
rollup-pluginutils "^1.5.1"
rollup-plugin-copy@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/rollup-plugin-copy/-/rollup-plugin-copy-0.2.3.tgz#dac1ab81d1f220baeb98e5c4c0108252e1edbb98"
dependencies:
colors "^1.1.2"
fs-extra "^3.0.0"
rollup-plugin-gzip@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-gzip/-/rollup-plugin-gzip-1.2.0.tgz#4b63c2fcfb7b5eefaf5ea187ef2b4496b2d418d0"
@@ -2724,6 +2753,10 @@ uid-number@^0.0.6, uid-number@~0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
universalify@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"