100 lines
5.0 KiB
JavaScript
100 lines
5.0 KiB
JavaScript
/* -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
*/
|
|
;(function($){
|
|
//pass in just the context as a $(obj) or a settings JS object
|
|
$.fn.autogrow = function(opts) {
|
|
var that = $(this).css({overflow: 'hidden', resize: 'none'}) //prevent scrollies
|
|
, selector = that.selector
|
|
, defaults = {
|
|
context: $(document) //what to wire events to
|
|
, animate: false //if you want the size change to animate
|
|
, speed: 200 //speed of animation
|
|
, fixMinHeight: true //if you don't want the box to shrink below its initial size
|
|
, cloneClass: 'autogrowclone' //helper CSS class for clone if you need to add special rules
|
|
, onInitialize: true //resizes the textareas when the plugin is initialized
|
|
}
|
|
;
|
|
opts = $.isPlainObject(opts) ? opts : {context: opts ? opts : $(document)};
|
|
opts = $.extend({}, defaults, opts);
|
|
that.each(function(i, elem){
|
|
var min, clone;
|
|
elem = $(elem);
|
|
//if the element is "invisible", we get an incorrect height value
|
|
//to get correct value, clone and append to the body.
|
|
if (elem.is(':visible') || parseInt(elem.css('height'), 10) > 0) {
|
|
min = parseInt(elem.css('height'), 10) || elem.innerHeight();
|
|
} else {
|
|
clone = elem.clone()
|
|
.addClass(opts.cloneClass)
|
|
.val(elem.val())
|
|
.css({
|
|
position: 'absolute'
|
|
, visibility: 'hidden'
|
|
, display: 'block'
|
|
})
|
|
;
|
|
$('body').append(clone);
|
|
min = clone.innerHeight();
|
|
clone.remove();
|
|
}
|
|
if (opts.fixMinHeight) {
|
|
elem.data('autogrow-start-height', min); //set min height
|
|
}
|
|
elem.css('height', min);
|
|
|
|
//if (opts.onInitialize) {
|
|
// resize.call(elem);
|
|
//}
|
|
});
|
|
opts.context
|
|
.on('keyup paste', selector, resize)
|
|
;
|
|
// Le code ci-dessus ne semble pas fonctionner. C'est la raison pour
|
|
// laquelle l'événement est provoqué ici. Le problème potentiel est
|
|
// que l'événement remonte toute la chaine DOM jusqu'au document.
|
|
if (opts.onInitialize) that.trigger('keyup');
|
|
|
|
function resize (e){
|
|
var box = $(this)
|
|
, oldHeight = box.innerHeight()
|
|
, newHeight = this.scrollHeight
|
|
, minHeight = box.data('autogrow-start-height') || 0
|
|
, clone
|
|
;
|
|
if (oldHeight < newHeight) { //user is typing
|
|
this.scrollTop = 0; //try to reduce the top of the content hiding for a second
|
|
opts.animate ? box.stop().animate({height: newHeight}, opts.speed) : box.innerHeight(newHeight);
|
|
} else if (!e || e.which === 8 || e.which === 46 || (e.ctrlKey && e.which === 88)) { //user is deleting, backspacing, or cutting
|
|
if (oldHeight > minHeight) { //shrink!
|
|
//this cloning part is not particularly necessary. however, it helps with animation
|
|
//since the only way to cleanly calculate where to shrink the box to is to incrementally
|
|
//reduce the height of the box until the $.innerHeight() and the scrollHeight differ.
|
|
//doing this on an exact clone to figure out the height first and then applying it to the
|
|
//actual box makes it look cleaner to the user
|
|
clone = box.clone()
|
|
.addClass(opts.cloneClass) //add clone class for extra css rules
|
|
.css({position: 'absolute', zIndex:-10}) //make "invisible"
|
|
.val(box.val()) //populate with content for consistent measuring
|
|
;
|
|
box.after(clone); //append as close to the box as possible for best CSS matching for clone
|
|
do { //reduce height until they don't match
|
|
newHeight = clone[0].scrollHeight - 1;
|
|
clone.innerHeight(newHeight);
|
|
} while (newHeight === clone[0].scrollHeight);
|
|
newHeight++; //adding one back eliminates a wiggle on deletion
|
|
clone.remove();
|
|
box.focus(); // Fix issue with Chrome losing focus from the textarea.
|
|
|
|
//if user selects all and deletes or holds down delete til beginning
|
|
//user could get here and shrink whole box
|
|
newHeight < minHeight && (newHeight = minHeight);
|
|
oldHeight > newHeight && opts.animate ? box.stop().animate({height: newHeight}, opts.speed) : box.innerHeight(newHeight);
|
|
} else { //just set to the minHeight
|
|
box.innerHeight(minHeight);
|
|
}
|
|
}
|
|
}
|
|
return that;
|
|
}
|
|
})(jQuery);
|