web-dev-qa-db-fra.com

Insérer des ellipses (...) dans une balise HTML si le contenu est trop large

J'ai une page Web avec une disposition élastique qui change de largeur si la fenêtre du navigateur est redimensionnée.

Dans cette présentation, il y a des titres (h2) qui auront une longueur variable (en fait, ce sont des titres de blogs que je n'ai pas le contrôle). Actuellement, s'ils sont plus larges que la fenêtre, ils sont divisés en deux lignes.

Existe-t-il une solution élégante et testée (multi-navigateurs) - par exemple avec jQuery - qui raccourcit le innerHTML de cette balise de titre et ajoute "..." si le texte est trop large pour tenir dans une ligne de l'écran actuel largeur du conteneur?

144
BlaM

J'ai une solution fonctionnant en FF3, Safari et IE6 + avec texte unique et multiligne

.Ellipsis {
    white-space: nowrap;
    overflow: hidden;
}

.Ellipsis.multiline {
    white-space: normal;
}

<div class="Ellipsis" style="width: 100px; border: 1px solid black;">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>
<div class="Ellipsis multiline" style="width: 100px; height: 40px; border: 1px solid black; margin-bottom: 100px">Lorem ipsum dolor sit amet, consectetur adipisicing elit</div>

<script type="text/javascript" src="/js/jquery.Ellipsis.js"></script>
<script type="text/javascript">
$(".Ellipsis").Ellipsis();
</script>

jquery.Ellipsis.js

(function($) {
    $.fn.Ellipsis = function()
    {
        return this.each(function()
        {
            var el = $(this);

            if(el.css("overflow") == "hidden")
            {
                var text = el.html();
                var multiline = el.hasClass('multiline');
                var t = $(this.cloneNode(true))
                    .hide()
                    .css('position', 'absolute')
                    .css('overflow', 'visible')
                    .width(multiline ? el.width() : 'auto')
                    .height(multiline ? 'auto' : el.height())
                    ;

                el.after(t);

                function height() { return t.height() > el.height(); };
                function width() { return t.width() > el.width(); };

                var func = multiline ? height : width;

                while (text.length > 0 && func())
                {
                    text = text.substr(0, text.length - 1);
                    t.html(text + "...");
                }

                el.html(t.html());
                t.remove();
            }
        });
    };
})(jQuery);
118
alex

La solution CSS uniquement suivante pour tronquer le texte sur une seule ligne fonctionne avec tous les ventilateurs répertoriés à http://www.caniuse.com à partir de l’écriture, à l’exception de Firefox 6.0. Notez que JavaScript est totalement inutile, sauf si vous avez besoin de prendre en charge le texte multiligne ou les versions antérieures de Firefox.

.Ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: Ellipsis;
    -o-text-overflow: Ellipsis;
}

Si vous avez besoin de support pour les versions antérieures de Firefox, consultez ma réponse à cette autre question .

179
Simon Lieschke

J'ai construit ce code en utilisant un certain nombre d'autres articles, avec les améliorations suivantes:

  1. Il utilise une recherche binaire pour trouver la longueur de texte qui convient parfaitement.
  2. Il gère les cas où le ou les éléments Ellipsis sont initialement masqués en configurant un événement show one-shot qui relance le code Ellipsis lors de la première visualisation de l'élément. C'est pratique pour les vues maître-détail ou les vues arborescentes où certains éléments ne sont pas initialement affichés.
  3. Il ajoute éventuellement un attribut title avec le texte d'origine pour un effet de survol.
  4. Ajout de display: block au style, pour que le travail s'étende
  5. Il utilise le caractère Ellipsis au lieu de 3 points.
  6. Il exécute automatiquement le script pour n'importe quoi avec la classe .Ellipsis

CSS:

.Ellipsis {
        white-space: nowrap;
        overflow: hidden;
        display: block;
}

.Ellipsis.multiline {
        white-space: normal;
}

jquery.Ellipsis.js

