Native.implement([Element], {
	grow: function() {
		if (this.tagName != 'TEXTAREA') return null;
		new Grow(this, this.retrieve('grow'));
		return this;
	}
});
String.implement({
	nl2br: function() {
		return this.replace(/\n/g, '<br />');
	}
});

var Grow = new Class({
	Implements: Options,
		
	options: {
	},
	
	initialize: function(element, options) {
		this.element = element;
		this.setOptions(options);
		this.prepare();
		this.attach();
	},
	
	prepare: function() {
		this.hidden = new Element('div', {
			styles: {
				'visibility': 'hidden',
				'clear': 'both',
				'top': 0,
				'left': 0,
				'width': this.element.getSize().x,
				'padding': this.element.getStyle('padding'),
				'border-top': this.element.getStyle('border-top'), // Had to separate the border declarations, thanks to IE
				'border-right': this.element.getStyle('border-right'),
				'border-bottom': this.element.getStyle('border-bottom'),
				'border-left': this.element.getStyle('border-left'),
				'line-height': this.element.getStyle('line-height'),
				'font-size': this.element.getStyle('font-size'),
				'font-spacing': this.element.getStyle('font-spacing'),
				'text-indent': this.element.getStyle('text-indent'),
				'word-wrap': this.element.getStyle('word-wrap')
			}
		}).inject(document.body);
		
		this.resize();
	},
	
	attach: function() {
		this.element.addEvent('keyup', this.resize.bind(this));
	},
	
	resize: function() {
		this.hidden.innerHTML = this.element.get('value').nl2br() + 'm<br />m'; // String appended avoids scroll bars
		var hiddenHeight = this.hidden.getSize().y;
		var minHeight = this.element.getStyle('min-height').toInt();
		
		if (this.element.getSize().x != hiddenHeight && hiddenHeight >= minHeight);
			this.element.setStyle('height', hiddenHeight);
	}
});


