|
| 1 | +/*! |
| 2 | + Autosize 1.18.17 |
| 3 | + license: MIT |
| 4 | + http://www.jacklmoore.com/autosize |
| 5 | +*/ |
| 6 | +(function ($) { |
| 7 | + var |
| 8 | + defaults = { |
| 9 | + className: 'autosizejs', |
| 10 | + id: 'autosizejs', |
| 11 | + append: '\n', |
| 12 | + callback: false, |
| 13 | + resizeDelay: 10, |
| 14 | + placeholder: true |
| 15 | + }, |
| 16 | + |
| 17 | + // border:0 is unnecessary, but avoids a bug in Firefox on OSX |
| 18 | + copy = '<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>', |
| 19 | + |
| 20 | + // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value. |
| 21 | + typographyStyles = [ |
| 22 | + 'fontFamily', |
| 23 | + 'fontSize', |
| 24 | + 'fontWeight', |
| 25 | + 'fontStyle', |
| 26 | + 'letterSpacing', |
| 27 | + 'textTransform', |
| 28 | + 'wordSpacing', |
| 29 | + 'textIndent', |
| 30 | + 'whiteSpace' |
| 31 | + ], |
| 32 | + |
| 33 | + // to keep track which textarea is being mirrored when adjust() is called. |
| 34 | + mirrored, |
| 35 | + |
| 36 | + // the mirror element, which is used to calculate what size the mirrored element should be. |
| 37 | + mirror = $(copy).data('autosize', true)[0]; |
| 38 | + |
| 39 | + // test that line-height can be accurately copied. |
| 40 | + mirror.style.lineHeight = '99px'; |
| 41 | + if ($(mirror).css('lineHeight') === '99px') { |
| 42 | + typographyStyles.push('lineHeight'); |
| 43 | + } |
| 44 | + mirror.style.lineHeight = ''; |
| 45 | + |
| 46 | + $.fn.autosize = function (options) { |
| 47 | + if (!this.length) { |
| 48 | + return this; |
| 49 | + } |
| 50 | + |
| 51 | + options = $.extend({}, defaults, options || {}); |
| 52 | + |
| 53 | + if (mirror.parentNode !== document.body) { |
| 54 | + $(document.body).append(mirror); |
| 55 | + } |
| 56 | + |
| 57 | + return this.each(function () { |
| 58 | + var |
| 59 | + ta = this, |
| 60 | + $ta = $(ta), |
| 61 | + maxHeight, |
| 62 | + minHeight, |
| 63 | + boxOffset = 0, |
| 64 | + callback = $.isFunction(options.callback), |
| 65 | + originalStyles = { |
| 66 | + height: ta.style.height, |
| 67 | + overflow: ta.style.overflow, |
| 68 | + overflowY: ta.style.overflowY, |
| 69 | + wordWrap: ta.style.wordWrap, |
| 70 | + resize: ta.style.resize |
| 71 | + }, |
| 72 | + timeout, |
| 73 | + width = $ta.width(), |
| 74 | + taResize = $ta.css('resize'); |
| 75 | + |
| 76 | + if ($ta.data('autosize')) { |
| 77 | + // exit if autosize has already been applied, or if the textarea is the mirror element. |
| 78 | + return; |
| 79 | + } |
| 80 | + $ta.data('autosize', true); |
| 81 | + |
| 82 | + if ($ta.css('box-sizing') === 'border-box' || $ta.css('-moz-box-sizing') === 'border-box' || $ta.css('-webkit-box-sizing') === 'border-box'){ |
| 83 | + boxOffset = $ta.outerHeight() - $ta.height(); |
| 84 | + } |
| 85 | + |
| 86 | + // IE8 and lower return 'auto', which parses to NaN, if no min-height is set. |
| 87 | + minHeight = Math.max(parseFloat($ta.css('minHeight')) - boxOffset || 0, $ta.height()); |
| 88 | + |
| 89 | + $ta.css({ |
| 90 | + overflow: 'hidden', |
| 91 | + overflowY: 'hidden', |
| 92 | + wordWrap: 'break-word' // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width |
| 93 | + }); |
| 94 | + |
| 95 | + if (taResize === 'vertical') { |
| 96 | + $ta.css('resize','none'); |
| 97 | + } else if (taResize === 'both') { |
| 98 | + $ta.css('resize', 'horizontal'); |
| 99 | + } |
| 100 | + |
| 101 | + // getComputedStyle is preferred here because it preserves sub-pixel values, while jQuery's .width() rounds to an integer. |
| 102 | + function setWidth() { |
| 103 | + var width; |
| 104 | + var style = window.getComputedStyle ? window.getComputedStyle(ta, null) : null; |
| 105 | + |
| 106 | + if (style) { |
| 107 | + width = parseFloat(style.width); |
| 108 | + if (style.boxSizing === 'border-box' || style.webkitBoxSizing === 'border-box' || style.mozBoxSizing === 'border-box') { |
| 109 | + $.each(['paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'], function(i,val){ |
| 110 | + width -= parseFloat(style[val]); |
| 111 | + }); |
| 112 | + } |
| 113 | + } else { |
| 114 | + width = $ta.width(); |
| 115 | + } |
| 116 | + |
| 117 | + mirror.style.width = Math.max(width,0) + 'px'; |
| 118 | + } |
| 119 | + |
| 120 | + function initMirror() { |
| 121 | + var styles = {}; |
| 122 | + |
| 123 | + mirrored = ta; |
| 124 | + mirror.className = options.className; |
| 125 | + mirror.id = options.id; |
| 126 | + maxHeight = parseFloat($ta.css('maxHeight')); |
| 127 | + |
| 128 | + // mirror is a duplicate textarea located off-screen that |
| 129 | + // is automatically updated to contain the same text as the |
| 130 | + // original textarea. mirror always has a height of 0. |
| 131 | + // This gives a cross-browser supported way getting the actual |
| 132 | + // height of the text, through the scrollTop property. |
| 133 | + $.each(typographyStyles, function(i,val){ |
| 134 | + styles[val] = $ta.css(val); |
| 135 | + }); |
| 136 | + |
| 137 | + $(mirror).css(styles).attr('wrap', $ta.attr('wrap')); |
| 138 | + |
| 139 | + setWidth(); |
| 140 | + |
| 141 | + // Chrome-specific fix: |
| 142 | + // When the textarea y-overflow is hidden, Chrome doesn't reflow the text to account for the space |
| 143 | + // made available by removing the scrollbar. This workaround triggers the reflow for Chrome. |
| 144 | + if (window.chrome) { |
| 145 | + var width = ta.style.width; |
| 146 | + ta.style.width = '0px'; |
| 147 | + var ignore = ta.offsetWidth; |
| 148 | + ta.style.width = width; |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + // Using mainly bare JS in this function because it is going |
| 153 | + // to fire very often while typing, and needs to very efficient. |
| 154 | + function adjust() { |
| 155 | + var height, originalHeight; |
| 156 | + |
| 157 | + if (mirrored !== ta) { |
| 158 | + initMirror(); |
| 159 | + } else { |
| 160 | + setWidth(); |
| 161 | + } |
| 162 | + |
| 163 | + if (!ta.value && options.placeholder) { |
| 164 | + // If the textarea is empty, copy the placeholder text into |
| 165 | + // the mirror control and use that for sizing so that we |
| 166 | + // don't end up with placeholder getting trimmed. |
| 167 | + mirror.value = ($ta.attr("placeholder") || ''); |
| 168 | + } else { |
| 169 | + mirror.value = ta.value; |
| 170 | + } |
| 171 | + |
| 172 | + mirror.value += options.append || ''; |
| 173 | + mirror.style.overflowY = ta.style.overflowY; |
| 174 | + originalHeight = parseFloat(ta.style.height) || 0; |
| 175 | + |
| 176 | + // Setting scrollTop to zero is needed in IE8 and lower for the next step to be accurately applied |
| 177 | + mirror.scrollTop = 0; |
| 178 | + |
| 179 | + mirror.scrollTop = 9e4; |
| 180 | + |
| 181 | + // Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding. |
| 182 | + height = mirror.scrollTop; |
| 183 | + |
| 184 | + if (maxHeight && height > maxHeight) { |
| 185 | + ta.style.overflowY = 'scroll'; |
| 186 | + height = maxHeight; |
| 187 | + } else { |
| 188 | + ta.style.overflowY = 'hidden'; |
| 189 | + if (height < minHeight) { |
| 190 | + height = minHeight; |
| 191 | + } |
| 192 | + } |
| 193 | + |
| 194 | + height += boxOffset; |
| 195 | + |
| 196 | + if (Math.abs(originalHeight - height) > 1/100) { |
| 197 | + ta.style.height = height + 'px'; |
| 198 | + |
| 199 | + // Trigger a repaint for IE8 for when ta is nested 2 or more levels inside an inline-block |
| 200 | + mirror.className = mirror.className; |
| 201 | + |
| 202 | + if (callback) { |
| 203 | + options.callback.call(ta,ta); |
| 204 | + } |
| 205 | + $ta.trigger('autosize.resized'); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + function resize () { |
| 210 | + clearTimeout(timeout); |
| 211 | + timeout = setTimeout(function(){ |
| 212 | + var newWidth = $ta.width(); |
| 213 | + |
| 214 | + if (newWidth !== width) { |
| 215 | + width = newWidth; |
| 216 | + adjust(); |
| 217 | + } |
| 218 | + }, parseInt(options.resizeDelay,10)); |
| 219 | + } |
| 220 | + |
| 221 | + if ('onpropertychange' in ta) { |
| 222 | + if ('oninput' in ta) { |
| 223 | + // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions, |
| 224 | + // so binding to onkeyup to catch most of those occasions. There is no way that I |
| 225 | + // know of to detect something like 'cut' in IE9. |
| 226 | + $ta.on('input.autosize keyup.autosize', adjust); |
| 227 | + } else { |
| 228 | + // IE7 / IE8 |
| 229 | + $ta.on('propertychange.autosize', function(){ |
| 230 | + if(event.propertyName === 'value'){ |
| 231 | + adjust(); |
| 232 | + } |
| 233 | + }); |
| 234 | + } |
| 235 | + } else { |
| 236 | + // Modern Browsers |
| 237 | + $ta.on('input.autosize', adjust); |
| 238 | + } |
| 239 | + |
| 240 | + // Set options.resizeDelay to false if using fixed-width textarea elements. |
| 241 | + // Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize. |
| 242 | + |
| 243 | + if (options.resizeDelay !== false) { |
| 244 | + $(window).on('resize.autosize', resize); |
| 245 | + } |
| 246 | + |
| 247 | + // Event for manual triggering if needed. |
| 248 | + // Should only be needed when the value of the textarea is changed through JavaScript rather than user input. |
| 249 | + $ta.on('autosize.resize', adjust); |
| 250 | + |
| 251 | + // Event for manual triggering that also forces the styles to update as well. |
| 252 | + // Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method. |
| 253 | + $ta.on('autosize.resizeIncludeStyle', function() { |
| 254 | + mirrored = null; |
| 255 | + adjust(); |
| 256 | + }); |
| 257 | + |
| 258 | + $ta.on('autosize.destroy', function(){ |
| 259 | + mirrored = null; |
| 260 | + clearTimeout(timeout); |
| 261 | + $(window).off('resize', resize); |
| 262 | + $ta |
| 263 | + .off('autosize') |
| 264 | + .off('.autosize') |
| 265 | + .css(originalStyles) |
| 266 | + .removeData('autosize'); |
| 267 | + }); |
| 268 | + |
| 269 | + // Call adjust in case the textarea already contains text. |
| 270 | + adjust(); |
| 271 | + }); |
| 272 | + }; |
| 273 | +}(jQuery || $)); // jQuery or jQuery-like library, such as Zepto |
0 commit comments