(function ($) {

    // this is a binary search that operates via a function
    // func should return < 0 if it should search smaller values
    // func should return > 0 if it should search larger values
    // func should return = 0 if the exact value is found
    // Note: this function handles multiple matches and will return the last match
    // this returns -1 if no match is found
    function binarySearch(length, func) {
        var low = 0;
        var high = length - 1;
        var best = -1;
        var mid;

        while (low <= high) {
            mid = ~ ~((low + high) / 2); //~~ is a fast way to convert something to an int
            var result = func(mid);
            if (result < 0) {
                high = mid - 1;
            } else if (result > 0) {
                low = mid + 1;
            } else {
                best = mid;
                low = mid + 1;
            }
        }

        return best;
    }

    // setup handlers for events for show/hide
    $.each(["show", "toggleClass", "addClass", "removeClass"], function () {

        //get the old function, e.g. $.fn.show   or $.fn.hide
        var oldFn = $.fn[this];
        $.fn[this] = function () {

            // get the items that are currently hidden
            var hidden = this.find(":hidden").add(this.filter(":hidden"));

            // run the original function
            var result = oldFn.apply(this, arguments);

            // for all of the hidden elements that are now visible
            hidden.filter(":visible").each(function () {
                // trigger the show msg
                $(this).triggerHandler("show");
            });

            return result;
        };
    });

    // create the Ellipsis function
    // when addTooltip = true, add a title attribute with the original text
    $.fn.Ellipsis = function (addTooltip) {

        return this.each(function () {
            var el = $(this);

            if (el.is(":visible")) {

                if (el.css("overflow") === "hidden") {
                    var content = el.html();
                    var multiline = el.hasClass('multiline');
                    var tempElement = $(this.cloneNode(true))
                        .hide()
                        .css('position', 'absolute')
                        .css('overflow', 'visible')
                        .width(multiline ? el.width() : 'auto')
                        .height(multiline ? 'auto' : el.height())
                    ;

                    el.after(tempElement);

                    var tooTallFunc = function () {
                        return tempElement.height() > el.height();
                    };

                    var tooWideFunc = function () {
                        return tempElement.width() > el.width();
                    };

                    var tooLongFunc = multiline ? tooTallFunc : tooWideFunc;

                    // if the element is too long...
                    if (tooLongFunc()) {

                        var tooltipText = null;
                        // if a tooltip was requested...
                        if (addTooltip) {
                            // trim leading/trailing whitespace
                            // and consolidate internal whitespace to a single space
                            tooltipText = $.trim(el.text()).replace(/\s\s+/g, ' ');
                        }

                        var originalContent = content;

                        var createContentFunc = function (i) {
                            content = originalContent.substr(0, i);
                            tempElement.html(content + "…");
                        };

                        var searchFunc = function (i) {
                            createContentFunc(i);
                            if (tooLongFunc()) {
                                return -1;
                            }
                            return 0;
                        };

                        var len = binarySearch(content.length - 1, searchFunc);

                        createContentFunc(len);

                        el.html(tempElement.html());

                        // add the tooltip if appropriate
                        if (tooltipText !== null) {
                            el.attr('title', tooltipText);
                        }
                    }

                    tempElement.remove();
                }
            }
            else {
                // if this isn't visible, then hook up the show event
                el.one('show', function () {
                    $(this).Ellipsis(addTooltip);
                });
            }
        });
    };

    // ellipsification for items with an Ellipsis
    $(document).ready(function () {
        $('.Ellipsis').Ellipsis(true);
    });

} (jQuery));
39
Adam Tegen

Ma réponse ne prend en charge que le texte sur une ligne. Découvrez le commentaire de gfullam ci-dessous pour la fourche multiligne, il semble plutôt prometteur.

J'ai réécrit le code de la première réponse à quelques reprises, et je pense que cela devrait être le plus rapide.

Il trouve d'abord une longueur de texte "estimée", puis ajoute ou supprime un caractère jusqu'à ce que la largeur soit correcte. 

La logique utilisée est la suivante:

enter image description here

Après avoir trouvé une longueur de texte "estimée", les caractères sont ajoutés ou supprimés jusqu'à ce que la largeur souhaitée soit atteinte.

Je suis sûr que cela nécessite quelques ajustements, mais voici le code:

