mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-01-26 19:19:57 +00:00
147 lines
5.7 KiB
JavaScript
147 lines
5.7 KiB
JavaScript
// From https://github.com/component/textarea-caret-position
|
|
|
|
TAC.getCaretCoordinates = class CaretUtils {
|
|
// We'll copy the properties below into the mirror div.
|
|
// Note that some browsers, such as Firefox, do not concatenate properties
|
|
// into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),
|
|
// so we have to list every single property explicitly.
|
|
static #properties = [
|
|
"direction", // RTL support
|
|
"boxSizing",
|
|
"width", // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does
|
|
"height",
|
|
"overflowX",
|
|
"overflowY", // copy the scrollbar for IE
|
|
|
|
"borderTopWidth",
|
|
"borderRightWidth",
|
|
"borderBottomWidth",
|
|
"borderLeftWidth",
|
|
"borderStyle",
|
|
|
|
"paddingTop",
|
|
"paddingRight",
|
|
"paddingBottom",
|
|
"paddingLeft",
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/font
|
|
"fontStyle",
|
|
"fontVariant",
|
|
"fontWeight",
|
|
"fontStretch",
|
|
"fontSize",
|
|
"fontSizeAdjust",
|
|
"lineHeight",
|
|
"fontFamily",
|
|
|
|
"textAlign",
|
|
"textTransform",
|
|
"textIndent",
|
|
"textDecoration", // might not make a difference, but better be safe
|
|
|
|
"letterSpacing",
|
|
"wordSpacing",
|
|
|
|
"tabSize",
|
|
"MozTabSize",
|
|
];
|
|
|
|
static #isBrowser = typeof window !== "undefined";
|
|
static #isFirefox = this.#isBrowser && window.mozInnerScreenX != null;
|
|
|
|
static getCaretCoordinates(element, position, options) {
|
|
if (!CaretUtils.#isBrowser) {
|
|
throw new Error(
|
|
"textarea-caret-position#getCaretCoordinates should only be called in a browser"
|
|
);
|
|
}
|
|
|
|
var debug = (options && options.debug) || false;
|
|
if (debug) {
|
|
var el = document.querySelector("#input-textarea-caret-position-mirror-div");
|
|
if (el) el.parentNode.removeChild(el);
|
|
}
|
|
|
|
// The mirror div will replicate the textarea's style
|
|
var div = document.createElement("div");
|
|
div.id = "input-textarea-caret-position-mirror-div";
|
|
document.body.appendChild(div);
|
|
|
|
var style = div.style;
|
|
var computed = window.getComputedStyle
|
|
? window.getComputedStyle(element)
|
|
: element.currentStyle; // currentStyle for IE < 9
|
|
var isInput = element.nodeName === "INPUT";
|
|
|
|
// Default textarea styles
|
|
style.whiteSpace = "pre-wrap";
|
|
if (!isInput) style.wordWrap = "break-word"; // only for textarea-s
|
|
|
|
// Position off-screen
|
|
style.position = "absolute"; // required to return coordinates properly
|
|
if (!debug) style.visibility = "hidden"; // not 'display: none' because we want rendering
|
|
|
|
// Transfer the element's properties to the div
|
|
CaretUtils.#properties.forEach(function (prop) {
|
|
if (isInput && prop === "lineHeight") {
|
|
// Special case for <input>s because text is rendered centered and line height may be != height
|
|
if (computed.boxSizing === "border-box") {
|
|
var height = parseInt(computed.height);
|
|
var outerHeight =
|
|
parseInt(computed.paddingTop) +
|
|
parseInt(computed.paddingBottom) +
|
|
parseInt(computed.borderTopWidth) +
|
|
parseInt(computed.borderBottomWidth);
|
|
var targetHeight = outerHeight + parseInt(computed.lineHeight);
|
|
if (height > targetHeight) {
|
|
style.lineHeight = height - outerHeight + "px";
|
|
} else if (height === targetHeight) {
|
|
style.lineHeight = computed.lineHeight;
|
|
} else {
|
|
style.lineHeight = 0;
|
|
}
|
|
} else {
|
|
style.lineHeight = computed.height;
|
|
}
|
|
} else {
|
|
style[prop] = computed[prop];
|
|
}
|
|
});
|
|
|
|
if (CaretUtils.#isFirefox) {
|
|
// Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275
|
|
if (element.scrollHeight > parseInt(computed.height)) style.overflowY = "scroll";
|
|
} else {
|
|
style.overflow = "hidden"; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
|
|
}
|
|
|
|
div.textContent = element.value.substring(0, position);
|
|
// The second special handling for input type="text" vs textarea:
|
|
// spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
|
|
if (isInput) div.textContent = div.textContent.replace(/\s/g, "\u00a0");
|
|
|
|
var span = document.createElement("span");
|
|
// Wrapping must be replicated *exactly*, including when a long word gets
|
|
// onto the next line, with whitespace at the end of the line before (#7).
|
|
// The *only* reliable way to do that is to copy the *entire* rest of the
|
|
// textarea's content into the <span> created at the caret position.
|
|
// For inputs, just '.' would be enough, but no need to bother.
|
|
span.textContent = element.value.substring(position) || "."; // || because a completely empty faux span doesn't render at all
|
|
div.appendChild(span);
|
|
|
|
var coordinates = {
|
|
top: span.offsetTop + parseInt(computed["borderTopWidth"]),
|
|
left: span.offsetLeft + parseInt(computed["borderLeftWidth"]),
|
|
height: parseInt(computed["lineHeight"]),
|
|
};
|
|
|
|
if (debug) {
|
|
span.style.backgroundColor = "#aaa";
|
|
} else {
|
|
document.body.removeChild(div);
|
|
}
|
|
|
|
return coordinates;
|
|
}
|
|
}.getCaretCoordinates;
|