// cliptext.js - Animation class to show/hide a block of text.
// animates the action by clipping the text to shorter/longer parts of the full text
//
// This class assumes that its safe to clip the region at any point
// other than inside a link tag <a> thus the content must not contain
// other html tags like <p></p> or <b></b> as the clipping may split
// inside a tag.  This is by design.
// 
// usage:
//    var clip = new Animation.ClipText({
//        id: "blockToClip", 
//        size: 240, 
//        buttonOpen: "Expand Description", 
//        buttonClose: "Collapse Description"
//    });

if (typeof Animation == "undefined") { var Animation = new Object(); }
Animation.ClipText = Class.create();
    
Animation.ClipText.prototype = {

    initialize: function(params) {

        this.options = Object.extend({
          id: "cliptext",    // object to clip/expand
          buttonOpen:  null, // what text to put in expand/collapse button - must be text, not html
          buttonClose: null,
          size: 80           // number of characters to attempt to clip at if not set in options
        },params || {});

        var el = $(this.options.id);

        this.expanded = false;

        this.collapseText = "";            // text block when its fully clipped
        this.expandedText = el.innerHTML;  // text block when its fully expanded

        this.currentText  = "";            // text while animating
        this.textArray    = new Array();   // array of words of full text

        this.clipIndex   = 0;              // ideal index in word array to clip
        this.currentClip = this.clipIndex; // clip position while animating

        this.animating = "";               // are we idle, animating up (collapse), or animating down (expand)

        this.timer = null;                 // holder for animation timer

        // if the clip setting is less than the length, then just bail out
        if (this.expandedText.length <= this.options.size) {
            return;
        }

        // gather text into textArray of the words
        var text = this.expandedText.split(" ");

        var notInsideTag = 0;
        var totalText = text.length;
        for (var i=0; i< totalText; i++) {
           var word = text[i].strip();

           if (notInsideTag) { 

               var wordindex = this.textArray.length - 1;
               if (wordindex < 0) { wordindex = 0; } // hack hack
               if (this.textArray[wordindex]) { 
                   this.textArray[wordindex] += (" " + word);
               } else {
                   this.textArray[wordindex] = word;
               }
                   
           } else { 
               this.textArray[this.textArray.length] = word;
           }

           // group links into a single "word"
           if (word.toLowerCase().include("<a")) { 
               notInsideTag++;
           }
           if (word.toLowerCase().include("</a>")) { 
               notInsideTag--;
           }

        }

        // measure array for where to clip it
        var chars = 0;
        while (chars < this.options.size) {
            try { 
                var word = this.textArray[this.clipIndex].stripTags();  // only measure words, not tags
                chars += word.length + 1; // add one for the space we've removed when measuring the length
            } catch(err) {
                chars = this.options.size;
                return;
            }
            this.clipIndex++;
        }

        // build clipped version w/ "..." at end
        this.collapseText = this.textArray.slice(0,this.clipIndex).join(" ");
        if (this.textArray[this.clipIndex - 1].search(/\.$/) == -1) { 
           this.collapseText += " ... ";
        } 

        // clip the text
        el.innerHTML = this.collapseText;

        // add button to toggle the state
        this.button = document.createElement("div");
        this.button.className = "clipTextButton clipTextClosed";
        Element.extend(this.button);

        if (this.options.buttonOpen) { 
            Element.update(this.button, this.options.buttonOpen);
        } else { 
            Element.update(this.button, " Expand ");
        }

        el.parentNode.insertBefore(this.button, el.nextSibling);
        Event.observe(this.button, "click", this.toggleClip.bindAsEventListener(this), false);

    },

    setCurrentText: function() { 
        var el = $(this.options.id);

        if (this.animating == "expand") { 
            if (this.currentClip >= this.textArray.length) {

                this.animating = "";
                clearInterval(this.timer);
                this.expanded = true;

                var sp = new Element("span");
                if (this.options.buttonClose) { 
                    sp.update(this.options.buttonClose);
                } else { 
                    sp.update(" Collapse ");
                }
                this.button.update(sp);

                el.innerHTML = this.expandedText;
                Element.removeClassName(this.button, "clipTextClosed");
                Element.addClassName(this.button, "clipTextOpen");

                return;

            } else { 
                this.currentClip += parseInt((this.textArray.length - this.currentClip) / 4) + 2;
            }
        } else {
            if (this.currentClip <= this.clipIndex) {
                this.animating = "";
                clearInterval(this.timer);
                this.expanded = false;

                var sp = new Element("span");
                if (this.options.buttonOpen) { 
                    sp.update(this.options.buttonOpen);
                } else { 
                    sp.update(" Expand ");
                }
                this.button.update(sp);

                el.innerHTML = this.collapseText;
                Element.removeClassName(this.button, "clipTextOpen");
                Element.addClassName(this.button, "clipTextClosed");

                return;

            } else { 
                this.currentClip -= parseInt((this.currentClip - this.clipIndex) / 4) + 2;
            }

        }

        this.currentText = this.textArray.slice(0,this.currentClip).join(" ");

        if (!this.expanded) {
            try { 
                if (this.textArray[this.currentClip - 1].search(/\.$/) == -1) { 
                    this.currentText += " ... ";
                } 
            } catch(err) { }
        }

        el.innerHTML = this.currentText;

    },

    toggleClip: function() {
        var el = $(this.options.id);

        if (this.animating == "") { 
            if (this.expanded) { 
                this.currentClip = this.textArray.length;
                this.animating = "collapse";
                this.timer = setInterval(this.setCurrentText.bindAsEventListener(this), 25);
            } else {
                this.currentClip = this.clipIndex;
                this.animating = "expand";
                this.timer = setInterval(this.setCurrentText.bindAsEventListener(this), 25);
            }
        }
    }

}


if (typeof Animation == "undefined") { var Animation = new Object(); }
Animation.BlindShowHide = Class.create();
    
Animation.BlindShowHide.prototype = {

    initialize: function(params) {

        this.options = Object.extend({
          clickEl: null,           // element to hook click event handler to
          clickElClass: "active",  // class to set on click target when open
          targetEl: null,          // element to show/hide when clickEl is clicked
          targetElClass: "active"  // class to set on hide/show when open
        },params || {});

        if (!this.options.clickEl || !this.options.targetEl) { return };

        this.options.clickEl.style.cursor = "pointer";
        Event.observe(this.options.clickEl, "click", this.toggle.bindAsEventListener(this), false);        

    },

    toggle: function() {
        var targetEl = this.options.targetEl;
        var clickEl = this.options.clickEl;

        if (!targetEl || !targetEl.style) return;
        if (targetEl.style.display == "none") { 
            new Effect.BlindDown(targetEl, {duration: 0.5, transition: Effect.Transitions.sinoidal}); 
            targetEl.addClassName(this.options.targetElClass);
            clickEl.addClassName(this.options.clickElClass);
        } else { 
            new Effect.BlindUp(targetEl, {duration: 0.5, transition: Effect.Transitions.sinoidal});
            targetEl.removeClassName(this.options.targetElClass);
            clickEl.removeClassName(this.options.clickElClass);
        }
    }

}

