var Flext = new Class({
Implements: Options,
options: {
aniTime: 300, //int (ms) - grow animation time
maxHeight: 0, //int (pixels) - one way to set a max height, if you dont set it via the class.
defaultMaxHeight: 1000, //int (pixels) - if not otherwise set, this is the max height
parentDepth: 6, //int - how many levels up should to check the parent el's height.
//trigger classes:

growClass: 'growme', //string (class name)- grow the text area
enterStoppedClass: 'stopenter', //string (class name)- stop the enter key
enterSubmitsClass: 'entersubmits', //string (class name)- submit the form when enter is pressed
replaceGhostTextClass: 'replaceghosttext', //string (class name)- tries to use the ghosted text features
growParentsClass: 'growparents', //string (class name)- grow the parent elements if needed

//other attributes:
ghostTextAttr: 'ghosttext',
ghostClassAttr: 'ghostclass'
},

initialize: function(el, options) {
this.setOptions(options);

this.el = document.id(el); //the textarea element.

//by default, we will do nothing to the text area unless it has the class...
this.autoGrow = el.hasClass(this.options.growClass);
this.stopEnter = el.hasClass(this.options.enterStoppedClass);
this.enterSubmits = el.hasClass(this.options.enterSubmitsClass);
this.useGhostText = el.hasClass(this.options.replaceGhostTextClass);
this.growParents = el.hasClass(this.options.growParentsClass);

//initialize, and add events:
if(this.autoGrow) {
this.resizer = new Fx.Tween(this.el, {duration: this.options.aniTime});
this.getMaxSize();
this.reachedMax = false;
this.startSize = this.origSize = this.el.getSize().y;
this.vertPadding = this.el.getStyle('padding-top').toInt()+this.el.getStyle('padding-bottom').toInt()+this.el.getStyle('border-top').toInt()+this.el.getStyle('border-bottom').toInt();
this.el.setStyle('overflow', 'hidden');
this.el.addEvents({
'keyup': function(e) {
this.checkSize(e);
}.bind(this),

'change': function(e) {

this.checkSize(e);

}.bind(this),

'click': function(e) {

this.checkSize(e);

}.bind(this)

});



//get inital state:

this.checkSize();

}

//watch this text area: keydown

if(this.stopEnter) {

this.el.addEvent('keydown', function(e) {

if(e.key == 'enter') {

e.stop();

if(this.enterSubmits) {

this.submitForm();

}

}

}.bind(this));

}

//replace ghost text:

if(this.useGhostText) {

this.ghostText = this.el.get(this.options.ghostTextAttr);

this.ghostClass = this.el.get(this.options.ghostClassAttr);

if(this.ghostText) {

//initial states: if populated with something else, remove the class:

if(this.el.value != this.ghostText) {

this.el.removeClass(this.ghostClass);

}

//add events to watch for ghosting:

this.el.addEvents({

//remove the ghosted text when the text area receives focus

'focus': function(e) {

if(this.el.value == this.ghostText) {

this.el.set('value', '');

if(this.ghostClass) {

this.el.removeClass(this.ghostClass);

}

}

}.bind(this),

//put the ghost text back if blur'ed and its empty

'blur': function(e) {

if(this.el.value == '') {

this.el.set('value', this.ghostText);

if(this.ghostClass) {

this.el.addClass(this.ghostClass);

}

}

}.bind(this)

});

}

}



},

getMaxSize: function() {

this.maxSize = this.options.maxHeight;

if(this.maxSize == 0) {

var testmax = this.el.className.match(/maxheight-(\d*)/);

if(testmax) {

this.maxSize = testmax[1];

}

else {

this.maxSize = this.options.defaultMaxHeight; //if one forgets to set a max height via options or class, use a reasonable number.

}

}

},

checkSize: function(e) {

var theSize = this.el.getSize();

var theScrollSize = this.el.getScrollSize();

if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { var checksize = (theScrollSize.y); }

else var checksize = (theScrollSize.y+this.vertPadding);



if(checksize > theSize.y) {

//we are scrolling, so grow:

this.resizeIt(theSize, theScrollSize);

}

},

resizeIt: function(theSize, scrollSize) {

var newSize = scrollSize.y;

if((scrollSize.y+this.vertPadding) > this.maxSize && !this.reachedMax) {

//we've reached the max size, grow to max size and make textarea scrollable again:

newSize = this.maxSize;

this.el.setStyle('overflow', '');

this.resizer.start('height', newSize);

if(this.growParents) {

var increasedSize = newSize - this.startSize;

this.resizeParents(this.el, 0, increasedSize);

}

//remember that we've reached the max size:

this.reachedMax = true;

}

if(!this.reachedMax) {

//grow the text area:

var increasedSize = newSize - this.startSize;

if(increasedSize < 0) increasedSize = 0;

this.startSize = newSize;

this.resizer.start('height', newSize);

//resize parent objects if needed:

if(this.growParents) {

this.resizeParents(this.el, 0, increasedSize);

}

}

},

resizeParents: function(el, num, incSize) {

if(num < this.options.parentDepth) {

var newel = el.getParent();

if(newel) {

if(newel.style.height && newel.style.height != '' ) {

if(newel.retrieve('flextAdjusted')) {

var newheight = (newel.getStyle('height').toInt()+incSize);

} else {

newel.store('flextAdjusted', true); //when resizing parents, the first time we enlarge them we have to include vertical padding

var newheight = (newel.getStyle('height').toInt()+incSize+this.vertPadding);

}

newel.setStyle('height', newheight);

}

return this.resizeParents(newel, (num+1), incSize);

}

return true;

} else {

return true;

}

},

submitForm: function() {

var thisForm = this.el.getParent('form');

if(thisForm) {

var formName = thisForm.get('name');

document[formName].submit();



}

}

});





//watch the text areas:

window.addEvent('domready', function() {

$$('textarea.flext').each(function(el, i) {

new Flext(el);

});

});
