web-dev-qa-db-ja.com

ドキュメント内の<pre>タグの現在のインデントレベルを除くHTML <pre>タグで囲まれたテキストの空白インデントを保持する方法

Webサイトにコードを表示しようとしていますが、空白のインデントを正しく保持するのに問題があります。

たとえば、次のスニペットを指定します。

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

これはブラウザに次のように表示されます。

Here is my code:

     def some_funtion
       return 'Hello, World!'
     end

次のように表示したい場合:

Here is my code:

def some_funtion
 return 'Hello, World!'
end

違いは、HTML preタグの現在のインデントレベルがコードのインデントに追加されていることです。私はnanocを静的Webサイトジェネレーターとして使用し、google prettifyを使用して構文の強調表示も追加しています。

誰でも提案を提供できますか?

45
Michael Barton

PREは、空白を表示どおりに保持することを目的としています(white-space CSSでは、フォーマットコードをサポートするのに十分な柔軟性がありません。

Before

フォーマットは保持されますが、PREタグの外側のすべてのインデントも保持されます。タグの場所を開始点として使用する空白を保存しておくと便利です。

enter image description here

After

内容は依然として宣言どおりにフォーマットされますが、ドキュメント内のPREタグの位置に起因する余分な先行空白は削除されます。

enter image description here

ドキュメントのアウトラインのインデントによって生じた余分な空白を削除したいという問題を解決するために、次のプラグインを思いつきました。このコードは、PREタグ内の最初の行を使用して、ドキュメントのインデントによって純粋にインデントされている量を判断します。

このコードはIE7、IE8、IE9、Firefox、Chromeで動作します。 Prettify ライブラリを使用して簡単にテストし、保存されたフォーマットときれいな印刷を組み合わせました。 PRE内の最初の行が、無視したいインデントのベースラインレベルを実際に表していることを確認してください(または、プラグインをよりインテリジェントに変更できます)。

これは大まかなコードです。間違いを見つけたり、思い通りに機能しない場合は、修正/コメントしてください。ただ投票しないでください。私が抱えていた問題を修正するためにこのコードを書いたので、それを積極的に使用しているので、できる限り堅実になりたいです!

/*!
*** prettyPre ***/

(function( $ ) {

    $.fn.prettyPre = function( method ) {

        var defaults = {
            ignoreExpression: /\s/ // what should be ignored?
        };

        var methods = {
            init: function( options ) {
                this.each( function() {
                    var context = $.extend( {}, defaults, options );
                    var $obj = $( this );
                    var usingInnerText = true;
                    var text = $obj.get( 0 ).innerText;

                    // some browsers support innerText...some don't...some ONLY work with innerText.
                    if ( typeof text == "undefined" ) {
                        text = $obj.html();
                        usingInnerText = false;
                    }

                    // use the first line as a baseline for how many unwanted leading whitespace characters are present
                    var superfluousSpaceCount = 0;
                    var currentChar = text.substring( 0, 1 );

                    while ( context.ignoreExpression.test( currentChar ) ) {
                        currentChar = text.substring( ++superfluousSpaceCount, superfluousSpaceCount + 1 );
                    }

                    // split
                    var parts = text.split( "\n" );
                    var reformattedText = "";

                    // reconstruct
                    var length = parts.length;
                    for ( var i = 0; i < length; i++ ) {
                        // cleanup, and don't append a trailing newline if we are on the last line
                        reformattedText += parts[i].substring( superfluousSpaceCount ) + ( i == length - 1 ? "" : "\n" );
                    }

                    // modify original
                    if ( usingInnerText ) {
                        $obj.get( 0 ).innerText = reformattedText;
                    }
                    else {
                        // This does not appear to execute code in any browser but the onus is on the developer to not 
                        // put raw input from a user anywhere on a page, even if it doesn't execute!
                        $obj.html( reformattedText );
                    }
                } );
            }
        }

        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
        }
        else if ( typeof method === "object" || !method ) {
            return methods.init.apply( this, arguments );
        }
        else {
            $.error( "Method " + method + " does not exist on jQuery.prettyPre." );
        }
    }
} )( jQuery );

このプラグインは、標準のjQueryセレクターを使用して適用できます。

<script>
    $( function() { $("PRE").prettyPre(); } );
</script>
23
Tim Medora

JavaScriptでこれを行うことができました。 Internet Explorer 9で動作し、Chrome 15、古いバージョンはテストしていません。Firefox11では、outerHTMLのサポートが追加されたときに動作するはずです( here )一方、ウェブ上で利用可能なカスタム実装がいくつかあります。読者にとっての練習は、末尾のインデントを取り除くことです(終了してこの回答を更新するまで)。

また、簡単に編集できるように、これをコミュニティWikiとしてマークします。

タブをインデントとして使用するように例を再フォーマットするか、スペースを使用するように正規表現を変更する必要があることに注意してください。

<!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>
5
user247702

これは、次の4行のJavaScriptで実行できます。

var pre= document.querySelector('pre');

//insert a span in front of the first letter.  (the span will automatically close.)
pre.innerHTML= pre.textContent.replace(/(\w)/, '<span>$1');

//get the new span's left offset:
var left= pre.querySelector('span').getClientRects()[0].left;

//move the code to the left, taking into account the body's margin:
pre.style.marginLeft= (-left + pre.getClientRects()[0].left)+'px';
 <body>
   Here is my code:
   <pre>
     def some_funtion
       return 'Hello, World!'
     end
   </pre>
 <body>
3
Rick Hitchcock
<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>
2
屎克螂

preまたはcodeの動作を変更するよりも具体的なものを思いつくことにしました。そこで、最初の改行文字\nを取得するために正規表現を作成しました(可能性のある空白文字が前に付きます-\s*は、コード行の最後で改行文字(あなたが持っていることに気づいた))、それに続くタブまたは空白文字を見つけます[\t\s]*(タブ文字、空白文字(0以上)を意味し、その値を変数に設定します。その変数は、正規表現置換関数で使用されます。そのすべてのインスタンスを見つけて、\n(改行)に置き換えます。2行目(patternが設定される)にはグローバルフラグ(正規表現の後のg)がないため、最初のインスタンスが見つかります。 \n改行文字を使用し、pattern変数をその値に設定します。したがって、改行とそれに続く2つのタブ文字の場合、patternの値は技術的には\n\t\tになります。すべての\n文字は、そのpre code要素(各関数を実行しているため)および\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>
2
ctwheels

また、hamlを使用している場合は、preserveメソッドを使用できることもわかりました。例えば:

preserve yield

これにより、生成されたyieldの空白が保持されます。これは通常、コードブロックを含むマークダウンです。

2
Michael Barton

これは面倒ですが、コードの折りたたみが重要な場合に機能します。

        <pre>def some_funtion</pre>
        <pre>    return 'Hello, World!'</pre>
        <pre>end</pre>

あなたのCSSでは、

    pre { margin:0 }

Vimでは、通常のコードを記述してから実行します。

    :s/\t\t\([^\n]\+\)/<pre>\1<\/pre>/

各行で機能します。

0
Paul Robert

次のようなコードブロックでこれを使用している場合:

<pre>
  <code>
    ...
  </code>
</pre>

このようなcssを使用するだけで、前面の大量の空白を相殺できます。

pre code {
  position: relative;
  left: -95px; // or whatever you want
}
0