How to preserve whitespace indentation of text enclosed in HTML
 tags excluding the current indentation level of the 
 tag in the document?

后端 未结 11 1455
萌比男神i
萌比男神i 2020-12-02 18:32

I\'m trying to display my code on a website but I\'m having problems preserving the whitespace indentation correctly.

For instance given the following snippet:

相关标签:
11条回答
  • 2020-12-02 18:54

    I decided to come up with something more concrete than changing the way pre or code work. So I made some regex to get the first newline character \n (preceded with possible whitespace - the \s* is used to cleanup extra whitespace at the end of a line of code and before the newline character (which I noticed yours had)) and find the tab or whitespace characters following it [\t\s]* (which means tab character, whitespace character (0 or more) and set that value to a variable. That variable is then used in the regex replace function to find all instances of it and replace it with \n (newline). Since the second line (where pattern gets set) doesn't have the global flag (a g after the regex), it will find the first instance of the \n newline character and set the pattern variable to that value. So in the case of a newline, followed by 2 tab characters, the value of pattern will technically be \n\t\t, which will be replaced where every \n character is found in that pre code element (since it's running through the each function) and replaced with \n

    $("pre code").each(function(){
        var html = $(this).html();
        var pattern = html.match(/\s*\n[\t\s]*/);
        $(this).html(html.replace(new RegExp(pattern, "g"),'\n'));
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <body>
        Here is some code:
    
        <pre><code>
            Here is some fun code!
            More code
              One tab
                One more tab
                
                Two tabs and an extra newline character precede me
        </code></pre>
    </body>

    0 讨论(0)
  • 2020-12-02 19:01

    If you're okay with changing the innerHTML of the element:

    Given:

    <pre>
      <code id="the-code">
        def some_funtion
          return 'Hello, World!'
        end
      </code
    </pre>
    

    Which renders as:

    
        def some_funtion
          return 'Hello, World!'
        end
    
    

    The following vanilla JS:

    // get block however you want.
    var block = document.getElementById("the-code");
    
    // remove leading and trailing white space.
    var code = block.innerHTML
                    .split('\n')
                    .filter(l => l.trim().length > 0)
                    .join('\n');
    
    // find the first non-empty line and use its
    // leading whitespace as the amount that needs to be removed
    var firstNonEmptyLine = block.textContent
                                 .split('\n')
                                 .filter(l => l.trim().length > 0)[0];
    
    // using regex get the first capture group
    var leadingWhiteSpace = firstNonEmptyLine.match(/^([ ]*)/);
    
    // if the capture group exists, then use that to
    // replace all subsequent lines.
    if(leadingWhiteSpace && leadingWhiteSpace[0]) {
      var whiteSpace = leadingWhiteSpace[0];
      code = code.split('\n')
                 .map(l => l.replace(new RegExp('^' + whiteSpace + ''), ''))
                 .join('\n');
    }
    
    // update the inner HTML with the edited code
    block.innerHTML = code;
    

    Will result in:

    <pre>
      <code id="the-code">def some_funtion
      return 'Hello, World!'
    end</code>
    </pre>
    

    And will render as:

    def some_funtion
      return 'Hello, World!'
    end
    
    0 讨论(0)
  • 2020-12-02 19:02

    Indenting With Comments

    Since browsers ignore comments, you can use them to indent your pre tag contents.

    Solution

    <html>
      <body>
        <main>
          Here is my code with hack:
          <pre>
    <!-- -->def some_function
    <!-- -->  return 'Hello, World!'
    <!-- -->end
          </pre>
          Here is my code without hack:
          <pre>
            def some_function
              return 'Hello, World!'
            end
          </pre>
        </main>
      <body>
    </html>

    NOTE: a main wrapper was added to provide enough space for the comments.

    Advantages

    • No JavaScript required
    • Can be added statically
    • Minification won't affect the indentation and reduces file size

    Disadvantages

    • Requires a minimum amount of space for the comments
    • Not very elegant unless build tools are used

    Removing Indentation With Node

    A better solution is to remove the leading white-space using either your build process or back-end rendering process. If you are using node.js, then you can use a stream I wrote called predentation. You can use any language you want to build a similar tool.

    Before

    <html>
     <body>
       Here is my code:
       <pre>
         def some_function
           return 'Hello, World!'
         end
       </pre>
     </body>
    </html>
    

    After

    <html>
     <body>
       Here is my code:
       <pre>
    def some_function
      return 'Hello, World!'
    end
       </pre>
     </body>
    </html>
    

    Advantages

    • Seamless way to write pre tags
    • Smaller output file size

    Disadvantages

    • Requires a build step in your workflow
    • Does not handle non pre elements with white-space: pre added by CSS

    Removing Indentation With JavaScript

    See this answer to remove indentation with JavaScript

    Advantages

    • Possible to target elements with white-space: pre

    Disadvantages

    • JavaScript can be disabled
    • White-space adds to the file size
    0 讨论(0)
  • 2020-12-02 19:04

    Managed to do this with JavaScript. It works in Internet Explorer 9 and Chrome 15, I haven't tested older versions. It should work in Firefox 11 when support for outerHTML is added (see here), meanwhile there are some custom implementations available on the web. An excercise for the reader is to get rid of trailing indentation (until I make time to finish it and update this answer).

    I'll also mark this as community wiki for easy editing.

    Please note that you'll have to reformat the example to use tabs as indentation, or change the regex to work with spaces.

    <!DOCTYPE html>
    <html>
        <head>
            <title>Hello, World!</title>
        </head>
        <body>
            <pre>
                &lt;html&gt;
                    &lt;head&gt;
                        &lt;title&gt;Hello World Example&lt;/title&gt;
                    &lt;/head&gt;
                    &lt;body&gt;
                        Hello, World!
                    &lt;/body&gt;
                &lt;/html&gt;
            </pre>
            <pre>
                class HelloWorld
                {
                    public static int Main(String[] args)
                    {
                        Console.WriteLine(&amp;quot;Hello, World!&amp;quot;);
                        return 0;
                    }
                }
            </pre>
            <script language="javascript">
                var pre_elements = document.getElementsByTagName('pre');
    
                for (var i = 0; i < pre_elements.length; i++)
                {
                    var content = pre_elements[i].innerHTML;
    
                    var tabs_to_remove = '';
                    while (content.indexOf('\t') == '0')
                    {
                      tabs_to_remove += '\t';
                      content = content.substring(1);
                    }
    
                    var re = new RegExp('\n' + tabs_to_remove, 'g');
                    content = content.replace(re, '\n');
                    pre_elements[i].outerHTML = '<pre>' + content + '</pre>';
                }
            </script>
        </body>
    </html>
    
    0 讨论(0)
  • 2020-12-02 19:04

    <script>
        $("pre[name='pre']").each(function () {
            var html = $(this).html()
            var blankLen = (html.split('\n')[0].match(/^\s+/)[0]).length
            $(this).html($.trim(html.replace(eval("/^ {" + blankLen + "}/gm"), "")))
        })
    </script>
    <div>
    	<pre name="pre">
    		1
    			2
    				3
    	</pre>
    </div>

    0 讨论(0)
提交回复
热议问题