From ec2272898489f98e8e7bafa76d2ea74547486300 Mon Sep 17 00:00:00 2001 From: Rodrigo Souto Date: Mon, 19 May 2014 16:40:51 -0300 Subject: [PATCH] wall: correct textarea growing indefinetely --- app/views/layouts/_javascript.html.erb | 2 +- app/views/profile/_profile_wall.html.erb | 2 +- public/javascripts/application.js | 12 +++--------- public/javascripts/autogrow.js | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 public/javascripts/autogrow.js diff --git a/app/views/layouts/_javascript.html.erb b/app/views/layouts/_javascript.html.erb index 4c5ab63..bba4015 100644 --- a/app/views/layouts/_javascript.html.erb +++ b/app/views/layouts/_javascript.html.erb @@ -3,7 +3,7 @@ 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', 'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', -'add-and-join', 'report-abuse', 'catalog', 'manage-products', +'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', 'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'rails.js', :cache => 'cache/application' %> <% language = FastGettext.locale %> diff --git a/app/views/profile/_profile_wall.html.erb b/app/views/profile/_profile_wall.html.erb index b79b1fc..3d95b94 100644 --- a/app/views/profile/_profile_wall.html.erb +++ b/app/views/profile/_profile_wall.html.erb @@ -2,7 +2,7 @@
<%= flash[:error] %> <%= form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "$('leave_scrap_content').value=''", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %> - <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2 %> + <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2, :class => 'autogrow' %> <%= submit_button :new, _('Share') %> <% end %>
diff --git a/public/javascripts/application.js b/public/javascripts/application.js index aa30c7b..fe80a0a 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -681,7 +681,6 @@ function hide_and_show(hide_elements, show_elements) { function limited_text_area(textid, limit) { var text = jQuery('#' + textid).val(); - grow_text_area(textid); var textlength = text.length; jQuery('#' + textid + '_left span').html(limit - textlength); if (textlength > limit) { @@ -696,14 +695,9 @@ function limited_text_area(textid, limit) { } } -function grow_text_area(textid) { - var height = jQuery('#' + textid).attr('scrollHeight'); - if (jQuery.browser.webkit) { - height -= parseInt(jQuery('#' + textid).css('padding-top')) + - parseInt(jQuery('#' + textid).css('padding-bottom')); - } - jQuery('#' + textid).css('height', height + 'px'); -} +jQuery(function($) { + $('.autogrow').autogrow(); +}); jQuery(function($) { $('a').each(function() { diff --git a/public/javascripts/autogrow.js b/public/javascripts/autogrow.js new file mode 100644 index 0000000..e8e42d8 --- /dev/null +++ b/public/javascripts/autogrow.js @@ -0,0 +1,93 @@ +;(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: true //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: false //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) + ; + + 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); -- libgit2 0.21.2