Bug 1418078 - Convert JS users of nsIDOMHTMLInputElement. r?bz draft
authorAdrian Wielgosik <adrian.wielgosik@gmail.com>
Wed, 18 Apr 2018 22:29:50 +0200
changeset 790209 c934465a9de69f5d0eaedca482c8ff0aab2e0c22
parent 790147 d2a4720d1c334b64d88a51678758c27ba8f03c89
child 790210 9ac947042a308ce5b5d384c1f8abf795d784b357
push id108450
push userbmo:adrian.wielgosik@gmail.com
push dateTue, 01 May 2018 17:53:12 +0000
reviewersbz
bugs1418078
milestone61.0a1
Bug 1418078 - Convert JS users of nsIDOMHTMLInputElement. r?bz MozReview-Commit-ID: 55aIiNHS0xs
accessible/tests/mochitest/events.js
browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
dom/browser-element/BrowserElementChildPreload.js
mobile/android/components/BrowserCLH.js
mobile/android/modules/ActionBarHandler.jsm
mobile/android/modules/FormAssistant.jsm
mobile/android/tests/browser/robocop/testAccessibleCarets.js
toolkit/components/passwordmgr/LoginHelper.jsm
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/satchel/formSubmitListener.js
toolkit/components/satchel/nsFormAutoComplete.js
toolkit/content/tests/chrome/test_menulist.xul
toolkit/modules/BrowserUtils.jsm
toolkit/modules/FormLikeFactory.jsm
toolkit/modules/sessionstore/FormData.jsm
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1417,17 +1417,17 @@ function closeCombobox(aComboboxID) {
 
 /**
  * Select all invoker.
  */
 function synthSelectAll(aNodeOrID, aCheckerOrEventSeq) {
   this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq);
 
   this.invoke = function synthSelectAll_invoke() {
-    if (this.DOMNode instanceof Ci.nsIDOMHTMLInputElement ||
+    if (ChromeUtils.getClassName(this.DOMNode) === "HTMLInputElement" ||
         this.DOMNode.localName == "textbox") {
       this.DOMNode.select();
 
     } else {
       window.getSelection().selectAllChildren(this.DOMNode);
     }
   };
 
--- a/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
@@ -57,17 +57,17 @@ function test() {
       Array.forEach(node.options, (aOpt, aIx) =>
         (aOpt.selected = aValue.indexOf(aIx) > -1));
   }
 
   function compareFormValue(aTab, aQuery, aValue) {
     let node = getElementByXPath(aTab, aQuery);
     if (!node)
       return false;
-    if (node instanceof Ci.nsIDOMHTMLInputElement)
+    if (ChromeUtils.getClassName(node) === "HTMLInputElement")
       return aValue == (node.type == "checkbox" || node.type == "radio" ?
                        node.checked : node.value);
     if (ChromeUtils.getClassName(node) === "HTMLTextAreaElement")
       return aValue == node.value;
     if (!node.multiple)
       return aValue == node.selectedIndex;
     return Array.every(node.options, (aOpt, aIx) =>
             (aValue.indexOf(aIx) > -1) == aOpt.selected);
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -598,17 +598,17 @@ var FormAutofillContent = {
 
   onPopupClosed() {
     ProfileAutocomplete._clearProfilePreview();
   },
 
   _markAsAutofillField(field) {
     // Since Form Autofill popup is only for input element, any non-Input
     // element should be excluded here.
-    if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
+    if (!field || ChromeUtils.getClassName(field) !== "HTMLInputElement") {
       return;
     }
 
     formFillController.markAsAutofillField(field);
   },
 
   _messageManagerFromWindow(win) {
     return win.QueryInterface(Ci.nsIInterfaceRequestor)
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -265,17 +265,17 @@ class FormAutofillSection {
       let element = fieldDetail.elementWeakRef.get();
       if (!element) {
         continue;
       }
 
       element.previewValue = "";
       let value = profile[fieldDetail.fieldName];
 
-      if (element instanceof Ci.nsIDOMHTMLInputElement && value) {
+      if (ChromeUtils.getClassName(element) === "HTMLInputElement" && value) {
         // For the focused input element, it will be filled with a valid value
         // anyway.
         // For the others, the fields should be only filled when their values
         // are empty.
         let focusedInput = focusedDetail.elementWeakRef.get();
         if (element == focusedInput ||
             (element != focusedInput && !element.value)) {
           element.setUserInput(value);
@@ -374,17 +374,17 @@ class FormAutofillSection {
       let element = fieldDetail.elementWeakRef.get();
       if (!element) {
         log.warn(fieldDetail.fieldName, "is unreachable");
         continue;
       }
 
       // Only reset value for input element.
       if (fieldDetail.state == FIELD_STATES.AUTO_FILLED &&
-          element instanceof Ci.nsIDOMHTMLInputElement) {
+          ChromeUtils.getClassName(element) === "HTMLInputElement") {
         element.setUserInput("");
       }
     }
   }
 
   /**
    * Change the state of a field to correspond with different presentations.
    *
@@ -583,17 +583,17 @@ class FormAutofillAddressSection extends
 
   addressTransformer(profile) {
     if (profile["street-address"]) {
       // "-moz-street-address-one-line" is used by the labels in
       // ProfileAutoCompleteResult.
       profile["-moz-street-address-one-line"] = this._getOneLineStreetAddress(profile["street-address"]);
       let streetAddressDetail = this.getFieldDetailByName("street-address");
       if (streetAddressDetail &&
-          (streetAddressDetail.elementWeakRef.get() instanceof Ci.nsIDOMHTMLInputElement)) {
+          (ChromeUtils.getClassName(streetAddressDetail.elementWeakRef.get()) === "HTMLInputElement")) {
         profile["street-address"] = profile["-moz-street-address-one-line"];
       }
 
       let waitForConcat = [];
       for (let f of ["address-line3", "address-line2", "address-line1"]) {
         waitForConcat.unshift(profile[f]);
         if (this.getFieldDetailByName(f)) {
           if (waitForConcat.length > 1) {
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -872,17 +872,17 @@ BrowserElementChild.prototype = {
     if (ChromeUtils.getClassName(elem) === "HTMLVideoElement" ||
         ChromeUtils.getClassName(elem) === "HTMLAudioElement") {
       let hasVideo = !(elem.readyState >= elem.HAVE_METADATA &&
                        (elem.videoWidth == 0 || elem.videoHeight == 0));
       return {uri: elem.currentSrc || elem.src,
               hasVideo: hasVideo,
               documentURI: documentURI};
     }
-    if (elem instanceof Ci.nsIDOMHTMLInputElement &&
+    if (ChromeUtils.getClassName(elem) === "HTMLInputElement" &&
         elem.hasAttribute("name")) {
       // For input elements, we look for a parent <form> and if there is
       // one we return the form's method and action uri.
       let parent = elem.parentNode;
       while (parent) {
         if (ChromeUtils.getClassName(parent) === "HTMLFormElement" &&
             parent.hasAttribute("action")) {
           let actionHref = docShell.QueryInterface(Ci.nsIWebNavigation)
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -193,17 +193,17 @@ BrowserCLH.prototype = {
       this.LoginManagerContent.onDOMInputPasswordAdded(event, event.target.ownerGlobal.top);
     }, options);
 
     aWindow.addEventListener("DOMAutoComplete", event => {
       this.LoginManagerContent.onUsernameInput(event);
     }, options);
 
     aWindow.addEventListener("blur", event => {
-      if (event.target instanceof Ci.nsIDOMHTMLInputElement) {
+      if (ChromeUtils.getClassName(event.target) === "HTMLInputElement") {
         this.LoginManagerContent.onUsernameInput(event);
       }
     }, options);
 
     aWindow.addEventListener("pageshow", event => {
       // XXXbz what about non-HTML documents??
       if (ChromeUtils.getClassName(event.target) == "HTMLDocument") {
         this.LoginManagerContent.onPageShow(event, event.target.defaultView.top);
--- a/mobile/android/modules/ActionBarHandler.jsm
+++ b/mobile/android/modules/ActionBarHandler.jsm
@@ -203,17 +203,17 @@ var ActionBarHandler = {
   _getSelectionTargets: function() {
     let [element, win] = [Services.focus.focusedElement, Services.focus.focusedWindow];
     if (!element) {
       // No focused editable.
       return [null, win];
     }
 
     // Return focused editable text element and its window.
-    if (((element instanceof Ci.nsIDOMHTMLInputElement) && element.mozIsTextField(false)) ||
+    if (((ChromeUtils.getClassName(element) === "HTMLInputElement") && element.mozIsTextField(false)) ||
         (ChromeUtils.getClassName(element) === "HTMLTextAreaElement") ||
         element.isContentEditable) {
       return [element, win];
     }
 
     // Focused element can't contain text.
     return [null, win];
   },
@@ -412,17 +412,18 @@ var ActionBarHandler = {
 
       selector: {
         matches: function(element, win) {
           // Can cut from editable, or design-mode document.
           if (!element && !ActionBarHandler._isInDesignMode(win)) {
             return false;
           }
           // Don't allow "cut" from password fields.
-          if (element instanceof Ci.nsIDOMHTMLInputElement &&
+          if (element &&
+              ChromeUtils.getClassName(element) === "HTMLInputElement" &&
               !element.mozIsTextField(true)) {
             return false;
           }
           // Don't allow "cut" from disabled/readonly fields.
           if (element && (element.disabled || element.readOnly)) {
             return false;
           }
           // Allow if selected text exists.
@@ -453,17 +454,18 @@ var ActionBarHandler = {
       label: () => Strings.browser.GetStringFromName("contextmenu.copy"),
       icon: "drawable://ab_copy",
       order: 3,
       floatingOrder: 2,
 
       selector: {
         matches: function(element, win) {
           // Don't allow "copy" from password fields.
-          if (element instanceof Ci.nsIDOMHTMLInputElement &&
+          if (element &&
+              ChromeUtils.getClassName(element) === "HTMLInputElement" &&
               !element.mozIsTextField(true)) {
             return false;
           }
           // Allow if selected text exists.
           return (ActionBarHandler._getSelectedText().length > 0);
         },
       },
 
@@ -601,17 +603,17 @@ var ActionBarHandler = {
       floatingOrder: 8,
 
       selector: {
         matches: function(element, win) {
           let chrome = GeckoViewUtils.getChromeWindow(win);
           if (!chrome.SearchEngines) {
             return false;
           }
-          if (!(element instanceof Ci.nsIDOMHTMLInputElement)) {
+          if (!element || ChromeUtils.getClassName(element) !== "HTMLInputElement") {
             return false;
           }
           let form = element.form;
           if (!form || element.type == "password") {
             return false;
           }
 
           let method = form.method.toUpperCase();
--- a/mobile/android/modules/FormAssistant.jsm
+++ b/mobile/android/modules/FormAssistant.jsm
@@ -193,17 +193,17 @@ var FormAssistant = {
         }
         break;
       }
     }
   },
 
   // We only want to show autocomplete suggestions for certain elements
   _isAutoComplete: function(aElement) {
-    return (aElement instanceof Ci.nsIDOMHTMLInputElement) &&
+    return (ChromeUtils.getClassName(aElement) === "HTMLInputElement") &&
            !aElement.readOnly &&
            !this._isDisabledElement(aElement) &&
            (aElement.type !== "password") &&
            (aElement.autocomplete !== "off");
   },
 
   // Retrieves autocomplete suggestions for an element from the form autocomplete service.
   // aCallback(array_of_suggestions) is called when results are available.
@@ -235,17 +235,17 @@ var FormAssistant = {
   },
 
   /**
    * This function is similar to getListSuggestions from
    * components/satchel/src/nsInputListAutoComplete.js but sadly this one is
    * used by the autocomplete.xml binding which is not in used in fennec
    */
   _getListSuggestions: function(aElement) {
-    if (!(aElement instanceof Ci.nsIDOMHTMLInputElement) || !aElement.list) {
+    if (ChromeUtils.getClassName(aElement) !== "HTMLInputElement" || !aElement.list) {
       return [];
     }
 
     let suggestions = [];
     let filter = !aElement.hasAttribute("mozNoFilter");
     let lowerFieldValue = aElement.value.toLowerCase();
 
     let options = aElement.list.options;
--- a/mobile/android/tests/browser/robocop/testAccessibleCarets.js
+++ b/mobile/android/tests/browser/robocop/testAccessibleCarets.js
@@ -43,19 +43,18 @@ function do_promiseTabChangeEvent(tabId,
 
 /**
  * Selection methods vary if we have an input / textarea element,
  * or if we have basic content.
  */
 function isInputOrTextarea(element) {
   // ChromeUtils isn't included in robocop tests, so we have to use a different
   // way to test elements.
-  return ((element instanceof Ci.nsIDOMHTMLInputElement) ||
-          (element.localName === "textarea" &&
-           element.namespaceURI === "http://www.w3.org/1999/xhtml"));
+  return (element.namespaceURI === "http://www.w3.org/1999/xhtml" &&
+         (element.localName === "input" || element.localName === "textarea"));
 }
 
 /**
  * Return the selection controller based on element.
  */
 function elementSelection(element) {
   return (isInputOrTextarea(element)) ?
     element.editor.selection :
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -524,17 +524,17 @@ var LoginHelper = {
    *
    * @param {Element} element
    *                  the field we want to check.
    *
    * @returns {Boolean} true if the field type is one
    *                    of the username types.
    */
   isUsernameFieldType(element) {
-    if (!(element instanceof Ci.nsIDOMHTMLInputElement))
+    if (ChromeUtils.getClassName(element) !== "HTMLInputElement")
       return false;
 
     let fieldType = (element.hasAttribute("type") ?
                      element.getAttribute("type").toLowerCase() :
                      element.type);
     if (fieldType == "text" ||
         fieldType == "email" ||
         fieldType == "url" ||
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -672,17 +672,17 @@ var LoginManagerContent = {
   _getPasswordFields(form, {
     fieldOverrideRecipe = null,
     skipEmptyFields = false,
   } = {}) {
     // Locate the password fields in the form.
     let pwFields = [];
     for (let i = 0; i < form.elements.length; i++) {
       let element = form.elements[i];
-      if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
+      if (ChromeUtils.getClassName(element) !== "HTMLInputElement" ||
           element.type != "password") {
         continue;
       }
 
       // Exclude ones matching a `notPasswordSelector`, if specified.
       if (fieldOverrideRecipe && fieldOverrideRecipe.notPasswordSelector &&
           element.matches(fieldOverrideRecipe.notPasswordSelector)) {
         log("skipping password field (id/name is", element.id, " / ",
@@ -1339,17 +1339,17 @@ var LoginManagerContent = {
    *                  A form field we want to verify.
    *
    * @returns {Object} an object with information about the
    *                   FormLike username and password field
    *                   or null if the passed field is invalid.
    */
   getFieldContext(aField) {
     // If the element is not a proper form field, return null.
-    if (!(aField instanceof Ci.nsIDOMHTMLInputElement) ||
+    if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
         (aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
         !aField.ownerDocument) {
       return null;
     }
     let form = LoginFormFactory.createFromField(aField);
 
     let doc = aField.ownerDocument;
     let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
@@ -1611,17 +1611,17 @@ var LoginFormFactory = {
    * Note that two LoginForms created from the same field won't return the same LoginForm object.
    * Use the `rootElement` property on the LoginForm as a key instead.
    *
    * @param {HTMLInputElement} aField - a password or username field in a document
    * @return {LoginForm}
    * @throws Error if aField isn't a password or username field in a document
    */
   createFromField(aField) {
-    if (!(aField instanceof Ci.nsIDOMHTMLInputElement) ||
+    if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
         (aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
         !aField.ownerDocument) {
       throw new Error("createFromField requires a password or username field in a document");
     }
 
     if (aField.form) {
       return this.createFromForm(aField.form);
     }
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -510,17 +510,17 @@ LoginManager.prototype = {
    * [toolkit/components/satchel/nsFormFillController.cpp]
    *
    * We really ought to have a simple way for code to register an
    * auto-complete provider, and not have satchel calling pwmgr directly.
    */
   autoCompleteSearchAsync(aSearchString, aPreviousResult,
                           aElement, aCallback) {
     // aPreviousResult is an nsIAutoCompleteResult, aElement is
-    // nsIDOMHTMLInputElement
+    // HTMLInputElement
 
     let form = LoginFormFactory.createFromField(aElement);
     let isSecure = InsecurePasswordUtils.isFormSecure(form);
     let isPasswordField = aElement.type == "password";
 
     let completeSearch = (autoCompleteLookupPromise, { logins, messageManager }) => {
       // If the search was canceled before we got our
       // results, don't bother reporting them.
--- a/toolkit/components/satchel/formSubmitListener.js
+++ b/toolkit/components/satchel/formSubmitListener.js
@@ -96,17 +96,17 @@ let satchelFormListener = {
       if (form.hasAttribute("autocomplete") &&
         form.getAttribute("autocomplete").toLowerCase() == "off") {
         return;
       }
 
       let entries = [];
       for (let i = 0; i < form.elements.length; i++) {
         let input = form.elements[i];
-        if (!(input instanceof Ci.nsIDOMHTMLInputElement)) {
+        if (ChromeUtils.getClassName(input) !== "HTMLInputElement") {
           continue;
         }
 
         // Only use inputs that hold text values (not including type="password")
         if (!input.mozIsTextField(true)) {
           continue;
         }
 
--- a/toolkit/components/satchel/nsFormAutoComplete.js
+++ b/toolkit/components/satchel/nsFormAutoComplete.js
@@ -261,17 +261,17 @@ FormAutoComplete.prototype = {
     Services.console.logStringMessage("FormAutoComplete: " + message);
   },
 
   /*
    * autoCompleteSearchAsync
    *
    * aInputName    -- |name| attribute from the form input being autocompleted.
    * aUntrimmedSearchString -- current value of the input
-   * aField -- nsIDOMHTMLInputElement being autocompleted (may be null if from chrome)
+   * aField -- HTMLInputElement being autocompleted (may be null if from chrome)
    * aPreviousResult -- previous search result, if any.
    * aDatalistResult -- results from list=datalist for aField.
    * aListener -- nsIFormAutoCompleteObserver that listens for the nsIAutoCompleteResult
    *              that may be returned asynchronously.
    */
   autoCompleteSearchAsync(aInputName,
                           aUntrimmedSearchString,
                           aField,
--- a/toolkit/content/tests/chrome/test_menulist.xul
+++ b/toolkit/content/tests/chrome/test_menulist.xul
@@ -134,17 +134,17 @@ function testtag_menulist_UI_finish(elem
 function test_nsIDOMXULMenuListElement(element, testprefix, editable)
 {
   is(element.open, false, testprefix + " open");
   is(element.editable, editable, testprefix + " editable");
 
   if (editable) {
     var inputField = element.inputField;
     is(inputField &&
-                  inputField instanceof Ci.nsIDOMHTMLInputElement,
+                  inputField instanceof HTMLInputElement,
                   true, testprefix + " inputField");
 
     // check if the select method works
     inputField.select();
     is(inputField.selectionStart, 0, testprefix + " empty select selectionStart");
     is(inputField.selectionEnd, 0, testprefix + " empty select selectionEnd");
 
     element.value = "Some Text";
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -483,17 +483,17 @@ var BrowserUtils = {
 
     let url;
     let linkText;
 
     // try getting a selected text in text input.
     if (!selectionStr && focusedElement instanceof Ci.nsIDOMNSEditableElement) {
       // Don't get the selection for password fields. See bug 565717.
       if (ChromeUtils.getClassName(focusedElement) === "HTMLTextAreaElement" ||
-          (focusedElement instanceof Ci.nsIDOMHTMLInputElement &&
+          (ChromeUtils.getClassName(focusedElement) === "HTMLInputElement" &&
            focusedElement.mozIsTextField(true))) {
         selection = focusedElement.editor.selection;
         selectionStr = selection.toString();
       }
     }
 
     let collapsed = selection.isCollapsed;
 
--- a/toolkit/modules/FormLikeFactory.jsm
+++ b/toolkit/modules/FormLikeFactory.jsm
@@ -56,17 +56,17 @@ let FormLikeFactory = {
    * Note that two FormLikes created from the same field won't return the same FormLike object.
    * Use the `rootElement` property on the FormLike as a key instead.
    *
    * @param {HTMLInputElement|HTMLSelectElement} aField - an <input> or <select> field in a document
    * @return {FormLike}
    * @throws Error if aField isn't a password or username field in a document
    */
   createFromField(aField) {
-    if ((!(aField instanceof Ci.nsIDOMHTMLInputElement) &&
+    if ((ChromeUtils.getClassName(aField) !== "HTMLInputElement" &&
          ChromeUtils.getClassName(aField) !== "HTMLSelectElement") ||
         !aField.ownerDocument) {
       throw new Error("createFromField requires a field in a document");
     }
 
     let rootElement = this.findRootForField(aField);
     if (ChromeUtils.getClassName(rootElement) === "HTMLFormElement") {
       return this.createFromForm(rootElement);
--- a/toolkit/modules/sessionstore/FormData.jsm
+++ b/toolkit/modules/sessionstore/FormData.jsm
@@ -193,22 +193,22 @@ var FormDataInternal = {
 
       // Only generate a limited number of XPath expressions for perf reasons
       // (cf. bug 477564)
       if (!node.id && generatedCount > MAX_TRAVERSED_XPATHS) {
         continue;
       }
 
       // We do not want to collect credit card numbers.
-      if (node instanceof Ci.nsIDOMHTMLInputElement &&
+      if (ChromeUtils.getClassName(node) === "HTMLInputElement" &&
           isValidCCNumber(node.value)) {
         continue;
       }
 
-      if (node instanceof Ci.nsIDOMHTMLInputElement ||
+      if (ChromeUtils.getClassName(node) === "HTMLInputElement" ||
           ChromeUtils.getClassName(node) === "HTMLTextAreaElement" ||
           (node.namespaceURI == this.namespaceURIs.xul && node.localName == "textbox")) {
         switch (node.type) {
           case "checkbox":
           case "radio":
             value = node.checked;
             hasDefaultValue = value == node.defaultChecked;
             break;