Comparing version
@@ -9,2 +9,3 @@ "use strict"; | ||
const Node = require("./Node.js"); | ||
const NonElementParentNode = require("./NonElementParentNode.js"); | ||
const ParentNode = require("./ParentNode.js"); | ||
@@ -33,2 +34,25 @@ | ||
DocumentFragment.prototype.getElementById = function getElementById(elementId) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'getElementById' on 'DocumentFragment': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'getElementById' on 'DocumentFragment': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return utils.tryWrapperForImpl(this[impl].getElementById(...args)); | ||
}; | ||
DocumentFragment.prototype.prepend = function prepend() { | ||
@@ -258,4 +282,6 @@ if (!this || !module.exports.is(this)) { | ||
NonElementParentNode._mixedIntoPredicates.push(module.exports.is); | ||
ParentNode._mixedIntoPredicates.push(module.exports.is); | ||
const Impl = require("../nodes/DocumentFragment-impl.js"); |
@@ -23,2 +23,41 @@ "use strict"; | ||
HTMLButtonElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLButtonElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLButtonElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLButtonElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLButtonElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
Object.defineProperty(HTMLButtonElement.prototype, "autofocus", { | ||
@@ -227,2 +266,41 @@ get() { | ||
Object.defineProperty(HTMLButtonElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLButtonElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLButtonElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLButtonElement.prototype, Symbol.toStringTag, { | ||
@@ -229,0 +307,0 @@ value: "HTMLButtonElement", |
@@ -23,2 +23,41 @@ "use strict"; | ||
HTMLFieldSetElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLFieldSetElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLFieldSetElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLFieldSetElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLFieldSetElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
Object.defineProperty(HTMLFieldSetElement.prototype, "disabled", { | ||
@@ -92,2 +131,43 @@ get() { | ||
Object.defineProperty(HTMLFieldSetElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLFieldSetElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.getSameObject(this, "validity", () => { | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLFieldSetElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLFieldSetElement.prototype, Symbol.toStringTag, { | ||
@@ -94,0 +174,0 @@ value: "HTMLFieldSetElement", |
@@ -39,2 +39,18 @@ "use strict"; | ||
HTMLFormElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLFormElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
Object.defineProperty(HTMLFormElement.prototype, "acceptCharset", { | ||
@@ -41,0 +57,0 @@ get() { |
@@ -25,2 +25,41 @@ "use strict"; | ||
HTMLInputElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLInputElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLInputElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLInputElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLInputElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
HTMLInputElement.prototype.select = function select() { | ||
@@ -944,2 +983,41 @@ if (!this || !module.exports.is(this)) { | ||
Object.defineProperty(HTMLInputElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLInputElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLInputElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLInputElement.prototype, "selectionStart", { | ||
@@ -946,0 +1024,0 @@ get() { |
@@ -23,2 +23,41 @@ "use strict"; | ||
HTMLObjectElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLObjectElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLObjectElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLObjectElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLObjectElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
Object.defineProperty(HTMLObjectElement.prototype, "data", { | ||
@@ -205,2 +244,41 @@ get() { | ||
Object.defineProperty(HTMLObjectElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLObjectElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLObjectElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLObjectElement.prototype, "align", { | ||
@@ -207,0 +285,0 @@ get() { |
@@ -23,2 +23,41 @@ "use strict"; | ||
HTMLOutputElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLOutputElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLOutputElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLOutputElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLOutputElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
Object.defineProperty(HTMLOutputElement.prototype, "name", { | ||
@@ -50,2 +89,41 @@ get() { | ||
Object.defineProperty(HTMLOutputElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLOutputElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLOutputElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLOutputElement.prototype, Symbol.toStringTag, { | ||
@@ -52,0 +130,0 @@ value: "HTMLOutputElement", |
@@ -145,2 +145,41 @@ "use strict"; | ||
HTMLSelectElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLSelectElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLSelectElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLSelectElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLSelectElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
Object.defineProperty(HTMLSelectElement.prototype, "autofocus", { | ||
@@ -445,2 +484,41 @@ get() { | ||
Object.defineProperty(HTMLSelectElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLSelectElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLSelectElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLSelectElement.prototype, Symbol.toStringTag, { | ||
@@ -447,0 +525,0 @@ value: "HTMLSelectElement", |
@@ -24,2 +24,41 @@ "use strict"; | ||
HTMLTextAreaElement.prototype.checkValidity = function checkValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].checkValidity(); | ||
}; | ||
HTMLTextAreaElement.prototype.reportValidity = function reportValidity() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl].reportValidity(); | ||
}; | ||
HTMLTextAreaElement.prototype.setCustomValidity = function setCustomValidity(error) { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
if (arguments.length < 1) { | ||
throw new TypeError( | ||
"Failed to execute 'setCustomValidity' on 'HTMLTextAreaElement': 1 argument required, but only " + | ||
arguments.length + | ||
" present." | ||
); | ||
} | ||
const args = []; | ||
{ | ||
let curArg = arguments[0]; | ||
curArg = conversions["DOMString"](curArg, { | ||
context: "Failed to execute 'setCustomValidity' on 'HTMLTextAreaElement': parameter 1" | ||
}); | ||
args.push(curArg); | ||
} | ||
return this[impl].setCustomValidity(...args); | ||
}; | ||
HTMLTextAreaElement.prototype.select = function select() { | ||
@@ -624,2 +663,41 @@ if (!this || !module.exports.is(this)) { | ||
Object.defineProperty(HTMLTextAreaElement.prototype, "willValidate", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["willValidate"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLTextAreaElement.prototype, "validity", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return utils.tryWrapperForImpl(this[impl]["validity"]); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLTextAreaElement.prototype, "validationMessage", { | ||
get() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return this[impl]["validationMessage"]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(HTMLTextAreaElement.prototype, "selectionStart", { | ||
@@ -626,0 +704,0 @@ get() { |
@@ -109,3 +109,3 @@ "use strict"; | ||
const timeRe = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2}(?:\.[0-9]{1,3})?))?$/; | ||
const timeRe = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2}(?:\.([0-9]{1,3}))?))?$/; | ||
@@ -126,7 +126,8 @@ // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-time-string | ||
} | ||
const second = matches[3] !== undefined ? Number(matches[3]) : 0; | ||
const second = matches[3] !== undefined ? Math.trunc(Number(matches[3])) : 0; | ||
if (second < 0 || second >= 60) { | ||
return null; | ||
} | ||
return { hour, minute, second }; | ||
const millisecond = matches[4] !== undefined ? Number(matches[4]) : 0; | ||
return { hour, minute, second, millisecond }; | ||
} | ||
@@ -138,12 +139,12 @@ | ||
} | ||
function serializeTime({ hour, minute, second }) { | ||
function serializeTime({ hour, minute, second, millisecond }) { | ||
const hourStr = leftPad(`${hour}`, 2, "0"); | ||
const minuteStr = leftPad(`${minute}`, 2, "0"); | ||
const milliseconds = Math.trunc(second * 1000); | ||
if (milliseconds === 0) { | ||
if (millisecond === 0) { | ||
return `${hourStr}:${minuteStr}`; | ||
} | ||
const secondIntegerStr = leftPad(`${Math.trunc(milliseconds / 1000)}`, 2, "0"); | ||
const secondDecimalStr = `${milliseconds % 1000 / 1000}`.slice(1); | ||
return `${hourStr}:${minuteStr}:${secondIntegerStr}${secondDecimalStr}`; | ||
const secondStr = leftPad(second, 2, "0"); | ||
const millisecondStr = leftPad(millisecond, 3, "0"); | ||
return `${hourStr}:${minuteStr}:${secondStr}.${millisecondStr}`; | ||
} | ||
@@ -154,6 +155,6 @@ | ||
let separatorIdx = str.indexOf("T"); | ||
if (!normalized && separatorIdx < -1) { | ||
if (separatorIdx < 0 && !normalized) { | ||
separatorIdx = str.indexOf(" "); | ||
} | ||
if (separatorIdx < -1) { | ||
if (separatorIdx < 0) { | ||
return null; | ||
@@ -192,3 +193,3 @@ } | ||
const weekRe = /^([0-9]{4})-W([0-9]{2})$/; | ||
const weekRe = /^([0-9]{4,5})-W([0-9]{2})$/; | ||
@@ -195,0 +196,0 @@ // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-week-string |
@@ -8,3 +8,4 @@ "use strict"; | ||
stripLeadingAndTrailingASCIIWhitespace, | ||
stripNewlines | ||
stripNewlines, | ||
splitOnCommas | ||
} = require("./strings"); | ||
@@ -19,2 +20,3 @@ const { | ||
} = require("./dates-and-times"); | ||
const whatwgURL = require("whatwg-url"); | ||
@@ -63,2 +65,20 @@ const submittableLocalNames = new Set(["button", "input", "keygen", "object", "select", "textarea"]); | ||
// https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address | ||
exports.isValidEmailAddress = (emailAddress, multiple = false) => { | ||
const emailAddressRegExp = new RegExp("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9]" + | ||
"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}" + | ||
"[a-zA-Z0-9])?)*$"); | ||
// A valid e-mail address list is a set of comma-separated tokens, where each token is itself | ||
// a valid e - mail address.To obtain the list of tokens from a valid e - mail address list, | ||
// an implementation must split the string on commas. | ||
if (multiple) { | ||
return splitOnCommas(emailAddress).every(value => emailAddressRegExp.test(value)); | ||
} | ||
return emailAddressRegExp.test(emailAddress); | ||
}; | ||
exports.isValidAbsoluteURL = url => { | ||
return whatwgURL.parseURL(url) !== null; | ||
}; | ||
exports.sanitizeValueByType = (input, val) => { | ||
@@ -65,0 +85,0 @@ switch (input.type.toLowerCase()) { |
@@ -54,2 +54,3 @@ "use strict"; | ||
exports.FileList = require("./generated/FileList").interface; | ||
exports.ValidityState = require("./generated/ValidityState").interface; | ||
@@ -56,0 +57,0 @@ exports.DOMParser = require("./generated/DOMParser").interface; |
@@ -37,2 +37,3 @@ "use strict"; | ||
const DOMImplementation = require("../generated/DOMImplementation"); | ||
const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation; | ||
const ParentNodeImpl = require("./ParentNode-impl").implementation; | ||
@@ -457,4 +458,5 @@ const Element = require("../generated/Element"); | ||
// This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not). | ||
getElementById(id) { | ||
// return the first element | ||
// Return the first element with this ID. | ||
return this._ids[id] && this._ids[id].length > 0 ? this._ids[id][0] : null; | ||
@@ -827,2 +829,3 @@ } | ||
mixin(DocumentImpl.prototype, GlobalEventHandlersImpl.prototype); | ||
mixin(DocumentImpl.prototype, NonElementParentNodeImpl.prototype); | ||
mixin(DocumentImpl.prototype, ParentNodeImpl.prototype); | ||
@@ -829,0 +832,0 @@ |
"use strict"; | ||
const { mixin } = require("../../utils"); | ||
const { domSymbolTree } = require("../helpers/internal-constants"); | ||
const NODE_TYPE = require("../node-type"); | ||
const NodeImpl = require("./Node-impl").implementation; | ||
const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation; | ||
const ParentNodeImpl = require("./ParentNode-impl").implementation; | ||
const NODE_TYPE = require("../node-type"); | ||
class DocumentFragmentImpl extends NodeImpl { | ||
@@ -14,4 +15,20 @@ constructor(args, privateData) { | ||
} | ||
// This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not). | ||
getElementById(id) { | ||
if (id === "") { | ||
return null; | ||
} | ||
for (const descendant of domSymbolTree.treeIterator(this)) { | ||
if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE && descendant.getAttributeNS(null, "id") === id) { | ||
return descendant; | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
mixin(DocumentFragmentImpl.prototype, NonElementParentNodeImpl.prototype); | ||
mixin(DocumentFragmentImpl.prototype, ParentNodeImpl.prototype); | ||
@@ -18,0 +35,0 @@ |
@@ -5,4 +5,13 @@ "use strict"; | ||
const { isDisabled } = require("../helpers/form-controls"); | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const { mixin } = require("../../utils"); | ||
class HTMLButtonElementImpl extends HTMLElementImpl { | ||
constructor(args, privateData) { | ||
super(args, privateData); | ||
this._customValidityErrorMessage = ""; | ||
} | ||
_activationBehavior() { | ||
@@ -51,6 +60,12 @@ const { form } = this; | ||
} | ||
_barredFromConstraintValidationSpecialization() { | ||
return this.type === "reset" || this.type === "button"; | ||
} | ||
} | ||
mixin(HTMLButtonElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLButtonElementImpl | ||
}; |
"use strict"; | ||
const HTMLElementImpl = require("./HTMLElement-impl").implementation; | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const { mixin } = require("../../utils"); | ||
const { closest } = require("../helpers/traversal"); | ||
@@ -9,6 +12,12 @@ | ||
} | ||
_barredFromConstraintValidationSpecialization() { | ||
return true; | ||
} | ||
} | ||
mixin(HTMLFieldSetElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLFieldSetElementImpl | ||
}; |
@@ -9,2 +9,3 @@ "use strict"; | ||
const { reflectURLAttribute } = require("../../utils"); | ||
const Event = require("../generated/Event"); | ||
@@ -14,2 +15,5 @@ // http://www.whatwg.org/specs/web-apps/current-work/#category-listed | ||
// https://html.spec.whatwg.org/multipage/forms.html#category-submit | ||
const submittableElements = new Set(["button", "input", "object", "select", "textarea"]); | ||
const encTypes = new Set([ | ||
@@ -27,2 +31,5 @@ "application/x-www-form-urlencoded", | ||
const constraintValidationPositiveResult = Symbol("positive"); | ||
const constraintValidationNegativeResult = Symbol("negative"); | ||
class HTMLFormElementImpl extends HTMLElementImpl { | ||
@@ -128,2 +135,46 @@ _descendantAdded(parent, child) { | ||
} | ||
// If the checkValidity() method is invoked, the user agent must statically validate the | ||
// constraints of the form element, and return true if the constraint validation returned | ||
// a positive result, and false if it returned a negative result. | ||
checkValidity() { | ||
return this._staticallyValidateConstraints().result === constraintValidationPositiveResult; | ||
} | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#interactively-validate-the-constraints | ||
reportValidity() { | ||
return this.checkValidity(); | ||
} | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#statically-validate-the-constraints | ||
_staticallyValidateConstraints() { | ||
const controls = []; | ||
for (const el of domSymbolTree.treeIterator(this)) { | ||
if (el.form === this && submittableElements.has(el.nodeName.toLowerCase())) { | ||
controls.push(el); | ||
} | ||
} | ||
const invalidControls = []; | ||
for (const control of controls) { | ||
if (control._isCandidateForConstraintValidation() && !control._satisfiesConstraints()) { | ||
invalidControls.push(control); | ||
} | ||
} | ||
if (invalidControls.length === 0) { | ||
return { result: constraintValidationPositiveResult }; | ||
} | ||
const unhandledInvalidControls = []; | ||
for (const invalidControl of invalidControls) { | ||
const notCancelled = invalidControl.dispatchEvent(Event.createImpl(["invalid", { cancelable: true }])); | ||
if (notCancelled) { | ||
unhandledInvalidControls.push(invalidControl); | ||
} | ||
} | ||
return { result: constraintValidationNegativeResult, unhandledInvalidControls }; | ||
} | ||
} | ||
@@ -130,0 +181,0 @@ |
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const DOMException = require("domexception"); | ||
const Event = require("../generated/Event"); | ||
const FileList = require("../generated/FileList"); | ||
const HTMLElementImpl = require("./HTMLElement-impl").implementation; | ||
const idlUtils = require("../generated/utils"); | ||
const Event = require("../generated/Event"); | ||
const FileList = require("../generated/FileList"); | ||
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 { closest } = require("../helpers/traversal"); | ||
const { isDisabled, sanitizeValueByType } = require("../helpers/form-controls"); | ||
const { parseFloatingPointNumber } = require("../helpers/strings"); | ||
const { | ||
isDisabled, | ||
isValidEmailAddress, | ||
isValidAbsoluteURL, | ||
sanitizeValueByType | ||
} = require("../helpers/form-controls"); | ||
const { | ||
parseFloatingPointNumber, | ||
asciiCaseInsensitiveMatch, | ||
splitOnCommas | ||
} = require("../helpers/strings"); | ||
const { | ||
parseDateString, | ||
@@ -29,2 +42,12 @@ parseLocalDateAndTimeString, | ||
const maxMinStepTypes = new Set(["date", "month", "week", "time", "datetime-local", "number", "range", "datetime"]); | ||
// https://html.spec.whatwg.org/multipage/input.html#concept-input-apply | ||
const applicableTypesForAttribute = { | ||
max: maxMinStepTypes, | ||
min: maxMinStepTypes, | ||
step: maxMinStepTypes, | ||
pattern: new Set(["text", "search", "tel", "url", "email", "password"]) | ||
}; | ||
function allowSelect(type) { | ||
@@ -54,6 +77,5 @@ return selectAllowedTypes.has(type.toLowerCase()); | ||
// Necessary because Date.UTC() treats year within [0, 99] as [1900, 1999]. | ||
function getUTCMs(year, month = 1, day = 1, hour = 0, minute = 0, second = 0) { | ||
const millisecond = second - Math.trunc(second); | ||
function getUTCMs(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, millisecond = 0) { | ||
if (year > 99 || year < 0) { | ||
return Date.UTC(year, month - 1, day, hour, minute, Math.trunc(second), millisecond); | ||
return Date.UTC(year, month - 1, day, hour, minute, second, millisecond); | ||
} | ||
@@ -66,3 +88,3 @@ const d = new Date(0); | ||
d.setUTCMinutes(minute); | ||
d.setUTCSeconds(Math.trunc(second), millisecond); | ||
d.setUTCSeconds(second, millisecond); | ||
return d.valueOf(); | ||
@@ -81,3 +103,3 @@ } | ||
} | ||
return getUTCMs(date.year, date.month - 1, date.day); | ||
return getUTCMs(date.year, date.month, date.day); | ||
} | ||
@@ -115,3 +137,3 @@ ], | ||
} | ||
return ((time.hours * 60 + time.minutes) * 60 + time.seconds) * 1000; | ||
return ((time.hour * 60 + time.minute) * 60 + time.second) * 1000 + time.millisecond; | ||
} | ||
@@ -126,5 +148,5 @@ ], | ||
} | ||
const { date: { year, month, day }, time: { hour, minute, second } } = dateAndTime; | ||
const { date: { year, month, day }, time: { hour, minute, second, millisecond } } = dateAndTime; | ||
// Doesn't quite matter whether or not UTC is used, since the offset from 1970-01-01 local time is returned. | ||
return getUTCMs(year, month, day, hour, minute, second); | ||
return getUTCMs(year, month, day, hour, minute, second, millisecond); | ||
} | ||
@@ -155,2 +177,4 @@ ], | ||
this.indeterminate = false; | ||
this._customValidityErrorMessage = ""; | ||
} | ||
@@ -193,3 +217,3 @@ | ||
if (this.type === "checkbox" || (this.type === "radio" && !this._preCheckedRadioState)) { | ||
const inputEvent = Event.createImpl(["input", { bubbles: true, cancelable: true }], {}); | ||
const inputEvent = Event.createImpl(["input", { isTrusted: true, bubbles: true, cancelable: true }], {}); | ||
this.dispatchEvent(inputEvent); | ||
@@ -242,9 +266,12 @@ | ||
} | ||
_removeOtherRadioCheckedness() { | ||
get _otherRadioGroupElements() { | ||
const wrapper = idlUtils.wrapperForImpl(this); | ||
const root = this._radioButtonGroupRoot; | ||
if (!root) { | ||
return; | ||
return []; | ||
} | ||
const result = []; | ||
const name = wrapper.name.toLowerCase(); | ||
@@ -264,6 +291,14 @@ | ||
if (candidate !== this) { | ||
candidate._checkedness = false; | ||
result.push(candidate); | ||
} | ||
} | ||
return result; | ||
} | ||
_removeOtherRadioCheckedness() { | ||
for (const radioGroupElement of this._otherRadioGroupElements) { | ||
radioGroupElement._checkedness = false; | ||
} | ||
} | ||
get _radioButtonGroupRoot() { | ||
@@ -286,8 +321,18 @@ const wrapper = idlUtils.wrapperForImpl(this); | ||
} | ||
_isRadioGroupChecked() { | ||
if (this.checked) { | ||
return true; | ||
} | ||
return this._otherRadioGroupElements.some(radioGroupElement => radioGroupElement.checked); | ||
} | ||
get form() { | ||
return closest(this, "form"); | ||
} | ||
get checked() { | ||
return this._checkedness; | ||
} | ||
set checked(checked) { | ||
@@ -300,2 +345,3 @@ this._checkedness = Boolean(checked); | ||
} | ||
get value() { | ||
@@ -605,2 +651,201 @@ switch (valueAttributeMode(this.type)) { | ||
get _parsedValue() { | ||
const converter = this._convertStringToNumber; | ||
if (converter !== undefined) { | ||
return converter(this.value); | ||
} | ||
return this.value; | ||
} | ||
// https://html.spec.whatwg.org/multipage/input.html#attr-input-step | ||
get _step() { | ||
let step = this._defaultStep; | ||
if (this.hasAttribute("step") && !asciiCaseInsensitiveMatch(this.getAttribute("step"), "any")) { | ||
const parsedStep = parseFloatingPointNumber(this.getAttribute("step")); | ||
if (!isNaN(parsedStep) && parsedStep > 0) { | ||
step = parsedStep; | ||
} | ||
} | ||
return step; | ||
} | ||
// 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() { | ||
const parseAttribute = attributeName => parseFloatingPointNumber(this.getAttribute(attributeName)); | ||
if (this.hasAttribute("min")) { | ||
const min = parseAttribute("min"); | ||
if (!isNaN(min)) { | ||
return min; | ||
} | ||
} | ||
if (this.hasAttribute("value")) { | ||
const value = parseAttribute("value"); | ||
if (!isNaN(value)) { | ||
return value; | ||
} | ||
} | ||
return this._defaultStepBase; | ||
} | ||
// 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 0; | ||
} | ||
_attributeApplies(attribute) { | ||
return applicableTypesForAttribute[attribute].has(this.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.hasAttribute("readonly"); | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled | ||
return willNotValidateTypes.has(this.type) || readOnly; | ||
} | ||
get validity() { | ||
if (!this._validity) { | ||
this._validity = ValidityState.createImpl(this, { | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-missing | ||
valueMissing: () => { | ||
if (!this.hasAttribute("required")) { | ||
return false; | ||
} | ||
if (this.type === "checkbox") { | ||
// 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. | ||
return !this.checked; | ||
} else if (this.type === "radio") { | ||
// 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. | ||
return !this._isRadioGroupChecked(); | ||
} | ||
return this.value === ""; | ||
}, | ||
// 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 | ||
// https://html.spec.whatwg.org/multipage/input.html#attr-input-max | ||
rangeOverflow: () => this._attributeApplies("max") && this._maximum !== null && | ||
this._parsedValue > this._maximum, | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-underflow | ||
// https://html.spec.whatwg.org/multipage/input.html#attr-input-min | ||
rangeUnderflow: () => this._attributeApplies("min") && this._minimum !== null && | ||
this._parsedValue < this._minimum, | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-pattern-mismatch | ||
patternMismatch: () => { | ||
if (!this.hasAttribute("pattern") || !this._attributeApplies("pattern") || this.value === "") { | ||
return false; | ||
} | ||
let regExp; | ||
try { | ||
regExp = new RegExp(this.getAttribute("pattern"), "u"); | ||
} catch (e) { | ||
return false; | ||
} | ||
if (this.type === "email" && this.hasAttribute("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: () => { | ||
// Constraint validation: When the element has an allowed value step, 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 that number subtracted from the step base is not an integral multiple of the | ||
// allowed value step, the element is suffering from a step mismatch. | ||
if (!this._attributeApplies("step")) { | ||
return false; | ||
} | ||
const step = parseFloatingPointNumber(this.getAttribute("step")); | ||
if (isNaN(step) || step <= 0) { | ||
return false; | ||
} | ||
let number = this._parsedValue; | ||
if (isNaN(number) || this.value === "") { | ||
return false; | ||
} | ||
if (this._type === "month") { | ||
number = parseMonthString(this.value).month - 1; | ||
} | ||
return number % (this._stepBase - (this._step * this._stepScaleFactor)) !== 0; | ||
}, | ||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-type-mismatch | ||
typeMismatch: () => { | ||
if (this.value === "") { | ||
return false; | ||
} | ||
if (this.type === "email") { | ||
// 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. | ||
return !isValidEmailAddress(this.value, this.hasAttribute("multiple")); | ||
} else if (this.type === "url") { | ||
// 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. | ||
return !isValidAbsoluteURL(this.value); | ||
} | ||
return false; | ||
} | ||
}); | ||
} | ||
return this._validity; | ||
} | ||
[cloningSteps](copy, node) { | ||
@@ -614,4 +859,6 @@ copy._value = node._value; | ||
mixin(HTMLInputElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLInputElementImpl | ||
}; |
"use strict"; | ||
const HTMLElementImpl = require("./HTMLElement-impl").implementation; | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const { mixin } = require("../../utils"); | ||
const { reflectURLAttribute } = require("../../utils"); | ||
@@ -30,6 +33,12 @@ const { closest } = require("../helpers/traversal"); | ||
} | ||
_barredFromConstraintValidationSpecialization() { | ||
return true; | ||
} | ||
} | ||
mixin(HTMLObjectElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLObjectElementImpl | ||
}; |
"use strict"; | ||
const HTMLElementImpl = require("./HTMLElement-impl").implementation; | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const { mixin } = require("../../utils"); | ||
class HTMLOutputElementImpl extends HTMLElementImpl { } | ||
class HTMLOutputElementImpl extends HTMLElementImpl { | ||
_barredFromConstraintValidationSpecialization() { | ||
return true; | ||
} | ||
} | ||
mixin(HTMLOutputElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLOutputElementImpl | ||
}; |
@@ -6,2 +6,6 @@ "use strict"; | ||
const idlUtils = require("../generated/utils.js"); | ||
const ValidityState = require("../generated/ValidityState"); | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const { mixin } = require("../../utils"); | ||
const HTMLElementImpl = require("./HTMLElement-impl").implementation; | ||
@@ -37,2 +41,4 @@ const NODE_TYPE = require("../node-type"); | ||
this._selectedOptions = null; // lazy | ||
this._customValidityErrorMessage = ""; | ||
} | ||
@@ -217,6 +223,44 @@ | ||
} | ||
_barredFromConstraintValidationSpecialization() { | ||
return this.hasAttribute("readonly"); | ||
} | ||
// Constraint validation: If the element has its required attribute specified, | ||
// and either none of the option elements in the select element's list of options | ||
// have their selectedness set to true, or the only option element in the select | ||
// element's list of options with its selectedness set to true is the placeholder | ||
// label option, then the element is suffering from being missing. | ||
get validity() { | ||
if (!this._validity) { | ||
this._validity = ValidityState.createImpl(this, { | ||
valueMissing: () => { | ||
if (!this.hasAttribute("required")) { | ||
return false; | ||
} | ||
const selectedOptionIndex = this.selectedIndex; | ||
return selectedOptionIndex < 0 || (selectedOptionIndex === 0 && this._hasPlaceholderOption); | ||
} | ||
}); | ||
} | ||
return this._validity; | ||
} | ||
// If a select element has a required attribute specified, does not have a multiple attribute | ||
// specified, and has a display size of 1; and if the value of the first option element in the | ||
// select element's list of options (if any) is the empty string, and that option element's parent | ||
// node is the select element(and not an optgroup element), then that option is the select | ||
// element's placeholder label option. | ||
// https://html.spec.whatwg.org/multipage/form-elements.html#placeholder-label-option | ||
get _hasPlaceholderOption() { | ||
return this.hasAttribute("required") && !this.hasAttribute("multiple") && | ||
this._displaySize === 1 && this.options.length > 0 && this.options.item(0).value === "" && | ||
this.options.item(0).parentNode._localName !== "optgroup"; | ||
} | ||
} | ||
mixin(HTMLSelectElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLSelectElementImpl | ||
}; |
@@ -5,2 +5,7 @@ "use strict"; | ||
const DefaultConstraintValidationImpl = | ||
require("../constraint-validation/DefaultConstraintValidation-impl").implementation; | ||
const ValidityState = require("../generated/ValidityState"); | ||
const { mixin } = require("../../utils"); | ||
const DOMException = require("domexception"); | ||
@@ -17,2 +22,4 @@ const { closest } = require("../helpers/traversal"); | ||
this._dirtyValue = false; | ||
this._customValidityErrorMessage = ""; | ||
} | ||
@@ -181,6 +188,22 @@ | ||
} | ||
_barredFromConstraintValidationSpecialization() { | ||
return this.hasAttribute("readonly"); | ||
} | ||
// https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-required | ||
get validity() { | ||
if (!this._validity) { | ||
this._validity = ValidityState.createImpl(this, { | ||
valueMissing: () => this.hasAttribute("required") && this.value === "" | ||
}); | ||
} | ||
return this._validity; | ||
} | ||
} | ||
mixin(HTMLTextAreaElementImpl.prototype, DefaultConstraintValidationImpl.prototype); | ||
module.exports = { | ||
implementation: HTMLTextAreaElementImpl | ||
}; |
"use strict"; | ||
// https://dom.spec.whatwg.org/#interface-nonelementparentnode | ||
// getElementById is implemented separately inside Document and DocumentFragment. | ||
class NonElementParentNodeImpl { | ||
@@ -4,0 +6,0 @@ |
{ | ||
"name": "jsdom", | ||
"version": "11.7.0", | ||
"version": "11.8.0", | ||
"description": "A JavaScript implementation of many web standards", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -359,3 +359,3 @@ # jsdom | ||
All invocations of the `framgment()` factory result in `DocumentFragment`s that share the same owner `Document` and `Window`. This allows many calls to `fragment()` with no extra overhead. But it also means that calls to `fragment()` cannot be customized with any options. | ||
All invocations of the `fragment()` factory result in `DocumentFragment`s that share the same owner `Document` and `Window`. This allows many calls to `fragment()` with no extra overhead. But it also means that calls to `fragment()` cannot be customized with any options. | ||
@@ -362,0 +362,0 @@ Note that serialization is not as easy with `DocumentFragment`s as it is with full `JSDOM` objects. If you need to serialize your DOM, you should probably use the `JSDOM` constructor more directly. But for the special case of a fragment containing a single element, it's pretty easy to do through normal means: |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2009189
2.18%397
0.76%58194
2.06%