Bug 1354211 - Add element.isDisabled. r?automatedtester
Adds a new function called element.isDisabled to test for disabledness.
An element is only considered disabled if it is indeed an element
that can be disabled, for example that it is a <button>, <input>,
<select>, <textarea>, <optgroup>, or <option> element. All other
elements are not disabled.
In nested trees the disabledness state of a containing element
affects child elements, without this being refelected in the child
element's content IDL attribute. In the following example, the
<option> element is disabled:
<select disabled>
<option>foo
</select>
Similarly:
<select>
<optgroup disabled>
<option>bar
</optgroup>
</select>
This means we have to traverse the tree to find the closest ancestral
parent element, whether it is <optgroup> or <select>, and inspect
its state before we can be sure the element in question is not disabled.
MozReview-Commit-ID: 578zLNj7nXK
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -794,16 +794,52 @@ element.isSelected = function(el) {
* True if element is read only.
*/
element.isReadOnly = function(el) {
return element.isDOMElement(el) &&
["input", "textarea"].includes(el.localName) && el.readOnly;
};
/**
+ * An element is considered disabled if it is a an element
+ * that can be disabled, or it belongs to a container group which
+ * <code>disabled</code> content IDL attribute affects it.
+ *
+ * @param {Element} el
+ * Element to test for disabledness.
+ *
+ * @return {boolean}
+ * True if element, or its container group, is disabled.
+ */
+element.isDisabled = function(el) {
+ if (!element.isDOMElement(el)) {
+ return false;
+ }
+
+ switch (el.localName) {
+ case "option":
+ case "optgroup":
+ if (el.disabled) {
+ return true;
+ }
+ let parent = element.findClosest(el, "optgroup,select");
+ return element.isDisabled(parent);
+
+ case "button":
+ case "input":
+ case "select":
+ case "textarea":
+ return el.disabled;
+
+ default:
+ return false;
+ }
+};
+
+/**
* This function generates a pair of coordinates relative to the viewport
* given a target element and coordinates relative to that element's
* top-left corner.
*
* @param {Node} node
* Target node.
* @param {number=} xOffset
* Horizontal offset relative to target's top-left corner.
--- a/testing/marionette/test_element.js
+++ b/testing/marionette/test_element.js
@@ -199,16 +199,40 @@ add_test(function test_isReadOnly() {
ok(!element.isReadOnly(domEl));
ok(!element.isReadOnly(new DOMElement("p", {readOnly: true})));
ok(element.isReadOnly(new DOMElement("input", {readOnly: true})));
ok(element.isReadOnly(new DOMElement("textarea", {readOnly: true})));
run_next_test();
});
+add_test(function test_isDisabled() {
+ ok(!element.isDisabled(new DOMElement("p")));
+ ok(!element.isDisabled(new SVGElement("rect", {disabled: true})));
+ ok(!element.isDisabled(new XULElement("browser", {disabled: true})));
+
+ let select = new DOMElement("select", {disabled: true});
+ let option = new DOMElement("option");
+ option.parentNode = select;
+ ok(element.isDisabled(option));
+
+ let optgroup = new DOMElement("optgroup", {disabled: true});
+ option.parentNode = optgroup;
+ optgroup.parentNode = select;
+ select.disabled = false;
+ ok(element.isDisabled(option));
+
+ ok(element.isDisabled(new DOMElement("button", {disabled: true})));
+ ok(element.isDisabled(new DOMElement("input", {disabled: true})));
+ ok(element.isDisabled(new DOMElement("select", {disabled: true})));
+ ok(element.isDisabled(new DOMElement("textarea", {disabled: true})));
+
+ run_next_test();
+});
+
add_test(function test_coordinates() {
let p = element.coordinates(domEl);
ok(p.hasOwnProperty("x"));
ok(p.hasOwnProperty("y"));
equal("number", typeof p.x);
equal("number", typeof p.y);
deepEqual({x: 50, y: 50}, element.coordinates(domEl));