2
0

autosize.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = global || self, global.autosize = factory());
  5. }(this, (function () {
  6. var map = typeof Map === "function" ? new Map() : function () {
  7. var keys = [];
  8. var values = [];
  9. return {
  10. has: function has(key) {
  11. return keys.indexOf(key) > -1;
  12. },
  13. get: function get(key) {
  14. return values[keys.indexOf(key)];
  15. },
  16. set: function set(key, value) {
  17. if (keys.indexOf(key) === -1) {
  18. keys.push(key);
  19. values.push(value);
  20. }
  21. },
  22. "delete": function _delete(key) {
  23. var index = keys.indexOf(key);
  24. if (index > -1) {
  25. keys.splice(index, 1);
  26. values.splice(index, 1);
  27. }
  28. }
  29. };
  30. }();
  31. var createEvent = function createEvent(name) {
  32. return new Event(name, {
  33. bubbles: true
  34. });
  35. };
  36. try {
  37. new Event('test');
  38. } catch (e) {
  39. // IE does not support `new Event()`
  40. createEvent = function createEvent(name) {
  41. var evt = document.createEvent('Event');
  42. evt.initEvent(name, true, false);
  43. return evt;
  44. };
  45. }
  46. function assign(ta) {
  47. if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
  48. var heightOffset = null;
  49. var clientWidth = null;
  50. var cachedHeight = null;
  51. function init() {
  52. var style = window.getComputedStyle(ta, null);
  53. if (style.resize === 'vertical') {
  54. ta.style.resize = 'none';
  55. } else if (style.resize === 'both') {
  56. ta.style.resize = 'horizontal';
  57. }
  58. if (style.boxSizing === 'content-box') {
  59. heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
  60. } else {
  61. heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
  62. } // Fix when a textarea is not on document body and heightOffset is Not a Number
  63. if (isNaN(heightOffset)) {
  64. heightOffset = 0;
  65. }
  66. update();
  67. }
  68. function changeOverflow(value) {
  69. {
  70. // Chrome/Safari-specific fix:
  71. // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
  72. // made available by removing the scrollbar. The following forces the necessary text reflow.
  73. var width = ta.style.width;
  74. ta.style.width = '0px'; // Force reflow:
  75. /* jshint ignore:end */
  76. ta.style.width = width;
  77. }
  78. ta.style.overflowY = value;
  79. }
  80. function getParentOverflows(el) {
  81. var arr = [];
  82. while (el && el.parentNode && el.parentNode instanceof Element) {
  83. if (el.parentNode.scrollTop) {
  84. arr.push({
  85. node: el.parentNode,
  86. scrollTop: el.parentNode.scrollTop
  87. });
  88. }
  89. el = el.parentNode;
  90. }
  91. return arr;
  92. }
  93. function resize() {
  94. if (ta.scrollHeight === 0) {
  95. // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
  96. return;
  97. }
  98. var overflows = getParentOverflows(ta);
  99. var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
  100. ta.style.height = '';
  101. ta.style.height = ta.scrollHeight + heightOffset + 'px'; // used to check if an update is actually necessary on window.resize
  102. clientWidth = ta.clientWidth; // prevents scroll-position jumping
  103. overflows.forEach(function (el) {
  104. el.node.scrollTop = el.scrollTop;
  105. });
  106. if (docTop) {
  107. document.documentElement.scrollTop = docTop;
  108. }
  109. }
  110. function update() {
  111. resize();
  112. var styleHeight = Math.round(parseFloat(ta.style.height));
  113. var computed = window.getComputedStyle(ta, null); // Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box
  114. var actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(computed.height)) : ta.offsetHeight; // The actual height not matching the style height (set via the resize method) indicates that
  115. // the max-height has been exceeded, in which case the overflow should be allowed.
  116. if (actualHeight < styleHeight) {
  117. if (computed.overflowY === 'hidden') {
  118. changeOverflow('scroll');
  119. resize();
  120. actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
  121. }
  122. } else {
  123. // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
  124. if (computed.overflowY !== 'hidden') {
  125. changeOverflow('hidden');
  126. resize();
  127. actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
  128. }
  129. }
  130. if (cachedHeight !== actualHeight) {
  131. cachedHeight = actualHeight;
  132. var evt = createEvent('autosize:resized');
  133. try {
  134. ta.dispatchEvent(evt);
  135. } catch (err) {// Firefox will throw an error on dispatchEvent for a detached element
  136. // https://bugzilla.mozilla.org/show_bug.cgi?id=889376
  137. }
  138. }
  139. }
  140. var pageResize = function pageResize() {
  141. if (ta.clientWidth !== clientWidth) {
  142. update();
  143. }
  144. };
  145. var destroy = function (style) {
  146. window.removeEventListener('resize', pageResize, false);
  147. ta.removeEventListener('input', update, false);
  148. ta.removeEventListener('keyup', update, false);
  149. ta.removeEventListener('autosize:destroy', destroy, false);
  150. ta.removeEventListener('autosize:update', update, false);
  151. Object.keys(style).forEach(function (key) {
  152. ta.style[key] = style[key];
  153. });
  154. map["delete"](ta);
  155. }.bind(ta, {
  156. height: ta.style.height,
  157. resize: ta.style.resize,
  158. overflowY: ta.style.overflowY,
  159. overflowX: ta.style.overflowX,
  160. wordWrap: ta.style.wordWrap
  161. });
  162. ta.addEventListener('autosize:destroy', destroy, false); // IE9 does not fire onpropertychange or oninput for deletions,
  163. // so binding to onkeyup to catch most of those events.
  164. // There is no way that I know of to detect something like 'cut' in IE9.
  165. if ('onpropertychange' in ta && 'oninput' in ta) {
  166. ta.addEventListener('keyup', update, false);
  167. }
  168. window.addEventListener('resize', pageResize, false);
  169. ta.addEventListener('input', update, false);
  170. ta.addEventListener('autosize:update', update, false);
  171. ta.style.overflowX = 'hidden';
  172. ta.style.wordWrap = 'break-word';
  173. map.set(ta, {
  174. destroy: destroy,
  175. update: update
  176. });
  177. init();
  178. }
  179. function destroy(ta) {
  180. var methods = map.get(ta);
  181. if (methods) {
  182. methods.destroy();
  183. }
  184. }
  185. function update(ta) {
  186. var methods = map.get(ta);
  187. if (methods) {
  188. methods.update();
  189. }
  190. }
  191. var autosize = null; // Do nothing in Node.js environment and IE8 (or lower)
  192. if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
  193. autosize = function autosize(el) {
  194. return el;
  195. };
  196. autosize.destroy = function (el) {
  197. return el;
  198. };
  199. autosize.update = function (el) {
  200. return el;
  201. };
  202. } else {
  203. autosize = function autosize(el, options) {
  204. if (el) {
  205. Array.prototype.forEach.call(el.length ? el : [el], function (x) {
  206. return assign(x);
  207. });
  208. }
  209. return el;
  210. };
  211. autosize.destroy = function (el) {
  212. if (el) {
  213. Array.prototype.forEach.call(el.length ? el : [el], destroy);
  214. }
  215. return el;
  216. };
  217. autosize.update = function (el) {
  218. if (el) {
  219. Array.prototype.forEach.call(el.length ? el : [el], update);
  220. }
  221. return el;
  222. };
  223. }
  224. var autosize$1 = autosize;
  225. return autosize$1;
  226. })));