mirror of
https://github.com/zulip/zulip.git
synced 2026-06-03 21:01:43 +08:00
When pasting a large amount of text (>5k), pasting in compose is noticeably slow due to `update` event in `autosize` causing layour reflows since it is called thousands of times during a paste. To fix it, we throttle the `update` event to only run once every 50ms by default.
603 lines
31 KiB
Diff
603 lines
31 KiB
Diff
diff --git a/changelog.md b/changelog.md
|
|
deleted file mode 100644
|
|
index 847f8ab82f7cc0494bd8ef79d7562532b9e66c19..0000000000000000000000000000000000000000
|
|
diff --git a/dist/autosize.esm.js b/dist/autosize.esm.js
|
|
index 48aa632f375217b7a60758ab7e8f1f97c5f8d4b1..6176ad30234029bd4a130790aad19457eb488845 100644
|
|
--- a/dist/autosize.esm.js
|
|
+++ b/dist/autosize.esm.js
|
|
@@ -1 +1 @@
|
|
-var e,t,n="function"==typeof Map?new Map:(e=[],t=[],{has:function(t){return e.indexOf(t)>-1},get:function(n){return t[e.indexOf(n)]},set:function(n,o){-1===e.indexOf(n)&&(e.push(n),t.push(o))},delete:function(n){var o=e.indexOf(n);o>-1&&(e.splice(o,1),t.splice(o,1))}}),o=function(e){return new Event(e,{bubbles:!0})};try{new Event("test")}catch(e){o=function(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}function r(e){var t=n.get(e);t&&t.destroy()}function i(e){var t=n.get(e);t&&t.update()}var l=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?((l=function(e){return e}).destroy=function(e){return e},l.update=function(e){return e}):((l=function(e,t){return e&&Array.prototype.forEach.call(e.length?e:[e],function(e){return function(e){if(e&&e.nodeName&&"TEXTAREA"===e.nodeName&&!n.has(e)){var t,r=null,i=null,l=null,a=function(){e.clientWidth!==i&&p()},d=function(t){window.removeEventListener("resize",a,!1),e.removeEventListener("input",p,!1),e.removeEventListener("keyup",p,!1),e.removeEventListener("autosize:destroy",d,!1),e.removeEventListener("autosize:update",p,!1),Object.keys(t).forEach(function(n){e.style[n]=t[n]}),n.delete(e)}.bind(e,{height:e.style.height,resize:e.style.resize,overflowY:e.style.overflowY,overflowX:e.style.overflowX,wordWrap:e.style.wordWrap});e.addEventListener("autosize:destroy",d,!1),"onpropertychange"in e&&"oninput"in e&&e.addEventListener("keyup",p,!1),window.addEventListener("resize",a,!1),e.addEventListener("input",p,!1),e.addEventListener("autosize:update",p,!1),e.style.overflowX="hidden",e.style.wordWrap="break-word",n.set(e,{destroy:d,update:p}),"vertical"===(t=window.getComputedStyle(e,null)).resize?e.style.resize="none":"both"===t.resize&&(e.style.resize="horizontal"),r="content-box"===t.boxSizing?-(parseFloat(t.paddingTop)+parseFloat(t.paddingBottom)):parseFloat(t.borderTopWidth)+parseFloat(t.borderBottomWidth),isNaN(r)&&(r=0),p()}function s(t){var n=e.style.width;e.style.width="0px",e.style.width=n,e.style.overflowY=t}function u(){if(0!==e.scrollHeight){var t=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&(e.parentNode.style.scrollBehavior="auto",t.push([e.parentNode,e.parentNode.scrollTop])),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0];t.scrollTop=e[1],t.style.scrollBehavior=null})}}(e);e.style.height="",e.style.height=e.scrollHeight+r+"px",i=e.clientWidth,t()}}function p(){u();var t=Math.round(parseFloat(e.style.height)),n=window.getComputedStyle(e,null),r="content-box"===n.boxSizing?Math.round(parseFloat(n.height)):e.offsetHeight;if(r<t?"hidden"===n.overflowY&&(s("scroll"),u(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight):"hidden"!==n.overflowY&&(s("hidden"),u(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight),l!==r){l=r;var i=o("autosize:resized");try{e.dispatchEvent(i)}catch(e){}}}}(e)}),e}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],r),e},l.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],i),e});var a=l;export default a;
|
|
+const e="function"==typeof Map?new Map:function(){const e=[],t=[];return{has:t=>e.indexOf(t)>-1,get:o=>t[e.indexOf(o)],set(o,n){-1===e.indexOf(o)&&(e.push(o),t.push(n))},delete(o){const n=e.indexOf(o);n>-1&&(e.splice(n,1),t.splice(n,1))}}}();let t=e=>new Event(e,{bubbles:!0});try{new Event("test")}catch(e){t=e=>{const t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}function o(t){const o=e.get(t);o&&o.destroy()}function n(t){const o=e.get(t);o&&o.update()}let r=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?(r=e=>e,r.destroy=e=>e,r.update=e=>e):(r=(o,n)=>(o&&Array.prototype.forEach.call(o.length?o:[o],o=>function(o){if(!o||!o.nodeName||"TEXTAREA"!==o.nodeName||e.has(o))return;let n=null,r=null,i=null;function l(e){{const e=o.style.width;o.style.width="0px",o.style.width=e}o.style.overflowY=e}function s(){if(0===o.scrollHeight)return;const e=function(e){const t=[];for(;e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&(e.parentNode.style.scrollBehavior="auto",t.push([e.parentNode,e.parentNode.scrollTop])),e=e.parentNode;return()=>t.forEach(([e,t])=>{e.scrollTop=t,e.style.scrollBehavior=null})}(o);o.style.height="",o.style.height=o.scrollHeight+n+"px",r=o.clientWidth,e()}function d(){s();const e=Math.round(parseFloat(o.style.height)),n=window.getComputedStyle(o,null);var r="content-box"===n.boxSizing?Math.round(parseFloat(n.height)):o.offsetHeight;if(r<e?"hidden"===n.overflowY&&(l("scroll"),s(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(o,null).height)):o.offsetHeight):"hidden"!==n.overflowY&&(l("hidden"),s(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(o,null).height)):o.offsetHeight),i!==r){i=r;const e=t("autosize:resized");try{o.dispatchEvent(e)}catch(e){}}}let a=0,p=null;const c=(e=50)=>{const t=Date.now(),o=t-a;o>=e?(a=t,d()):(p&&clearTimeout(p),p=setTimeout(()=>{a=Date.now(),d()},e-o))},u=()=>{o.clientWidth!==r&&d()},h=(t=>{window.removeEventListener("resize",u,!1),o.removeEventListener("input",c,!1),o.removeEventListener("keyup",d,!1),o.removeEventListener("autosize:destroy",h,!1),o.removeEventListener("autosize:update",d,!1),Object.keys(t).forEach(e=>{o.style[e]=t[e]}),e.delete(o)}).bind(o,{height:o.style.height,resize:o.style.resize,overflowY:o.style.overflowY,overflowX:o.style.overflowX,wordWrap:o.style.wordWrap});o.addEventListener("autosize:destroy",h,!1),"onpropertychange"in o&&"oninput"in o&&o.addEventListener("keyup",d,!1),window.addEventListener("resize",u,!1),o.addEventListener("input",c,!1),o.addEventListener("autosize:update",d,!1),o.style.overflowX="hidden",o.style.wordWrap="break-word",e.set(o,{destroy:h,update:d}),function(){const e=window.getComputedStyle(o,null);"vertical"===e.resize?o.style.resize="none":"both"===e.resize&&(o.style.resize="horizontal"),n="content-box"===e.boxSizing?-(parseFloat(e.paddingTop)+parseFloat(e.paddingBottom)):parseFloat(e.borderTopWidth)+parseFloat(e.borderBottomWidth),isNaN(n)&&(n=0),d()}()}(o)),o),r.destroy=e=>(e&&Array.prototype.forEach.call(e.length?e:[e],o),e),r.update=e=>(e&&Array.prototype.forEach.call(e.length?e:[e],n),e));var i=r;export{i as default};
|
|
diff --git a/dist/autosize.js b/dist/autosize.js
|
|
index 84e622861e0e1037c3115fabbe07c2029d3598ef..ac92cad4ee5e1934bfa1b9746dc2120ff26a5b50 100644
|
|
--- a/dist/autosize.js
|
|
+++ b/dist/autosize.js
|
|
@@ -2,270 +2,280 @@
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(global = global || self, global.autosize = factory());
|
|
-}(this, (function () {
|
|
- var map = typeof Map === "function" ? new Map() : function () {
|
|
- var keys = [];
|
|
- var values = [];
|
|
- return {
|
|
- has: function has(key) {
|
|
- return keys.indexOf(key) > -1;
|
|
- },
|
|
- get: function get(key) {
|
|
- return values[keys.indexOf(key)];
|
|
- },
|
|
- set: function set(key, value) {
|
|
- if (keys.indexOf(key) === -1) {
|
|
- keys.push(key);
|
|
- values.push(value);
|
|
- }
|
|
- },
|
|
- "delete": function _delete(key) {
|
|
- var index = keys.indexOf(key);
|
|
-
|
|
- if (index > -1) {
|
|
- keys.splice(index, 1);
|
|
- values.splice(index, 1);
|
|
- }
|
|
- }
|
|
- };
|
|
- }();
|
|
-
|
|
- var createEvent = function createEvent(name) {
|
|
- return new Event(name, {
|
|
- bubbles: true
|
|
- });
|
|
- };
|
|
-
|
|
+})(this, (function () {
|
|
+ const map = (typeof Map === "function") ? new Map() : (function () {
|
|
+ const keys = [];
|
|
+ const values = [];
|
|
+
|
|
+ return {
|
|
+ has(key) {
|
|
+ return keys.indexOf(key) > -1;
|
|
+ },
|
|
+ get(key) {
|
|
+ return values[keys.indexOf(key)];
|
|
+ },
|
|
+ set(key, value) {
|
|
+ if (keys.indexOf(key) === -1) {
|
|
+ keys.push(key);
|
|
+ values.push(value);
|
|
+ }
|
|
+ },
|
|
+ delete(key) {
|
|
+ const index = keys.indexOf(key);
|
|
+ if (index > -1) {
|
|
+ keys.splice(index, 1);
|
|
+ values.splice(index, 1);
|
|
+ }
|
|
+ },
|
|
+ }
|
|
+ })();
|
|
+
|
|
+ let createEvent = (name)=> new Event(name, {bubbles: true});
|
|
try {
|
|
- new Event('test');
|
|
- } catch (e) {
|
|
- // IE does not support `new Event()`
|
|
- createEvent = function createEvent(name) {
|
|
- var evt = document.createEvent('Event');
|
|
- evt.initEvent(name, true, false);
|
|
- return evt;
|
|
- };
|
|
+ new Event('test');
|
|
+ } catch(e) {
|
|
+ // IE does not support `new Event()`
|
|
+ createEvent = (name)=> {
|
|
+ const evt = document.createEvent('Event');
|
|
+ evt.initEvent(name, true, false);
|
|
+ return evt;
|
|
+ };
|
|
}
|
|
|
|
function assign(ta) {
|
|
- if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
|
|
- var heightOffset = null;
|
|
- var clientWidth = null;
|
|
- var cachedHeight = null;
|
|
-
|
|
- function init() {
|
|
- var style = window.getComputedStyle(ta, null);
|
|
-
|
|
- if (style.resize === 'vertical') {
|
|
- ta.style.resize = 'none';
|
|
- } else if (style.resize === 'both') {
|
|
- ta.style.resize = 'horizontal';
|
|
- }
|
|
-
|
|
- if (style.boxSizing === 'content-box') {
|
|
- heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
|
|
- } else {
|
|
- heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
|
|
- } // Fix when a textarea is not on document body and heightOffset is Not a Number
|
|
-
|
|
-
|
|
- if (isNaN(heightOffset)) {
|
|
- heightOffset = 0;
|
|
- }
|
|
-
|
|
- update();
|
|
- }
|
|
-
|
|
- function changeOverflow(value) {
|
|
- {
|
|
- // Chrome/Safari-specific fix:
|
|
- // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
|
|
- // made available by removing the scrollbar. The following forces the necessary text reflow.
|
|
- var width = ta.style.width;
|
|
- ta.style.width = '0px'; // Force reflow:
|
|
- /* jshint ignore:end */
|
|
-
|
|
- ta.style.width = width;
|
|
- }
|
|
- ta.style.overflowY = value;
|
|
- }
|
|
-
|
|
- function bookmarkOverflows(el) {
|
|
- var arr = [];
|
|
-
|
|
- while (el && el.parentNode && el.parentNode instanceof Element) {
|
|
- if (el.parentNode.scrollTop) {
|
|
- el.parentNode.style.scrollBehavior = 'auto';
|
|
- arr.push([el.parentNode, el.parentNode.scrollTop]);
|
|
- }
|
|
-
|
|
- el = el.parentNode;
|
|
- }
|
|
-
|
|
- return function () {
|
|
- return arr.forEach(function (_ref) {
|
|
- var node = _ref[0],
|
|
- scrollTop = _ref[1];
|
|
- node.scrollTop = scrollTop;
|
|
- node.style.scrollBehavior = null;
|
|
- });
|
|
- };
|
|
- }
|
|
-
|
|
- function resize() {
|
|
- if (ta.scrollHeight === 0) {
|
|
- // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
|
|
- return;
|
|
- } // remove smooth scroll & prevent scroll-position jumping by restoring original scroll position
|
|
-
|
|
-
|
|
- var restoreOverflows = bookmarkOverflows(ta);
|
|
- ta.style.height = '';
|
|
- ta.style.height = ta.scrollHeight + heightOffset + 'px'; // used to check if an update is actually necessary on window.resize
|
|
-
|
|
- clientWidth = ta.clientWidth;
|
|
- restoreOverflows();
|
|
- }
|
|
-
|
|
- function update() {
|
|
- resize();
|
|
- var styleHeight = Math.round(parseFloat(ta.style.height));
|
|
- 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
|
|
-
|
|
- 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
|
|
- // the max-height has been exceeded, in which case the overflow should be allowed.
|
|
-
|
|
- if (actualHeight < styleHeight) {
|
|
- if (computed.overflowY === 'hidden') {
|
|
- changeOverflow('scroll');
|
|
- resize();
|
|
- actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
|
- }
|
|
- } else {
|
|
- // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
|
|
- if (computed.overflowY !== 'hidden') {
|
|
- changeOverflow('hidden');
|
|
- resize();
|
|
- actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
|
- }
|
|
- }
|
|
-
|
|
- if (cachedHeight !== actualHeight) {
|
|
- cachedHeight = actualHeight;
|
|
- var evt = createEvent('autosize:resized');
|
|
-
|
|
- try {
|
|
- ta.dispatchEvent(evt);
|
|
- } catch (err) {// Firefox will throw an error on dispatchEvent for a detached element
|
|
- // https://bugzilla.mozilla.org/show_bug.cgi?id=889376
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- var pageResize = function pageResize() {
|
|
- if (ta.clientWidth !== clientWidth) {
|
|
- update();
|
|
- }
|
|
- };
|
|
-
|
|
- var destroy = function (style) {
|
|
- window.removeEventListener('resize', pageResize, false);
|
|
- ta.removeEventListener('input', update, false);
|
|
- ta.removeEventListener('keyup', update, false);
|
|
- ta.removeEventListener('autosize:destroy', destroy, false);
|
|
- ta.removeEventListener('autosize:update', update, false);
|
|
- Object.keys(style).forEach(function (key) {
|
|
- ta.style[key] = style[key];
|
|
- });
|
|
- map["delete"](ta);
|
|
- }.bind(ta, {
|
|
- height: ta.style.height,
|
|
- resize: ta.style.resize,
|
|
- overflowY: ta.style.overflowY,
|
|
- overflowX: ta.style.overflowX,
|
|
- wordWrap: ta.style.wordWrap
|
|
- });
|
|
-
|
|
- ta.addEventListener('autosize:destroy', destroy, false); // IE9 does not fire onpropertychange or oninput for deletions,
|
|
- // so binding to onkeyup to catch most of those events.
|
|
- // There is no way that I know of to detect something like 'cut' in IE9.
|
|
-
|
|
- if ('onpropertychange' in ta && 'oninput' in ta) {
|
|
- ta.addEventListener('keyup', update, false);
|
|
- }
|
|
-
|
|
- window.addEventListener('resize', pageResize, false);
|
|
- ta.addEventListener('input', update, false);
|
|
- ta.addEventListener('autosize:update', update, false);
|
|
- ta.style.overflowX = 'hidden';
|
|
- ta.style.wordWrap = 'break-word';
|
|
- map.set(ta, {
|
|
- destroy: destroy,
|
|
- update: update
|
|
- });
|
|
- init();
|
|
+ if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
|
|
+
|
|
+ let heightOffset = null;
|
|
+ let clientWidth = null;
|
|
+ let cachedHeight = null;
|
|
+
|
|
+ function init() {
|
|
+ const style = window.getComputedStyle(ta, null);
|
|
+
|
|
+ if (style.resize === 'vertical') {
|
|
+ ta.style.resize = 'none';
|
|
+ } else if (style.resize === 'both') {
|
|
+ ta.style.resize = 'horizontal';
|
|
+ }
|
|
+
|
|
+ if (style.boxSizing === 'content-box') {
|
|
+ heightOffset = -(parseFloat(style.paddingTop)+parseFloat(style.paddingBottom));
|
|
+ } else {
|
|
+ heightOffset = parseFloat(style.borderTopWidth)+parseFloat(style.borderBottomWidth);
|
|
+ }
|
|
+ // Fix when a textarea is not on document body and heightOffset is Not a Number
|
|
+ if (isNaN(heightOffset)) {
|
|
+ heightOffset = 0;
|
|
+ }
|
|
+
|
|
+ update();
|
|
+ }
|
|
+
|
|
+ function changeOverflow(value) {
|
|
+ {
|
|
+ // Chrome/Safari-specific fix:
|
|
+ // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
|
|
+ // made available by removing the scrollbar. The following forces the necessary text reflow.
|
|
+ const width = ta.style.width;
|
|
+ ta.style.width = '0px';
|
|
+ /* jshint ignore:end */
|
|
+ ta.style.width = width;
|
|
+ }
|
|
+
|
|
+ ta.style.overflowY = value;
|
|
+ }
|
|
+
|
|
+ function bookmarkOverflows(el) {
|
|
+ const arr = [];
|
|
+
|
|
+ while (el && el.parentNode && el.parentNode instanceof Element) {
|
|
+ if (el.parentNode.scrollTop) {
|
|
+ el.parentNode.style.scrollBehavior = 'auto';
|
|
+ arr.push([el.parentNode, el.parentNode.scrollTop]);
|
|
+ }
|
|
+ el = el.parentNode;
|
|
+ }
|
|
+
|
|
+ return ()=> arr.forEach(([node, scrollTop]) => {
|
|
+ node.scrollTop = scrollTop;
|
|
+ node.style.scrollBehavior = null;
|
|
+ });
|
|
+ }
|
|
+
|
|
+ function resize() {
|
|
+ if (ta.scrollHeight === 0) {
|
|
+ // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // remove smooth scroll & prevent scroll-position jumping by restoring original scroll position
|
|
+ const restoreOverflows = bookmarkOverflows(ta);
|
|
+
|
|
+ ta.style.height = '';
|
|
+ ta.style.height = (ta.scrollHeight+heightOffset)+'px';
|
|
+
|
|
+ // used to check if an update is actually necessary on window.resize
|
|
+ clientWidth = ta.clientWidth;
|
|
+
|
|
+ restoreOverflows();
|
|
+ }
|
|
+
|
|
+ function update() {
|
|
+ resize();
|
|
+
|
|
+ const styleHeight = Math.round(parseFloat(ta.style.height));
|
|
+ const computed = window.getComputedStyle(ta, null);
|
|
+
|
|
+ // Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box
|
|
+ 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
|
|
+ // the max-height has been exceeded, in which case the overflow should be allowed.
|
|
+ if (actualHeight < styleHeight) {
|
|
+ if (computed.overflowY === 'hidden') {
|
|
+ changeOverflow('scroll');
|
|
+ resize();
|
|
+ actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
|
+ }
|
|
+ } else {
|
|
+ // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
|
|
+ if (computed.overflowY !== 'hidden') {
|
|
+ changeOverflow('hidden');
|
|
+ resize();
|
|
+ actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (cachedHeight !== actualHeight) {
|
|
+ cachedHeight = actualHeight;
|
|
+ const evt = createEvent('autosize:resized');
|
|
+ try {
|
|
+ ta.dispatchEvent(evt);
|
|
+ } catch (err) {
|
|
+ // Firefox will throw an error on dispatchEvent for a detached element
|
|
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=889376
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ let lastUpdateTime = 0;
|
|
+ let updateTimeoutId = null;
|
|
+
|
|
+ const throttledUpdate = (throttleInterval = 50 /* ms */) => {
|
|
+ // Adds a small throttle to prevent flooding of updates
|
|
+ // in case of a huge pasting of text.
|
|
+ const now = Date.now();
|
|
+ const timeSinceLastCall = now - lastUpdateTime;
|
|
+
|
|
+ if (timeSinceLastCall >= throttleInterval) {
|
|
+ lastUpdateTime = now;
|
|
+ update();
|
|
+ } else {
|
|
+ if (updateTimeoutId) {
|
|
+ clearTimeout(updateTimeoutId);
|
|
+ }
|
|
+ // We still want to ensure that the last change is picked up
|
|
+ // so we schedule an update for the near future.
|
|
+ updateTimeoutId = setTimeout(() => {
|
|
+ lastUpdateTime = Date.now();
|
|
+ update();
|
|
+ }, throttleInterval - timeSinceLastCall);
|
|
+ }
|
|
+ };
|
|
+
|
|
+ const pageResize = () => {
|
|
+ if (ta.clientWidth !== clientWidth) {
|
|
+ update();
|
|
+ }
|
|
+ };
|
|
+
|
|
+ const destroy = (style => {
|
|
+ window.removeEventListener('resize', pageResize, false);
|
|
+ ta.removeEventListener('input', throttledUpdate, false);
|
|
+ ta.removeEventListener('keyup', update, false);
|
|
+ ta.removeEventListener('autosize:destroy', destroy, false);
|
|
+ ta.removeEventListener('autosize:update', update, false);
|
|
+
|
|
+ Object.keys(style).forEach(key => {
|
|
+ ta.style[key] = style[key];
|
|
+ });
|
|
+
|
|
+ map.delete(ta);
|
|
+ }).bind(ta, {
|
|
+ height: ta.style.height,
|
|
+ resize: ta.style.resize,
|
|
+ overflowY: ta.style.overflowY,
|
|
+ overflowX: ta.style.overflowX,
|
|
+ wordWrap: ta.style.wordWrap,
|
|
+ });
|
|
+
|
|
+ ta.addEventListener('autosize:destroy', destroy, false);
|
|
+
|
|
+ // IE9 does not fire onpropertychange or oninput for deletions,
|
|
+ // so binding to onkeyup to catch most of those events.
|
|
+ // There is no way that I know of to detect something like 'cut' in IE9.
|
|
+ if ('onpropertychange' in ta && 'oninput' in ta) {
|
|
+ ta.addEventListener('keyup', update, false);
|
|
+ }
|
|
+
|
|
+ window.addEventListener('resize', pageResize, false);
|
|
+ ta.addEventListener('input', throttledUpdate, false);
|
|
+ ta.addEventListener('autosize:update', update, false);
|
|
+ ta.style.overflowX = 'hidden';
|
|
+ ta.style.wordWrap = 'break-word';
|
|
+
|
|
+ map.set(ta, {
|
|
+ destroy,
|
|
+ update,
|
|
+ });
|
|
+
|
|
+ init();
|
|
}
|
|
|
|
function destroy(ta) {
|
|
- var methods = map.get(ta);
|
|
-
|
|
- if (methods) {
|
|
- methods.destroy();
|
|
- }
|
|
+ const methods = map.get(ta);
|
|
+ if (methods) {
|
|
+ methods.destroy();
|
|
+ }
|
|
}
|
|
|
|
function update(ta) {
|
|
- var methods = map.get(ta);
|
|
-
|
|
- if (methods) {
|
|
- methods.update();
|
|
- }
|
|
+ const methods = map.get(ta);
|
|
+ if (methods) {
|
|
+ methods.update();
|
|
+ }
|
|
}
|
|
|
|
- var autosize = null; // Do nothing in Node.js environment and IE8 (or lower)
|
|
+ let autosize = null;
|
|
|
|
+ // Do nothing in Node.js environment and IE8 (or lower)
|
|
if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
|
|
- autosize = function autosize(el) {
|
|
- return el;
|
|
- };
|
|
-
|
|
- autosize.destroy = function (el) {
|
|
- return el;
|
|
- };
|
|
-
|
|
- autosize.update = function (el) {
|
|
- return el;
|
|
- };
|
|
+ autosize = el => el;
|
|
+ autosize.destroy = el => el;
|
|
+ autosize.update = el => el;
|
|
} else {
|
|
- autosize = function autosize(el, options) {
|
|
- if (el) {
|
|
- Array.prototype.forEach.call(el.length ? el : [el], function (x) {
|
|
- return assign(x);
|
|
- });
|
|
- }
|
|
-
|
|
- return el;
|
|
- };
|
|
-
|
|
- autosize.destroy = function (el) {
|
|
- if (el) {
|
|
- Array.prototype.forEach.call(el.length ? el : [el], destroy);
|
|
- }
|
|
-
|
|
- return el;
|
|
- };
|
|
-
|
|
- autosize.update = function (el) {
|
|
- if (el) {
|
|
- Array.prototype.forEach.call(el.length ? el : [el], update);
|
|
- }
|
|
-
|
|
- return el;
|
|
- };
|
|
+ autosize = (el, options) => {
|
|
+ if (el) {
|
|
+ Array.prototype.forEach.call(el.length ? el : [el], x => assign(x));
|
|
+ }
|
|
+ return el;
|
|
+ };
|
|
+ autosize.destroy = el => {
|
|
+ if (el) {
|
|
+ Array.prototype.forEach.call(el.length ? el : [el], destroy);
|
|
+ }
|
|
+ return el;
|
|
+ };
|
|
+ autosize.update = el => {
|
|
+ if (el) {
|
|
+ Array.prototype.forEach.call(el.length ? el : [el], update);
|
|
+ }
|
|
+ return el;
|
|
+ };
|
|
}
|
|
|
|
var autosize$1 = autosize;
|
|
|
|
return autosize$1;
|
|
|
|
-})));
|
|
+}));
|
|
diff --git a/dist/autosize.min.js b/dist/autosize.min.js
|
|
index d9c6490a632def3c5233145ff4d469503a29fcc9..de14ff83e73718a531d42de1fce7b38454fc52f5 100644
|
|
--- a/dist/autosize.min.js
|
|
+++ b/dist/autosize.min.js
|
|
@@ -1 +1 @@
|
|
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).autosize=t()}(this,function(){var e,t,n="function"==typeof Map?new Map:(e=[],t=[],{has:function(t){return e.indexOf(t)>-1},get:function(n){return t[e.indexOf(n)]},set:function(n,o){-1===e.indexOf(n)&&(e.push(n),t.push(o))},delete:function(n){var o=e.indexOf(n);o>-1&&(e.splice(o,1),t.splice(o,1))}}),o=function(e){return new Event(e,{bubbles:!0})};try{new Event("test")}catch(e){o=function(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}function r(e){var t=n.get(e);t&&t.destroy()}function i(e){var t=n.get(e);t&&t.update()}var l=null;return"undefined"==typeof window||"function"!=typeof window.getComputedStyle?((l=function(e){return e}).destroy=function(e){return e},l.update=function(e){return e}):((l=function(e,t){return e&&Array.prototype.forEach.call(e.length?e:[e],function(e){return function(e){if(e&&e.nodeName&&"TEXTAREA"===e.nodeName&&!n.has(e)){var t,r=null,i=null,l=null,a=function(){e.clientWidth!==i&&f()},d=function(t){window.removeEventListener("resize",a,!1),e.removeEventListener("input",f,!1),e.removeEventListener("keyup",f,!1),e.removeEventListener("autosize:destroy",d,!1),e.removeEventListener("autosize:update",f,!1),Object.keys(t).forEach(function(n){e.style[n]=t[n]}),n.delete(e)}.bind(e,{height:e.style.height,resize:e.style.resize,overflowY:e.style.overflowY,overflowX:e.style.overflowX,wordWrap:e.style.wordWrap});e.addEventListener("autosize:destroy",d,!1),"onpropertychange"in e&&"oninput"in e&&e.addEventListener("keyup",f,!1),window.addEventListener("resize",a,!1),e.addEventListener("input",f,!1),e.addEventListener("autosize:update",f,!1),e.style.overflowX="hidden",e.style.wordWrap="break-word",n.set(e,{destroy:d,update:f}),"vertical"===(t=window.getComputedStyle(e,null)).resize?e.style.resize="none":"both"===t.resize&&(e.style.resize="horizontal"),r="content-box"===t.boxSizing?-(parseFloat(t.paddingTop)+parseFloat(t.paddingBottom)):parseFloat(t.borderTopWidth)+parseFloat(t.borderBottomWidth),isNaN(r)&&(r=0),f()}function s(t){var n=e.style.width;e.style.width="0px",e.style.width=n,e.style.overflowY=t}function u(){if(0!==e.scrollHeight){var t=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&(e.parentNode.style.scrollBehavior="auto",t.push([e.parentNode,e.parentNode.scrollTop])),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0];t.scrollTop=e[1],t.style.scrollBehavior=null})}}(e);e.style.height="",e.style.height=e.scrollHeight+r+"px",i=e.clientWidth,t()}}function f(){u();var t=Math.round(parseFloat(e.style.height)),n=window.getComputedStyle(e,null),r="content-box"===n.boxSizing?Math.round(parseFloat(n.height)):e.offsetHeight;if(r<t?"hidden"===n.overflowY&&(s("scroll"),u(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight):"hidden"!==n.overflowY&&(s("hidden"),u(),r="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight),l!==r){l=r;var i=o("autosize:resized");try{e.dispatchEvent(i)}catch(e){}}}}(e)}),e}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],r),e},l.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],i),e}),l});
|
|
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).autosize=t()}(this,function(){const e="function"==typeof Map?new Map:function(){const e=[],t=[];return{has:t=>e.indexOf(t)>-1,get:o=>t[e.indexOf(o)],set(o,n){-1===e.indexOf(o)&&(e.push(o),t.push(n))},delete(o){const n=e.indexOf(o);n>-1&&(e.splice(n,1),t.splice(n,1))}}}();let t=e=>new Event(e,{bubbles:!0});try{new Event("test")}catch(e){t=e=>{const t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}function o(t){const o=e.get(t);o&&o.destroy()}function n(t){const o=e.get(t);o&&o.update()}let i=null;return"undefined"==typeof window||"function"!=typeof window.getComputedStyle?(i=e=>e,i.destroy=e=>e,i.update=e=>e):(i=(o,n)=>(o&&Array.prototype.forEach.call(o.length?o:[o],o=>function(o){if(!o||!o.nodeName||"TEXTAREA"!==o.nodeName||e.has(o))return;let n=null,i=null,r=null;function l(e){{const e=o.style.width;o.style.width="0px",o.style.width=e}o.style.overflowY=e}function s(){if(0===o.scrollHeight)return;const e=function(e){const t=[];for(;e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&(e.parentNode.style.scrollBehavior="auto",t.push([e.parentNode,e.parentNode.scrollTop])),e=e.parentNode;return()=>t.forEach(([e,t])=>{e.scrollTop=t,e.style.scrollBehavior=null})}(o);o.style.height="",o.style.height=o.scrollHeight+n+"px",i=o.clientWidth,e()}function d(){s();const e=Math.round(parseFloat(o.style.height)),n=window.getComputedStyle(o,null);var i="content-box"===n.boxSizing?Math.round(parseFloat(n.height)):o.offsetHeight;if(i<e?"hidden"===n.overflowY&&(l("scroll"),s(),i="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(o,null).height)):o.offsetHeight):"hidden"!==n.overflowY&&(l("hidden"),s(),i="content-box"===n.boxSizing?Math.round(parseFloat(window.getComputedStyle(o,null).height)):o.offsetHeight),r!==i){r=i;const e=t("autosize:resized");try{o.dispatchEvent(e)}catch(e){}}}let a=0,u=null;const p=(e=50)=>{const t=Date.now(),o=t-a;o>=e?(a=t,d()):(u&&clearTimeout(u),u=setTimeout(()=>{a=Date.now(),d()},e-o))},c=()=>{o.clientWidth!==i&&d()},h=(t=>{window.removeEventListener("resize",c,!1),o.removeEventListener("input",p,!1),o.removeEventListener("keyup",d,!1),o.removeEventListener("autosize:destroy",h,!1),o.removeEventListener("autosize:update",d,!1),Object.keys(t).forEach(e=>{o.style[e]=t[e]}),e.delete(o)}).bind(o,{height:o.style.height,resize:o.style.resize,overflowY:o.style.overflowY,overflowX:o.style.overflowX,wordWrap:o.style.wordWrap});o.addEventListener("autosize:destroy",h,!1),"onpropertychange"in o&&"oninput"in o&&o.addEventListener("keyup",d,!1),window.addEventListener("resize",c,!1),o.addEventListener("input",p,!1),o.addEventListener("autosize:update",d,!1),o.style.overflowX="hidden",o.style.wordWrap="break-word",e.set(o,{destroy:h,update:d}),function(){const e=window.getComputedStyle(o,null);"vertical"===e.resize?o.style.resize="none":"both"===e.resize&&(o.style.resize="horizontal"),n="content-box"===e.boxSizing?-(parseFloat(e.paddingTop)+parseFloat(e.paddingBottom)):parseFloat(e.borderTopWidth)+parseFloat(e.borderBottomWidth),isNaN(n)&&(n=0),d()}()}(o)),o),i.destroy=e=>(e&&Array.prototype.forEach.call(e.length?e:[e],o),e),i.update=e=>(e&&Array.prototype.forEach.call(e.length?e:[e],n),e)),i});
|
|
diff --git a/src/autosize.js b/src/autosize.js
|
|
index b199f5aa7b438ef375137d109787d171e6142843..5c9f7742ea5905f4f954643857e6c74c9dfad10d 100644
|
|
--- a/src/autosize.js
|
|
+++ b/src/autosize.js
|
|
@@ -156,6 +156,31 @@ function assign(ta) {
|
|
}
|
|
}
|
|
|
|
+ let lastUpdateTime = 0;
|
|
+ let updateTimeoutId = null;
|
|
+
|
|
+ const throttledUpdate = (throttleInterval = 50 /* ms */) => {
|
|
+ // Adds a small throttle to prevent flooding of updates
|
|
+ // in case of a huge pasting of text.
|
|
+ const now = Date.now();
|
|
+ const timeSinceLastCall = now - lastUpdateTime;
|
|
+
|
|
+ if (timeSinceLastCall >= throttleInterval) {
|
|
+ lastUpdateTime = now;
|
|
+ update();
|
|
+ } else {
|
|
+ if (updateTimeoutId) {
|
|
+ clearTimeout(updateTimeoutId);
|
|
+ }
|
|
+ // We still want to ensure that the last change is picked up
|
|
+ // so we schedule an update for the near future.
|
|
+ updateTimeoutId = setTimeout(() => {
|
|
+ lastUpdateTime = Date.now();
|
|
+ update();
|
|
+ }, throttleInterval - timeSinceLastCall);
|
|
+ }
|
|
+ };
|
|
+
|
|
const pageResize = () => {
|
|
if (ta.clientWidth !== clientWidth) {
|
|
update();
|
|
@@ -164,7 +189,7 @@ function assign(ta) {
|
|
|
|
const destroy = (style => {
|
|
window.removeEventListener('resize', pageResize, false);
|
|
- ta.removeEventListener('input', update, false);
|
|
+ ta.removeEventListener('input', throttledUpdate, false);
|
|
ta.removeEventListener('keyup', update, false);
|
|
ta.removeEventListener('autosize:destroy', destroy, false);
|
|
ta.removeEventListener('autosize:update', update, false);
|
|
@@ -192,7 +217,7 @@ function assign(ta) {
|
|
}
|
|
|
|
window.addEventListener('resize', pageResize, false);
|
|
- ta.addEventListener('input', update, false);
|
|
+ ta.addEventListener('input', throttledUpdate, false);
|
|
ta.addEventListener('autosize:update', update, false);
|
|
ta.style.overflowX = 'hidden';
|
|
ta.style.wordWrap = 'break-word';
|