From d110b8eebb7d912b808e71ba93dfba40dde4eaea Mon Sep 17 00:00:00 2001 From: Benard Ebinu Date: Fri, 5 Jan 2018 12:09:56 -0800 Subject: [PATCH] DIV-624: Auto resize of all textareas --- edivorce/apps/core/static/js/main.js | 2 + .../apps/core/static/js/vendor/autogrow.js | 121 ++++++++++++++++++ edivorce/apps/core/templates/base.html | 1 + 3 files changed, 124 insertions(+) create mode 100644 edivorce/apps/core/static/js/vendor/autogrow.js diff --git a/edivorce/apps/core/static/js/main.js b/edivorce/apps/core/static/js/main.js index a9275e15..80e01925 100755 --- a/edivorce/apps/core/static/js/main.js +++ b/edivorce/apps/core/static/js/main.js @@ -28,6 +28,8 @@ $(function () { placement:'auto right' }); + $('textarea').autogrow({onInitialize: true}); + // All elements tagged with the following sum related data attributes // will be added together and the result written to the html element // at the sum target id. diff --git a/edivorce/apps/core/static/js/vendor/autogrow.js b/edivorce/apps/core/static/js/vendor/autogrow.js new file mode 100644 index 00000000..4a691f52 --- /dev/null +++ b/edivorce/apps/core/static/js/vendor/autogrow.js @@ -0,0 +1,121 @@ +;(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 && elem.length) { + resize.call(elem[0]); + } + }); + 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 + if(opts.animate) { + box.stop().animate({height: newHeight}, {duration: opts.speed, complete: notifyGrown}); + } else { + box.innerHeight(newHeight); + notifyGrown(); + } + + } 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() + //add clone class for extra css rules + .addClass(opts.cloneClass) + //make "invisible", remove height restriction potentially imposed by existing CSS + .css({position: 'absolute', zIndex:-10, height: ''}) + //populate with content for consistent measuring + .val(box.val()) + ; + 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); + if(oldHeight > newHeight) { + if(opts.animate) { + box.stop().animate({height: newHeight}, {duration: opts.speed, complete: notifyShrunk}); + } else { + box.innerHeight(newHeight); + notifyShrunk(); + } + } + + } else { //just set to the minHeight + box.innerHeight(minHeight); + } + } + } + + // Trigger event to indicate a textarea has grown. + function notifyGrown() { + opts.context.trigger('autogrow:grow'); + } + + // Trigger event to indicate a textarea has shrunk. + function notifyShrunk() { + opts.context.trigger('autogrow:shrink'); + } + + return that; + } +})(jQuery); diff --git a/edivorce/apps/core/templates/base.html b/edivorce/apps/core/templates/base.html index 9d335bf3..52b8501c 100644 --- a/edivorce/apps/core/templates/base.html +++ b/edivorce/apps/core/templates/base.html @@ -206,6 +206,7 @@ +