pinafore/src/routes/_thirdparty/autosize/autosize.js

125 lines
3 KiB
JavaScript
Raw Normal View History

2018-02-25 22:29:12 -08:00
// Modified from https://github.com/jackmoore/autosize/blob/113f1b3/src/autosize.js
2018-02-25 20:45:11 -08:00
// The only change is to remove IE-specific hacks,
// remove parent overflow checks, make page resizes more performant,
// add deferredUpdate, and add perf marks.
import { mark, stop } from '../../_utils/marks'
import debounce from 'lodash-es/debounce'
import { getScrollContainer } from '../../_utils/scrollContainer'
import { throttleTimer } from '../../_utils/throttleTimer'
const doUpdate = process.browser && throttleTimer(requestAnimationFrame)
2018-02-25 20:45:11 -08:00
const map = new Map()
function assign (ta) {
2018-02-25 22:29:12 -08:00
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) {
return
}
2018-02-25 20:45:11 -08:00
// TODO: hack - grab our scroll container so we can maintain the scrollTop
2019-08-03 13:49:37 -07:00
const container = getScrollContainer()
2018-02-25 23:01:15 -08:00
let heightOffset = null
2018-02-25 20:45:11 -08:00
function init () {
2018-02-25 23:01:15 -08:00
const style = window.getComputedStyle(ta, null)
if (style.boxSizing === 'content-box') {
heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom))
} else {
heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth)
}
2018-02-25 20:45:11 -08:00
update()
}
function resize () {
mark('autosize:resize()')
_resize()
2018-02-25 20:45:11 -08:00
stop('autosize:resize()')
}
function _resize () {
const originalHeight = ta.style.height
const scrollTop = container.scrollTop
2018-02-25 20:45:11 -08:00
ta.style.height = '' // this may change the scrollTop in Firefox
2018-02-25 20:45:11 -08:00
const endHeight = ta.scrollHeight + heightOffset
2018-02-25 20:45:11 -08:00
if (ta.scrollHeight === 0) {
// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
ta.style.height = originalHeight
} else {
ta.style.height = `${endHeight}px`
container.scrollTop = scrollTop // Firefox jiggles if we don't reset the scrollTop of the container
2018-02-25 20:45:11 -08:00
}
}
const deferredUpdate = () => doUpdate(update)
2018-02-25 20:45:11 -08:00
function update () {
mark('autosize:update()')
_update()
stop('autosize:update()')
}
function _update () {
resize()
2018-02-25 20:45:11 -08:00
}
const pageResize = debounce(() => requestAnimationFrame(update), 1000)
2018-02-25 20:45:11 -08:00
2018-02-25 22:29:12 -08:00
const destroy = () => {
2018-02-25 20:45:11 -08:00
window.removeEventListener('resize', pageResize, false)
ta.removeEventListener('input', deferredUpdate, false)
map.delete(ta)
2018-02-25 22:29:12 -08:00
}
2018-02-25 20:45:11 -08:00
window.addEventListener('resize', pageResize, false)
ta.addEventListener('input', deferredUpdate, false)
map.set(ta, {
destroy,
update
})
init()
}
function destroy (ta) {
const methods = map.get(ta)
if (methods) {
methods.destroy()
}
}
function update (ta) {
const methods = map.get(ta)
if (methods) {
methods.update()
}
}
2019-08-03 13:49:37 -07:00
const autosize = (el, options) => {
2018-02-25 22:29:12 -08:00
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], x => assign(x, options))
2018-02-25 20:45:11 -08:00
}
2018-02-25 22:29:12 -08:00
return el
}
autosize.destroy = el => {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], destroy)
2018-02-25 20:45:11 -08:00
}
2018-02-25 22:29:12 -08:00
return el
}
autosize.update = el => {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], update)
2018-02-25 20:45:11 -08:00
}
2018-02-25 22:29:12 -08:00
return el
2018-02-25 20:45:11 -08:00
}
export { autosize }