Initial commit

This commit is contained in:
2025-09-06 17:22:25 -04:00
commit dc96e8570c
27 changed files with 2248 additions and 0 deletions

264
src/fluent-dom-esm.ts Normal file
View File

@@ -0,0 +1,264 @@
/**
* fluent-dom-esm v1.1.0
*
* Fluent DOM Manipulation, adapted to ESM and cranked up to v1.1(.0).
*
* https://git.itsericwoodward.com/eric/fluent-dom-esm
*
* v1.1.0 Copyright (c) 2025 Eric Woodward
* Original copyright (c) 2009 Tommy Montgomery (https://glacius.tmont.com/articles/fluent-dom-manipulation-in-javascript)
*
* Released under the WTFPL (Do What the Fuck You Want to Public License)
*
* @author Eric Woodward (v1.1.0 update)
* @author Tommy Montgomery (original)
* @license http://sam.zoy.org/wtfpl/
*/
import type { FluentDomObject } from "./fluent-dom-esm.types";
import { version } from "../package.json";
import {
isFluentDomObject,
isHTMLElement,
isNumber,
isString,
} from "./fluent-dom-esm.type-guards";
/**
* IIFE that creates the FluentDomObject as default export
*/
export default (function () {
/**
* Wraps provided element in a FluentDomObject which is then returned
*/
const FluentDom = function (node: HTMLElement) {
return new (FluentDomInternal as any)(node);
};
/**
* Creates a new HTML element which is wrapped in a FluentDomObject and returned
*/
FluentDom.create = FluentDom.c = function (tagName: string) {
const f = new (FluentDomInternal as any)();
f.create(tagName);
return f;
};
/**
* The internal representation of the FluentDomObject
*/
const FluentDomInternal = function (
this: FluentDomObject,
node?: HTMLElement,
) {
let root = node || null;
// adds several new features
this.fluentDom = version;
/**
* Gets or sets the named attribute on the wrapped HTMLElement
*/
this.a = this.attr = function (name, value) {
if (!root || (value && !root.setAttribute)) {
throw new Error("Cannot set an attribute on a non-element");
}
if (!value) return root.getAttribute(name);
root.setAttribute(name, value);
return this;
};
/**
* Appends value to wrapped HTMLElement
*/
this.app = this.append = function (value) {
if (!root || !root?.appendChild) {
throw new Error("Cannot append to a non-element");
}
const type = typeof value;
if (type === "object") {
if (isFluentDomObject(value)) {
const domVal = value.toDom();
if (domVal !== null) root.appendChild(domVal);
} else if (isHTMLElement(value)) {
root.appendChild(value);
} else {
throw new Error(
"Invalid argument: not an HTMLElement or FluentDom object",
);
}
} else if (isNumber(value) || isString(value)) {
root.appendChild(document.createTextNode(`${value}`));
} else {
throw new Error(
`Invalid argument: not a valid type (${typeof value})`,
);
}
return this;
};
/**
* Creates a new wrapped HTMLElement of the indicated tag
*/
this.c = this.create = function (tagName) {
root = document.createElement(tagName);
return this;
};
/**
* Gets or sets the "class" attribute on the wrapped HTMLElement
*/
this.className = this.cls = function (value) {
return this.attr("class", value);
};
/**
* Sets the wrapped HTMLElement to null
*/
this.clear = function () {
root = null;
return this;
};
/**
* Gets or sets the "href" attribute on the wrapped HTMLElement
*/
this.h = this.href = function (link) {
return this.attr("href", link);
};
/**
* Gets or sets the wrapped HTMLElement's "innerHTML" property
*/
this.html = function (content) {
if (!root) {
throw new Error(
"Cannot get or set innerHTML for a non-element",
);
}
if (!content) return root.innerHTML;
root.innerHTML = content;
return this;
};
/**
* Gets or sets the "id" attribute on the wrapped HTMLElement
*/
this.id = function (value) {
return this.attr("id", value);
};
/**
* Passes props to the "addEventListener" function on the wrapped HTMLElement
*/
this.l = this.listen = function (...props) {
if (!root || !root.addEventListener) {
throw new Error("Cannot addEventListener to a non-element");
}
root.addEventListener(...props);
return this;
};
/**
* Gets or sets the wrapped HTMLElement's "outerHTML" property
*/
this.ohtml = function (content) {
if (!root) {
throw new Error(
"Cannot get or set outerHTML for a non-element",
);
}
if (!content) return root.outerHTML;
root.outerHTML = content;
return this;
};
/**
* Gets or sets a one or more style attributes on the wrapped HTMLElement
*/
this.s = this.style = function (prop, value) {
if (!root) {
throw new Error("Cannot get or set style for a non-element");
}
if (typeof prop === "undefined") return root.style;
if (typeof value !== "undefined") {
root.style[prop as any] = value;
return this;
}
if (typeof prop === "string") return root.style[prop as any];
if (typeof prop !== "object") {
throw new Error(
`Invalid argument: "prop" must be string or object (found ${typeof prop})`,
);
}
Object.keys(prop).forEach((key) => {
(root as HTMLElement).style[key as any] = prop[key as any];
});
return this;
};
/**
* Gets or sets the wrapped HTMLElement's "innerText" property
*/
this.t = this.text = function (text) {
if (!root) {
throw new Error(
"Cannot get or set innerText for a non-element",
);
}
if (typeof text === "undefined") return root.innerText;
return this.append(text);
};
/**
* Gets or sets the "title" attribute on the wrapped HTMLElement
*/
this.title = function (value) {
if (!root) {
throw new Error(
"Cannot get or set outerHTML for a non-element",
);
}
return this.attr("title", value);
};
/**
* Gets the wrapped HTMLElement itself
*/
this.toDom = function () {
return root;
};
/**
* Passes props to the "removeEventListener" function on the wrapped HTMLElement
*/
this.unlisten = function (...props) {
if (!root || !root.removeEventListener) {
throw new Error("Cannot removeEventListener on a non-element");
}
root.removeEventListener(...props);
return this;
};
};
return FluentDom;
})();