Bug 1354211 - Add element.isDisabled. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Sun, 31 Dec 2017 14:48:46 +0000
changeset 719574 355b838c62d040190dd39a8d572e9a04da6f593d
parent 719573 1f60473180a0de1c360fc6b6efbf62af3d8ec6bc
child 719575 c32906294b1b1bc5f089957ea06cee91c63619f8
push id95293
push userbmo:ato@sny.no
push dateFri, 12 Jan 2018 10:32:36 +0000
reviewersautomatedtester
bugs1354211
milestone59.0a1
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
testing/marionette/element.js
testing/marionette/test_element.js
--- 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));