mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 03:40:00 +08:00
DEV: Update ExpandingTextArea component (#25890)
This commit is contained in:
parent
3200e276b7
commit
5dc95eaacc
|
@ -24,8 +24,9 @@
|
|||
{{/if}}
|
||||
|
||||
<ExpandingTextArea
|
||||
@value={{this.buffered.value}}
|
||||
@rows="1"
|
||||
{{on "input" (with-event-value (fn (mut this.buffered.value)))}}
|
||||
value={{this.buffered.value}}
|
||||
rows="1"
|
||||
class="site-text-value"
|
||||
/>
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { on } from "@ember/modifier";
|
||||
import autosize from "autosize";
|
||||
import { modifier } from "ember-modifier";
|
||||
import autoFocus from "discourse/modifiers/auto-focus";
|
||||
|
||||
const resize = modifier((element) => {
|
||||
autosize(element);
|
||||
return () => autosize.destroy(element);
|
||||
});
|
||||
|
||||
const ExpandingTextArea = <template>
|
||||
<textarea
|
||||
{{autoFocus}}
|
||||
{{resize}}
|
||||
{{! deprecated args: }}
|
||||
autocorrect={{@autocorrect}}
|
||||
class={{@class}}
|
||||
maxlength={{@maxlength}}
|
||||
name={{@name}}
|
||||
rows={{@rows}}
|
||||
value={{@value}}
|
||||
{{(if @input (modifier on "input" @input))}}
|
||||
...attributes
|
||||
></textarea>
|
||||
</template>;
|
||||
|
||||
export default ExpandingTextArea;
|
|
@ -1,30 +0,0 @@
|
|||
import { TextArea } from "@ember/legacy-built-in-components";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import $ from "jquery";
|
||||
import autosize from "discourse/lib/autosize";
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
|
||||
export default TextArea.extend({
|
||||
@on("didInsertElement")
|
||||
_startWatching() {
|
||||
schedule("afterRender", () => {
|
||||
$(this.element).focus();
|
||||
autosize(this.element);
|
||||
});
|
||||
},
|
||||
|
||||
@observes("value")
|
||||
_updateAutosize() {
|
||||
this.element.value = this.value;
|
||||
const event = new Event("autosize:update", {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
});
|
||||
this.element.dispatchEvent(event);
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_disableAutosize() {
|
||||
autosize.destroy($(this.element));
|
||||
},
|
||||
});
|
|
@ -42,8 +42,12 @@
|
|||
</label>
|
||||
|
||||
<ExpandingTextArea
|
||||
@name="membership-request-template"
|
||||
@value={{this.model.membership_request_template}}
|
||||
{{on
|
||||
"input"
|
||||
(with-event-value (fn (mut this.model.membership_request_template)))
|
||||
}}
|
||||
value={{this.model.membership_request_template}}
|
||||
name="membership-request-template"
|
||||
class="group-form-membership-request-template input-xxlarge"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,11 @@
|
|||
{{i18n "groups.membership_request.reason"}}
|
||||
</label>
|
||||
|
||||
<ExpandingTextArea @value={{this.reason}} @maxlength="5000" />
|
||||
<ExpandingTextArea
|
||||
{{on "input" (with-event-value (fn (mut this.reason)))}}
|
||||
value={{this.reason}}
|
||||
maxlength="5000"
|
||||
/>
|
||||
</div>
|
||||
</:body>
|
||||
|
||||
|
|
|
@ -1,216 +0,0 @@
|
|||
const set =
|
||||
typeof Set === "function"
|
||||
? new Set()
|
||||
: (function () {
|
||||
const list = [];
|
||||
|
||||
return {
|
||||
has(key) {
|
||||
return Boolean(list.includes(key));
|
||||
},
|
||||
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 event = new Event("autosize:resized", {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
});
|
||||
ta.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
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 event = new Event("autosize:destroy", {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
});
|
||||
ta.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function exportUpdate(ta) {
|
||||
if (!(ta && ta.nodeName && ta.nodeName === "TEXTAREA")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = new Event("autosize:update", {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
});
|
||||
ta.dispatchEvent(event);
|
||||
}
|
||||
|
||||
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;
|
|
@ -59,6 +59,7 @@
|
|||
"@uppy/xhr-upload": "3.1.1",
|
||||
"a11y-dialog": "8.0.4",
|
||||
"admin": "1.0.0",
|
||||
"autosize": "^6.0.1",
|
||||
"babel-import-util": "^2.0.1",
|
||||
"babel-plugin-ember-template-compilation": "^2.2.1",
|
||||
"bootstrap": "3.4.1",
|
||||
|
|
|
@ -3084,6 +3084,11 @@ atob@^2.1.2:
|
|||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
autosize@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/autosize/-/autosize-6.0.1.tgz#64ee78dd7029be959eddd3afbbd33235b957e10f"
|
||||
integrity sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==
|
||||
|
||||
available-typed-arrays@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
||||
|
|
Loading…
Reference in New Issue
Block a user