parent
70465ef7bd
commit
9beda27c23
89
Gruntfile.js
89
Gruntfile.js
|
@ -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"]);
|
||||
};
|
||||
|
|
18
README.md
18
README.md
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
|
@ -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 {};
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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,
|
||||
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}"]`);
|
||||
if (card == null) throw new Error("Could not find status card.");
|
||||
}
|
||||
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 {};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue