codefordayton/metroparks-tribute

View on GitHub
tribute_files/dotdot.js

Summary

Maintainability
F
4 days
Test Coverage
/*
 *    jQuery dotdotdot 1.7.4
 *
 *    Copyright (c) Fred Heusschen
 *    www.frebsite.nl
 *
 *    Plugin website:
 *    dotdotdot.frebsite.nl
 *
 *    Licensed under the MIT license.
 *    http://en.wikipedia.org/wiki/MIT_License
 */

(function( $, undef )
{
    if ( $.fn.dotdotdot )
    {
        return;
    }

    $.fn.dotdotdot = function( o )
    {
        if ( this.length == 0 )
        {
            $.fn.dotdotdot.debug( 'No element found for "' + this.selector + '".' );
            return this;
        }
        if ( this.length > 1 )
        {
            return this.each(
                function()
                {
                    $(this).dotdotdot( o );
                }
            );
        }


        var $dot = this;
        var orgContent    = $dot.contents();

        if ( $dot.data( 'dotdotdot' ) )
        {
            $dot.trigger( 'destroy.dot' );
        }

        $dot.data( 'dotdotdot-style', $dot.attr( 'style' ) || '' );
        $dot.css( 'word-wrap', 'break-word' );
        if ($dot.css( 'white-space' ) === 'nowrap')
        {
            $dot.css( 'white-space', 'normal' );
        }

        $dot.bind_events = function()
        {
            $dot.bind(
                'update.dot',
                function( e, c )
                {
                    $dot.removeClass("is-truncated");
                    e.preventDefault();
                    e.stopPropagation();

                    switch( typeof opts.height )
                    {
                        case 'number':
                            opts.maxHeight = opts.height;
                            break;

                        case 'function':
                            opts.maxHeight = opts.height.call( $dot[ 0 ] );
                            break;

                        default:
                            opts.maxHeight = getTrueInnerHeight( $dot );
                            break;
                    }

                    opts.maxHeight += opts.tolerance;

                    if ( typeof c != 'undefined' )
                    {
                        if ( typeof c == 'string' || ('nodeType' in c && c.nodeType === 1) )
                        {
                             c = $('<div />').append( c ).contents();
                        }
                        if ( c instanceof $ )
                        {
                            orgContent = c;
                        }
                    }

                    $inr = $dot.wrapInner( '<div class="dotdotdot" />' ).children();
                    $inr.contents()
                        .detach()
                        .end()
                        .append( orgContent.clone( true ) )
                        .find( 'br' )
                        .replaceWith( '  <br />  ' )
                        .end()
                        .css({
                            'height'    : 'auto',
                            'width'        : 'auto',
                            'border'    : 'none',
                            'padding'    : 0,
                            'margin'    : 0
                        });

                    var after = false,
                        trunc = false;

                    if ( conf.afterElement )
                    {
                        after = conf.afterElement.clone( true );
                        after.show();
                        conf.afterElement.detach();
                    }

                    if ( test( $inr, opts ) )
                    {
                        if ( opts.wrap == 'children' )
                        {
                            trunc = children( $inr, opts, after );
                        }
                        else
                        {
                            trunc = ellipsis( $inr, $dot, $inr, opts, after );
                        }
                    }
                    $inr.replaceWith( $inr.contents() );
                    $inr = null;

                    if ( $.isFunction( opts.callback ) )
                    {
                        opts.callback.call( $dot[ 0 ], trunc, orgContent );
                    }

                    conf.isTruncated = trunc;
                    return trunc;
                }

            ).bind(
                'isTruncated.dot',
                function( e, fn )
                {
                    e.preventDefault();
                    e.stopPropagation();

                    if ( typeof fn == 'function' )
                    {
                        fn.call( $dot[ 0 ], conf.isTruncated );
                    }
                    return conf.isTruncated;
                }

            ).bind(
                'originalContent.dot',
                function( e, fn )
                {
                    e.preventDefault();
                    e.stopPropagation();

                    if ( typeof fn == 'function' )
                    {
                        fn.call( $dot[ 0 ], orgContent );
                    }
                    return orgContent;
                }

            ).bind(
                'destroy.dot',
                function( e )
                {
                    e.preventDefault();
                    e.stopPropagation();

                    $dot.unwatch()
                        .unbind_events()
                        .contents()
                        .detach()
                        .end()
                        .append( orgContent )
                        .attr( 'style', $dot.data( 'dotdotdot-style' ) || '' )
                        .data( 'dotdotdot', false );
                }
            );
            return $dot;
        };    //    /bind_events

        $dot.unbind_events = function()
        {
            $dot.unbind('.dot');
            return $dot;
        };    //    /unbind_events

        $dot.watch = function()
        {
            $dot.unwatch();
            if ( opts.watch == 'window' )
            {
                var $window = $(window),
                    _wWidth = $window.width(),
                    _wHeight = $window.height();

                $window.bind(
                    'resize.dot' + conf.dotId,
                    function()
                    {
                        if ( _wWidth != $window.width() || _wHeight != $window.height() || !opts.windowResizeFix )
                        {
                            _wWidth = $window.width();
                            _wHeight = $window.height();

                            if ( watchInt )
                            {
                                clearInterval( watchInt );
                            }
                            watchInt = setTimeout(
                                function()
                                {
                                    $dot.trigger( 'update.dot' );
                                }, 100
                            );
                        }
                    }
                );
            }
            else
            {
                watchOrg = getSizes( $dot );
                watchInt = setInterval(
                    function()
                    {
                        if ( $dot.is( ':visible' ) )
                        {
                            var watchNew = getSizes( $dot );
                            if ( watchOrg.width  != watchNew.width ||
                                 watchOrg.height != watchNew.height )
                            {
                                $dot.trigger( 'update.dot' );
                                watchOrg = watchNew;
                            }
                        }
                    }, 500
                );
            }
            return $dot;
        };
        $dot.unwatch = function()
        {
            $(window).unbind( 'resize.dot' + conf.dotId );
            if ( watchInt )
            {
                clearInterval( watchInt );
            }
            return $dot;
        };

        var    opts         = $.extend( true, {}, $.fn.dotdotdot.defaults, o ),
            conf        = {},
            watchOrg    = {},
            watchInt    = null,
            $inr        = null;


        if ( !( opts.lastCharacter.remove instanceof Array ) )
        {
            opts.lastCharacter.remove = $.fn.dotdotdot.defaultArrays.lastCharacter.remove;
        }
        if ( !( opts.lastCharacter.noEllipsis instanceof Array ) )
        {
            opts.lastCharacter.noEllipsis = $.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis;
        }


        conf.afterElement    = getElement( opts.after, $dot );
        conf.isTruncated    = false;
        conf.dotId            = dotId++;


        $dot.data( 'dotdotdot', true )
            .bind_events()
            .trigger( 'update.dot' );

        if ( opts.watch )
        {
            $dot.watch();
        }

        return $dot;
    };


    //    public
    $.fn.dotdotdot.defaults = {
        'ellipsis'            : '... ',
        'wrap'                : 'word',
        'fallbackToLetter'    : true,
        'lastCharacter'        : {},
        'tolerance'            : 0,
        'callback'            : null,
        'after'                : null,
        'height'            : null,
        'watch'                : false,
        'windowResizeFix'    : true
    };
    $.fn.dotdotdot.defaultArrays = {
        'lastCharacter'        : {
            'remove'            : [ ' ', '\u3000', ',', ';', '.', '!', '?' ],
            'noEllipsis'        : []
        }
    };
    $.fn.dotdotdot.debug = function( msg ) {};


    //    private
    var dotId = 1;

    function children( $elem, o, after )
    {
        var $elements     = $elem.children(),
            isTruncated    = false;

        $elem.empty();

        for ( var a = 0, l = $elements.length; a < l; a++ )
        {
            var $e = $elements.eq( a );
            $elem.append( $e );
            if ( after )
            {
                $elem.append( after );
            }
            if ( test( $elem, o ) )
            {
                $e.remove();
                isTruncated = true;
                break;
            }
            else
            {
                if ( after )
                {
                    after.detach();
                }
            }
        }
        return isTruncated;
    }
    function ellipsis( $elem, $d, $i, o, after )
    {
        var isTruncated    = false;

        //    Don't put the ellipsis directly inside these elements
        var notx = 'a, table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style';

        //    Don't remove these elements even if they are after the ellipsis
        var noty = 'script, .dotdotdot-keep';

        $elem
            .contents()
            .detach()
            .each(
                function()
                {

                    var e    = this,
                        $e    = $(e);

                    if ( typeof e == 'undefined' )
                    {
                        return true;
                    }
                    else if ( $e.is( noty ) )
                    {
                        $elem.append( $e );
                    }
                    else if ( isTruncated )
                    {
                        return true;
                    }
                    else
                    {
                        $elem.append( $e );
                        if ( after && !$e.is( o.after ) && !$e.find( o.after ).length  )
                        {
                            $elem[ $elem.is( notx ) ? 'after' : 'append' ]( after );
                        }
                        if ( test( $i, o ) )
                        {
                            if ( e.nodeType == 3 ) // node is TEXT
                            {
                                isTruncated = ellipsisElement( $e, $d, $i, o, after );
                            }
                            else
                            {
                                isTruncated = ellipsis( $e, $d, $i, o, after );
                            }
                        }

                        if ( !isTruncated )
                        {
                            if ( after )
                            {
                                after.detach();
                            }
                        }
                    }
                }
            );
        $d.addClass("is-truncated");
        return isTruncated;
    }
    function ellipsisElement( $e, $d, $i, o, after )
    {
        var e = $e[ 0 ];

        if ( !e )
        {
            return false;
        }

        var txt            = getTextContent( e ),
            space        = ( txt.indexOf(' ') !== -1 ) ? ' ' : '\u3000',
            separator    = ( o.wrap == 'letter' ) ? '' : space,
            textArr        = txt.split( separator ),
            position     = -1,
            midPos        = -1,
            startPos    = 0,
            endPos        = textArr.length - 1;


        //    Only one word
        if ( o.fallbackToLetter && startPos == 0 && endPos == 0 )
        {
            separator    = '';
            textArr        = txt.split( separator );
            endPos        = textArr.length - 1;
        }

        while ( startPos <= endPos && !( startPos == 0 && endPos == 0 ) )
        {
            var m = Math.floor( ( startPos + endPos ) / 2 );
            if ( m == midPos )
            {
                break;
            }
            midPos = m;

            setTextContent( e, textArr.slice( 0, midPos + 1 ).join( separator ) + o.ellipsis );
            $i.children()
                .each(
                    function()
                    {
                        $(this).toggle().toggle();
                    }
                );

            if ( !test( $i, o ) )
            {
                position = midPos;
                startPos = midPos;
            }
            else
            {
                endPos = midPos;

                //    Fallback to letter
                if (o.fallbackToLetter && startPos == 0 && endPos == 0 )
                {
                    separator    = '';
                    textArr        = textArr[ 0 ].split( separator );
                    position    = -1;
                    midPos        = -1;
                    startPos    = 0;
                    endPos        = textArr.length - 1;
                }
            }
        }

        if ( position != -1 && !( textArr.length == 1 && textArr[ 0 ].length == 0 ) )
        {
            txt = addEllipsis( textArr.slice( 0, position + 1 ).join( separator ), o );
            setTextContent( e, txt );
        }
        else
        {
            var $w = $e.parent();
            $e.detach();

            var afterLength = ( after && after.closest($w).length ) ? after.length : 0;

            if ( $w.contents().length > afterLength )
            {
                e = findLastTextNode( $w.contents().eq( -1 - afterLength ), $d );
            }
            else
            {
                e = findLastTextNode( $w, $d, true );
                if ( !afterLength )
                {
                    $w.detach();
                }
            }
            if ( e )
            {
                txt = addEllipsis( getTextContent( e ), o );
                setTextContent( e, txt );
                if ( afterLength && after )
                {
                    $(e).parent().append( after );
                }
            }
        }

        return true;
    }
    function test( $i, o )
    {
        return $i.innerHeight() > o.maxHeight;
    }
    function addEllipsis( txt, o )
    {
        while( $.inArray( txt.slice( -1 ), o.lastCharacter.remove ) > -1 )
        {
            txt = txt.slice( 0, -1 );
        }
        if ( $.inArray( txt.slice( -1 ), o.lastCharacter.noEllipsis ) < 0 )
        {
            txt += o.ellipsis;
        }
        return txt;
    }
    function getSizes( $d )
    {
        return {
            'width'    : $d.innerWidth(),
            'height': $d.innerHeight()
        };
    }
    function setTextContent( e, content )
    {
        if ( e.innerText )
        {
            e.innerText = content;
        }
        else if ( e.nodeValue )
        {
            e.nodeValue = content;
        }
        else if (e.textContent)
        {
            e.textContent = content;
        }

    }
    function getTextContent( e )
    {
        if ( e.innerText )
        {
            return e.innerText;
        }
        else if ( e.nodeValue )
        {
            return e.nodeValue;
        }
        else if ( e.textContent )
        {
            return e.textContent;
        }
        else
        {
            return "";
        }
    }
    function getPrevNode( n )
    {
        do
        {
            n = n.previousSibling;
        }
        while ( n && n.nodeType !== 1 && n.nodeType !== 3 );

        return n;
    }
    function findLastTextNode( $el, $top, excludeCurrent )
    {
        var e = $el && $el[ 0 ], p;
        if ( e )
        {
            if ( !excludeCurrent )
            {
                if ( e.nodeType === 3 )
                {
                    return e;
                }
                if ( $.trim( $el.text() ) )
                {
                    return findLastTextNode( $el.contents().last(), $top );
                }
            }
            p = getPrevNode( e );
            while ( !p )
            {
                $el = $el.parent();
                if ( $el.is( $top ) || !$el.length )
                {
                    return false;
                }
                p = getPrevNode( $el[0] );
            }
            if ( p )
            {
                return findLastTextNode( $(p), $top );
            }
        }
        return false;
    }
    function getElement( e, $i )
    {
        if ( !e )
        {
            return false;
        }
        if ( typeof e === 'string' )
        {
            e = $(e, $i);
            return ( e.length )
                ? e
                : false;
        }
        return !e.jquery
            ? false
            : e;
    }
    function getTrueInnerHeight( $el )
    {
        var h = $el.innerHeight(),
            a = [ 'paddingTop', 'paddingBottom' ];

        for ( var z = 0, l = a.length; z < l; z++ )
        {
            var m = parseInt( $el.css( a[ z ] ), 10 );
            if ( isNaN( m ) )
            {
                m = 0;
            }
            h -= m;
        }
        return h;
    }


    //    override jQuery.html
    var _orgHtml = $.fn.html;
    $.fn.html = function( str )
    {
        if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) )
        {
            return this.trigger( 'update', [ str ] );
        }
        return _orgHtml.apply( this, arguments );
    };


    //    override jQuery.text
    var _orgText = $.fn.text;
    $.fn.text = function( str )
    {
        if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) )
        {
            str = $( '<div />' ).text( str ).html();
            return this.trigger( 'update', [ str ] );
        }
        return _orgText.apply( this, arguments );
    };


})( jQuery );