(function ($) {
    $.fn.Ellipsis = function () {
        return this.each(function () {
            var el = $(this);

            if (el.css("overflow") == "hidden") {
                var text = el.html().trim();
                var t = $(this.cloneNode(true))
                                        .hide()
                                        .css('position', 'absolute')
                                        .css('overflow', 'visible')
                                        .width('auto')
                                        .height(el.height())
                                        ;
                el.after(t);

                function width() { return t.width() > el.width(); };

                if (width()) {

                    var myElipse = "....";

                    t.html(text);

                    var suggestedCharLength = (text.length * el.width() / t.width()) - myElipse.length;

                    t.html(text.substr(0, suggestedCharLength) + myElipse);

                    var x = 1;
                    if (width()) {
                        while (width()) {
                            t.html(text.substr(0, suggestedCharLength - x) + myElipse);
                            x++;
                        }
                    }
                    else {
                        while (!width()) {
                            t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                            x++;
                        }
                        x--;
                        t.html(text.substr(0, suggestedCharLength + x) + myElipse);
                    }

                    el.html(t.html());
                    t.remove();
                }
            }
        });
    };
})(jQuery);
20
Mikey G

J'ai créé un plugin jQuery vraiment génial pour gérer toutes les variétés d'Ellipsis de texte appelé ThreeDots @ http://tpgblog.com/threedots

Il est beaucoup plus flexible que les approches CSS et prend en charge des comportements et des interactions personnalisables beaucoup plus avancés.

Prendre plaisir.

18
Jeremy Horn

Juste au cas où vous vous retrouveriez tous ici en 2013 - voici une approche de css pure que j'ai trouvée ici: http://css-tricks.com/snippets/css/truncate-string-with-Ellipsis/

.truncate {
  width: 250px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: Ellipsis;
}

Ça marche bien. 

18
Joseph Juhnke

Un plugin jQuery plus flexible vous permettant de conserver un élément après Ellipsis (par exemple un bouton "lire plus") et de mettre à jour onWindowResize. Cela fonctionne également autour du texte avec le balisage:

http://dotdotdot.frebsite.nl

8
Matt

le plugin jQuery trunk8 prend en charge plusieurs lignes et peut utiliser n'importe quel code html, pas seulement les caractères Ellipsis, pour le suffixe de troncature: https://github.com/rviscomi/trunk8

Démo ici: http://jrvis.com/trunk8/

8
Eliot Sykes

Il existe en fait un moyen assez simple de faire ceci en CSS exploitant le fait que IE étend cela avec des non-standards et que FF supporte :after

Vous pouvez également faire ceci dans JS si vous le souhaitez en inspectant la largeur de défilement de la cible et en la comparant à la largeur de ses parents, mais à mon humble avis, cette méthode est moins robuste. 

Edit: c'est apparemment plus développé que je ne le pensais. Le support CSS3 pourrait bientôt exister, et certaines extensions imparfaites sont disponibles pour que vous puissiez les essayer.

Ce dernier est une bonne lecture.

5
annakata

Eh bien, une solution simple, qui n’ajoute pas vraiment le "...", mais empêche le <h2> de se diviser en deux lignes, serait d’ajouter ce css: 

h2 {
    height:some_height_in_px; /* this is the height of the line */
    overflow:hidden; /* so that the second (or third, fourth, etc.)
                        line is not visible */
}

J'y ai réfléchi un peu plus, et j'ai proposé cette solution, vous devez envelopper le contenu textuel de votre balise h2 avec une autre balise (par exemple, un span) vous pouvez utiliser cette sorte de javascript pour filtrer les mots inutiles:

var elems = document.getElementById('conainter_of_h2s').
                     getElementsByTagName('h2');

    for ( var i = 0, l = elems.length; i < l; i++) {
        var span = elems.item(i).getElementsByTagName('span')[0];
        if ( span.offsetHeight > elems.item(i).offsetHeight ) {
            var text_arr = span.innerHTML.split(' ');
            for ( var j = text_arr.length - 1; j>0 ; j--) {
                delete text_arr[j];
                span.innerHTML = text_arr.join(' ') + '...';
                if ( span.offsetHeight <= 
                                        elems.item(i).offsetHeight ){
                    break;
                }
            }
        }
    }
3
Ramuns Usovs

Voici une autre solution JavaScript . Fonctionne très bien et très vite.

https://github.com/dobiatowski/jQuery.FastEllipsis

Testé sur Chrome, FF, IE sous Windows et Mac.

3
Adam Lukaszczyk

Il existe une solution pour le texte multiligne avec du css pur. Cela s'appelle line-clamp, mais cela ne fonctionne que dans les navigateurs webkit. Il y a cependant un moyen de l'imiter dans tous les navigateurs modernes (tout ce qui est plus récent que IE8.) En outre, cela ne fonctionnera que sur des fonds solides, car vous aurez besoin d'une image de fond pour masquer les derniers mots de la dernière ligne. Voici comment ça se passe:

Étant donné ce code HTML:

<p class="example" id="example-1">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

Voici le CSS:

p {
    position:relative;
    line-height:1.4em;
    height:4.2em;      /* 3 times the line-height to show 3 lines */
}
p::after {
    content:"...";
    font-weight:bold;
    position:absolute;
    bottom:0;
    right:0;
    padding:0 20px 1px 45px;
    background:url(Ellipsis_bg.png) repeat-y;
}

Ellipsis_bg.png étant une image de la même couleur que votre arrière-plan, elle ferait environ 100 pixels de large et aurait la même hauteur que votre hauteur de ligne.

Ce n'est pas très joli, car votre texte peut être coupé au milieu d'une lettre, mais il peut être utile dans certains cas.

Référence: http://www.css-101.org/articles/line-clamp/line-clamp_for_non_webkit-based_browsers.php

3
Jules Colle

J'avais fait quelque chose de similaire pour un client récemment. Voici une version de ce que j'ai fait pour eux (exemple testé dans toutes les dernières versions de navigateur sous Win Vista). Pas parfait tout au long du tableau, mais pourrait être réglé assez facilement.

Démo: http://enobrev.info/Ellipsis/

Code:

<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script>            
            google.load("jquery", "1.2.6");
            google.setOnLoadCallback(function() {
                $('.longtext').each(function() {
                    if ($(this).attr('scrollWidth') > $(this).width()) {
                        $more = $('<b class="more">&hellip;</b>');

                        // add it to the dom first, so it will have dimensions
                        $(this).append($more);

                        // now set the position
                        $more.css({
                            top: '-' + $(this).height() + 'px',
                            left: ($(this).attr('offsetWidth') - $more.attr('offsetWidth')) + 'px'
                        });
                    }
                });
            });
        </script>

        <style>
            .longtext {
                height: 20px;
                width: 300px;
                overflow: hidden;
                white-space: nowrap;
                border: 1px solid #f00;
            }

            .more {
                z-index: 10;
                position: relative;
                display: block;
                background-color: #fff;
                width: 18px;
                padding: 0 2px;
            }
        </style>
    </head>
    <body>
        <p class="longtext">This is some really long text.  This is some really long text.  This is some really long text.  This is some really long text.</p>
    </body>
</html>
3
enobrev

Ellipsis multilignes purs CSS pour contenu textuel:

.container{
    position: relative;  /* Essential */
    background-color: #bbb;  /* Essential */
    padding: 20px; /* Arbritrary */
}
.text {
    overflow: hidden;  /* Essential */
    /*text-overflow: Ellipsis; Not needed */
    line-height: 16px;  /* Essential */
    max-height: 48px; /* Multiples of line-height */
}
.Ellipsis {
    position: absolute;/* Relies on relative container */
    bottom: 20px; /* Matches container padding */
    right: 20px; /* Matches container padding */
    height: 16px; /* Matches line height */
    width: 30px; /* Arbritrary */
    background-color: inherit; /* Essential...or specify a color */
    padding-left: 8px; /* Arbritrary */
}
<div class="container">
    <div class="text">
        Lorem ipsum dolor sit amet, consectetur eu in adipiscing elit. Aliquam consectetur venenatis blandit. Praesent vehicula, libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta bibendum lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
    </div>
    <div class="Ellipsis">...</div>
</div>

Veuillez vérifier l'extrait pour un exemple en direct.

2
Jason Williams

Ceci est similaire à celui d'Alex mais le fait en temps de log au lieu de linéaire et prend un paramètre maxHeight.

jQuery.fn.Ellipsis = function(text, maxHeight) {
  var element = $(this);
  var characters = text.length;
  var step = text.length / 2;
  var newText = text;
  while (step > 0) {
    element.html(newText);
    if (element.outerHeight() <= maxHeight) {
      if (text.length == newText.length) {
        step = 0;
      } else {
        characters += step;
        newText = text.substring(0, characters);
      }
    } else {
      characters -= step;
      newText = newText.substring(0, characters);
    }
    step = parseInt(step / 2);
  }
  if (text.length > newText.length) {
    element.html(newText + "...");
    while (element.outerHeight() > maxHeight && newText.length >= 1) {
      newText = newText.substring(0, newText.length - 1);
      element.html(newText + "...");
    }
  }
};
2
Dave Aaron Smith

Il existe une solution jQuery simple de Devon Govett :

https://Gist.github.com/digulla/5796047

Pour l'utiliser, il suffit d'appeler Ellipsis () sur un objet jQuery. Par exemple:

$ ("span"). Ellipsis ();

2
BlaM

J'ai réécrit la fonction d'Alex à utiliser dans la bibliothèque MooTools. Je l'ai un peu changé en Word jump plutôt que d'ajouter l'Ellipsis au milieu d'un Word.

Element.implement({
Ellipsis: function() {
    if(this.getStyle("overflow") == "hidden") {
        var text = this.get('html');
        var multiline = this.hasClass('multiline');
        var t = this.clone()
            .setStyle('display', 'none')
            .setStyle('position', 'absolute')
            .setStyle('overflow', 'visible')
            .setStyle('width', multiline ? this.getSize().x : 'auto')
            .setStyle('height', multiline ? 'auto' : this.getSize().y)
            .inject(this, 'after');

        function height() { return t.measure(t.getSize).y > this.getSize().y; };
        function width() { return t.measure(t.getSize().x > this.getSize().x; };

        var func = multiline ? height.bind(this) : width.bind(this);

        while (text.length > 0 && func()) {
            text = text.substr(0, text.lastIndexOf(' '));
            t.set('html', text + "...");
        }

        this.set('html', t.get('html'));
        t.dispose();
    }
}
});
1
iloveitaly

J'ai été un peu surpris par le comportement du CSS cependant. 

var cssEllipsis = 
{   "width": "100%","display": "inline-block", 
"vertical-align": "middle", "white-space": "nowrap", 
"overflow": "hidden", "text-overflow": "Ellipsis" 
};

À moins que je fournis la largeur au contrôle auquel j’avais besoin de lier l’Ellipsis, je n’ai pas soutenu ma cause. Est-ce que la largeur est une propriété indispensable à ajouter ??? S'il vous plaît mettez vos pensées.

1
Premanshu

UTILISEZ LES Ellipsis ONLY CSS

<html>
<head>
<style type="text/css">
#ellipsisdiv {
    width:200px;
    white-space: nowrap;  
    overflow: hidden;  
    text-overflow: Ellipsis;  
}  
</style>
</head>
<body>
<div id="ellipsisdiv">
This content is more than 200px and see how the the Ellipsis comes at the end when the content width exceeds the div width.
</div>
</body>
</html>

* Ce code fonctionne sur la plupart des navigateurs actuels. Si vous rencontrez des problèmes avec Opera et IE (ce qui ne sera probablement pas votre cas), ajoutez-les dans le style:

-o-text-overflow: Ellipsis;  
-ms-text-overflow: Ellipsis;

* Cette fonctionnalité fait partie de CSS3. Sa syntaxe complète est la suivante:

text-overflow: clip|Ellipsis|string;
1
Robin Rizvi

Voici une bibliothèque de widgets/plugins Nice dans laquelle Ellipsis est intégré: http://www.codeitbetter.co.uk/widgets/Ellipsis/ Il vous suffit de référencer la bibliothèque et d'appeler le numéro suivant: 

<script type="text/javascript"> 
   $(document).ready(function () { 
      $(".Ellipsis_10").Ellipsis({ 
         numberOfCharacters: 10, 
         showLessText: "less", 
         showMoreText: "more" 
      }); 
   }); 
</script> 
<div class="Ellipsis_10"> 
   Some text here that's longer than 10 characters. 
</div>
1
Tim

Je ne pouvais pas trouver un script qui marchait exactement comme je le voulais, alors le mien le fut pour jQuery - de nombreuses options à définir avec davantage de chemin à parcourir :)

https://github.com/rmorse/AutoEllipsis

1
acSlater

vous pouvez le faire beaucoup plus facilement avec css seulement, par exemple: mode sass

.truncatedText {
   font-size: 0.875em;
   line-height: 1.2em;
   height: 2.4em; // 2 lines * line-height
   &:after {
      content: " ...";
   }
}

et vous avez Ellipsis;)

1
Apopii Dumitru
<html>
<head>
    <!-- By Warren E. Downs, copyright 2016.  Based loosely on a single/multiline JQuery using example by Alex,
    but optimized to avoid JQuery, to use binary search, to use CSS text-overflow: Ellipsis for end,
    and adding Marquee option as well.
    Credit: Marquee: http://jsfiddle.net/jonathansampson/xxuxd/
            JQuery version: http://stackoverflow.com/questions/536814/insert-Ellipsis-into-html-tag-if-content-too-wide
            (by Alex, http://stackoverflow.com/users/71953/alex)
            (Improved with Binary Search as suggested by StanleyH, http://stackoverflow.com/users/475848/stanleyh)
    -->
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <style>

        .single {
            overflow:hidden;
            white-space: nowrap;
            width: 10em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

        .multiline {
            overflow: hidden;
            white-space: wrap;
            width: 10em;
            height: 4.5em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

        .Marquee {
            overflow: hidden;
            width: 40em;
            padding: 10px;
            margin: 0 auto;
            border: solid 1px blue;
        }

</style>
    <script>
        var _marqueeNumber=0;
        // mode=start,end,middle
        function clipText(text, len, mode) {
            if(!mode) { mode="end"; }
            else { mode=mode.toLowerCase(); }
            if(mode == "start") { return "&hellip;"+clipText(text,len,"_start"); }
            if(mode == "_start") { return text.substr(text.length - len); }
            if(mode == "middle") { 
                return clipText(text, len/2, "end") + clipText(text, len/2, "_start");
            }
            return text.substr(0, len) + "&hellip;";
        }

        function generateKeyframes(clsName, start, end) {
            var sec=5;
            var totalLen=parseFloat(start)-parseFloat(end);
            if(start.indexOf('em') > -1)      { sec=Math.round(totalLen/3); }
            else if(start.indexOf('px') > -1) { sec=Math.round(totalLen/42); }

            var style = document.createElement('style');
            style.type = 'text/css';
            style.innerHTML = 'body {}';
            document.getElementsByTagName('head')[0].appendChild(style);
            this.stylesheet = document.styleSheets[document.styleSheets.length-1];
            try {
                this.stylesheet.insertRule('.'+clsName+' {\n'+
                    '    animation: '+clsName+' '+sec+'s linear infinite;\n'+
                    '}\n', this.stylesheet.rules.length);
                this.stylesheet.insertRule('.'+clsName+':hover {\n'+
                    '    animation-play-state: paused\n'+
                    '}\n', this.stylesheet.rules.length);
                this.stylesheet.insertRule('@keyframes '+clsName+' {\n'+
                    '    0%   { text-indent: '+start+' }\n'+
                    '    100% { text-indent: '+end+' }\n'+
                    '}', this.stylesheet.rules.length);
            } catch (e) {
                console.log(e.message);
            }
        }

        function addClone(el, multiline, estyle) {
            if(!estyle) { 
                try { estyle=window.getComputedStyle(el); }
                catch(e) { return null; }
            }
            var t = el.cloneNode(true);
            var s=t.style;
            //s.display='none';
            s.visibility='hidden'; // WARNING: Infinite loop if this is not hidden (e.g. while testing)
            s.display='inline-block';
            s.background='black';
            s.color='white';
            s.position='absolute';
            s.left=0;
            s.top=0;
            s.overflow='visible';
            s.width=(multiline ? parseFloat(estyle.width) : 'auto');
            s.height=(multiline ? 'auto' : parseFloat(estyle.height));

            el.parentNode.insertBefore(t, el.nextSibling);

            return t;
        }
        function getTextWidth(el, multiline) {
            var t=addClone(el, multiline);
            if(!t) { return null; }
            var ts=window.getComputedStyle(t);
            var w=ts.width;
            if(multiline) {
                var es=window.getComputedStyle(el);
                var lines=Math.round(parseInt(ts.height)/parseInt(es.height))*2+0.5;
                w=w+'';
                var unit=''; // Extract unit
                for(var xa=0; xa<w.length; xa++) {
                    var c=w[xa];
                    if(c <= '0' || c >= '9') { unit=w.substr(xa-1); }
                }
                w=parseFloat(w);
                w*=lines; // Multiply by lines
                w+=unit; // Append unit again
            }
            t.parentNode.removeChild(t);
            return w;
        }

        // cls=class of element to ellipsize
        // mode=start,end,middle,marq (scrolling Marquee instead of clip)
        function Ellipsis(cls, mode) {
            mode=mode.toLowerCase();
            var elems=document.getElementsByClassName(cls);
            for(xa in elems) {
                var el=elems[xa];
                var multiline = el.className ? el.className.indexOf('multiline') > -1 : true;
                if(mode == "marq") {       
                    var w=getTextWidth(el, multiline);
                    if(!w) { continue; }
                    var mCls="dsmarquee"+(_marqueeNumber++);
                    var es=window.getComputedStyle(el);
                    generateKeyframes(mCls,es.width, '-'+w);
                    el.className+=" "+mCls; 
                    continue; 
                }
                if(mode == "end" && !multiline) { el.style.textOverflow="Ellipsis"; continue; }
                var estyle=null;
                try { estyle=window.getComputedStyle(el); }
                catch(e) { continue; }
                if(estyle.overflow == "hidden") {
                    var text = el.innerHTML;
                    var t=addClone(el, multiline, estyle);

                    function height() {
                        var ts=window.getComputedStyle(t);
                        var es=window.getComputedStyle(el);
                        return parseFloat(ts.height) - parseFloat(es.height); 
                    }
                    function width() { 
                        var ts=window.getComputedStyle(t);
                        var es=window.getComputedStyle(el);
                        return parseFloat(ts.width) - parseFloat(es.width); 
                    }

                    var tooLong = multiline ? height : width;

                    var len=text.length;
                    var diff=1;
                    var olen=0;
                    var jump=len/2;
                    while (len > 0) {
                        var diff=tooLong();
                        if(diff > 0) { len-=jump; jump/=2; }
                        else if(diff < 0) { len+=jump; }
                        len=Math.round(len);
                        //alert('len='+len+';olen='+olen+';diff='+diff+';jump='+jump+';t='+JSON.stringify(t.innerHTML));
                        t.innerHTML=clipText(text, len, mode);
                        if(olen == len) { break; }
                        olen=len;
                    }
                    el.innerHTML=t.innerHTML;
                    t.parentNode.removeChild(t);
                }           
                //break;
                t.style.visibility='hidden';
            }
        }

        function testHarness() {
            Ellipsis('Ellipsis1', 'start'); 
            Ellipsis('Ellipsis2', 'end'); 
            Ellipsis('Ellipsis3', 'middle'); 
            Ellipsis('Marquee', 'marq')
        }
    </script>
    </head>
    <body onload="testHarness()">
    <div class="single Ellipsis1" style="float:left">some long text that should be clipped left</div>
    <div class="single Ellipsis2" style="float:right">right clip long text that should be clipped</div>
    <div class="single Ellipsis3" style="float:center">some long text that should be clipped in the middle</div>

    <br />

    <p class="single Marquee">Windows 8 and Windows RT are focused on your life—your friends and family, your apps, and your stuff. With new things like the <a href="http://windows.Microsoft.com/en-US/windows-8/start-screen">Start screen</a>, <a href="http://windows.Microsoft.com/en-US/windows-8/charms">charms</a>, and a <a href="http://windows.Microsoft.com/en-US/windows-8/Microsoft-account">Microsoft account</a>, you can spend less time searching and more time doing.</p>
    &nbsp;

    <br />

    <div class="multiline Ellipsis1" style="float:left">Test test test test test test, some more long text, such as asdasdasdasdasd, that should be multiline clipped left(*)</div>

    <div class="multiline Ellipsis2" style="float:right">right clip multiline long text, such as Test test test test test test, and some more long text that should be multiline clipped right.</div>

    <div class="multiline Ellipsis3" style="float:center">Test test test test test test, some more long text, such as asdasdasdasdasd, that should be multiline clipped in the middle(*)</div>

    <br />

    <p class="multiline Marquee">Multiline Marquee: Windows 8 and Windows RT are focused on your life—your friends and family, your apps, and your stuff. With new things like the <a href="http://windows.Microsoft.com/en-US/windows-8/start-screen">Start screen</a>, <a href="http://windows.Microsoft.com/en-US/windows-8/charms">charms</a>, and a <a href="http://windows.Microsoft.com/en-US/windows-8/Microsoft-account">Microsoft account</a>, you can spend less time searching and more time doing.</p>
    &nbsp;

    </body>
</html>
0
Warren Downs