Highlighting comments in CSS rendered with HTML
Using techniques to encode and decode HTML explored in the last few posts, let’s bring them together to add syntax highlighting to a CSS snippet rendered in HTML on this site.
const encodeHtml = html => {
const t = document.createElement('textarea');
t.value = html;
return t.innerHTML;
}
const decodeHtml = html => {
const t = document.createElement('textarea');
t.innerHTML = html;
return t.value;
}
const parse = cssStr => {
const state = {};
let tokens = [];
let cache = '';
for (let i = 0; i < cssStr.length; i++) {
// Consume comments
const startComment = !state.isComment && (cssStr[i] === '/') && (cssStr[i+1] === '*')
if (startComment) {
state.isComment = true;
tokens.push({t: 'comment', v: cache});
cache = '';
}
cache += cssStr[i];
if (state.isComment && (cssStr[i-1] === '*') && (cssStr[i] === '/')) {
state.isComment = false;
tokens.push({t: 'comment', v: cache});
cache = '';
}
}
if (cache) {
tokens.push({t: 'plain', v: cache});
}
return output;
}
const highlightSnippet = () => {
const snippetElement = document.getElementById('syntax-highlight-1');
const htmlEncodedCss = snippetElement.innerHTML;
const html = decodeHtml(htmlEncodedCss);
const tokens = parse(html);
let output = '';
tokens.forEach(token => {
let part = '';
switch(token.t): {
case 'comment': part = `<span class="comment">${encodeHtml(token.v)}</span>`; break;
default: part = `<span>${encodeHtml(token.v)}</span>`
}
output += part;
});
snippetElement.innerHTML = output;
}
Here is a snippet to be run through this comment-highlighting process:
/* comment should be highlighted but nothing else */
p > span:first-child { font-weight: bold; }
Here is the result:
/* comment should be highlighted but nothing else */
p > span:first-child { font-weight: bold; }
Oh no! It doesn’t work because of a bug in WordPress causing some of the characters in the JavaScript to be HTML encoded.