4 http://www.jacklmoore.com/autosize
6 (function (global, factory) {
7 if (typeof define === 'function' && define.amd) {
8 define(['exports', 'module'], factory);
9 } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
10 factory(exports, module);
15 factory(mod.exports, mod);
16 global.autosize = mod.exports;
18 })(this, function (exports, module) {
21 var set = typeof Set === 'function' ? new Set() : (function () {
25 has: function has(key) {
26 return Boolean(list.indexOf(key) > -1);
28 add: function add(key) {
31 'delete': function _delete(key) {
32 list.splice(list.indexOf(key), 1);
36 var createEvent = function createEvent(name) {
37 return new Event(name);
42 // IE does not support `new Event()`
43 createEvent = function (name) {
44 var evt = document.createEvent('Event');
45 evt.initEvent(name, true, false);
51 if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || set.has(ta)) return;
53 var heightOffset = null;
54 var clientWidth = ta.clientWidth;
55 var cachedHeight = null;
58 var style = window.getComputedStyle(ta, null);
60 if (style.resize === 'vertical') {
61 ta.style.resize = 'none';
62 } else if (style.resize === 'both') {
63 ta.style.resize = 'horizontal';
66 if (style.boxSizing === 'content-box') {
67 heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
69 heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
71 // Fix when a textarea is not on document body and heightOffset is Not a Number
72 if (isNaN(heightOffset)) {
79 function changeOverflow(value) {
81 // Chrome/Safari-specific fix:
82 // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
83 // made available by removing the scrollbar. The following forces the necessary text reflow.
84 var width = ta.style.width;
85 ta.style.width = '0px';
87 /* jshint ignore:start */
89 /* jshint ignore:end */
90 ta.style.width = width;
93 ta.style.overflowY = value;
98 function getParentOverflows(el) {
101 while (el && el.parentNode && el.parentNode instanceof Element) {
102 if (el.parentNode.scrollTop) {
105 scrollTop: el.parentNode.scrollTop });
114 var originalHeight = ta.style.height;
115 var overflows = getParentOverflows(ta);
116 var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
118 ta.style.height = 'auto';
120 var endHeight = ta.scrollHeight + heightOffset;
122 if (ta.scrollHeight === 0) {
123 // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
124 ta.style.height = originalHeight;
128 ta.style.height = endHeight + 'px';
130 // used to check if an update is actually necessary on window.resize
131 clientWidth = ta.clientWidth;
133 // prevents scroll-position jumping
134 overflows.forEach(function (el) {
135 el.node.scrollTop = el.scrollTop;
139 document.documentElement.scrollTop = docTop;
146 var computed = window.getComputedStyle(ta, null);
147 var computedHeight = Math.round(parseFloat(computed.height));
148 var styleHeight = Math.round(parseFloat(ta.style.height));
150 // The computed height not matching the height set via resize indicates that
151 // the max-height has been exceeded, in which case the overflow should be set to visible.
152 if (computedHeight !== styleHeight) {
153 if (computed.overflowY !== 'visible') {
154 changeOverflow('visible');
157 // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
158 if (computed.overflowY !== 'hidden') {
159 changeOverflow('hidden');
163 if (cachedHeight !== computedHeight) {
164 cachedHeight = computedHeight;
165 var evt = createEvent('autosize:resized');
166 ta.dispatchEvent(evt);
170 var pageResize = function pageResize() {
171 if (ta.clientWidth !== clientWidth) {
176 var destroy = (function (style) {
177 window.removeEventListener('resize', pageResize, false);
178 ta.removeEventListener('input', update, false);
179 ta.removeEventListener('keyup', update, false);
180 ta.removeEventListener('autosize:destroy', destroy, false);
181 ta.removeEventListener('autosize:update', update, false);
184 Object.keys(style).forEach(function (key) {
185 ta.style[key] = style[key];
188 height: ta.style.height,
189 resize: ta.style.resize,
190 overflowY: ta.style.overflowY,
191 overflowX: ta.style.overflowX,
192 wordWrap: ta.style.wordWrap });
194 ta.addEventListener('autosize:destroy', destroy, false);
196 // IE9 does not fire onpropertychange or oninput for deletions,
197 // so binding to onkeyup to catch most of those events.
198 // There is no way that I know of to detect something like 'cut' in IE9.
199 if ('onpropertychange' in ta && 'oninput' in ta) {
200 ta.addEventListener('keyup', update, false);
203 window.addEventListener('resize', pageResize, false);
204 ta.addEventListener('input', update, false);
205 ta.addEventListener('autosize:update', update, false);
207 ta.style.overflowX = 'hidden';
208 ta.style.wordWrap = 'break-word';
213 function destroy(ta) {
214 if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
215 var evt = createEvent('autosize:destroy');
216 ta.dispatchEvent(evt);
219 function update(ta) {
220 if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
221 var evt = createEvent('autosize:update');
222 ta.dispatchEvent(evt);
227 // Do nothing in Node.js environment and IE8 (or lower)
228 if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
229 autosize = function (el) {
232 autosize.destroy = function (el) {
235 autosize.update = function (el) {
239 autosize = function (el, options) {
241 Array.prototype.forEach.call(el.length ? el : [el], function (x) {
242 return assign(x, options);
247 autosize.destroy = function (el) {
249 Array.prototype.forEach.call(el.length ? el : [el], destroy);
253 autosize.update = function (el) {
255 Array.prototype.forEach.call(el.length ? el : [el], update);
261 module.exports = autosize;