/*
* jQuery Expander plugin
* Version 0.4  (12/09/2008)
* @requires jQuery v1.1.1+
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/


(function ($) {

    $.fn.expander = function (options) {

        var opts = $.extend({}, $.fn.expander.defaults, options);
        var delayedCollapse;
        return this.each(function () {
            var $this = $(this);
            var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
            var cleanedTag, startTags, endTags;
            var allText = $this.html();
            var startText = allText.slice(0, o.slicePoint).replace(/\w+$/, '');
            startTags = startText.match(/<\w[^>]*>/g);
            if (startTags) { startText = allText.slice(0, o.slicePoint + startTags.join('').length).replace(/\w+$/, ''); }

            if (startText.lastIndexOf('<') > startText.lastIndexOf('>')) {
                startText = startText.slice(0, startText.lastIndexOf('<'));
            }
            var endText = allText.slice(startText.length);
            // create necessary expand/collapse elements if they don't already exist
            if (!$('span.details', this).length) {
                // end script if text length isn't long enough.
                if (endText.replace(/\s+$/, '').split(' ').length < o.widow) { return; }
                // otherwise, continue...    
                if (endText.indexOf('</') > -1) {
                    endTags = endText.match(/<(\/)?[^>]*>/g);
                    for (var i = 0; i < endTags.length; i++) {

                        if (endTags[i].indexOf('</') > -1) {
                            var startTag, startTagExists = false;
                            for (var j = 0; j < i; j++) {
                                startTag = endTags[j].slice(0, endTags[j].indexOf(' ')).replace(/(\w)$/, '$1>');
                                if (startTag == rSlash(endTags[i])) {
                                    startTagExists = true;
                                }
                            }
                            if (!startTagExists) {
                                startText = startText + endTags[i];
                                var matched = false;
                                for (var s = startTags.length - 1; s >= 0; s--) {
                                    if (startTags[s].slice(0, startTags[s].indexOf(' ')).replace(/(\w)$/, '$1>') == rSlash(endTags[i])
                  && matched == false) {
                                        cleanedTag = cleanedTag ? startTags[s] + cleanedTag : startTags[s];
                                        matched = true;
                                    }
                                };
                            }
                        }
                    }

                    endText = cleanedTag && cleanedTag + endText || endText;
                }
                $this.html([
     		startText,
     		'<span class="read-more">',
     		o.expandPrefix,
       		'<a href="#">',
       		  o.expandText,
       		'</a>',
        '</span>',
     		'<span class="details">',
     		  endText,
     		'</span>'
     		].join('')
     	  );
            }
            var $thisDetails = $('span.details', this),
        $readMore = $('span.read-more', this);
            $thisDetails.hide();
            $readMore.find('a').click(function () {
                $readMore.hide();

                if (o.expandEffect === 'show' && !o.expandSpeed) {
                    o.beforeExpand($this);
                    $thisDetails.show();
                    o.afterExpand($this);
                    delayCollapse(o, $thisDetails);
                } else {
                    o.beforeExpand($this);
                    $thisDetails[o.expandEffect](o.expandSpeed, function () {
                        $thisDetails.css({ zoom: '' });
                        o.afterExpand($this);
                        delayCollapse(o, $thisDetails);
                    });
                }
                return false;
            });
            if (o.userCollapse) {
                $this
        .find('span.details').append('<span class="re-collapse">' + o.userCollapsePrefix + '<a href="#">' + o.userCollapseText + '</a></span>');
                $this.find('span.re-collapse a').click(function () {

                    clearTimeout(delayedCollapse);
                    var $detailsCollapsed = $(this).parents('span.details');
                    reCollapse($detailsCollapsed);
                    o.onCollapse($this, true);
                    return false;
                });
            }
        });
        function reCollapse(el) {
            el.hide()
        .prev('span.read-more').show();
        }
        function delayCollapse(option, $collapseEl) {
            if (option.collapseTimer) {
                delayedCollapse = setTimeout(function () {
                    reCollapse($collapseEl);
                    option.onCollapse($collapseEl.parent(), false);
                },
          option.collapseTimer
        );
            }
        }
        function rSlash(rString) {
            return rString.replace(/\//, '');
        }
    };
    // plugin defaults
    $.fn.expander.defaults = {
        slicePoint: 100,  // the number of characters at which the contents will be sliced into two parts. 
        // Note: any tag names in the HTML that appear inside the sliced element before 
        // the slicePoint will be counted along with the text characters.
        widow: 4,  // a threshold of sorts for whether to initially hide/collapse part of the element's contents. 
        // If after slicing the contents in two there are fewer words in the second part than 
        // the value set by widow, we won't bother hiding/collapsing anything.
        expandText: 'read more', // text displayed in a link instead of the hidden part of the element. 
        // clicking this will expand/show the hidden/collapsed text
        expandPrefix: '&hellip; ',
        collapseTimer: 0, // number of milliseconds after text has been expanded at which to collapse the text again
        expandEffect: 'fadeIn',
        expandSpeed: '',   // speed in milliseconds of the animation effect for expanding the text
        userCollapse: true, // allow the user to re-collapse the expanded text.
        userCollapseText: '[collapse expanded text]',  // text to use for the link to re-collapse the text
        userCollapsePrefix: ' ',
        beforeExpand: function ($thisEl) { },
        afterExpand: function ($thisEl) { },
        onCollapse: function ($thisEl, byUser) { }
    };
})(jQuery);

