إدراج القطع (...) في علامة HTML إذا كان المحتوى واسع جدا

StackOverflow https://stackoverflow.com/questions/536814

سؤال

لدي صفحة ويب تحتوي على تخطيط مرن يغير عرضه إذا تم تغيير حجم نافذة المتصفح.

في هذا التخطيط هناك عناوين (h2) سيكون له طول متغير (يجري في الواقع عناوين العقائد من BlogPosts التي لا أتحكم فيها). حاليا - إذا كانت أوسع من النافذة - يتم تقسيمها إلى سطرين.

هل يوجد حل أنيق ومختبر (متصفح) - على سبيل المثال مع JQuery - الذي تقصر Innerhtml من علامة العنوان هذه وإضافة "..." إذا كان النص سيكون واسعا جدا لتناسب سطر واحد على الشاشة الحالية / عرض الحاويات؟

هل كانت مفيدة؟

المحلول

لدي حل يعمل في FF3، Safari و IE6 + مع نص واحد ومتعدد

.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);

نصائح أخرى

يعمل الحل CSS التالي فقط للنص المقترض على خط واحد يعمل مع جميع المجفئة المدرجة في http://www.caniuse.com. اعتبارا من الكتابة باستثناء Firefox 6.0. لاحظ أن JavaScript غير ضروري تماما إلا إذا كنت بحاجة إلى دعم كتابة النص المتعدد أو الإصدارات السابقة من Firefox.

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

إذا كنت بحاجة إلى دعم الإصدارات السابقة من فايرفوكس تحقق إجابتي على هذا السؤال الآخر.

لقد قمت ببناء هذا الرمز باستخدام عدد من المشاركات الأخرى، مع التحسينات التالية:

  1. يستخدم بحث ثنائي للعثور على طول النص المناسب تماما.
  2. إنه يتعامل مع الحالات التي يتم فيها إخفاء عنصر (ELLIPSIS) في البداية عن طريق إعداد حدث إظهار طلقة واحدا يقوم بإعادة تشغيل رمز القطع القطع عند عرض العنصر لأول مرة. هذا مفيد لآراء التفاصيل الرئيسية أو وجهات نظر الأشجار حيث لا يتم عرض بعض العناصر في البداية.
  3. يضيف اختياريا سمة عنوان مع النص الأصلي لتأثير الحوامات.
  4. وأضاف display: block إلى النمط، لذلك يمتد العمل
  5. يستخدم حرف القطع بدلا من 3 فترات.
  6. يعمل تلقائيا البرنامج النصي لأي شيء به.

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));

إجابتي تدعم فقط نص خط واحد. تحقق من تعليق GUFFFULLAM أدناه للشوكة متعددة الخطوط، فإنه يبدو واعدا جدا.

أعد كتابة التعليمات البرمجية من الإجابة الأولى عدة مرات، وأعتقد أن هذا يجب أن يكون الأسرع.

يجد أولا طول النص "المقدر"، ثم يضيف أو يزيل حرف حتى يكون العرض صحيحا.

يظهر استخدام المنطق الذي يستخدمه أدناه:

enter image description here

بعد العثور على طول النص "المقدر"، تتم إضافة الأحرف أو إزالتها حتى يتم الوصول إلى العرض المطلوب.

أنا متأكد من أنه يحتاج إلى بعض التغيير والتبديل، ولكن إليك الرمز:

(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);

قمت بإجراء مسافة جائق رائعة حقا للتعامل مع جميع أنواع القطع النصية من النص هي واحدة تسمى ThreeDots @ http://tpgblog.com/threedots.

إنه أكثر مرونة من نهج CSS، ويدعم المزيد من السلوكيات والتفاعلات القابلة للتخصيص أكثر تقدما.

استمتع.

فقط في حالة انتهاء صلاحية Y'all هنا في عام 2013 - فيما يلي نهج CSS نقي وجدت هنا: http://css-tricks.com/snippets/css/truncate-string-with-ellipsis/

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

أنه يعمل بشكل جيد.

مسافة جائق أكثر مرونة تمكنك من الاحتفاظ بعنصر بعد علامة القطع (على سبيل المثال زر "قراءة أكثر") وتحديث OnWindowResize. يعمل أيضا حول النص مع العلامات:

http://dotdotdot.frebsite.nl.

يدعم البرنامج المساعد JQuery Trunk8 خطوط متعددة، ويمكنه استخدام أي أحرف HTML، وليس فقط أحرف القطع المنفدة، لاحقة اقتطاع: https://github.com/rviscomi/trunk8.

تجريبي هنا: http://jrvis.com/trunk8/

هناك في الواقع طريقة واضحة جدا ل القيام بذلك في CSS استغلال حقيقة أن أي يمتد هذا مع عدم المعايير ودعم FF :after

يمكنك أيضا افعل هذا في JS إذا كنت ترغب في تفتيش عملية التمرير للهدف ومقارنتها بعرض أولياء الأمور، ولكن IMHO هذا أقل قوة.

