HTML Typer
by soulwire
HTML
<div id="output"></div>
Babel + JSX
const html = 'this <a href="#">is</a> some<br/>text <h1>big</h1> <strong>cool <em>beans</em></strong>… :)';
// t,h, ,<a href="">,i
// split into columns
// cells can be empty but keep tags in place
// they can then either collapse or example
// only perform scramble / type on non-tag cells
// for swapping text:
// take 2 arrays for old and new
// pad shortest to match longest
// third array of bools whether to use new
// progressively toggle to new
// merge
const shuffle = (a) => {
let n, i = a.length - 1;
for (; i > 0; i--) {
n = Math.floor(Math.random() * (i + 1));
[ a[n], a[i] ] = [ a[i], a[n] ];
}
return a;
};
const reTag = /<[^>]+>/;
const reEntity = /&[^;\s]+;/;
const reMatchStart = new RegExp(`^(${reTag.source}|${reEntity.source})`);
// reduce string from front taking tags that match at start
let str = html;
const chars = [];
while (str.length) {
//let match = str.match(/^<[^>]+>/);
//let match = str.match(/^(<[^>]+>|&[^;\s]+;)/);
let match = str.match(reMatchStart);
let item = match ? match[0] : str[0];
str = str.substr(item.length);
chars.push(item);
}
const isTag = chars.map(c => c.length > 1);
//const state = chars.map(c => c.length > 1 ? c : ' ');
const state = chars.map(char => {
// maintain tags
if (reTag.test(char)) { return char; }
// maintain spaces
if (char === ' ') { return ' ' }
return ' ';
});
const queue = chars.reduce((memo, char, index) => {
// not tag or space (allow spaces for different effect)
//console.log(char, reEntity.test(char))
if (reEntity.test(char) || (char.length === 1 && char !== ' ')) {
memo.push({
char,
index
});
}
return memo;
}, []);
console.log(chars);
console.log(isTag);
console.log(state);
console.log(JSON.stringify(queue));
shuffle(queue);
const el = document.getElementById('output');
let interval = setInterval(() => {
const item = queue.pop();
state[item.index] = item.char;
el.innerHTML = state.join('');
if (!queue.length) {
...