web-dev-qa-db-fra.com

Comment préserver l'indentation d'espacement de texte entre les balises <pre> HTML, à l'exclusion du niveau d'indentation actuel de la balise <pre> dans le document?

J'essaie d'afficher mon code sur un site Web, mais je ne parviens pas à conserver correctement l'indentation des espaces.

Par exemple, étant donné l'extrait suivant:

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

Ceci est affiché dans le navigateur comme:

Here is my code:

     def some_funtion
       return 'Hello, World!'
     end

Quand je voudrais qu'il soit affiché comme:

Here is my code:

def some_funtion
 return 'Hello, World!'
end

La différence est que le niveau d'indentation actuel de la balise HTML avant est ajouté à l'indentation du code. J'utilise nanoc en tant que générateur de site Web statique et j'utilise google prettify pour ajouter également la coloration syntaxique.

Quelqu'un peut-il offrir des suggestions? 

41
Michael Barton

PRE est destiné à préserver les espaces tels qu'ils apparaissent (à moins qu'ils ne soient modifiés par white-space dans CSS, qui ne dispose pas de suffisamment de flexibilité pour prendre en charge le code de formatage).

Avant

Le formatage est préservé, de même que toute l'indentation en dehors de la balise PRE. Il serait bien d’avoir une conservation des espaces qui utilise l’emplacement de la balise comme point de départ.

enter image description here

Après

Le contenu est toujours formaté tel que déclaré, mais les espaces non-normaux superflus provoqués par la position de la balise PRE dans le document sont supprimés.

enter image description here

Je suis venu avec le plugin suivant pour résoudre le problème de vouloir supprimer les espaces superflus causés par l'indentation du contour du document. Ce code utilise la première ligne à l'intérieur de la balise PRE pour déterminer combien il a été mis en retrait uniquement en raison de l'indentation du document.

Ce code fonctionne dans IE7, IE8, IE9, Firefox et Chrome. Je l’ai brièvement testé avec la bibliothèque Prettify pour combiner le formatage préservé avec de jolies impressions. Assurez-vous que la première ligne de la PRE représente réellement le niveau d'indentation de base que vous souhaitez ignorer (ou vous pouvez modifier le plug-in pour qu'il soit plus intelligent).

Ceci est un code approximatif. Si vous trouvez une erreur ou si cela ne fonctionne pas comme vous le souhaitez, corrigez-le/commentez; ne vous contentez pas de voter par inversion. J'ai écrit ce code pour résoudre un problème que j'avais et je suis activement en l'utilisant, j'aimerais donc qu'il soit aussi solide que possible!

/*!
*** 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 );

Ce plugin peut ensuite être appliqué à l’aide d’un sélecteur jQuery standard:

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

Mise en retrait avec des commentaires

Les navigateurs ignorant les commentaires, vous pouvez les utiliser pour mettre en retrait le contenu de votre balise pre.

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: un wrapper principal a été ajouté pour fournir assez d'espace pour les commentaires.

Avantages

  • Pas de JavaScript requis
  • Peut être ajouté statiquement
  • La minification n'affectera pas l'indentation et réduira la taille du fichier

Désavantages

  • Nécessite un minimum d'espace pour les commentaires
  • Pas très élégant sauf si des outils de construction sont utilisés

Suppression de l'indentation avec le nœud

Une meilleure solution consiste à supprimer le plus grand espace blanc en utilisant soit votre processus de construction, soit votre processus de rendu principal. Si vous utilisez node.js, vous pouvez utiliser un flux que j'ai écrit appelé predentation . Vous pouvez utiliser n’importe quel langage pour construire un outil similaire.

Avant

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

Après

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

Avantages

  • Manière transparente d'écrire les balises pre
  • Taille de fichier de sortie plus petite

Désavantages

  • Nécessite une étape de construction dans votre flux de travail
  • Ne gère pas les éléments non pre avec white-space: pre ajouté par CSS

Suppression de l'indentation avec JavaScript

Voir cette réponse pour supprimer l'indentation avec JavaScript

Avantages

  • Possible de cibler des éléments avec white-space: pre

Désavantages

  • JavaScript peut être désactivé
  • L'espace blanc ajoute à la taille du fichier
12
Dale

Réussi à le faire avec JavaScript. Cela fonctionne dans Internet Explorer 9 et Chrome 15, je n'ai pas testé les anciennes versions. Cela devrait fonctionner dans Firefox 11 lorsque le support de outerHTML est ajouté (voir ici ), en attendant, certaines implémentations personnalisées sont disponibles sur le Web. Un exercice pour le lecteur est de se débarrasser de l’indentation finale (jusqu’à ce que je prenne le temps de le terminer et de mettre à jour cette réponse).

Je marquerai également ceci comme wiki de communauté pour une édition facile.

Notez que vous devrez reformater l'exemple pour utiliser des tabulations comme indentation ou modifier la regex pour qu'elle utilise des espaces.

<!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
Stijn

Cela peut être fait en quatre lignes de 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
屎克螂

J'ai décidé de proposer quelque chose de plus concret que de changer la façon dont le travail pre ou code. J'ai donc créé des expressions rationnelles pour obtenir le premier caractère de nouvelle ligne \n (précédé d'espaces possibles - le \s* est utilisé pour nettoyer les espaces supplémentaires à la fin d'une ligne de code et avant le caractère de nouvelle ligne (que j'avais remarqué), et trouver le Caractères de tabulation ou d’espace suivant le [\t\s]* (qui signifie caractère de tabulation, caractère d’espace (0 ou plus) et définissez cette valeur comme variable. Cette variable est ensuite utilisée dans la fonction regex replace pour en rechercher toutes les instances et la remplacer par \n ( Comme la seconde ligne (où pattern est défini) ne contient pas l'indicateur global (un g après l'expression régulière), il trouvera la première instance du caractère newcode \n et définira la variable pattern sur cette valeur. Dans le cas d'une nouvelle ligne, suivie de 2 caractères de tabulation, la valeur de pattern sera techniquement \n\t\t, elle sera remplacée lorsque chaque caractère \n est trouvé dans cet élément pre code (puisqu'il est exécuté dans chaque fonction). ) et remplacé par \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>

1
ctwheels

J'ai également constaté que si vous utilisez haml, vous pouvez utiliser la méthode preserve. Par exemple:

preserve yield

Cela préservera les espaces dans la yield produite, qui est généralement une démarque contenant les blocs de code.

1
Michael Barton

C'est fastidieux, mais cela fonctionne si le pliage de code est important pour vous:

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

Dans votre css,

    pre { margin:0 }

Dans vim, écrivez votre code normalement, puis exécutez:

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

pour chaque ligne fonctionnerait.

0
Paul Robert

Si vous utilisez ceci sur un bloc de code comme:

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

Vous pouvez simplement utiliser css comme celui-ci pour compenser cette grande quantité d'espace blanc à l'avant.

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