Bundle modules together into one

Fixes #26.
This commit is contained in:
Florine W. Dekker 2022-11-20 21:18:46 +01:00
parent 70465ef7bd
commit 9beda27c23
Signed by: FWDekker
GPG Key ID: D3DCFAA8A4560BE0
8 changed files with 77 additions and 139 deletions

View File

@ -14,33 +14,23 @@ module.exports = grunt => {
},
},
focus: {
deploy: {
include: ["css", "storage", "template", "validation"],
dev: {
include: ["css", "ts"],
},
},
watch: {
css: {
files: ["src/main/**/*.css"],
tasks: ["cssmin"],
},
ts: {
files: ["src/main/**/*.ts"],
tasks: ["webpack:dev"],
},
},
webpack: {
storage: {
entry: "./src/main/js/Storage.ts",
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".ts"],
},
output: {
filename: "storage.js",
path: path.resolve(__dirname, "dist/"),
},
mode: "production",
},
template: {
entry: "./src/main/js/Template.ts",
options: {
entry: "./src/main/js/Main.ts",
module: {
rules: [
{
@ -55,49 +45,17 @@ module.exports = grunt => {
},
output: {
filename: "template.js",
path: path.resolve(__dirname, "dist"),
},
mode: "production",
},
validation: {
entry: "./src/main/js/Validation.ts",
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".ts"],
},
output: {
filename: "validation.js",
path: path.resolve(__dirname, "dist/"),
},
},
dev: {
mode: "development",
devtool: "inline-source-map",
},
deploy: {
mode: "production",
},
},
watch: {
css: {
files: ["src/main/**/*.css"],
tasks: ["cssmin"],
},
storage: {
files: ["src/main/js/Storage.ts"],
tasks: ["webpack:storage"],
},
template: {
files: ["src/main/js/Template.ts"],
tasks: ["webpack:template"],
},
validation: {
files: ["src/main/js/Validation.ts"],
tasks: ["webpack:validation"],
},
},
});
grunt.loadNpmTasks("grunt-contrib-clean");
@ -106,8 +64,9 @@ module.exports = grunt => {
grunt.loadNpmTasks("grunt-focus");
grunt.loadNpmTasks("grunt-webpack");
grunt.registerTask("deploy", ["webpack:storage", "webpack:template", "webpack:validation", "cssmin"]);
grunt.registerTask("deploy:server", ["deploy", "focus:deploy"]);
grunt.registerTask("dev", ["clean", "webpack:dev", "cssmin"]);
grunt.registerTask("dev:server", ["dev", "focus:dev"]);
grunt.registerTask("deploy", ["clean", "webpack:deploy", "cssmin"]);
grunt.registerTask("default", ["deploy"]);
grunt.registerTask("default", ["dev"]);
};

View File

@ -4,16 +4,6 @@ The base template for pages on fwdekker.com.
This module contains templating functions (e.g. `nav`, `footer`), CSS libraries, and some common utility methods that
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 can be used stand-alone.
If `template.js` is used, modules should be loaded after `template.js`.
Current available modules are:
* `storage.js` for interfacing with local storage, and
Main module optional.
* `validation.js` for form validation.
Requires main module.
## Development
### Requirements
@ -27,8 +17,10 @@ $> npm ci
### Building
```shell script
# Build the template in `dist/` for deployment
# Build the tool in `dist/` for development
$> npm run dev
# Same as above, but automatically rerun it whenever files are changed
$> npm run dev:server
# Build the tool in `dist/` for deployment
$> npm run deploy
# Run the `deploy` task and automatically rerun it whenever files are changed
$> npm run deploy:server
```

View File

@ -14,14 +14,14 @@
},
"browser": "template.js",
"files": [
"dist/storage.js",
"dist/template.js",
"dist/template.css"
],
"scripts": {
"clean": "grunt clean",
"deploy": "grunt deploy",
"deploy:server": "grunt deploy:server"
"dev": "grunt dev",
"dev:server": "grunt dev:server",
"deploy": "grunt deploy"
},
"dependencies": {
"@picocss/pico": "^1.5.6"

7
src/main/js/Main.ts Normal file
View File

@ -0,0 +1,7 @@
import * as template from "./Template";
import * as storage from "./Storage";
import * as validation from "./Validation";
(window as any).fwdekker = template;
(window as any).fwdekker.storage = storage;
(window as any).fwdekker.validation = validation;

View File

@ -5,7 +5,7 @@ export interface Storage {
/**
* Removes the data from storage.
*/
clear(): void
clear(): void;
/**
* Retrieves an array from storage.
@ -13,7 +13,7 @@ export interface Storage {
* @param name the name of the array to retrieve
* @param def the value to return if no array is stored with the given name
*/
getArray(name: string, def: any[]): any[]
getArray(name: string, def: any[]): any[];
/**
* Stores an array.
@ -22,7 +22,7 @@ export interface Storage {
* @param value the array to store under the given name
* @protected
*/
setArray(name: string, value: any[]): void
setArray(name: string, value: any[]): void;
/**
* Retrieves a boolean from storage.
@ -31,7 +31,7 @@ export interface Storage {
* @param def the value to return if no boolean is stored with the given name
* @protected
*/
getBoolean(name: string, def: boolean): boolean
getBoolean(name: string, def: boolean): boolean;
/**
* Stores a boolean.
@ -40,7 +40,7 @@ export interface Storage {
* @param value the boolean to store under the given name
* @protected
*/
setBoolean(name: string, value: boolean): void
setBoolean(name: string, value: boolean): void;
/**
* Retrieves a number from storage.
@ -49,7 +49,7 @@ export interface Storage {
* @param def the value to return if no number is stored with the given name
* @protected
*/
getNumber(name: string, def: number): number
getNumber(name: string, def: number): number;
/**
* Stores a number.
@ -58,7 +58,7 @@ export interface Storage {
* @param value the number to store under the given name
* @protected
*/
setNumber(name: string, value: number): void
setNumber(name: string, value: number): void;
}
/**
@ -176,9 +176,3 @@ export class MemoryStorage implements Storage {
return this.storage[name] ?? def;
}
}
// Export to `window`
(window as any).fwdekker = (window as any).fwdekker ?? {};
(window as any).fwdekker.storage = {Storage, LocalStorage, MemoryStorage};
export {};

View File

@ -5,7 +5,7 @@
* @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 {
export function stringToHtml(string: string, query: string): HTMLElement | null {
return (new DOMParser()).parseFromString(string, "text/html").body.querySelector(query);
}
@ -16,7 +16,7 @@ function stringToHtml(string: string, query: string): HTMLElement | null {
* @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 | null | undefined, root?: HTMLElement): HTMLElement | null {
export function $(query: string | null | undefined, root?: HTMLElement): HTMLElement | null {
if (query == null) return null;
return root === undefined ? document.querySelector(query) : root.querySelector(query);
}
@ -28,7 +28,7 @@ function $(query: string | null | undefined, root?: HTMLElement): HTMLElement |
* @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> {
export function $a(query: string, root?: HTMLElement): NodeListOf<Element> {
return root === undefined ? document.querySelectorAll(query) : root.querySelectorAll(query);
}
@ -40,7 +40,7 @@ function $a(query: string, root?: HTMLElement): NodeListOf<Element> {
*
* @param fun the function to run
*/
function doAfterLoad(fun: () => void): void {
export function doAfterLoad(fun: () => void): void {
if (document.readyState === "complete") {
fun();
return;
@ -63,7 +63,7 @@ function doAfterLoad(fun: () => void): void {
* @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 {
export function getMetaProperty(name: string): string | null | undefined {
const metaTag = $(`meta[name="${name}"]`);
return metaTag == null ? undefined : metaTag.getAttribute("content");
}
@ -252,8 +252,3 @@ doAfterLoad(() => {
);
}
});
// Export to `window`
(window as any).fwdekker = {$, $a, doAfterLoad, getMetaProperty, stringToHtml};
export {};

View File

@ -1,5 +1,4 @@
if ((window as any).fwdekker == null) throw new Error("Validation module requires main module.");
const {$, $a, doAfterLoad, getMetaProperty} = (window as any).fwdekker;
import {$, $a, doAfterLoad, getMetaProperty} from "./Template";
/**
@ -7,9 +6,13 @@ const {$, $a, doAfterLoad, getMetaProperty} = (window as any).fwdekker;
*
* @param form the form to hide validation information from
*/
function clearFormValidity(form: HTMLFormElement): void {
export function clearFormValidity(form: HTMLFormElement): void {
clearMessageStatus(form);
$a("input", form).forEach((input: HTMLInputElement) => clearInputValidity(input));
$a("input", form).forEach((input: Element) => {
if (!(input instanceof HTMLInputElement)) return;
clearInputValidity(input);
});
}
@ -20,22 +23,21 @@ function clearFormValidity(form: HTMLFormElement): void {
* @param message the message to show in `card`, or `undefined` if `card` should be hidden
* @param type the type of message to show in `card`, or `undefined` if `card` should be hidden
*/
function showMessageType(card: HTMLElement | HTMLFormElement,
message?: string,
type?: "error" | "info" | "success" | "warning"): void {
if (card instanceof HTMLFormElement) {
card = $(`article[data-status-for="${card.id}"]`);
if (card == null) throw new Error("Could not find status card.");
}
export function showMessageType(card: HTMLElement | HTMLFormElement,
message?: string,
type?: "error" | "info" | "success" | "warning"): void {
if (card instanceof HTMLFormElement)
card = $(`article[data-status-for="${card.id}"]`)!;
const output = $("output", card)!;
card.classList.remove("hidden", "error", "info", "success", "warning");
if (message == null || type == null) {
card.classList.add("hidden");
$("output", card).innerText = "";
output.innerText = "";
} else {
card.classList.add(type);
$("output", card).innerText = message;
output.innerText = message;
}
}
@ -44,7 +46,7 @@ function showMessageType(card: HTMLElement | HTMLFormElement,
*
* @param card the card to clear the message from
*/
function clearMessageStatus(card: HTMLElement): void {
export function clearMessageStatus(card: HTMLElement): void {
showMessageType(card);
}
@ -54,7 +56,7 @@ function clearMessageStatus(card: HTMLElement): void {
* @param card the card to show `message` in
* @param message the error message to show in `card`
*/
function showMessageError(card: HTMLElement, message: string): void {
export function showMessageError(card: HTMLElement, message: string): void {
showMessageType(card, message, "error");
}
@ -64,7 +66,7 @@ function showMessageError(card: HTMLElement, message: string): void {
* @param card the card to show `message` in
* @param message the message to show in `card`
*/
function showMessageInfo(card: HTMLElement, message: string): void {
export function showMessageInfo(card: HTMLElement, message: string): void {
showMessageType(card, message, "info");
}
@ -74,7 +76,7 @@ function showMessageInfo(card: HTMLElement, message: string): void {
* @param card the card to show `message` in
* @param message the success message to show in `card`
*/
function showMessageSuccess(card: HTMLElement, message: string): void {
export function showMessageSuccess(card: HTMLElement, message: string): void {
showMessageType(card, message, "success");
}
@ -84,7 +86,7 @@ function showMessageSuccess(card: HTMLElement, message: string): void {
* @param card the card to show `message` in
* @param message the success message to show in `card`
*/
function showMessageWarning(card: HTMLElement, message: string): void {
export function showMessageWarning(card: HTMLElement, message: string): void {
showMessageType(card, message, "warning");
}
@ -94,7 +96,7 @@ function showMessageWarning(card: HTMLElement, message: string): void {
*
* @param input
*/
function clearInputValidity(input: HTMLInputElement): void {
export function clearInputValidity(input: HTMLInputElement): void {
input.classList.remove("valid", "invalid");
input.removeAttribute("aria-invalid");
input.removeAttribute("aria-errormessage");
@ -118,7 +120,7 @@ function clearInputValidity(input: HTMLInputElement): void {
* @param input the input to show as invalid
* @param message the message explaining what is invalid
*/
function showInputInvalid(input: HTMLInputElement, message?: string): void {
export function showInputInvalid(input: HTMLInputElement, message?: string): void {
clearInputValidity(input);
input.classList.add("invalid");
@ -145,7 +147,7 @@ function showInputInvalid(input: HTMLInputElement, message?: string): void {
* @param input the input to show as valid
* @param message the message to show at the input
*/
function showInputValid(input: HTMLInputElement, message?: string): void {
export function showInputValid(input: HTMLInputElement, message?: string): void {
clearInputValidity(input);
input.classList.add("valid");
@ -170,7 +172,9 @@ function showInputValid(input: HTMLInputElement, message?: string): void {
doAfterLoad(() => {
if (getMetaProperty("fwd:validation:load-forms") === undefined) return;
$a(".status-card .close").forEach((close: HTMLElement) => {
$a(".status-card .close").forEach((close: Element) => {
if (!(close instanceof HTMLElement)) return;
close.addEventListener("click", (event: MouseEvent) => {
event.preventDefault();
@ -184,13 +188,3 @@ doAfterLoad(() => {
hint.innerText = hint.dataset["hint"] ?? "";
});
});
// Export to `window`
(window as any).fwdekker = (window as any).fwdekker ?? {};
(window as any).fwdekker.validation = {
clearFormValidity,
clearMessageStatus, showMessageError, showMessageInfo, showMessageSuccess, showMessageWarning,
clearInputValidity, showInputInvalid, showInputValid
};
export {};

View File

@ -95,9 +95,6 @@
<!--suppress HtmlUnknownTarget -->
<script src="../../dist/template.js"></script>
<script src="../../dist/storage.js"></script>
<script src="../../dist/validation.js"></script>
<script>
const {$} = window.fwdekker;