From 96303583addedccba5586d2de8bef3c59a7e0ed4 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 25 Feb 2018 22:29:12 -0800 Subject: [PATCH] improve perf of autosize.js --- .../_components/compose/LiteComposeBox.html | 11 ++- routes/_utils/autosize.js | 80 +++++-------------- 2 files changed, 28 insertions(+), 63 deletions(-) diff --git a/routes/_components/compose/LiteComposeBox.html b/routes/_components/compose/LiteComposeBox.html index cb038fcb..ae904f0f 100644 --- a/routes/_components/compose/LiteComposeBox.html +++ b/routes/_components/compose/LiteComposeBox.html @@ -87,6 +87,7 @@ margin-top: 10px; resize: none; overflow: hidden; + word-wrap: break-word; /* Text must be at least 16px or else iOS Safari zooms in */ font-size: 1.2em; /* Hack to make Edge stretch the element all the way to the right. @@ -152,10 +153,6 @@ export default { oncreate() { this.set({inputText: store.get('currentInputTextInCompose')}) - mark('autosize()') - autosize(this.refs.textarea) // TODO: this layout thrashes, could maybe find a better design - stop('autosize()') - const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000) this.observe('inputText', inputText => { @@ -166,6 +163,12 @@ saveText() }, {init: false}) + requestAnimationFrame(() => { + mark('autosize()') + autosize(this.refs.textarea) + stop('autosize()') + }) + // Avoid input delays by updating these values after a rAF this.observe('inputLengthToDisplay', inputLengthToDisplay => { requestAnimationFrame(() => { diff --git a/routes/_utils/autosize.js b/routes/_utils/autosize.js index c7d55955..b29befb3 100644 --- a/routes/_utils/autosize.js +++ b/routes/_utils/autosize.js @@ -1,4 +1,4 @@ -// Modified from https://github.com/jackmoore/autosize/commit/113f1b345868901619d4b01cda02b09aa1690ebd +// Modified from https://github.com/jackmoore/autosize/blob/113f1b3/src/autosize.js // The only change is to remove IE-specific hacks, // remove parent overflow checks, make page resizes more performant, // add deferredUpdate, and add perf marks. @@ -11,30 +11,13 @@ const map = new Map() let createEvent = (name) => new Event(name, {bubbles: true}) function assign (ta) { - if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return + if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) { + return + } - let heightOffset = 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() } @@ -50,7 +33,7 @@ function assign (ta) { ta.style.height = '' - let endHeight = ta.scrollHeight + heightOffset + let endHeight = ta.scrollHeight if (ta.scrollHeight === 0) { // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM. @@ -86,32 +69,20 @@ function assign (ta) { const pageResize = debounce(update, 1000) - const destroy = (style => { + const destroy = () => { window.removeEventListener('resize', pageResize, false) ta.removeEventListener('input', deferredUpdate, 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) window.addEventListener('resize', pageResize, false) ta.addEventListener('input', deferredUpdate, false) ta.addEventListener('autosize:update', update, false) - ta.style.overflowX = 'hidden' - ta.style.wordWrap = 'break-word' map.set(ta, { destroy, @@ -135,32 +106,23 @@ function update (ta) { } } -let autosize = null - -// Do nothing in Node.js environment and IE8 (or lower) -if (!process.browser) { - autosize = el => el - autosize.destroy = el => el - autosize.update = el => el -} else { - autosize = (el, options) => { - if (el) { - Array.prototype.forEach.call(el.length ? el : [el], x => assign(x, options)) - } - return el +let autosize = (el, options) => { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], x => assign(x, options)) } - autosize.destroy = el => { - if (el) { - Array.prototype.forEach.call(el.length ? el : [el], destroy) - } - return el + return el +} +autosize.destroy = el => { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], destroy) } - autosize.update = el => { - if (el) { - Array.prototype.forEach.call(el.length ? el : [el], update) - } - return el + return el +} +autosize.update = el => { + if (el) { + Array.prototype.forEach.call(el.length ? el : [el], update) } + return el } export { autosize }