Rewrite `template.js` to TypeScript
This commit is contained in:
parent
723974d103
commit
bf4aa0289b
|
@ -40,7 +40,7 @@ module.exports = grunt => {
|
|||
mode: "production",
|
||||
},
|
||||
template: {
|
||||
entry: "./src/main/js/template.js",
|
||||
entry: "./src/main/js/Template.ts",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
|
|
@ -6,7 +6,8 @@ are used on nearly all pages anyway.
|
|||
|
||||
The main functionality is provided in `template.js` and `template.css`.
|
||||
There also exist optional modules for easily reusing common code.
|
||||
Modules should be loaded after `template.js` and `template.css`.
|
||||
Modules can be used stand-alone.
|
||||
If `template.js` is used, modules should be loaded after `template.js`.
|
||||
Currently, the only module is `storage.js` for interfacing with local storage.
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"browser": "template.js",
|
||||
"files": [
|
||||
"dist/storage.js",
|
||||
"dist/template.js",
|
||||
"dist/template.css"
|
||||
],
|
||||
|
|
|
@ -178,9 +178,6 @@ export class MemoryStorage implements Storage {
|
|||
}
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
if (typeof window.fwdekker === "undefined")
|
||||
// @ts-ignore
|
||||
window.fwdekker = {};
|
||||
// @ts-ignore
|
||||
window.fwdekker.storage = {Storage, LocalStorage, MemoryStorage};
|
||||
// Export to `window`
|
||||
(window as any).fwdekker = (window as any).fwdekker ?? {};
|
||||
(window as any).fwdekker.storage = {Storage, LocalStorage, MemoryStorage};
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
/**
|
||||
* Converts the given string to an HTML element.
|
||||
*
|
||||
* @param string the string to convert to an HTML element
|
||||
* @param query the type of element to return
|
||||
* @returns the HTML element described by the given string, or `null` if `query` did not match any element
|
||||
*/
|
||||
function stringToHtml(string: string, query: string): HTMLElement | null {
|
||||
return (new DOMParser()).parseFromString(string, "text/html").body.querySelector(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `root.querySelector(query)`.
|
||||
*
|
||||
* @param query the query string
|
||||
* @param root the element to start searching in, or `undefined` if searching should start in `document`
|
||||
* @returns the element identified by `query` in `root`, or `null` if that element could not be found
|
||||
*/
|
||||
function $(query: string, root?: HTMLElement): HTMLElement | null {
|
||||
return root === undefined ? document.querySelector(query) : root.querySelector(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `root.querySelectorAll(query)`.
|
||||
*
|
||||
* @param query the query string
|
||||
* @param root the element to start searching in, or `undefined` if searching should start in `document`
|
||||
* @returns the elements identified by `query` in `root`
|
||||
*/
|
||||
function $a(query: string, root?: HTMLElement): NodeListOf<Element> {
|
||||
return root === undefined ? document.querySelectorAll(query) : root.querySelectorAll(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given function once the page is loaded.
|
||||
*
|
||||
* This function can be used multiple times. It does not overwrite existing callbacks for the page load event. If the
|
||||
* page has already loaded when this function is invoked, `fun` is invoked immediately inside this function.
|
||||
*
|
||||
* @param fun the function to run
|
||||
*/
|
||||
function doAfterLoad(fun: () => void): void {
|
||||
if (document.readyState === "complete") {
|
||||
fun();
|
||||
return;
|
||||
}
|
||||
|
||||
const oldOnLoad = onload || (() => {
|
||||
});
|
||||
|
||||
onload = (() => {
|
||||
// @ts-ignore Works fine
|
||||
oldOnLoad();
|
||||
fun();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `content` attribute of the `<meta>` tag identified by `name`.
|
||||
*
|
||||
* @param name the name of the meta tag of which to return the `content`
|
||||
* @return the `content` attribute of the `<meta>` tag identified by `name`, or `null` if the meta tag has no content,
|
||||
* or `undefined` if the meta tag does not exist
|
||||
*/
|
||||
function getMetaProperty(name: string): string | null | undefined {
|
||||
const metaTag = $(`meta[name="${name}"]`);
|
||||
return metaTag == null ? undefined : metaTag.getAttribute("content");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a navigation element for navigating through the website.
|
||||
*
|
||||
* Fetches entries asynchronously from the website's API.
|
||||
*
|
||||
* @param highlightPath the path to highlight together with its parents, or `undefined` if no element should be
|
||||
* highlighted
|
||||
* @param cb the callback to execute on the fetched entries, to prevent the need to re-fetch elsewhere, or `undefined`
|
||||
* if no callback should be invoked
|
||||
* @returns a base navigation element that will eventually be filled with contents
|
||||
*/
|
||||
function nav(highlightPath?: string, cb?: (json: any) => void): HTMLElement {
|
||||
const base = stringToHtml(
|
||||
`<ul><li><a href="https://fwdekker.com/">` +
|
||||
`<div class="logo"><img class="logo" src="https://fwdekker.com/favicon.png" alt="FWDekker" /></div>` +
|
||||
`<b>FWDekker</b>` +
|
||||
`</a></li></ul>`,
|
||||
"ul"
|
||||
)!;
|
||||
|
||||
fetch("https://fwdekker.com/api/nav/")
|
||||
.then(it => it.json())
|
||||
.then(json => {
|
||||
if (cb !== undefined)
|
||||
cb(json);
|
||||
|
||||
json.entries.forEach(
|
||||
(entry: any) =>
|
||||
base.appendChild(stringToHtml(unpackEntry(entry, "/", highlightPath), "li")!)
|
||||
);
|
||||
})
|
||||
.catch(error => console.error("Failed to fetch navigation elements", error));
|
||||
|
||||
const nav = stringToHtml(
|
||||
`<nav class="fwd-nav">` +
|
||||
`<input id="nav-hamburger-checkbox" type="checkbox" hidden />` +
|
||||
`<label id="nav-hamburger-label" for="nav-hamburger-checkbox">☰</label>` +
|
||||
`</nav>`,
|
||||
"nav"
|
||||
)!;
|
||||
nav.appendChild(base);
|
||||
return nav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks a navigation entry returned from the navigation API into an HTML element.
|
||||
*
|
||||
* @param entry the entry to unpack
|
||||
* @param path the current path traversed, found by joining the names of the entries with `/`s; always starts and ends
|
||||
* with a `/`
|
||||
* @param highlightPath the path to highlight together with its parents, or `undefined` if no path should be highlighted
|
||||
* @returns the navigation list entry as HTML, described by its children
|
||||
*/
|
||||
function unpackEntry(entry: any, path: string = "/", highlightPath?: string): string {
|
||||
const shouldHighlight = highlightPath?.startsWith(`${path + entry.name}/`) ?? false;
|
||||
const isExternalLink = !(/^https:\/\/.*fwdekker.com/i.test(entry.link)) && entry.link !== "#";
|
||||
|
||||
if (entry.entries.length === 0)
|
||||
return "" +
|
||||
`<li ${shouldHighlight ? "class=\"currentPage\"" : ""}>` +
|
||||
`<a href="${entry.link}" ${isExternalLink ? "target=\"_blank\"" : ""}>${entry.name}</a>` +
|
||||
`</li>`;
|
||||
|
||||
const depth = path.split("/").length - 2; // -1 because count parts, then another -1 because of leading `/`
|
||||
const arrow = depth === 0 ? "▾" : "▸";
|
||||
|
||||
return "" +
|
||||
`<li class="${shouldHighlight ? "currentPage" : ""}">` +
|
||||
`<a href="${entry.link}">${entry.name} ${arrow}</a>` +
|
||||
`<ul>${entry.entries.map((it: any) => unpackEntry(it, `${path + entry.name}/`, highlightPath)).join("")}</ul>` +
|
||||
`</li>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a footer element with the given data.
|
||||
*
|
||||
* Setting an argument to `undefined` or not giving that argument will cause the default value to be used. Setting an
|
||||
* argument to `null` will result in a footer without the corresponding element.
|
||||
*
|
||||
* @param author the author
|
||||
* @param authorURL the URL to link the author's name to
|
||||
* @param license the type of license
|
||||
* @param licenseURL the URL to the license file
|
||||
* @param vcs the type of version control
|
||||
* @param vcsURL the URL to the repository
|
||||
* @param version the page version
|
||||
* @param privacyPolicyURL the URL to the privacy policy
|
||||
* @returns a footer element
|
||||
*/
|
||||
function footer(
|
||||
{
|
||||
author = undefined,
|
||||
authorURL = undefined,
|
||||
license = undefined,
|
||||
licenseURL = undefined,
|
||||
vcs = undefined,
|
||||
vcsURL = undefined,
|
||||
version = undefined,
|
||||
privacyPolicyURL = undefined
|
||||
}: {
|
||||
author: string | null | undefined,
|
||||
authorURL: string | null | undefined,
|
||||
license: string | null | undefined,
|
||||
licenseURL: string | null | undefined,
|
||||
vcs: string | null | undefined,
|
||||
vcsURL: string | null | undefined,
|
||||
version: string | null | undefined,
|
||||
privacyPolicyURL: string | null | undefined
|
||||
}
|
||||
): HTMLElement {
|
||||
if (author === undefined) author = "Florine W. Dekker";
|
||||
if (authorURL === undefined) authorURL = "https://fwdekker.com/";
|
||||
if (license === undefined) license = "MIT";
|
||||
if (licenseURL === undefined && vcsURL !== undefined) licenseURL = `${vcsURL}src/branch/master/LICENSE`;
|
||||
if (vcs === undefined && vcsURL !== undefined) vcs = "git";
|
||||
if (privacyPolicyURL === undefined) privacyPolicyURL = "https://fwdekker.com/privacy/";
|
||||
|
||||
return stringToHtml(
|
||||
`<footer class="fwd-footer"><hr /><small>` +
|
||||
footerLink("Made by ", author, authorURL, ". ") +
|
||||
footerLink("Licensed ", license, licenseURL, ". ") +
|
||||
footerLink("Source and support on ", vcs, vcsURL, ". ") +
|
||||
footerLink("Read the ", privacyPolicyURL && "privacy policy", privacyPolicyURL, ". ") +
|
||||
`</small><div id="fwd-footer-version"><small>${version || ""}</small></div></footer>`,
|
||||
"footer"
|
||||
)!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a link that is used in footers.
|
||||
*
|
||||
* @param prefix the text to display before the text if the text is not `null` or `undefined`
|
||||
* @param text the text to display, or `null` or `undefined` if the returned element should be the empty string
|
||||
* @param url the URL to link the text to, or `null` or `undefined` if the text should not be a link
|
||||
* @param suffix the text to display after the text if the text is not `null` or `undefined`
|
||||
* @returns a footer link element
|
||||
*/
|
||||
function footerLink(prefix: string, text: string | null | undefined, url: string | null | undefined,
|
||||
suffix: string): string {
|
||||
if (text == null) return "";
|
||||
|
||||
return `${prefix}${url != null ? `<a href="${url}">${text}</a>` : text}${suffix}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the functions `nav` and `footer` after the page has loaded using properties defined in the meta tags.
|
||||
*
|
||||
* Meta tags are read as interpreted as `<meta name="fwd:<function>:<property>" content="<value>" />` from the
|
||||
* document's head. Given a `function` of `nav` or `footer`, if the `value` of `fwd:<function>:target` is the ID of an
|
||||
* element in the page, that element is replaced by the output of `function`. The `function` is invoked with parameters
|
||||
* also read from meta elements, where each `property` is the same as the name of the parameter of that function, except
|
||||
* that instead of camelcase words are separated by dashes. For example, `vcsURL` becomes `vcs-url`.
|
||||
*
|
||||
* If a meta tag is missing, its value is considered `undefined`. If a meta tag exists but has no `content` attribute,
|
||||
* its value is considered `null`. Otherwise, the value is the string contents of the `content` attribute. If `null` is
|
||||
* not a valid value as a parameter for that function, its value is considered `undefined`.
|
||||
*/
|
||||
doAfterLoad(() => {
|
||||
const navTargetQuery = getMetaProperty("fwd:nav:target");
|
||||
if (navTargetQuery != null) {
|
||||
const navTarget = $(navTargetQuery);
|
||||
navTarget?.parentElement?.replaceChild(
|
||||
nav(getMetaProperty("fwd:nav:highlight-path") ?? undefined),
|
||||
navTarget
|
||||
);
|
||||
}
|
||||
|
||||
const footerTargetQuery = getMetaProperty("fwd:footer:target");
|
||||
if (footerTargetQuery != null) {
|
||||
const footerTarget = $(footerTargetQuery);
|
||||
footerTarget?.parentElement?.replaceChild(
|
||||
footer({
|
||||
author: getMetaProperty("fwd:footer:author"),
|
||||
authorURL: getMetaProperty("fwd:footer:author-url"),
|
||||
license: getMetaProperty("fwd:footer:license"),
|
||||
licenseURL: getMetaProperty("fwd:footer:license-url"),
|
||||
vcs: getMetaProperty("fwd:footer:vcs"),
|
||||
vcsURL: getMetaProperty("fwd:footer:vcs-url"),
|
||||
version: getMetaProperty("fwd:footer:version"),
|
||||
privacyPolicyURL: getMetaProperty("fwd:footer:privacy-policy-url"),
|
||||
}),
|
||||
footerTarget
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Export to `window`
|
||||
(window as any).fwdekker = {stringToHtml, $, $a, doAfterLoad};
|
|
@ -1,228 +0,0 @@
|
|||
/**
|
||||
* Converts the given string to an HTML element.
|
||||
*
|
||||
* @param string the string to convert to an HTML element
|
||||
* @param query the type of element to return
|
||||
* @returns {HTMLElement} the HTML element described by the given string
|
||||
*/
|
||||
const stringToHtml = function(string, query) {
|
||||
return (new DOMParser()).parseFromString(string, "text/html").body.querySelector(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `root.querySelector(query)`.
|
||||
*
|
||||
* @param query {string} the query string
|
||||
* @param root {HTMLElement} the element to start searching in, or `undefined` if searching should start in `document`
|
||||
* @returns {HTMLElement} the element identified by `query` in `root`
|
||||
*/
|
||||
const $ = (query, root) => root === undefined ? document.querySelector(query) : root.querySelector(query);
|
||||
|
||||
/**
|
||||
* Alias for `root.querySelectorAll(query)`.
|
||||
*
|
||||
* @param query {string} the query string
|
||||
* @param root {HTMLElement} the element to start searching in, or `undefined` if searching should start in `document`
|
||||
* @returns {NodeListOf<HTMLElement>} the elements identified by `query` in `root`
|
||||
*/
|
||||
const $a = (query, root) => root === undefined ? document.querySelectorAll(query) : root.querySelectorAll(query);
|
||||
|
||||
/**
|
||||
* Runs the given function once the page is loaded.
|
||||
*
|
||||
* This function can be used multiple times. It does not overwrite existing callbacks for the page load event. If the
|
||||
* page has already loaded when this function is invoked, `fun` is invoked immediately inside this function.
|
||||
*
|
||||
* @param fun {function(...*): *} the function to run
|
||||
*/
|
||||
const doAfterLoad = function(fun) {
|
||||
if (document.readyState === "complete") {
|
||||
fun();
|
||||
return;
|
||||
}
|
||||
|
||||
const oldOnLoad = onload || (() => {
|
||||
});
|
||||
|
||||
onload = (() => {
|
||||
oldOnLoad();
|
||||
fun();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a navigation element for navigating through the website.
|
||||
*
|
||||
* Fetches entries asynchronously from the website's API.
|
||||
*
|
||||
* @param [highlightPath] {String} the path to highlight together with its parents
|
||||
* @param [cb] {Function} the callback to execute on the fetched entries, to prevent the need to re-fetch elsewhere
|
||||
* @returns {HTMLElement} a base navigation element that will eventually be filled with contents
|
||||
*/
|
||||
const nav = function(highlightPath = "", cb = undefined) {
|
||||
const base = stringToHtml(
|
||||
`<ul><li><a href="https://fwdekker.com/">` +
|
||||
`<div class="logo"><img class="logo" src="https://fwdekker.com/favicon.png" alt="FWDekker" /></div>` +
|
||||
`<b>FWDekker</b>` +
|
||||
`</a></li></ul>`,
|
||||
"ul"
|
||||
);
|
||||
|
||||
fetch("https://fwdekker.com/api/nav/")
|
||||
.then(it => it.json())
|
||||
.then(json => {
|
||||
if (cb !== undefined) cb(json);
|
||||
|
||||
json.entries.forEach(entry => base.appendChild(stringToHtml(unpackEntry(entry, "/", highlightPath), "li")));
|
||||
})
|
||||
.catch(e => {
|
||||
console.error("Failed to fetch navigation elements", e);
|
||||
return [];
|
||||
});
|
||||
|
||||
const nav = stringToHtml(
|
||||
`<nav class="fwd-nav">` +
|
||||
`<input id="nav-hamburger-checkbox" type="checkbox" hidden />` +
|
||||
`<label id="nav-hamburger-label" for="nav-hamburger-checkbox">☰</label>` +
|
||||
`</nav>`,
|
||||
"nav"
|
||||
);
|
||||
nav.appendChild(base);
|
||||
return nav;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unpacks a navigation entry returned from the navigation API into an HTML element.
|
||||
*
|
||||
* @param entry {Object} the entry to unpack
|
||||
* @param [path] {number} the current path traversed, found by joining the names of the entries with `/`s; always starts
|
||||
* and ends with a `/`
|
||||
* @param [highlightPath] {String} the path to highlight together with its parents
|
||||
* @returns {string} the navigation list entry as HTML, described by its children
|
||||
*/
|
||||
const unpackEntry = function(entry, path = "/", highlightPath = "") {
|
||||
const shouldHighlight = highlightPath.startsWith(`${path + entry.name}/`);
|
||||
const isExternalLink = !(/^https:\/\/.*fwdekker.com/i.test(entry.link)) && entry.link !== "#";
|
||||
|
||||
if (entry.entries.length === 0)
|
||||
return "" +
|
||||
`<li ${shouldHighlight ? "class=\"currentPage\"" : ""}>` +
|
||||
`<a href="${entry.link}" ${isExternalLink ? "target=\"_blank\"" : ""}>${entry.name}</a>` +
|
||||
`</li>`;
|
||||
|
||||
const depth = path.split("/").length - 2; // -1 because count parts, then another -1 because of leading `/`
|
||||
const arrow = depth === 0 ? "▾" : "▸";
|
||||
|
||||
return "" +
|
||||
`<li class="${shouldHighlight ? "currentPage" : ""}">` +
|
||||
`<a href="${entry.link}">${entry.name} ${arrow}</a>` +
|
||||
`<ul>${entry.entries.map(it => unpackEntry(it, `${path + entry.name}/`, highlightPath)).join("")}</ul>` +
|
||||
`</li>`;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a footer element with the given data.
|
||||
*
|
||||
* Setting an argument to `undefined` or not giving that argument will cause the default value to be used. Setting an
|
||||
* argument to `null` will result in a footer without the corresponding element.
|
||||
*
|
||||
* @param [author] {string|null|undefined} the author
|
||||
* @param [authorURL] {string|null|undefined} the URL to link the author's name to
|
||||
* @param [license] {string|null|undefined} the type of license
|
||||
* @param [licenseURL] {string|null|undefined} the URL to the license file
|
||||
* @param [vcs] {string|null|undefined} the type of version control
|
||||
* @param [vcsURL] {string|null|undefined} the URL to the repository
|
||||
* @param [version] {string|null|undefined} the page version
|
||||
* @param [privacyPolicyURL] {string|null|undefined} the URL to the privacy policy
|
||||
* @returns {HTMLElement} a footer element
|
||||
*/
|
||||
const footer = function(
|
||||
{
|
||||
author = undefined,
|
||||
authorURL = undefined,
|
||||
license = undefined,
|
||||
licenseURL = undefined,
|
||||
vcs = undefined,
|
||||
vcsURL = undefined,
|
||||
version = undefined,
|
||||
privacyPolicyURL = undefined
|
||||
}) {
|
||||
if (author === undefined) author = "Florine W. Dekker";
|
||||
if (authorURL === undefined) authorURL = "https://fwdekker.com/";
|
||||
if (license === undefined) license = "MIT";
|
||||
if (licenseURL === undefined && vcsURL !== undefined) licenseURL = `${vcsURL}src/branch/master/LICENSE`;
|
||||
if (vcs === undefined && vcsURL !== undefined) vcs = "git";
|
||||
if (privacyPolicyURL === undefined) privacyPolicyURL = "https://fwdekker.com/privacy/";
|
||||
|
||||
return stringToHtml(
|
||||
`<footer class="fwd-footer"><hr /><small>` +
|
||||
footerLink("Made by ", author, authorURL, ". ") +
|
||||
footerLink("Licensed ", license, licenseURL, ". ") +
|
||||
footerLink("Source and support on ", vcs, vcsURL, ". ") +
|
||||
footerLink("Read the ", privacyPolicyURL && "privacy policy", privacyPolicyURL, ". ") +
|
||||
`</small><div id="fwd-footer-version"><small>${version || ""}</small></div></footer>`,
|
||||
"footer");
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a link that is used in footers.
|
||||
*
|
||||
* @param prefix {string} the text to display before the text if the text is not undefined
|
||||
* @param text {string|null} the text to display, or `null` if the returned element should be empty
|
||||
* @param url {string|null} the URL to link the text to, or `null` if the text should not be a link
|
||||
* @param suffix {string} the text to display after the text if the text is not undefined
|
||||
* @returns {string} a footer link element
|
||||
*/
|
||||
const footerLink = function(prefix, text, url, suffix) {
|
||||
if (text === null) return "";
|
||||
|
||||
return `${prefix}${url !== null ? `<a href="${url}">${text}</a>` : text}${suffix}`;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Runs the functions `nav` and `footer` after the page has loaded using properties defined in the meta tags.
|
||||
*
|
||||
* Meta tags are read as interpreted as `<meta name="fwd:<function>:<property>" content="<value>" />` from the
|
||||
* document's head. Given a `function` of `nav` or `footer`, if the `value` of `fwd:<function>:target` is the ID of an
|
||||
* element in the page, that element is replaced by the output of `function`. The `function` is invoked with parameters
|
||||
* also read from meta elements, where each `property` is the same as the name of the parameter of that function, except
|
||||
* that instead of camelcase words are separated by dashes. For example, `vcsURL` becomes `vcs-url`.
|
||||
*/
|
||||
doAfterLoad(() => {
|
||||
const getMetaProperty = (name) => {
|
||||
const element = $(`meta[name="${name}"]`);
|
||||
return element === null ? undefined : element.getAttribute("content");
|
||||
};
|
||||
|
||||
const navTarget = $(getMetaProperty("fwd:nav:target"));
|
||||
if (navTarget !== null) {
|
||||
navTarget.parentElement.replaceChild(
|
||||
nav(getMetaProperty("fwd:nav:highlight-path")),
|
||||
navTarget
|
||||
);
|
||||
}
|
||||
|
||||
const footerTarget = $(getMetaProperty("fwd:footer:target"));
|
||||
if (footerTarget !== null) {
|
||||
footerTarget.parentElement.replaceChild(
|
||||
footer({
|
||||
author: getMetaProperty("fwd:footer:author"),
|
||||
authorURL: getMetaProperty("fwd:footer:author-url"),
|
||||
license: getMetaProperty("fwd:footer:license"),
|
||||
licenseURL: getMetaProperty("fwd:footer:license-url"),
|
||||
vcs: getMetaProperty("fwd:footer:vcs"),
|
||||
vcsURL: getMetaProperty("fwd:footer:vcs-url"),
|
||||
version: getMetaProperty("fwd:footer:version"),
|
||||
privacyPolicyURL: getMetaProperty("fwd:footer:privacy-policy-url"),
|
||||
}),
|
||||
footerTarget
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Export to namespace
|
||||
window.fwdekker = {stringToHtml, $, $a, doAfterLoad};
|
|
@ -92,7 +92,7 @@
|
|||
<script src="../../dist/storage.js"></script>
|
||||
|
||||
<script>
|
||||
const storage = new fwdekker.storage.MemoryStorage();
|
||||
const storage = new window.fwdekker.storage.MemoryStorage();
|
||||
storage.setNumber("test-key", 11);
|
||||
|
||||
console.log("Expected: 11. Actual: " + storage.getNumber("test-key", 0) + ".");
|
||||
|
|
Loading…
Reference in New Issue