summaryrefslogtreecommitdiff
path: root/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
diff options
context:
space:
mode:
Diffstat (limited to 'school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js')
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js1128
1 files changed, 0 insertions, 1128 deletions
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
deleted file mode 100644
index edd299d..0000000
--- a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
+++ /dev/null
@@ -1,1128 +0,0 @@
-"use strict";
-const DOMException = require("domexception/webidl2js-wrapper");
-const FileList = require("../generated/FileList");
-const Decimal = require("decimal.js");
-const HTMLElementImpl = require("./HTMLElement-impl").implementation;
-const idlUtils = require("../generated/utils");
-const DefaultConstraintValidationImpl =
- require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
-const ValidityState = require("../generated/ValidityState");
-const { mixin } = require("../../utils");
-const { domSymbolTree, cloningSteps } = require("../helpers/internal-constants");
-const { getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
-const { fireAnEvent } = require("../helpers/events");
-const {
- isDisabled,
- isValidEmailAddress,
- isValidAbsoluteURL,
- sanitizeValueByType
-} = require("../helpers/form-controls");
-const {
- asciiCaseInsensitiveMatch,
- asciiLowercase,
- parseFloatingPointNumber,
- splitOnCommas
-} = require("../helpers/strings");
-const { isDate } = require("../helpers/dates-and-times");
-const {
- convertStringToNumberByType,
- convertStringToDateByType,
- serializeDateByType,
- convertNumberToStringByType
-} = require("../helpers/number-and-date-inputs");
-
-const filesSymbol = Symbol("files");
-
-// https://html.spec.whatwg.org/multipage/input.html#attr-input-type
-const inputAllowedTypes = new Set([
- "hidden", "text", "search", "tel", "url", "email", "password", "date",
- "month", "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
- "file", "submit", "image", "reset", "button"
-]);
-
-// https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
-
-const variableLengthSelectionAllowedTypes = new Set(["text", "search", "url", "tel", "password"]);
-const numericTypes = new Set(["date", "month", "week", "time", "datetime-local", "number", "range"]);
-
-const applicableTypesForIDLMember = {
- valueAsDate: new Set(["date", "month", "week", "time"]),
- valueAsNumber: numericTypes,
-
- select: new Set([
- "text", "search", "url", "tel", "email", "password", "date", "month", "week",
- "time", "datetime-local", "number", "color", "file"
- ]),
- selectionStart: variableLengthSelectionAllowedTypes,
- selectionEnd: variableLengthSelectionAllowedTypes,
- selectionDirection: variableLengthSelectionAllowedTypes,
- setRangeText: variableLengthSelectionAllowedTypes,
- setSelectionRange: variableLengthSelectionAllowedTypes,
- stepDown: numericTypes,
- stepUp: numericTypes
-};
-
-const lengthPatternSizeTypes = new Set(["text", "search", "url", "tel", "email", "password"]);
-const readonlyTypes =
- new Set([...lengthPatternSizeTypes, "date", "month", "week", "time", "datetime-local", "number"]);
-
-const applicableTypesForContentAttribute = {
- list: new Set(["text", "search", "url", "tel", "email", ...numericTypes, "color"]),
- max: numericTypes,
- maxlength: lengthPatternSizeTypes,
- min: numericTypes,
- minlength: lengthPatternSizeTypes,
- multiple: new Set(["email", "file"]),
- pattern: lengthPatternSizeTypes,
- readonly: readonlyTypes,
- required: new Set([...readonlyTypes, "checkbox", "radio", "file"]),
- step: numericTypes
-};
-
-const valueAttributeDefaultMode = new Set(["hidden", "submit", "image", "reset", "button"]);
-const valueAttributeDefaultOnMode = new Set(["checkbox", "radio"]);
-
-function valueAttributeMode(type) {
- if (valueAttributeDefaultMode.has(type)) {
- return "default";
- }
- if (valueAttributeDefaultOnMode.has(type)) {
- return "default/on";
- }
- if (type === "file") {
- return "filename";
- }
- return "value";
-}
-
-function getTypeFromAttribute(typeAttribute) {
- if (typeof typeAttribute !== "string") {
- return "text";
- }
- const type = asciiLowercase(typeAttribute);
- return inputAllowedTypes.has(type) ? type : "text";
-}
-
-class HTMLInputElementImpl extends HTMLElementImpl {
- constructor(globalObject, args, privateData) {
- super(globalObject, args, privateData);
-
- this._selectionStart = this._selectionEnd = 0;
- this._selectionDirection = "none";
- this._value = "";
- this._dirtyValue = false;
- this._checkedness = false;
- this._dirtyCheckedness = false;
-
- this._preCheckedRadioState = null;
- this._legacyActivationBehaviorPreviousIndeterminateState = false;
-
- this.indeterminate = false;
-
- this._customValidityErrorMessage = "";
-
- this._labels = null;
-
- this._hasActivationBehavior = true;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-number
- get _convertStringToNumber() {
- return convertStringToNumberByType[this.type];
- }
-
- get _convertNumberToString() {
- return convertNumberToStringByType[this.type];
- }
-
- get _convertDateToString() {
- return serializeDateByType[this.type];
- }
-
- get _convertStringToDate() {
- return convertStringToDateByType[this.type];
- }
-
- _isStepAligned(v) {
- return new Decimal(v).minus(this._stepBase)
- .modulo(this._allowedValueStep)
- .isZero();
- }
-
- // Returns a Decimal.
- _stepAlign(v, roundUp) {
- const allowedValueStep = this._allowedValueStep;
- const stepBase = this._stepBase;
-
- return new Decimal(v).minus(stepBase)
- .toNearest(allowedValueStep, roundUp ? Decimal.ROUND_UP : Decimal.ROUND_DOWN)
- .add(stepBase);
- }
-
- // For <input>, https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-value
- // is a simple value that is gotten and set, not computed.
- _getValue() {
- return this._value;
- }
-
- _legacyPreActivationBehavior() {
- if (this.type === "checkbox") {
- this.checked = !this.checked;
- this._legacyActivationBehaviorPreviousIndeterminateState = this.indeterminate;
- this.indeterminate = false;
- } else if (this.type === "radio") {
- this._preCheckedRadioState = this.checked;
- this.checked = true;
- }
- }
-
- _legacyCanceledActivationBehavior() {
- if (this.type === "checkbox") {
- this.checked = !this.checked;
- this.indeterminate = this._legacyActivationBehaviorPreviousIndeterminateState;
- } else if (this.type === "radio") {
- if (this._preCheckedRadioState !== null) {
- this.checked = this._preCheckedRadioState;
- this._preCheckedRadioState = null;
- }
- }
- }
-
- _activationBehavior() {
- if (!this._mutable && this.type !== "checkbox" && this.type !== "radio") {
- return;
- }
-
- const { form } = this;
-
- if (this.type === "checkbox" || (this.type === "radio" && !this._preCheckedRadioState)) {
- if (this.isConnected) {
- fireAnEvent("input", this, undefined, { bubbles: true });
- fireAnEvent("change", this, undefined, { bubbles: true });
- }
- } else if (form && this.type === "submit") {
- form._doSubmit();
- } else if (form && this.type === "reset") {
- form._doReset();
- }
- }
-
- _attrModified(name, value, oldVal) {
- const wrapper = idlUtils.wrapperForImpl(this);
- if (!this._dirtyValue && name === "value") {
- this._value = sanitizeValueByType(this, wrapper.defaultValue);
- }
- if (!this._dirtyCheckedness && name === "checked") {
- this._checkedness = wrapper.defaultChecked;
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- if (name === "name" || name === "type") {
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- if (name === "type") {
- const prevType = getTypeFromAttribute(oldVal);
- const curType = getTypeFromAttribute(value);
- // When an input element's type attribute changes stateā€¦
- if (prevType !== curType) {
- const prevValueMode = valueAttributeMode(prevType);
- const curValueMode = valueAttributeMode(curType);
- if (prevValueMode === "value" && this._value !== "" &&
- (curValueMode === "default" || curValueMode === "default/on")) {
- this.setAttributeNS(null, "value", this._value);
- } else if (prevValueMode !== "value" && curValueMode === "value") {
- this._value = this.getAttributeNS(null, "value") || "";
- this._dirtyValue = false;
- } else if (prevValueMode !== "filename" && curValueMode === "filename") {
- this._value = "";
- }
-
- this._signalATypeChange();
-
- this._value = sanitizeValueByType(this, this._value);
-
- const previouslySelectable = this._idlMemberApplies("setRangeText", prevType);
- const nowSelectable = this._idlMemberApplies("setRangeText", curType);
- if (!previouslySelectable && nowSelectable) {
- this._selectionStart = 0;
- this._selectionEnd = 0;
- this._selectionDirection = "none";
- }
- }
- }
-
- super._attrModified(name, value, oldVal);
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#signal-a-type-change
- _signalATypeChange() {
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- _formReset() {
- const wrapper = idlUtils.wrapperForImpl(this);
- this._value = sanitizeValueByType(this, wrapper.defaultValue);
- this._dirtyValue = false;
- this._checkedness = wrapper.defaultChecked;
- this._dirtyCheckedness = false;
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- _changedFormOwner() {
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- get _otherRadioGroupElements() {
- const wrapper = idlUtils.wrapperForImpl(this);
- const root = this._radioButtonGroupRoot;
- if (!root) {
- return [];
- }
-
- const result = [];
-
- const descendants = domSymbolTree.treeIterator(root);
- for (const candidate of descendants) {
- if (candidate._radioButtonGroupRoot !== root) {
- continue;
- }
-
- const candidateWrapper = idlUtils.wrapperForImpl(candidate);
- if (!candidateWrapper.name || candidateWrapper.name !== wrapper.name) {
- continue;
- }
-
- if (candidate !== this) {
- result.push(candidate);
- }
- }
- return result;
- }
-
- _removeOtherRadioCheckedness() {
- for (const radioGroupElement of this._otherRadioGroupElements) {
- radioGroupElement._checkedness = false;
- }
- }
-
- get _radioButtonGroupRoot() {
- const wrapper = idlUtils.wrapperForImpl(this);
- if (this.type !== "radio" || !wrapper.name) {
- return null;
- }
-
- let e = domSymbolTree.parent(this);
- while (e) {
- // root node of this home sub tree
- // or the form element we belong to
- if (!domSymbolTree.parent(e) || e.nodeName.toUpperCase() === "FORM") {
- return e;
- }
- e = domSymbolTree.parent(e);
- }
- return null;
- }
-
- _someInRadioGroup(name) {
- if (this[name]) {
- return true;
- }
- return this._otherRadioGroupElements.some(radioGroupElement => radioGroupElement[name]);
- }
-
- get _mutable() {
- return !isDisabled(this) && !this._hasAttributeAndApplies("readonly");
- }
-
- get labels() {
- return getLabelsForLabelable(this);
- }
-
- get form() {
- return formOwner(this);
- }
-
- get checked() {
- return this._checkedness;
- }
-
- set checked(checked) {
- this._checkedness = Boolean(checked);
- this._dirtyCheckedness = true;
- if (this._checkedness) {
- this._removeOtherRadioCheckedness();
- }
- }
-
- get value() {
- switch (valueAttributeMode(this.type)) {
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
- case "value":
- return this._getValue();
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
- case "default": {
- const attr = this.getAttributeNS(null, "value");
- return attr !== null ? attr : "";
- }
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
- case "default/on": {
- const attr = this.getAttributeNS(null, "value");
- return attr !== null ? attr : "on";
- }
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
- case "filename":
- return this.files.length ? "C:\\fakepath\\" + this.files[0].name : "";
- default:
- throw new Error("jsdom internal error: unknown value attribute mode");
- }
- }
-
- set value(val) {
- switch (valueAttributeMode(this.type)) {
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
- case "value": {
- const oldValue = this._value;
- this._value = sanitizeValueByType(this, val);
- this._dirtyValue = true;
-
- if (oldValue !== this._value) {
- this._selectionStart = this._selectionEnd = this._getValueLength();
- this._selectionDirection = "none";
- }
- break;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
- case "default":
- case "default/on":
- this.setAttributeNS(null, "value", val);
- break;
-
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
- case "filename":
- if (val === "") {
- this.files.length = 0;
- } else {
- throw DOMException.create(this._globalObject, [
- "This input element accepts a filename, which may only be programmatically set to the empty string.",
- "InvalidStateError"
- ]);
- }
- break;
-
- default:
- throw new Error("jsdom internal error: unknown value attribute mode");
- }
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasdate
- get valueAsDate() {
- if (!this._idlMemberApplies("valueAsDate")) {
- return null;
- }
-
- const window = this._ownerDocument._defaultView;
- const convertedValue = this._convertStringToDate(this._value);
-
- if (convertedValue instanceof Date) {
- return new window.Date(convertedValue.getTime());
- }
-
- return null;
- }
-
- set valueAsDate(v) {
- if (!this._idlMemberApplies("valueAsDate")) {
- throw DOMException.create(this._globalObject, [
- "Failed to set the 'valueAsDate' property on 'HTMLInputElement': This input element does not support Date " +
- "values.",
- "InvalidStateError"
- ]);
- }
-
- if (v !== null && !isDate(v)) {
- throw new TypeError("Failed to set the 'valueAsDate' property on 'HTMLInputElement': The provided value is " +
- "not a Date.");
- }
-
- if (v === null || isNaN(v)) {
- this._value = "";
- }
-
- this._value = this._convertDateToString(v);
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasnumber
- get valueAsNumber() {
- if (!this._idlMemberApplies("valueAsNumber")) {
- return NaN;
- }
-
- const parsedValue = this._convertStringToNumber(this._value);
- return parsedValue !== null ? parsedValue : NaN;
- }
-
- set valueAsNumber(v) {
- if (!isFinite(v)) {
- throw new TypeError("Failed to set infinite value as Number");
- }
-
- if (!this._idlMemberApplies("valueAsNumber")) {
- throw DOMException.create(this._globalObject, [
- "Failed to set the 'valueAsNumber' property on 'HTMLInputElement': This input element does not support " +
- "Number values.",
- "InvalidStateError"
- ]);
- }
-
- this._value = this._convertNumberToString(v);
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#dom-input-stepup
- _stepUpdate(n, isUp) {
- const methodName = isUp ? "stepUp" : "stepDown";
- if (!this._idlMemberApplies(methodName)) {
- throw DOMException.create(this._globalObject, [
- `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
- "This input element does not support Number values.",
- "InvalidStateError"
- ]);
- }
-
- const allowedValueStep = this._allowedValueStep;
- if (allowedValueStep === null) {
- throw DOMException.create(this._globalObject, [
- `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
- "This input element does not support value step.",
- "InvalidStateError"
- ]);
- }
-
- const min = this._minimum;
- const max = this._maximum;
-
- if (min !== null && max !== null) {
- if (min > max) {
- return;
- }
-
- const candidateStepValue = this._stepAlign(Decimal.add(min, allowedValueStep), /* roundUp = */ false);
- if (candidateStepValue.lt(min) || candidateStepValue.gt(max)) {
- return;
- }
- }
-
- let value = 0;
- try {
- value = this.valueAsNumber;
- if (isNaN(value)) { // Empty value is parsed as NaN.
- value = 0;
- }
- } catch (error) {
- // Step 5. Default value is 0.
- }
- value = new Decimal(value);
-
- const valueBeforeStepping = value;
-
- if (!this._isStepAligned(value)) {
- value = this._stepAlign(value, /* roundUp = */ isUp);
- } else {
- let delta = Decimal.mul(n, allowedValueStep);
- if (!isUp) {
- delta = delta.neg();
- }
- value = value.add(delta);
- }
-
- if (min !== null && value.lt(min)) {
- value = this._stepAlign(min, /* roundUp = */ true);
- }
-
- if (max !== null && value.gt(max)) {
- value = this._stepAlign(max, /* roundUp = */ false);
- }
-
- if (isUp ? value.lt(valueBeforeStepping) : value.gt(valueBeforeStepping)) {
- return;
- }
-
- this._value = this._convertNumberToString(value.toNumber());
- }
-
- stepDown(n = 1) {
- return this._stepUpdate(n, false);
- }
-
- stepUp(n = 1) {
- return this._stepUpdate(n, true);
- }
-
- get files() {
- if (this.type === "file") {
- this[filesSymbol] = this[filesSymbol] || FileList.createImpl(this._globalObject);
- } else {
- this[filesSymbol] = null;
- }
- return this[filesSymbol];
- }
-
- set files(value) {
- if (this.type === "file" && value !== null) {
- this[filesSymbol] = value;
- }
- }
-
- get type() {
- const typeAttribute = this.getAttributeNS(null, "type");
- return getTypeFromAttribute(typeAttribute);
- }
-
- set type(type) {
- this.setAttributeNS(null, "type", type);
- }
-
- _dispatchSelectEvent() {
- fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
- }
-
- _getValueLength() {
- return typeof this.value === "string" ? this.value.length : 0;
- }
-
- select() {
- if (!this._idlMemberApplies("select")) {
- return;
- }
-
- this._selectionStart = 0;
- this._selectionEnd = this._getValueLength();
- this._selectionDirection = "none";
- this._dispatchSelectEvent();
- }
-
- get selectionStart() {
- if (!this._idlMemberApplies("selectionStart")) {
- return null;
- }
-
- return this._selectionStart;
- }
-
- set selectionStart(start) {
- if (!this._idlMemberApplies("selectionStart")) {
- throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
- }
-
- this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
- }
-
- get selectionEnd() {
- if (!this._idlMemberApplies("selectionEnd")) {
- return null;
- }
-
- return this._selectionEnd;
- }
-
- set selectionEnd(end) {
- if (!this._idlMemberApplies("selectionEnd")) {
- throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
- }
-
- this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
- }
-
- get selectionDirection() {
- if (!this._idlMemberApplies("selectionDirection")) {
- return null;
- }
-
- return this._selectionDirection;
- }
-
- set selectionDirection(dir) {
- if (!this._idlMemberApplies("selectionDirection")) {
- throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
- }
-
- this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
- }
-
- setSelectionRange(start, end, dir) {
- if (!this._idlMemberApplies("setSelectionRange")) {
- throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
- }
-
- 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 (!this._idlMemberApplies("setRangeText")) {
- throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
- }
-
- 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);
- }
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#the-list-attribute
- get list() {
- const id = this._getAttributeIfApplies("list");
- if (!id) {
- return null;
- }
-
- const el = this.getRootNode({}).getElementById(id);
-
- if (el && el.localName === "datalist") {
- return el;
- }
-
- return null;
- }
-
- // Reflected IDL attribute does not care about whether the content attribute applies.
- get maxLength() {
- if (!this.hasAttributeNS(null, "maxlength")) {
- return 524288; // stole this from chrome
- }
- return parseInt(this.getAttributeNS(null, "maxlength"));
- }
-
- set maxLength(value) {
- if (value < 0) {
- throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
- }
- this.setAttributeNS(null, "maxlength", String(value));
- }
-
- get minLength() {
- if (!this.hasAttributeNS(null, "minlength")) {
- return 0;
- }
- return parseInt(this.getAttributeNS(null, "minlength"));
- }
-
- set minLength(value) {
- if (value < 0) {
- throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
- }
- this.setAttributeNS(null, "minlength", String(value));
- }
-
- get size() {
- if (!this.hasAttributeNS(null, "size")) {
- return 20;
- }
- return parseInt(this.getAttributeNS(null, "size"));
- }
-
- set size(value) {
- if (value <= 0) {
- throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
- }
- this.setAttributeNS(null, "size", String(value));
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
- get _minimum() {
- let min = this._defaultMinimum;
- const attr = this._getAttributeIfApplies("min");
- if (attr !== null && this._convertStringToNumber !== undefined) {
- const parsed = this._convertStringToNumber(attr);
- if (parsed !== null) {
- min = parsed;
- }
- }
- return min;
- }
-
- get _maximum() {
- let max = this._defaultMaximum;
- const attr = this._getAttributeIfApplies("max");
- if (attr !== null && this._convertStringToNumber !== undefined) {
- const parsed = this._convertStringToNumber(attr);
- if (parsed !== null) {
- max = parsed;
- }
- }
- return max;
- }
-
- get _defaultMinimum() {
- if (this.type === "range") {
- return 0;
- }
- return null;
- }
-
- get _defaultMaximum() {
- if (this.type === "range") {
- return 100;
- }
- return null;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-step
- get _allowedValueStep() {
- if (!this._contentAttributeApplies("step")) {
- return null;
- }
- const attr = this.getAttributeNS(null, "step");
- if (attr === null) {
- return this._defaultStep * this._stepScaleFactor;
- }
- if (asciiCaseInsensitiveMatch(attr, "any")) {
- return null;
- }
- const parsedStep = parseFloatingPointNumber(attr);
- if (parsedStep === null || parsedStep <= 0) {
- return this._defaultStep * this._stepScaleFactor;
- }
- return parsedStep * this._stepScaleFactor;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-scale
- get _stepScaleFactor() {
- const dayInMilliseconds = 24 * 60 * 60 * 1000;
- switch (this.type) {
- case "week":
- return 7 * dayInMilliseconds;
- case "date":
- return dayInMilliseconds;
- case "datetime-local":
- case "datetime":
- case "time":
- return 1000;
- }
- return 1;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default
- get _defaultStep() {
- if (this.type === "datetime-local" || this.type === "datetime" || this.type === "time") {
- return 60;
- }
- return 1;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-min-zero
- get _stepBase() {
- if (this._hasAttributeAndApplies("min")) {
- const min = this._convertStringToNumber(this.getAttributeNS(null, "min"));
- if (min !== null) {
- return min;
- }
- }
- if (this.hasAttributeNS(null, "value")) {
- const value = this._convertStringToNumber(this.getAttributeNS(null, "value"));
- if (value !== null) {
- return value;
- }
- }
- if (this._defaultStepBase !== null) {
- return this._defaultStepBase;
- }
- return 0;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default-base
- get _defaultStepBase() {
- if (this.type === "week") {
- // The start of week 1970-W01
- return -259200000;
- }
- return null;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#common-input-element-attributes
- // When an attribute doesn't apply to an input element, user agents must ignore the attribute.
- _contentAttributeApplies(attribute) {
- return applicableTypesForContentAttribute[attribute].has(this.type);
- }
-
- _hasAttributeAndApplies(attribute) {
- return this._contentAttributeApplies(attribute) && this.hasAttributeNS(null, attribute);
- }
-
- _getAttributeIfApplies(attribute) {
- if (this._contentAttributeApplies(attribute)) {
- return this.getAttributeNS(null, attribute);
- }
- return null;
- }
-
- _idlMemberApplies(member, type = this.type) {
- return applicableTypesForIDLMember[member].has(type);
- }
-
- _barredFromConstraintValidationSpecialization() {
- // https://html.spec.whatwg.org/multipage/input.html#hidden-state-(type=hidden)
- // https://html.spec.whatwg.org/multipage/input.html#reset-button-state-(type=reset)
- // https://html.spec.whatwg.org/multipage/input.html#button-state-(type=button)
- const willNotValidateTypes = new Set(["hidden", "reset", "button"]);
- // https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
- const readOnly = this._hasAttributeAndApplies("readonly");
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
- return willNotValidateTypes.has(this.type) || readOnly;
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#concept-input-required
- get _required() {
- return this._hasAttributeAndApplies("required");
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#has-a-periodic-domain
- get _hasAPeriodicDomain() {
- return this.type === "time";
- }
-
- // https://html.spec.whatwg.org/multipage/input.html#has-a-reversed-range
- get _hasAReversedRange() {
- return this._hasAPeriodicDomain && this._maximum < this._minimum;
- }
-
- get validity() {
- if (!this._validity) {
- // Constraint validation: When an element has a reversed range, and the result of applying
- // the algorithm to convert a string to a number to the string given by the element's value
- // is a number, and the number obtained from that algorithm is more than the maximum and less
- // than the minimum, the element is simultaneously suffering from an underflow and suffering
- // from an overflow.
- const reversedRangeSufferingOverUnderflow = () => {
- const parsedValue = this._convertStringToNumber(this._value);
- return parsedValue !== null && parsedValue > this._maximum && parsedValue < this._minimum;
- };
-
- const state = {
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-missing
- valueMissing: () => {
- // https://html.spec.whatwg.org/multipage/input.html#the-required-attribute
- // Constraint validation: If the element is required, and its value IDL attribute applies
- // and is in the mode value, and the element is mutable, and the element's value is the
- // empty string, then the element is suffering from being missing.
- //
- // Note: As of today, the value IDL attribute always applies.
- if (this._required && valueAttributeMode(this.type) === "value" && this._mutable && this._value === "") {
- return true;
- }
-
- switch (this.type) {
- // https://html.spec.whatwg.org/multipage/input.html#checkbox-state-(type=checkbox)
- // Constraint validation: If the element is required and its checkedness is
- // false, then the element is suffering from being missing.
- case "checkbox":
- if (this._required && !this._checkedness) {
- return true;
- }
- break;
-
- // https://html.spec.whatwg.org/multipage/input.html#radio-button-state-(type=radio)
- // Constraint validation: If an element in the radio button group is required,
- // and all of the input elements in the radio button group have a checkedness
- // that is false, then the element is suffering from being missing.
- case "radio":
- if (this._someInRadioGroup("_required") && !this._someInRadioGroup("checked")) {
- return true;
- }
- break;
-
- // https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file)
- // Constraint validation: If the element is required and the list of selected files is
- // empty, then the element is suffering from being missing.
- case "file":
- if (this._required && this.files.length === 0) {
- return true;
- }
- break;
- }
-
- return false;
- },
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-long
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-maxlength
- // jsdom has no way at the moment to emulate a user interaction, so tooLong/tooShort have
- // to be set to false.
- tooLong: () => false,
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-short
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-minlength
- tooShort: () => false,
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-overflow
- rangeOverflow: () => {
- // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
- if (this._hasAReversedRange) {
- return reversedRangeSufferingOverUnderflow();
- }
- // Constraint validation: When the element has a maximum and does not have a reversed
- // range, and the result of applying the algorithm to convert a string to a number to the
- // string given by the element's value is a number, and the number obtained from that
- // algorithm is more than the maximum, the element is suffering from an overflow.
- if (this._maximum !== null) {
- const parsedValue = this._convertStringToNumber(this._value);
- if (parsedValue !== null && parsedValue > this._maximum) {
- return true;
- }
- }
- return false;
- },
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-underflow
- rangeUnderflow: () => {
- // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
- if (this._hasAReversedRange) {
- return reversedRangeSufferingOverUnderflow();
- }
- // Constraint validation: When the element has a minimum and does not have a reversed
- // range, and the result of applying the algorithm to convert a string to a number to the
- // string given by the element's value is a number, and the number obtained from that
- // algorithm is less than the minimum, the element is suffering from an underflow.
- if (this._minimum !== null) {
- const parsedValue = this._convertStringToNumber(this._value);
- if (parsedValue !== null && parsedValue < this._minimum) {
- return true;
- }
- }
- return false;
- },
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-pattern-mismatch
- patternMismatch: () => {
- // https://html.spec.whatwg.org/multipage/input.html#the-pattern-attribute
- if (this._value === "" || !this._hasAttributeAndApplies("pattern")) {
- return false;
- }
- let regExp;
- try {
- const pattern = this.getAttributeNS(null, "pattern");
- // The pattern attribute should be matched against the entire value, not just any
- // subset, so add ^ and $ anchors. But also check the validity of the regex itself
- // first.
- new RegExp(pattern, "u"); // eslint-disable-line no-new
- regExp = new RegExp("^(?:" + pattern + ")$", "u");
- } catch (e) {
- return false;
- }
- if (this._hasAttributeAndApplies("multiple")) {
- return !splitOnCommas(this._value).every(value => regExp.test(value));
- }
- return !regExp.test(this._value);
- },
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-step-mismatch
- // https://html.spec.whatwg.org/multipage/input.html#attr-input-step
- stepMismatch: () => {
- const allowedValueStep = this._allowedValueStep;
- if (allowedValueStep === null) {
- return false;
- }
- const number = this._convertStringToNumber(this._value);
- return number !== null && !this._isStepAligned(number);
- },
-
- // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-type-mismatch
- typeMismatch: () => {
- switch (this.type) {
- // https://html.spec.whatwg.org/multipage/input.html#url-state-(type=url)
- // Constraint validation: While the value of the element is neither the empty string
- // nor a valid absolute URL, the element is suffering from a type mismatch.
- case "url":
- if (this._value !== "" && !isValidAbsoluteURL(this._value)) {
- return true;
- }
- break;
-
- // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type=email)
- // Constraint validation [multiple=false]: While the value of the element is neither the empty
- // string nor a single valid e - mail address, the element is suffering from a type mismatch.
- // Constraint validation [multiple=true]: While the value of the element is not a valid e-mail address list,
- // the element is suffering from a type mismatch.
- case "email":
- if (this._value !== "" && !isValidEmailAddress(this._getValue(), this.hasAttributeNS(null, "multiple"))) {
- return true;
- }
- break;
- }
- return false;
- }
- };
-
- this._validity = ValidityState.createImpl(this._globalObject, [], {
- element: this,
- state
- });
- }
- return this._validity;
- }
-
- [cloningSteps](copy, node) {
- copy._value = node._value;
- copy._checkedness = node._checkedness;
- copy._dirtyValue = node._dirtyValue;
- copy._dirtyCheckedness = node._dirtyCheckedness;
- }
-}
-
-mixin(HTMLInputElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
-
-module.exports = {
- implementation: HTMLInputElementImpl
-};