This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/lib/autosize.js
Robin Ward a3f0543f99
Support for transpiling .js files (#9160)
* Remove some `.es6` from comments where it does not matter

* Use a post processor for transpilation

This will allow us to eventually use the directory structure to
transpile rather than the extension.

* FIX: Some errors and clean up in confirm-new-email

It would throw an error if the webauthn element wasn't present.
Also I changed things so that no-module is not explicitly
referenced.

* Remove `no-module`

Instead we allow a magic comment: `// discourse-skip-module` to prevent
the asset pipeline from creating a module.

* DEV: Enable babel transpilation based on directory

If it's in `app/assets/javascripts/dicourse` it will be transpiled
even without the `.es6` extension.

* REFACTOR: Remove Tilt/ES6ModuleTranspiler
2020-03-11 09:43:55 -04:00

203 lines
5.1 KiB
JavaScript

const set =
typeof Set === "function"
? new Set()
: (function() {
const list = [];
return {
has(key) {
return Boolean(list.indexOf(key) > -1);
},
add(key) {
list.push(key);
},
delete(key) {
list.splice(list.indexOf(key), 1);
}
};
})();
function assign(ta, { setOverflowX = true, setOverflowY = true } = {}) {
if (!ta || !ta.nodeName || ta.nodeName !== "TEXTAREA" || set.has(ta)) return;
let heightOffset = null;
let overflowY = null;
let clientWidth = ta.clientWidth;
function init() {
const style = window.getComputedStyle(ta, null);
overflowY = style.overflowY;
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";
// Force reflow:
/* jshint ignore:start */
ta.offsetWidth;
/* jshint ignore:end */
ta.style.width = width;
}
overflowY = value;
if (setOverflowY) {
ta.style.overflowY = value;
}
resize();
}
function resize() {
const htmlTop = window.pageYOffset;
const bodyTop = document.body.scrollTop;
const originalHeight = ta.style.height;
ta.style.height = "auto";
let endHeight = ta.scrollHeight + heightOffset;
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;
return;
}
ta.style.height = endHeight + "px";
// used to check if an update is actually necessary on window.resize
clientWidth = ta.clientWidth;
// prevents scroll-position jumping
document.documentElement.scrollTop = htmlTop;
document.body.scrollTop = bodyTop;
}
function update() {
const startHeight = ta.style.height;
resize();
const style = window.getComputedStyle(ta, null);
if (style.height !== ta.style.height) {
if (overflowY !== "visible") {
changeOverflow("visible");
}
} else {
if (overflowY !== "hidden") {
changeOverflow("hidden");
}
}
if (startHeight !== ta.style.height) {
const evt = document.createEvent("Event");
evt.initEvent("autosize:resized", true, false);
ta.dispatchEvent(evt);
}
}
const pageResize = () => {
if (ta.clientWidth !== clientWidth) {
update();
}
};
const destroy = 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);
set.delete(ta);
Object.keys(style).forEach(key => {
ta.style[key] = style[key];
});
};
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);
set.add(ta);
if (setOverflowX) {
ta.style.overflowX = "hidden";
ta.style.wordWrap = "break-word";
}
init();
}
function exportDestroy(ta) {
if (!(ta && ta.nodeName && ta.nodeName === "TEXTAREA")) return;
const evt = document.createEvent("Event");
evt.initEvent("autosize:destroy", true, false);
ta.dispatchEvent(evt);
}
function exportUpdate(ta) {
if (!(ta && ta.nodeName && ta.nodeName === "TEXTAREA")) return;
const evt = document.createEvent("Event");
evt.initEvent("autosize:update", true, false);
ta.dispatchEvent(evt);
}
let autosize = (el, options) => {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], x =>
assign(x, options)
);
}
return el;
};
autosize.destroy = el => {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], exportDestroy);
}
return el;
};
autosize.update = el => {
if (el) {
Array.prototype.forEach.call(el.length ? el : [el], exportUpdate);
}
return el;
};
export default autosize;