1/* 2 * jQuery.fn.autoResize 1.14 3 * -- 4 * https://github.com/jamespadolsey/jQuery.fn.autoResize 5 * -- 6 * This program is free software. It comes without any warranty, to 7 * the extent permitted by applicable law. You can redistribute it 8 * and/or modify it under the terms of the Do What The Fuck You Want 9 * To Public License, Version 2, as published by Sam Hocevar. See 10 * http://sam.zoy.org/wtfpl/COPYING for more details. */ 11 12(function($){ 13 14 var uid = 'ar' + +new Date, 15 16 defaults = autoResize.defaults = { 17 onResize: function(){}, 18 onBeforeResize: function(){return 123}, 19 onAfterResize: function(){return 555}, 20 animate: { 21 duration: 200, 22 complete: function(){} 23 }, 24 extraSpace: 50, 25 minHeight: 'original', 26 maxHeight: 500, 27 minWidth: 'original', 28 maxWidth: 500 29 }; 30 31 autoResize.cloneCSSProperties = [ 32 'lineHeight', 'textDecoration', 'letterSpacing', 33 'fontSize', 'fontFamily', 'fontStyle', 'fontWeight', 34 'textTransform', 'textAlign', 'direction', 'wordSpacing', 'fontSizeAdjust', 35 'paddingTop', 'paddingLeft', 'paddingBottom', 'paddingRight', 'width' 36 ]; 37 38 autoResize.cloneCSSValues = { 39 position: 'absolute', 40 top: -9999, 41 left: -9999, 42 opacity: 0, 43 overflow: 'hidden' 44 }; 45 46 autoResize.resizableFilterSelector = [ 47 'textarea:not(textarea.' + uid + ')', 48 'input:not(input[type])', 49 'input[type=text]', 50 'input[type=password]', 51 'input[type=email]', 52 'input[type=url]' 53 ].join(','); 54 55 autoResize.AutoResizer = AutoResizer; 56 57 $.fn.autoResize = autoResize; 58 59 function autoResize(config) { 60 this.filter(autoResize.resizableFilterSelector).each(function(){ 61 new AutoResizer( $(this), config ); 62 }); 63 return this; 64 } 65 66 function AutoResizer(el, config) { 67 68 if (el.data('AutoResizer')) { 69 el.data('AutoResizer').destroy(); 70 } 71 72 config = this.config = $.extend({}, autoResize.defaults, config); 73 this.el = el; 74 75 this.nodeName = el[0].nodeName.toLowerCase(); 76 77 this.originalHeight = el.height(); 78 this.previousScrollTop = null; 79 80 this.value = el.val(); 81 82 if (config.maxWidth === 'original') config.maxWidth = el.width(); 83 if (config.minWidth === 'original') config.minWidth = el.width(); 84 if (config.maxHeight === 'original') config.maxHeight = el.height(); 85 if (config.minHeight === 'original') config.minHeight = el.height(); 86 87 if (this.nodeName === 'textarea') { 88 el.css({ 89 resize: 'none', 90 overflowY: 'hidden' 91 }); 92 } 93 94 el.data('AutoResizer', this); 95 96 // Make sure onAfterResize is called upon animation completion 97 config.animate.complete = (function(f){ 98 return function() { 99 config.onAfterResize.call(el); 100 return f.apply(this, arguments); 101 }; 102 }(config.animate.complete)); 103 104 this.bind(); 105 106 } 107 108 AutoResizer.prototype = { 109 110 bind: function() { 111 112 var check = $.proxy(function(){ 113 this.check(); 114 return true; 115 }, this); 116 117 this.unbind(); 118 119 this.el 120 .bind('keyup.autoResize', check) 121 //.bind('keydown.autoResize', check) 122 .bind('change.autoResize', check) 123 .bind('paste.autoResize', function() { 124 setTimeout(function() { check(); }, 0); 125 }); 126 127 if (!this.el.is(':hidden')) { 128 this.check(null, true); 129 } 130 131 }, 132 133 unbind: function() { 134 this.el.unbind('.autoResize'); 135 }, 136 137 createClone: function() { 138 139 var el = this.el, 140 clone = this.nodeName === 'textarea' ? el.clone() : $('<span/>'); 141 142 this.clone = clone; 143 144 $.each(autoResize.cloneCSSProperties, function(i, p){ 145 clone[0].style[p] = el.css(p); 146 }); 147 148 clone 149 .removeAttr('name') 150 .removeAttr('id') 151 .addClass(uid) 152 .attr('tabIndex', -1) 153 .css(autoResize.cloneCSSValues); 154 155 if (this.nodeName === 'textarea') { 156 clone.height('auto'); 157 } else { 158 clone.width('auto').css({ 159 whiteSpace: 'nowrap' 160 }); 161 } 162 163 }, 164 165 check: function(e, immediate) { 166 167 if (!this.clone) { 168 this.createClone(); 169 this.injectClone(); 170 } 171 172 var config = this.config, 173 clone = this.clone, 174 el = this.el, 175 value = el.val(); 176
177 // Do nothing if value hasn't changed 178 if (value === this.prevValue) { return true; } 179 this.prevValue = value; 180 181 if (this.nodeName === 'input') { 182 183 clone.text(value); 184 185 // Calculate new width + whether to change 186 var cloneWidth = clone.width(), 187 newWidth = (cloneWidth + config.extraSpace) >= config.minWidth ? 188 cloneWidth + config.extraSpace : config.minWidth, 189 currentWidth = el.width(); 190 191 newWidth = Math.min(newWidth, config.maxWidth); 192 193 if ( 194 (newWidth < currentWidth && newWidth >= config.minWidth) || 195 (newWidth >= config.minWidth && newWidth <= config.maxWidth) 196 ) { 197 198 config.onBeforeResize.call(el); 199 config.onResize.call(el); 200 201 el.scrollLeft(0); 202 203 if (config.animate && !immediate) { 204 el.stop(1,1).animate({ 205 width: newWidth 206 }, config.animate); 207 } else { 208 el.width(newWidth); 209 config.onAfterResize.call(el); 210 } 211 212 } 213 214 return; 215 216 } 217 218 // TEXTAREA 219 220 clone.width(el.width()).height(0).val(value).scrollTop(10000); 221 222 var scrollTop = clone[0].scrollTop; 223 224 // Don't do anything if scrollTop hasen't changed: 225 if (this.previousScrollTop === scrollTop) { 226 return; 227 } 228 229 this.previousScrollTop = scrollTop; 230 231 if (scrollTop + config.extraSpace >= config.maxHeight) { 232 el.css('overflowY', ''); 233 scrollTop = config.maxHeight; 234 immediate = true; 235 } else if (scrollTop <= config.minHeight) { 236 scrollTop = config.minHeight; 237 } else { 238 el.css('overflowY', 'hidden'); 239 scrollTop += config.extraSpace; 240 } 241 242 config.onBeforeResize.call(el); 243 config.onResize.call(el); 244 245 // Either animate or directly apply height: 246 if (config.animate && !immediate) { 247 el.stop(1,1).animate({ 248 height: scrollTop 249 }, config.animate); 250 } else { 251 el.height(scrollTop); 252 config.onAfterResize.call(el); 253 } 254 255 }, 256 257 destroy: function() { 258 this.unbind(); 259 this.el.removeData('AutoResizer'); 260 this.clone.remove(); 261 delete this.el; 262 delete this.clone; 263 }, 264 265 injectClone: function() { 266 ( 267 autoResize.cloneContainer || 268 (autoResize.cloneContainer = $('<arclones/>').appendTo('body')) 269 ).append(this.clone); 270 } 271 272 }; 273 274})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.