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.

Leave a Reply

Your email address will not be published.

Color scheme: