Skip to content

Instantly share code, notes, and snippets.

@DimitarChristoff
Created November 20, 2014 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DimitarChristoff/afebbba65245d0cd5818 to your computer and use it in GitHub Desktop.
Save DimitarChristoff/afebbba65245d0cd5818 to your computer and use it in GitHub Desktop.
Dynamic Textarea plugin for mootools
(function(){
'use strict';
/*
---
description: DynamicTextarea
license: MIT-style
authors:
- Amadeus Demarzi (http://amadeusamade.us)
requires:
core/1.3: [Core/Class, Core/Element, Core/Element.Event, Core/Element.Style, Core/Element.Dimensions]
provides: [DynamicTextarea]
...
*/
var DynamicTextarea = this.DynamicTextarea = new Class({
Implements: [Options, Events],
options: {
value: '',
minRows: 1,
delay: true,
lineHeight: null,
offset: 0,
padding: 0
// AVAILABLE EVENTS
// onCustomLineHeight: (function) - custom ways of determining lineHeight if necessary
// onInit: (function)
// onFocus: (function)
// onBlur: (function)
// onKeyPress: (function)
// onResize: (function)
// onEnable: (function)
// onDisable: (function)
// onClean: (function)
},
textarea: null,
initialize: function(textarea, options){
this.textarea = document.id(textarea);
if (!this.textarea) return;
this.setOptions(options);
this.parentEl = new Element('div', {
styles: {
padding: 0,
margin: 0,
border: 0,
height: 'auto',
width: 'auto'
}
})
.inject(this.textarea, 'after')
.adopt(this.textarea);
// Prebind common methods
['focus', 'delayCheck', 'blur', 'scrollFix', 'checkSize', 'clean', 'disable', 'enable', 'getLineHeight']
.each(function(method){
this[method] = this[method].bind(this);
}, this);
// Firefox and Opera handle scroll heights differently than all other browsers
if (window.Browser.firefox || window.Browser.opera){
this.options.offset =
parseInt(this.textarea.getStyle('padding-top'), 10) +
parseInt(this.textarea.getStyle('padding-bottom'), 10) +
parseInt(this.textarea.getStyle('border-bottom-width'), 10) +
parseInt(this.textarea.getStyle('border-top-width'), 10);
} else {
this.options.offset =
parseInt(this.textarea.getStyle('border-bottom-width'), 10) +
parseInt(this.textarea.getStyle('border-top-width'), 10);
this.options.padding =
parseInt(this.textarea.getStyle('padding-top'), 10) +
parseInt(this.textarea.getStyle('padding-bottom'), 10);
}
// Disable browser resize handles, set appropriate styles
this.textarea.set({
'rows': 1,
'styles': {
'resize': 'none',
'-moz-resize': 'none',
'-webkit-resize': 'none',
'position': 'relative',
'display': 'block',
'overflow': 'hidden',
'height': 'auto'
}
});
this.getLineHeight();
this.fireEvent('customLineHeight');
// Set the height of the textarea, based on content
this.checkSize(true);
this.textarea.addEvent('focus', this.focus);
this.fireEvent('init', [textarea, options]);
},
// This is the only crossbrowser method to determine ACTUAL lineHeight in a textarea (that I am aware of)
getLineHeight: function(){
var backupValue = this.textarea.get('value');
this.textarea.set('value', 'M');
this.options.lineHeight = this.textarea.getScrollSize().y - this.options.padding;
this.textarea.set('value', backupValue);
this.textarea.setStyle('height', this.options.lineHeight * this.options.minRows);
},
// Stops a small scroll jump on some browsers
scrollFix: function(){
this.textarea.scrollTo(0, 0);
},
// Add interactive events, and fire focus event
focus: function(){
this.textarea.addEvents({
'keydown': this.delayCheck,
'keypress': this.delayCheck,
'blur': this.blur,
'scroll': this.scrollFix
});
return this.fireEvent('focus');
},
// Clean out extraneaous events, and fire blur event
blur: function(){
this.textarea.removeEvents({
'keydown': this.delayCheck,
'keypress': this.delayCheck,
'blur': this.blur,
'scroll': this.scrollFix
});
return this.fireEvent('blur');
},
// Delay checkSize because text hasn't been injected into the textarea yet
delayCheck: function(){
if (this.options.delay === true)
this.options.delay = this.checkSize.delay(1);
},
// Determine if it needs to be resized or not, and resize if necessary
checkSize: function(forced){
var oldValue = this.options.value,
modifiedParent = false;
this.options.value = this.textarea.get('value');
this.options.delay = false;
if (this.options.value === oldValue && forced !== true)
return this.options.delay = true;
if (!oldValue || this.options.value.length < oldValue.length || forced){
modifiedParent = true;
this.parentEl.setStyle('height', this.parentEl.getSize().y);
this.textarea.setStyle('height', this.options.minRows * this.options.lineHeight);
}
var tempHeight = this.textarea.getScrollSize().y,
offsetHeight = this.textarea.offsetHeight,
cssHeight = tempHeight - this.options.padding,
scrollHeight = tempHeight + this.options.offset;
if (scrollHeight !== offsetHeight && cssHeight > this.options.minRows * this.options.lineHeight){
this.textarea.setStyle('height', cssHeight);
this.fireEvent('resize');
}
if (modifiedParent) this.parentEl.setStyle('height', 'auto');
this.options.delay = true;
if (forced !== true)
return this.fireEvent('keyPress');
},
// Clean out this textarea's event handlers
clean: function(){
this.textarea.removeEvents({
'focus': this.focus,
'keydown': this.delayCheck,
'keypress': this.delayCheck,
'blur': this.blur,
'scroll': this.scrollFix
});
return this.fireEvent('clean');
},
// Disable the textarea
disable: function(){
this.textarea.blur();
this.clean();
this.textarea.set(this.options.disabled, true);
return this.fireEvent('disable');
},
// Enables the textarea
enable: function(){
this.textarea.addEvents({
'focus': this.focus,
'scroll': this.scrollFix
});
this.textarea.set(this.options.disabled, false);
return this.fireEvent('enable');
}
});
}.call(this));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment