Created
November 20, 2014 14:54
-
-
Save DimitarChristoff/afebbba65245d0cd5818 to your computer and use it in GitHub Desktop.
Dynamic Textarea plugin for mootools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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