Skip to content

Instantly share code, notes, and snippets.

@gabor-m
Last active July 27, 2022 15:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabor-m/0d562247c457b55ade0ee6fee63e75cf to your computer and use it in GitHub Desktop.
Save gabor-m/0d562247c457b55ade0ee6fee63e75cf to your computer and use it in GitHub Desktop.
$.state = function (val) {
if (val && typeof val === 'object' && typeof val.onChange === "function") {
throw new Error("Cannot put state into state");
}
const handlers = [];
return {
onChange: function (f) {
handlers.push(f);
},
get: function () {
return val;
},
set: function (v) {
val = v;
handlers.forEach(function (h) { h(v); });
}
};
};
$.html = function (strings, ...keys) {
let source = [];
strings.forEach(function (value, index) {
source.push(value);
source.push('<span data-placeholder="' + index + '"></span>');
});
source = source.join("");
let $pseudoRoot = $('<div></div>');
let $elem = $(source);
$pseudoRoot.append($elem);
$pseudoRoot.find('[data-placeholder]').each(function () {
function handleItem($e, item) {
if (item instanceof jQuery) {
$e.replaceWith(item);
} else if (item && typeof item === 'object' && typeof item.render === "function") {
$e.replaceWith(item.render());
} else if (item && typeof item === 'object' && typeof item.onChange === "function") {
var unpacked = item.get();
if (!(unpacked instanceof jQuery)) {
unpacked = $('<span data-text-placeholder>' + String(unpacked) + '</span>');
}
$e.replaceWith(unpacked);
item.onChange((newVal) => {
handleItem(unpacked, newVal);
if (newVal instanceof jQuery) {
unpacked = newVal;
}
});
} else {
if (typeof $e.data('text-placeholder') !== 'undefined') {
$e.html(item);
} else {
$e.replaceWith(String(item));
}
}
}
let index = $(this).data('placeholder');
let item = keys[+index];
handleItem($(this), item);
});
$elem.find('[data-placeholder]').remove();
return $pseudoRoot.children();
};
class Counter {
constructor() {
this.c = $.state(0);
}
incr() {
this.c.set(this.c.get() + 1);
}
render() {
var $elem = $.html`<button>${ this.c }</button>`;
$elem.click(() => this.incr());
return $elem;
}
}
var state = $.state($.html`<b>0</b>`);
setInterval(function () { state.set($.html`<b>${ Date.now() }</b>`); }, 1000);
var item = "Hello World";
var $elem = $.html`
<div>
${ state }
<strong>
${ item }
</strong>
</div>
${ new Counter() }
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment