/* -*- 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);