summaryrefslogtreecommitdiff
path: root/alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
diff options
context:
space:
mode:
Diffstat (limited to 'alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js')
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js272
1 files changed, 272 insertions, 0 deletions
diff --git a/alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js b/alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
new file mode 100644
index 0000000..427dfa4
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
@@ -0,0 +1,272 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const ValidityState = require("../generated/ValidityState");
+const { mixin } = require("../../utils");
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { cloningSteps } = require("../helpers/internal-constants");
+const { isDisabled, getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+const { childTextContent } = require("../helpers/text");
+const { fireAnEvent } = require("../helpers/events");
+
+class HTMLTextAreaElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._selectionStart = this._selectionEnd = 0;
+ this._selectionDirection = "none";
+ this._rawValue = "";
+ this._dirtyValue = false;
+
+ this._customValidityErrorMessage = "";
+
+ this._labels = null;
+ }
+
+ _formReset() {
+ this._rawValue = childTextContent(this);
+ this._dirtyValue = false;
+ }
+
+ _getAPIValue() {
+ return this._rawValue.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#textarea-wrapping-transformation
+ _getValue() {
+ const apiValue = this._getAPIValue();
+ const wrap = this.getAttributeNS(null, "wrap");
+ return wrap === "hard" ?
+ textareaWrappingTransformation(apiValue, this.cols) :
+ apiValue;
+ }
+
+ _childTextContentChangeSteps() {
+ super._childTextContentChangeSteps();
+
+ if (this._dirtyValue === false) {
+ this._rawValue = childTextContent(this);
+ }
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get defaultValue() {
+ return childTextContent(this);
+ }
+
+ set defaultValue(val) {
+ this.textContent = val;
+ }
+
+ get value() {
+ return this._getAPIValue();
+ }
+
+ set value(val) {
+ // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value
+ const oldAPIValue = this._getAPIValue();
+ this._rawValue = val;
+ this._dirtyValue = true;
+
+ if (oldAPIValue !== this._getAPIValue()) {
+ this._selectionStart = this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ }
+ }
+
+ get textLength() {
+ return this.value.length; // code unit length (16 bit)
+ }
+
+ get type() {
+ return "textarea";
+ }
+
+ _dispatchSelectEvent() {
+ fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
+ }
+
+ _getValueLength() {
+ return typeof this.value === "string" ? this.value.length : 0;
+ }
+
+ select() {
+ this._selectionStart = 0;
+ this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ this._dispatchSelectEvent();
+ }
+
+ get selectionStart() {
+ return this._selectionStart;
+ }
+
+ set selectionStart(start) {
+ this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
+ }
+
+ get selectionEnd() {
+ return this._selectionEnd;
+ }
+
+ set selectionEnd(end) {
+ this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
+ }
+
+ get selectionDirection() {
+ return this._selectionDirection;
+ }
+
+ set selectionDirection(dir) {
+ this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
+ }
+
+ setSelectionRange(start, end, dir) {
+ this._selectionEnd = Math.min(end, this._getValueLength());
+ this._selectionStart = Math.min(start, this._selectionEnd);
+ this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
+ this._dispatchSelectEvent();
+ }
+
+ setRangeText(repl, start, end, selectionMode = "preserve") {
+ if (arguments.length < 2) {
+ start = this._selectionStart;
+ end = this._selectionEnd;
+ } else if (start > end) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+
+ start = Math.min(start, this._getValueLength());
+ end = Math.min(end, this._getValueLength());
+
+ const val = this.value;
+ let selStart = this._selectionStart;
+ let selEnd = this._selectionEnd;
+
+ this.value = val.slice(0, start) + repl + val.slice(end);
+
+ const newEnd = start + this.value.length;
+
+ if (selectionMode === "select") {
+ this.setSelectionRange(start, newEnd);
+ } else if (selectionMode === "start") {
+ this.setSelectionRange(start, start);
+ } else if (selectionMode === "end") {
+ this.setSelectionRange(newEnd, newEnd);
+ } else { // preserve
+ const delta = repl.length - (end - start);
+
+ if (selStart > end) {
+ selStart += delta;
+ } else if (selStart > start) {
+ selStart = start;
+ }
+
+ if (selEnd > end) {
+ selEnd += delta;
+ } else if (selEnd > start) {
+ selEnd = newEnd;
+ }
+
+ this.setSelectionRange(selStart, selEnd);
+ }
+ }
+
+ get cols() {
+ if (!this.hasAttributeNS(null, "cols")) {
+ return 20;
+ }
+ return parseInt(this.getAttributeNS(null, "cols"));
+ }
+
+ set cols(value) {
+ if (value <= 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "cols", String(value));
+ }
+
+ get rows() {
+ if (!this.hasAttributeNS(null, "rows")) {
+ return 2;
+ }
+ return parseInt(this.getAttributeNS(null, "rows"));
+ }
+
+ set rows(value) {
+ if (value <= 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "rows", String(value));
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return this.hasAttributeNS(null, "readonly");
+ }
+
+ get _mutable() {
+ return !isDisabled(this) && !this.hasAttributeNS(null, "readonly");
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-required
+ get validity() {
+ if (!this._validity) {
+ const state = {
+ valueMissing: () => this.hasAttributeNS(null, "required") && this._mutable && this.value === ""
+ };
+
+ this._validity = ValidityState.createImpl(this._globalObject, [], {
+ element: this,
+ state
+ });
+ }
+ return this._validity;
+ }
+
+ [cloningSteps](copy, node) {
+ copy._dirtyValue = node._dirtyValue;
+ copy._rawValue = node._rawValue;
+ }
+}
+
+mixin(HTMLTextAreaElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLTextAreaElementImpl
+};
+
+function textareaWrappingTransformation(text, cols) {
+ let lineStart = 0;
+ let lineEnd = text.indexOf("\n");
+ if (lineEnd === -1) {
+ lineEnd = text.length;
+ }
+
+ while (lineStart < text.length) {
+ const lineLength = lineEnd - lineStart;
+ if (lineLength > cols) {
+ // split the line
+ lineEnd = lineStart + cols;
+ text = text.slice(0, lineEnd) + "\n" + text.slice(lineEnd);
+ }
+ // move to next line
+ lineStart = lineEnd + 1; // step over the newline
+ lineEnd = text.indexOf("\n", lineStart);
+ if (lineEnd === -1) {
+ lineEnd = text.length;
+ }
+ }
+
+ return text;
+}