skip to Main Content

Thanks for any time dedicated to this conundrum, in advance.
I am attempting to reprint the html markup of a button inside of a code element. However, I need to split the code elements up into separate spans, to add some color to the output.
Using Regex and HTML character encoding, I am able to correctly wrap all targeted element strings. This is where I hit the wall.
The out of the code is markup, indeed, but I need the wrapping spans to be only that… wrappers of a particular portion of the code string. I was thinking .split() .join(), but really do not want to deal with a huge array of substrings.

<span class="chev"><<span>button id=<span class="quote">">"<span>btn<span class="quote">">"<span> class=<span class="quote">">"<span>btn btn-primary tru-btn<span class="quote">">"<span> data-value=<span class="quote">">"<span>btn-primary<span class="quote">">"<span> type=<span class="quote">">"<span>button<span class="quote">">"<span><span class="chev">><span>Button<span class="chev"><<span>/butt
on<span class="chev">><span> 
generateHTMLBlock = () => {
  let someButton = document.querySelector('div').innerHTML,
    modBtnCode = someButton.replace(/^.s+|s+$/gm, ''),
    btnMarkup = modBtnCode.replace(/(.{100})/g, "$1r");
  encodeElement = (output) => {
    return output.replace(/</g, '&lt;span class=&quot;chev&quot;&gt;<&lt;span&gt;')
      .replace(/>/g, '&lt;span class=&quot;chev&quot;&gt;>&lt;span&gt;')
      .replace(/"/g, '&lt;span class=&quot;quote&quot;&gt;"&lt;/span&gt;');
  let code = encodeElement(btnMarkup);
  document.getElementsByTagName('code').appendChild(code);
};
.btn-primary:not(disabled):not(.disabled),
.btn-secondary:not(disabled):not(.disabled) {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  max-width: fit-content;
  padding: 0.338rem 1.5rem;
  margin: 0;
  overflow: hidden;
  background: black;
  border-radius: .625rem;
  border-width: .125rem;
  border: 1px solid transparent;
  border-color: black;
  box-shadow: none;
  font-family: arial;
  color: white;
  font-size: 16px;
  font-weight: 400;
  text-align: center;
  vertical-align: middle;
  text-transform: none;
  user-select: none;
  line-height: 2.2rem;
  letter-spacing: .25px;
  text-decoration: none !important;
  cursor: pointer;
  transition: all .3s ease-in-out;
}

pre {
  padding: 1rem;
  margin-bottom: 0;
  width: 100%;
  height: 6em;
}

code {
  display: block;
  color: black;
  width: 100%;
  height: 100%;
  border: 1px solid red;
}

.quote {
  color: green;
}

.chev {
  color: blue;
}
<div>
  <button id="btn" class="btn btn-primary" data-value="btn-primary" type="button">Button</button>
</div>
<pre>
  <code></code>
</pre>

2

Answers


  1. Let’s solve the encoding problem and the appendChild issue:

    generateHTMLBlock = () => {
      let someButton = document.querySelector('div').innerHTML.trim();
    
      encodeElement = (output) => {
        return output.replace(/</g, '<span class="chev">&lt;</span>')
          .replace(/>/g, '<span class="chev">&gt;</span>')
          .replace(/"/g, '<span class="quote">&quot;</span>');
      };
    
      let code = encodeElement(someButton);
      document.querySelector('code').innerHTML = code;
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    To try it out you can add a button to your page that, when clicked, runs this function:

    <button onclick="generateHTMLBlock()">Generate Code Block</button>
    

    Clicking on this button will then encode your button’s markup and place it inside the <code> element.

    Login or Signup to reply.
  2. Since you have access to the element that you want to generate the code for, you can use the DOM methods to extract the data.

    This solution doesn’t try to parse the HTML with regular expressions, but uses the data parsed by the browser.

    By creating a span, and then using textContent to set the data, the browser will not treat the code as HTML, but as text.

    This is just an example. You have to adopt it for your needs.

    function generateHTMLBlock(node) {
      const parent = document.getElementById('output');
      function ce(parent, ...args) {
        for (let i = 0; i < args.length; i += 2) {
          const e = document.createElement('span');
          e.className = args[i + 0];
          e.textContent = args[i + 1];
          parent.appendChild(e);
        }
      }
    
      function genNode(parent, node) {
        const e = document.createElement('div');
        parent.appendChild(e);
        e.className = 'node';
    
        switch (node.nodeType) {
          case Node.ELEMENT_NODE: {
            e.classList.add('element');
            const tagName = node.nodeName.toLowerCase();
            ce(e, 'tagStart', '<', 'tagName', tagName);
            for (const attrName of node.getAttributeNames()) {
              ce(
                e,
                'space', ' ',
                'attrName', attrName,
                'attrEqual', '=',
                'attrQuote', '"',
                'attrValue', node.getAttribute(attrName).replace(/"/g, '&quot;'),
                'attrQuote', '"'
              );
            }
            ce(e, 'tagEnd', '>');
            for (const child of node.childNodes) genNode(e, child);
            ce(e, 'tagStart', '</', 'tagName', tagName, 'tagEnd', '>');
            break;
          }
          case Node.TEXT_NODE: {
            e.classList.add('text');
            ce(e, 'textValue', node.textContent);
            break;
          }
          case Node.COMMENT_NODE: {
            e.classList.add('comment');
            ce(e, 'commentStart', '<!--', 'commentValue', node.textContent, 'commentEnd', '-->');
            break;
          }
        }
      }
    
      genNode(parent, node);
    }
    
    generateHTMLBlock(document.getElementById('btn'));
    body { background-color:#1d1b1b; color:#aaa;}
    div.node { display:inline; white-space: pre-line; }
    div.node.element { }
    div.node.text { color:#fff; }
    div.node.comment { color:#999; }
    .attrQuote, .attrEqual, .tagEnd, .tagStart { color: #fff; }
    .tagName { color: #f09449; }
    .attrName { color: #88afce; }
    .attrValue { color: #bfbd68; }
    .attrQuote { color: #bfbd68; }
    <div>
      <button id="btn" class="btn btn-primary" data-value="btn-primary" type="button">
        Some text
        <span class="cap">B</span>utton<!--A comment-->
      </button>
    </div>
    
    <code id="output"></code>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search