تحرير: يبدو أن هذا أكثر تطورا أكثر مما اعتقدت. قد توجد دعم CSS3 قريبا، وبعض الإضافات غير المكتملة متاحة لك لمحاولة.

هذا الأخير هو قراءة جيدة.

لقد فعلت شيئا مشابها للعميل مؤخرا. إليك نسخة من ما فعلته لهم (مثال تم اختباره في أحدث إصدارات المتصفح على Win Vista). ليس مثاليا في جميع أنحاء اللوحة، ولكن يمكن تعديلها بسهولة.

التجريبي: http://enobrev.info/ellipsis/

رمز:

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

حسنا، حل بسيط واحد، هذا لا يضيف تماما "..."، ولكنه يمنعu003Ch2 style=";text-align:right;direction:rtl"> من الانهيار إلى سطرين سيكون لإضافة هذا القليل من 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 */
}

أعطيتها بعض الفكر أكثر، وتوصلت إلى هذا الحل، عليك أن تلتف على المحتويات النصية لعلامة H2 الخاصة بك مع علامة أخرى (مثل SPAN) (أو ملتف بدلا من فتح H2S بشيء يحتوي على ارتفاع معين) ثم يمكنك استخدام هذا النوع من JavaScript لتصفية الكلمات غير الضرورية:

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;
                }
            }
        }
    }

هنا حل جافا سكريبت آخر. يعمل بشكل جيد جدا وسريع جدا.

https://github.com/dobiatowski/jquery.ptellipsis.

تم اختباره على Chrome، FF، IE على Windows و Mac.

هناك حل للنص متعدد الخطوط مع CSS نقي. تسمى line-clamp, ، ولكن يعمل فقط في متصفحات WebKit. ومع ذلك، هناك طريقة لتقليد هذا في جميع المتصفحات الحديثة (كل شيء آخر حديثة من IE8.) أيضا، لن يعمل فقط على خلفيات صلبة لأنك تحتاج إلى صورة خلفية لإخفاء الكلمات الأخيرة من السطر الأخير. إليك كيف تسير الأمور:

بالنظر إلى هذا 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>

إليك 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 كونها صورة لنفس لون خلفيتك، والتي ستكون حوالي 100px واسعة الحجم لها نفس ارتفاع خطك.

إنها ليست جميلة جدا، حيث قد يتم تخفيض نصك في منتصف الرسالة، لكن قد يكون مفيدا في بعض الحالات.

مرجع: http://www.css-101.org/articles/line-clamp/line-clamp_for_non_webkit-based_browsers.php.

Ellipsis Pure CSS متعدد الخطوط لمحتوى النص:

.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>

يرجى الخروج من المقتطف مثال حي.

هذا مشابه أليكس ولكن يفعل ذلك في وقت السجل بدلا من الخطي، ويأخذ معلمة 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 + "...");
    }
  }
};

هناك حل مسج بسيط ديفون جوفيت:

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

لاستخدامها، ما عليك سوى الاتصال بالقولبة () على كائن مسج. علي سبيل المثال:

$ ("span"). القطع ()؛

أعد كتابة وظيفة أليكس للاستخدام إلى مكتبة Mootools. لقد غيرت ذلك قليلا إلى القفز 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();
    }
}
});

لم أستطع العثور على برنامج نصي يعمل بالضبط كما أردت ذلك فعلت ذلك في مسج الخاص بي - بعض الخيارات لتعيين أكثر في طريقهم :)

https://github.com/rmorse/autoellipsis.

لقد فوجئت بعض الشيء بسلوك CSS على الرغم من.

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

ما لم أبلغت العرض إلى التحكم الذي كنت بحاجة إليه لربط القطع القطع الذي لم يفوق قضيتي. هو عرض يجب أن تضاف الممتلكات ؟؟ يرجى وضع أفكارك.

هل ellipsis باستخدام فقط 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>

* يعمل هذا الرمز على معظم المتصفحات الحالية. إذا واجهت أي مشكلة مع Opera و IE (والتي ربما لن تفعلها)، أضف هذه في النمط:

-o-text-overflow: ellipsis;  
-ms-text-overflow: ellipsis;

* هذه الميزة هي جزء من CSS3. بناء الجملة الكامل هو:

text-overflow: clip|ellipsis|string;

فيما يلي مكتبة Widget / Plugin لطيفة والتي تم إنشاؤها في: http://www.codeitbetter.co.uk/widgets/ellipsis/ كل ما تحتاج إلى القيام به مرجع المكتبة واتصل بما يلي:

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

يمكنك القيام بذلك أسهل بكثير مع CSS فقط، على سبيل المثال: وضع SASS

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

ولديك ELLIPSIS؛)

تماما مثل LaSlater لم أستطع العثور على شيء ما كنت بحاجة إليه، فأنت توالت بنفسي. المشاركة في حالة يمكن لأي شخص آخر استخدام:

طريقة:
ellipsisIfNecessary(mystring,maxlength);
الاستعمال:
trimmedString = ellipsisIfNecessary(mystring,50);
الرمز والرابط التجريبي: https://gist.github.com/cemerson/10368014.
<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>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top