function $e(t='div',p={},c=[]){
let el=document.createElement(t);
Object.assign(el,p);
el.append(...c);
return el;
}
var $t=document.createTextNode.bind(document);
That's 173 bytes not minified, might be useful for someone.Interestingly, the function names are exactly the same - I guess people think similarly :-)
It looks like append() also accepts strings directly. This eliminates the need for $T, which makes things even nicer.
The small bytes also mean that for simple sites I can just copy paste it before transitioning to a real setup.
You’re not wrong about clarity; it wouldn’t hurt here at all, but it wouldn’t hinder without, so I imagine it’s to reduce cognitive load and make it abundantly clear the function is logicless glue.
// data driven HTMLElement creation
var $element = function(type, p={}) {
let h, elem = document.createElement(type);
if (!p || (typeof(p) !== "object")) {
elem.innerHTML = p || '';
return(elem);
}
h = p.attributes; delete p.attributes; if (h) for (let e of Object.entries(h)) { elem.setAttribute(e[0],e[1]) }
h = p.classList; delete p.classList; if (h) for (let c of h) { elem.classList.add(c) }
h = p.dataset; delete p.dataset; if (h) Object.assign(elem.dataset, h);
h = p.style; delete p.style; if (h) Object.assign(elem.style, h);
h = p.innerHTML; delete p.innerHTML; if (h) elem.innerHTML = h;
h = p.children; delete p.children; if (h) for (let ch of h) { if (ch) elem.appendChild(ch) }
h = p.parentNode; delete p.parentNode; if (h) h.appendChild(elem);
h = p.event; delete p.event; if (h) for (let e of Object.entries(h)) { elem.addEventListener(e[0],e[1]) }
return(Object.assign(elem, p));
};This mindset right here is exactly why XSS is still an issue.
If you pull user generated content and put it in the DOM like this, you will open your users to XSS from other users. Basing your personal use DOM APIs on setting `el.innerHTML` will lead to a slip-up. Use `textContent` by default.
I don't think it says anything about you, it's a very easy mistake to make. But it should say something to you, which is to stay vigilant and to try very hard to not dismiss security concerns without giving them some thought.
And of course always assume code will be misused if you let it, by others who don't know what you're going for and by yourself when you're trying to make a deadline. So always design your interfaces to be secure by default. Obviously easier said than done...
Dynamically setting text is very common. While dynamically setting innerHTML is a rare and dangerous operation which should be explicit in the code. The alternative syntax also supported by this function $element("span", { innerHTML: html }) is much better.
You protect against someone else abusing it on other users.
This can be accomplished non-destructively with destructuring.
const {
attributes,
classList,
style,
...rest
} = p
// elem = ...consume attributes, classList, style...
return Object.assign(elem, rest)https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/...
https://preactjs.com/guide/v10/getting-started#no-build-tool...
I personally use preact over react because it's tiny - 3kb for the entire library.
> Preact is packaged to be used directly in the browser, and doesn't require any build or tools
I suppose I could rephrase my question to something like "What is the point of this library?". Every other page on that site that includes examples uses JSX... which means there needs to be a build step.
I guess if someone really just wants to include a 3rd party library to programatically create elements, but get none of the benefits of using them this would be great! Then again there is like 3 examples in this thread of tiny functions (< 10 LoC) that appear to do the same thing.
I guess 3.5kb is about 10x smaller than React + React DOM, but 35kb isn't exactly breaking the bank either. I can't tell specifically by glancing over their examples, but I also suspect feature parity is not quite there. Specifically, I develop with Typescript so being able to type hint `React.ChangeEvent<HTMLInputElement>` etc. is sometimes necessary. It's not clear if Preact exposes a sufficient API. Maybe you know?
It's just a lightweight, no-build-steps-required library that's similar to React. If you already like using React there's nothing much compelling to make you switch.
I like using it with HTM for a nice alternative to JSX which doesn't need any build steps.
I can't speak on its interaction with TypeScript, I've only used this for simple pages where I want to add some interactivity without involving the rest of the nightmarish JS ecosystem.
<esc>vi`:edit-indirect-region<ret>:html-mode
And edit the string contents as HTML.See “tagged templates” here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
For event handlers, only the event name is in the string. The handler function is passed directly in and we add it to elements with addEventListener().
The only "magic" is that we wrap the user's handler call it with the host component as the `this` value so that you don't have to create closures like in Reach. You can just do:
class MyElement extends LitElement {
render() {
return html`<button @click=${this._onClick}`>Click Ma</button>
}
_onClick(e) {
console.log('this is', this);
}
}When will we ever get that jQuery’s thing wasn’t only cross-browser compatibility. It’s that the DOM’s native API is terrible and jQuery is a much terser, powerful, chainable alternative.
* getNodesByType - allows me to get things like attributes, text, and comments directly
* getAncestor - allows me to get a specified element somewhere between a target element and the document.documentElement
I wonder how many XSS vulns this decision has caused in the wild.
You can grep for {{{ without false positives matching {{. Conversely, it's harder to find places where == was used when === should have been used (although I'll concede it's not much harder). In general I'd prefer to go the extra mile to be unsafe than accidentally miss something out.
You shouldn't have to squint at your templating code to see if there's an XSS vector or not, or defensively/neurotically grep for "{{{" just in case you didn't trust your team to squint sufficiently.
For comparison, here's JSX: <div dangerouslySetInnerHTML={{__html: username}} />.
vs. Mustache: {{{username}}} in a file of 1000 other { and } glyphs.
Mustache's hey-dey is long over thankfully.
I've never seen JSX before (I haven't learned anything new in front-end later than ES5). In your example, it looks more like an attribute than an inner tag, the former of which I'd almost always escape. Is that how you set inner HTML as well?
// create an element with 'tag'
const elem = document.createElement(tag)
// copy properties into the new element one at a time
for (const k in props) {
elem[k] = props[k]
}
// append child elements one at a time
for (const kid of kids) {
elem.appendChild(kid)
}
// and that's it
return elem
Applied recursively, you can make dom elements with very little boilerplate.May I suggest a repo. Github is great, I hear. :)
This isn’t as nice as JSX, but it makes a reasonably ergonomic API for quick little projects. Here’s what the example in the article would look like (admittedly it’s a bit easier to follow with syntax highlighting):