- cca085e60090ca21edf0dee6aa012fc4c949809a start of import/export - f816da146c32f010476872d15b58ec8301b9fdf2 start of changing stuff until I can get a bundle - c92adde147792356ff206107b2311590e8b2c054 first bundle without errors - e652dd2b785e355e0ac33566da7eaaaa19c7c539 Bundling works with ts files - 60fdb2539a757ca2f66258b21adf81246873893f meta info in compilation - 8ccae783cbf65ac186d5669dedd9f945f7608694 new build doesn't cause errors on page load as userscript - 6fa11c42a05572779870f94b7ef4ea8dac373450 work in progress: load userscript in browser and fix bugs - b15c557d483de544a38a28cb78f25139d1d8421f migrated yotsuba templates to plain js the old templates caused some variable be in a wrong scope after decaffeinate, causing them to be unreadable from the old template the old templates caused some variable be in a wrong scope after decaffeinate, causing them to be unreadable from the old template - 9d763e852fde74808ca14d5a8d6be45f51ae2765 update readme - 924eda8268bcfc4f1c0a83062ecd1d0d65bd92aa added more imports, and now the circular dependencies are haunting me - ddd2d23315d801c7deaa28313833e667698aadd3 jsx templates for escaped strings, more bug fixed from circular dependencies - fee484dd447820d908c77b1e9d31235ab95a481c some fixes, clarify jsx - e1d01d02eba5db2f604a5df786c525e95f32a2f9 Unpacked extension more fixes - 97d9090b712d20f7d851c82af84c65060f1a9c6e fixed class on post that caused catalog to appear empty - 96a2c7b4a1e69f5812d1e53b2e4c90f6d8447b02 A child class that's not supposed to run the parents constructor? That needs a workaround in es6 classes. - fc06b4e1b2769550d4c69377b84d3ccacdb2e013 changed jsx to make the tests pass - 7b317b2a0feabe8caa547c76baf0c908b21592f1 revert archive and banners to json
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
/*
|
|
* This file has the code for the jsx to { innerHTML: "safe string" }
|
|
*
|
|
* Usage: import h from this file.
|
|
* Attributes are stringified raw, so the names must be like html text: eg class and not className.
|
|
* Boolean values are stringified as followed: true will mean the attribute is there, false means it will be omitted.
|
|
* Strings bound to attributes and children will be escaped automatically.
|
|
* It returns interface EscapedHtml { innerHTML: "safe string", [isEscaped]: true }
|
|
*
|
|
* For strings that don't have a parent element you can use fragments: <></>.
|
|
* Note that you need to import hFragment, which for some reason isn't auto imported on "add all missing imports"
|
|
*/
|
|
|
|
import { E } from "./globals";
|
|
|
|
/**
|
|
* The symbol indicating that a string is safely escaped.
|
|
* This is a symbol so it can't be faked by a json blob from the internet.
|
|
*/
|
|
export const isEscaped = Symbol('isEscaped');
|
|
|
|
export interface EscapedHtml {
|
|
innerHTML: string,
|
|
[isEscaped]: true,
|
|
}
|
|
|
|
const voidElements = new Set(
|
|
['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr',]
|
|
);
|
|
|
|
export const hFragment = Symbol('hFragment');
|
|
|
|
/** Function that jsx/tsx will be compiled to. */
|
|
export default function h(
|
|
tag: string | typeof hFragment,
|
|
attributes: Record<string, unknown> | null,
|
|
...children: unknown[]
|
|
): EscapedHtml {
|
|
let innerHTML = tag === hFragment ? '' : `<${tag}`;
|
|
|
|
if (attributes) {
|
|
for (const [attribute, value] of Object.entries(attributes)) {
|
|
if (!value && value !== 0) continue;
|
|
innerHTML += ` ${attribute}`;
|
|
if (value === true) continue;
|
|
innerHTML += `="${E(value.toString())}"`;
|
|
}
|
|
}
|
|
if (tag !== hFragment) innerHTML += '>';
|
|
|
|
const isVoid = tag !== hFragment && voidElements.has(tag);
|
|
if (isVoid) {
|
|
if (children.length) throw new TypeError(`${tag} is a void html element and can't have child elements`);
|
|
} else {
|
|
for (const child of children) {
|
|
if (child === null || child === undefined || child === '') continue;
|
|
|
|
if (child instanceof Object && "innerHTML" in child && child[isEscaped]) {
|
|
innerHTML += child.innerHTML;
|
|
continue;
|
|
}
|
|
|
|
innerHTML += E(child.toString());
|
|
}
|
|
}
|
|
|
|
if (!isVoid && tag !== hFragment) innerHTML += `</${tag}>`;
|
|
|
|
return { innerHTML, [isEscaped]: true };
|
|
}
|