Bug 824150 - Code cleanup in /mail/ and /mailnews/: Use new String methods like startsWith, endsWith, contains, remaining Services.jsm switches and querySelector use instead of NodeList calls: compose. r=mconley
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sat, 09 Feb 2013 19:52:42 +0100
changeset 14840 aeb1127152ac457aef2ec6484c5a177f9d34358d
parent 14839 b66b5fafc36d265a58475ad9fc5e8c620d7ca169
child 14841 9e7319029574532affae61a2b6e9dc5b2453ba5d
push id867
push userbugzilla@standard8.plus.com
push dateMon, 01 Apr 2013 20:44:27 +0000
treeherdercomm-beta@797726b8d244 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs824150
Bug 824150 - Code cleanup in /mail/ and /mailnews/: Use new String methods like startsWith, endsWith, contains, remaining Services.jsm switches and querySelector use instead of NodeList calls: compose. r=mconley
mail/components/compose/content/MsgComposeCommands.js
mail/components/compose/content/addressingWidgetOverlay.js
mail/test/mozmill/attachment/test-attachment-events.js
mail/test/mozmill/attachment/test-attachment.js
mail/test/mozmill/composition/test-attachment.js
mail/test/mozmill/composition/test-eml-actions.js
mail/test/mozmill/composition/test-forwarded-content.js
mail/test/mozmill/composition/test-forwarded-eml-actions.js
mail/test/mozmill/composition/test-image-insertion-dialog.js
mail/test/mozmill/composition/test-signature-updating.js
mail/test/mozmill/shared-modules/test-compose-helpers.js
mailnews/compose/content/mailComposeEditorOverlay.xul
mailnews/compose/test/unit/test_attachment.js
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -167,17 +167,17 @@ function ReleaseGlobalVariables()
  */
 function updateEditableFields(aDisable)
 {
   if (aDisable)
     gMsgCompose.editor.flags |= nsIPlaintextEditorMail.eEditorReadonlyMask;
   else
     gMsgCompose.editor.flags &= ~nsIPlaintextEditorMail.eEditorReadonlyMask;
 
-  let elements = document.getElementsByAttribute("disableonsend", "true");
+  let elements = document.querySelectorAll('[disableonsend="true"]');
   for (let i = 0; i < elements.length; i++)
     elements[i].disabled = aDisable;
 }
 
 var gComposeRecyclingListener = {
   onClose: function() {
     //Reset recipients and attachments
     ReleaseAutoCompleteState();
@@ -892,18 +892,18 @@ function updateAllItems(aDisable)
       aElement.setAttribute("disabled", aValue ? "true" : "false");
   }
 
 
   // This array will contain HTMLCollection objects as members.
   let commandItemCollections = [];
   commandItemCollections.push(document.getElementsByTagName("menu"));
   commandItemCollections.push(document.getElementsByTagName("toolbarbutton"));
-  commandItemCollections.push(document.getElementsByAttribute("command", "*"));
-  commandItemCollections.push(document.getElementsByAttribute("oncommand", "*"));
+  commandItemCollections.push(document.querySelectorAll('[command]'));
+  commandItemCollections.push(document.querySelectorAll('[oncommand]'));
   for each (let itemCollection in commandItemCollections) {
     for (let item = 0; item < itemCollection.length; item++) {
       let commandItem = itemCollection[item];
       if (aDisable) {
         // Any element can appear multiple times in the commandItemCollections
         // list so only act on it if we didn't already set the "stateBeforeSend"
         // attribute on previous visit.
         if (!commandItem.hasAttribute("stateBeforeSend")) {
@@ -1907,17 +1907,17 @@ function GetArgs(originalData)
 
   for (let i = pairs.length - 1; i >= 0; i--)
   {
     var pos = pairs[i].indexOf('=');
     if (pos == -1)
       continue;
     var argname = pairs[i].substring(0, pos);
     var argvalue = pairs[i].substring(pos + 1);
-    if (argvalue.charAt(0) == "'" && argvalue.charAt(argvalue.length - 1) == "'")
+    if (argvalue.startsWith("'") && argvalue.endsWith("'"))
       args[argname] = argvalue.substring(1, argvalue.length - 1);
     else
       try {
         args[argname] = decodeURIComponent(argvalue);
       } catch (e) {args[argname] = argvalue;}
     // dump("[" + argname + "=" + args[argname] + "]\n");
   }
   return args;
@@ -1940,23 +1940,23 @@ function ComposeFieldsReady()
   updateEditableFields(false);
 }
 
 // checks if the passed in string is a mailto url, if it is, generates nsIMsgComposeParams
 // for the url and returns them.
 function handleMailtoArgs(mailtoUrl)
 {
   // see if the string is a mailto url....do this by checking the first 7 characters of the string
-  if (mailtoUrl.startsWith("mailto:"))
+  if (mailtoUrl.toLowerCase().startsWith("mailto:"))
   {
     // if it is a mailto url, turn the mailto url into a MsgComposeParams object....
     let uri = Services.io.newURI(mailtoUrl, null, null);
 
     if (uri) {
-      var composeSvc = Components.classes["@mozilla.org/messengercompose;1"]
+      let composeSvc = Components.classes["@mozilla.org/messengercompose;1"]
                                  .getService(Components.interfaces.nsIMsgComposeService);
       return composeSvc.getParamsForMailto(uri);
     }
   }
 
   return null;
 }
 
@@ -2066,31 +2066,30 @@ function ShouldShowAttachmentNotificatio
 {
   let bucket = document.getElementById("attachmentBucket");
   let warn = getPref("mail.compose.attachment_reminder");
   if (warn && !bucket.itemCount) {
     let keywordsInCsv = Services.prefs.getComplexValue(
       "mail.compose.attachment_reminder_keywords",
       Components.interfaces.nsIPrefLocalizedString).data;
     let mailBody = document.getElementById("content-frame")
-                           .contentDocument.getElementsByTagName("body")[0];
+                           .contentDocument.querySelector("body");
     let mailBodyNode = mailBody.cloneNode(true);
 
     // Don't check quoted text from reply.
     let blockquotes = mailBodyNode.getElementsByTagName("blockquote");
     for (let i = blockquotes.length - 1; i >= 0; i--) {
       blockquotes[i].parentNode.removeChild(blockquotes[i]);
     }
 
     // For plaintext composition the quotes we need to find and exclude are
     // <span _moz_quote="true">.
-    let spans = mailBodyNode.getElementsByTagName("span");
+    let spans = mailBodyNode.querySelectorAll("span[_moz_quote]");
     for (let i = spans.length - 1; i >= 0; i--) {
-      if (spans[i].hasAttribute("_moz_quote"))
-        spans[i].parentNode.removeChild(spans[i]);
+      spans[i].parentNode.removeChild(spans[i]);
     }
 
     // Ignore signature (html compose mode).
     let sigs = mailBodyNode.getElementsByClassName("moz-signature");
     for (let i = sigs.length - 1; i >= 0; i--) {
       sigs[i].parentNode.removeChild(sigs[i]);
     }
 
@@ -2171,18 +2170,18 @@ function ComposeStartup(recycled, aParam
     }
   }
 
   // Set a sane starting width/height for all resolutions on new profiles.
   // Do this before the window loads.
   if (!document.documentElement.hasAttribute("width"))
   {
     // Prefer 860x800.
-    let defaultHeight = (screen.availHeight >= 800) ? 800 : screen.availHeight;
-    let defaultWidth = (screen.availWidth >= 860) ? 860 : screen.availWidth;
+    let defaultHeight = Math.min(screen.availHeight, 800);
+    let defaultWidth = Math.min(screen.availWidth, 860);
 
     // On small screens, default to maximized state.
     if (defaultHeight <= 600)
       document.documentElement.setAttribute("sizemode", "maximized");
 
     document.documentElement.setAttribute("width", defaultWidth);
     document.documentElement.setAttribute("height", defaultHeight);
     // Make sure we're safe at the left/top edge of screen
@@ -2679,18 +2678,17 @@ function GenericSendMessage(msgType)
                         "chrome,close,titlebar,modal", true, true);
 
       if (window.cancelSendMessage)
         return;
     }
 
     // Strip trailing spaces and long consecutive WSP sequences from the
     // subject line to prevent getting only WSP chars on a folded line.
-    var fixedSubject = subject.replace(/\s{74,}/g, "    ")
-                              .replace(/\s*$/, "");
+    let fixedSubject = subject.replace(/\s{74,}/g, "    ").trimRight();
     if (fixedSubject != subject)
     {
       subject = fixedSubject;
       msgCompFields.subject = fixedSubject;
       GetMsgSubjectElement().value = fixedSubject;
     }
 
     // Remind the person if there isn't a subject
@@ -2895,21 +2893,21 @@ function GenericSendMessage(msgType)
     SetDocumentCharacterSet(gMsgCompose.compFields.characterSet);
 }
 
 function CheckValidEmailAddress(to, cc, bcc)
 {
   var invalidStr = null;
   // crude check that the to, cc, and bcc fields contain at least one '@'.
   // We could parse each address, but that might be overkill.
-  if (to.length > 0 && (to.indexOf("@") <= 0 && to.toLowerCase() != "postmaster" || to.indexOf("@") == to.length - 1))
+  if (to.length > 0 && (!to.contains("@", 1) && to.toLowerCase() != "postmaster" || to.endsWith("@")))
     invalidStr = to;
-  else if (cc.length > 0 && (cc.indexOf("@") <= 0 && cc.toLowerCase() != "postmaster" || cc.indexOf("@") == cc.length - 1))
+  else if (cc.length > 0 && (!cc.contains("@", 1) && cc.toLowerCase() != "postmaster" || cc.endsWith("@")))
     invalidStr = cc;
-  else if (bcc.length > 0 && (bcc.indexOf("@") <= 0 && bcc.toLowerCase() != "postmaster" || bcc.indexOf("@") == bcc.length - 1))
+  else if (bcc.length > 0 && (!bcc.contains("@", 1) && bcc.toLowerCase() != "postmaster" || bcc.endsWith("@")))
     invalidStr = bcc;
   if (invalidStr)
   {
     Services.prompt.alert(window, getComposeBundle().getString("addressInvalidTitle"),
                           getComposeBundle().getFormattedString("addressInvalid",
                           [invalidStr], 1));
     return false;
   }
@@ -3030,18 +3028,18 @@ function MessageFcc(aFolder)
 function updatePriorityMenu()
 {
   if (gMsgCompose)
   {
     var msgCompFields = gMsgCompose.compFields;
     if (msgCompFields && msgCompFields.priority)
     {
       var priorityMenu = document.getElementById('priorityMenu' );
-      priorityMenu.getElementsByAttribute( "checked", 'true' )[0].removeAttribute('checked');
-      priorityMenu.getElementsByAttribute( "value", msgCompFields.priority )[0].setAttribute('checked', 'true');
+      priorityMenu.querySelector('[checked="true"]').removeAttribute('checked');
+      priorityMenu.querySelector('[value="' + msgCompFields.priority + '"]').setAttribute('checked', 'true');
     }
   }
 }
 
 function updatePriorityToolbarButton(newPriorityValue)
 {
   var prioritymenu = document.getElementById('priorityMenu-button');
   if (prioritymenu)
@@ -3210,21 +3208,21 @@ function InitLanguageMenu()
     item.setAttribute('type', 'radio');
     languageMenuList.appendChild(item);
   }
 }
 
 function OnShowDictionaryMenu(aTarget)
 {
   InitLanguageMenu();
-  var spellChecker = gSpellChecker.mInlineSpellChecker.spellChecker;
-  var curLang = spellChecker.GetCurrentDictionary();
-  var languages = aTarget.getElementsByAttribute("value", curLang);
-  if (languages.length > 0)
-    languages[0].setAttribute("checked", true);
+  let spellChecker = gSpellChecker.mInlineSpellChecker.spellChecker;
+  let curLang = spellChecker.GetCurrentDictionary();
+  let language = aTarget.querySelector('[value="' + curLang + '"]');
+  if (language)
+    language.setAttribute("checked", true);
 }
 
 function ChangeLanguage(event)
 {
   // We need to change the dictionary language and if we are using inline spell check,
   // recheck the message
 
   var spellChecker = gSpellChecker.mInlineSpellChecker.spellChecker;
@@ -4261,20 +4259,19 @@ var envelopeDragObserver = {
         // We could be dropping an attachment OR an address, check and do the right thing..
 
         if (item.flavour.contentType == "text/x-moz-url" ||
             item.flavour.contentType == "text/x-moz-message" ||
             item.flavour.contentType == "application/x-moz-file")
         {
           if (item.flavour.contentType == "application/x-moz-file")
           {
-            var fileHandler = Components.classes["@mozilla.org/network/io-service;1"]
-                                        .getService(Components.interfaces.nsIIOService)
-                                        .getProtocolHandler("file")
-                                        .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
+            let fileHandler = Services.io
+                                      .getProtocolHandler("file")
+                                      .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
 
             size = rawData.fileSize;
             rawData = fileHandler.getURLSpecFromFile(rawData);
           }
           else if (item.flavour.contentType == "text/x-moz-message")
           {
             size = gMessenger.messageServiceFromURI(rawData)
                              .messageURIToMsgHdr(rawData).messageSize;
@@ -4289,17 +4286,17 @@ var envelopeDragObserver = {
               size = parseInt(pieces[2]);
           }
 
           var isValid = true;
           if (item.flavour.contentType == "text/x-moz-url") {
             // if this is a url (or selected text)
             // see if it's a valid url by checking
             // if we can extract a scheme
-            // using the ioservice
+            // using Services.io
             //
             // also skip mailto:, since it doesn't make sense
             // to attach and send mailto urls
             try {
               let scheme = Services.io.extractScheme(rawData);
               // don't attach mailto: urls
               if (scheme == "mailto")
                 isValid = false;
--- a/mail/components/compose/content/addressingWidgetOverlay.js
+++ b/mail/components/compose/content/addressingWidgetOverlay.js
@@ -153,59 +153,59 @@ function Recipients2CompFields(msgCompFi
     dump("Message Compose Error: msgCompFields is null (ExtractRecipients)");
 }
 
 function CompFields2Recipients(msgCompFields)
 {
   if (msgCompFields) {
     gMimeHeaderParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
 
-    var listbox = document.getElementById('addressingWidget');
-    var newListBoxNode = listbox.cloneNode(false);
-    var listBoxColsClone = listbox.firstChild.cloneNode(true);
+    let listbox = document.getElementById('addressingWidget');
+    let newListBoxNode = listbox.cloneNode(false);
+    let listBoxColsClone = listbox.firstChild.cloneNode(true);
     newListBoxNode.appendChild(listBoxColsClone);
-    var templateNode = listbox.getElementsByTagName("listitem")[0];
+    let templateNode = listbox.querySelector("listitem");
     // dump("replacing child in comp fields 2 recips \n");
     listbox.parentNode.replaceChild(newListBoxNode, listbox);
 
     top.MAX_RECIPIENTS = 0;
-    var msgReplyTo = msgCompFields.replyTo;
-    var msgTo = msgCompFields.to;
-    var msgCC = msgCompFields.cc;
-    var msgBCC = msgCompFields.bcc;
-    var msgRandomHeaders = msgCompFields.otherRandomHeaders;
-    var msgNewsgroups = msgCompFields.newsgroups;
-    var msgFollowupTo = msgCompFields.followupTo;
-    var havePrimaryRecipient = false;
-    if(msgReplyTo)
+    let msgReplyTo = msgCompFields.replyTo;
+    let msgTo = msgCompFields.to;
+    let msgCC = msgCompFields.cc;
+    let msgBCC = msgCompFields.bcc;
+    let msgRandomHeaders = msgCompFields.otherRandomHeaders;
+    let msgNewsgroups = msgCompFields.newsgroups;
+    let msgFollowupTo = msgCompFields.followupTo;
+    let havePrimaryRecipient = false;
+    if (msgReplyTo)
       awSetInputAndPopupFromArray(msgCompFields.splitRecipients(msgReplyTo, false, {}),
                                   "addr_reply", newListBoxNode, templateNode);
-    if(msgTo)
+    if (msgTo)
     {
-      var rcp = msgCompFields.splitRecipients(msgTo, false, {});
+      let rcp = msgCompFields.splitRecipients(msgTo, false, {});
       if (rcp.length)
       {
         awSetInputAndPopupFromArray(rcp, "addr_to", newListBoxNode, templateNode);
         havePrimaryRecipient = true;
       }
     }
-    if(msgCC)
+    if (msgCC)
       awSetInputAndPopupFromArray(msgCompFields.splitRecipients(msgCC, false, {}),
                                   "addr_cc", newListBoxNode, templateNode);
-    if(msgBCC)
+    if (msgBCC)
       awSetInputAndPopupFromArray(msgCompFields.splitRecipients(msgBCC, false, {}),
                                   "addr_bcc", newListBoxNode, templateNode);
-    if(msgRandomHeaders)
+    if (msgRandomHeaders)
       awSetInputAndPopup(msgRandomHeaders, "addr_other", newListBoxNode, templateNode);
-    if(msgNewsgroups)
+    if (msgNewsgroups)
     {
       awSetInputAndPopup(msgNewsgroups, "addr_newsgroups", newListBoxNode, templateNode);
       havePrimaryRecipient = true;
     }
-    if(msgFollowupTo)
+    if (msgFollowupTo)
       awSetInputAndPopup(msgFollowupTo, "addr_followup", newListBoxNode, templateNode);
 
     // If it's a new message, we need to add an extra empty recipient.
     if (!havePrimaryRecipient)
       _awSetInputAndPopup("", "addr_to", newListBoxNode, templateNode);
     awFitDummyRows(2);
 
     // CompFields2Recipients is called whenever a user replies or edits an existing message. We want to
@@ -220,19 +220,17 @@ function awSetInputAndPopupId(inputElem,
 {
   popupElem.id = "addressCol1#" + rowNumber;
   inputElem.id = "addressCol2#" + rowNumber;
   inputElem.setAttribute("aria-labelledby", popupElem.id);
 }
 
 function awSetInputAndPopupValue(inputElem, inputValue, popupElem, popupValue, rowNumber)
 {
-  // remove leading spaces
-  while (inputValue && inputValue[0] == " " )
-    inputValue = inputValue.substring(1, inputValue.length);
+  inputValue = inputValue.trimLeft();
 
   inputElem.setAttribute("value", inputValue);
   inputElem.value = inputValue;
 
   popupElem.selectedItem = popupElem.childNodes[0].childNodes[awGetSelectItemIndex(popupValue)];
 
   if (rowNumber >= 0)
     awSetInputAndPopupId(inputElem, popupElem, rowNumber);
@@ -350,30 +348,30 @@ function awTestRowSequence()
     This function is for debug and testing purpose only, normal user should not run it!
 
     Everytime we insert or delete a row, we must be sure we didn't break the ID sequence of
     the addressing widget rows. This function will run a quick test to see if the sequence still ok
 
     You need to define the pref mail.debug.test_addresses_sequence to true in order to activate it
   */
 
-  if (! test_addresses_sequence)
+  if (!test_addresses_sequence)
     return true;
 
   /* debug code to verify the sequence still good */
 
-  var listbox = document.getElementById('addressingWidget');
-  var listitems = listbox.getElementsByTagName('listitem');
+  let listbox = document.getElementById('addressingWidget');
+  let listitems = listbox.getElementsByTagName('listitem');
   if (listitems.length >= top.MAX_RECIPIENTS )
   {
-    for (var i = 1; i <= listitems.length; i ++)
+    for (let i = 1; i <= listitems.length; i ++)
     {
-      var item = listitems [i - 1];
-      var inputID = item.getElementsByTagName(awInputElementName())[0].getAttribute("id").split("#")[1];
-      var popupID = item.getElementsByTagName(awSelectElementName())[0].getAttribute("id").split("#")[1];
+      let item = listitems [i - 1];
+      let inputID = item.querySelector(awInputElementName()).id.split("#")[1];
+      let popupID = item.querySelector(awSelectElementName()).id.split("#")[1];
       if (inputID != i || popupID != i)
       {
         dump("#ERROR: sequence broken at row " + i + ", inputID=" + inputID + ", popupID=" + popupID + "\n");
         return false;
       }
       dump("---SEQUENCE OK---\n");
       return true;
     }
@@ -831,17 +829,17 @@ function awRecipientKeyPress(event, elem
     awArrowHit(element, -1);
     break;
   case KeyEvent.DOM_VK_DOWN:
     awArrowHit(element, 1);
     break;
   case KeyEvent.DOM_VK_RETURN:
   case KeyEvent.DOM_VK_TAB:
     // if the user text contains a comma or a line return, ignore
-    if (element.value.search(',') != -1)
+    if (element.value.contains(','))
     {
       var addresses = element.value;
       element.value = ""; // clear out the current line so we don't try to autocomplete it..
       parseAndAddAddresses(addresses, awGetPopupElement(awGetRowByInputElement(element)).selectedItem.getAttribute("value"));
     }
     else if (event.keyCode == KeyEvent.DOM_VK_TAB)
       awTabFromRecipient(element, event);
 
@@ -914,31 +912,29 @@ var gAWRowHeight = 0;
 function awFitDummyRows()
 {
   awCalcContentHeight();
   awCreateOrRemoveDummyRows();
 }
 
 function awCreateOrRemoveDummyRows()
 {
-  var listbox = document.getElementById("addressingWidget");
-  var listboxHeight = listbox.boxObject.height;
+  let listbox = document.getElementById("addressingWidget");
+  let listboxHeight = listbox.boxObject.height;
 
   // remove rows to remove scrollbar
-  var kids = listbox.childNodes;
-  for (var i = kids.length-1; gAWContentHeight > listboxHeight && i >= 0; --i) {
-    if (kids[i].hasAttribute("_isDummyRow")) {
-      gAWContentHeight -= gAWRowHeight;
-      listbox.removeChild(kids[i]);
-    }
+  let kids = listbox.querySelectorAll('[_isDummyRow]');
+  for (let i = kids.length - 1; gAWContentHeight > listboxHeight && i >= 0; --i) {
+    gAWContentHeight -= gAWRowHeight;
+    listbox.removeChild(kids[i]);
   }
 
   // add rows to fill space
   if (gAWRowHeight) {
-    while (gAWContentHeight+gAWRowHeight < listboxHeight) {
+    while (gAWContentHeight + gAWRowHeight < listboxHeight) {
       awCreateDummyItem(listbox);
       gAWContentHeight += gAWRowHeight;
     }
   }
 }
 
 function awCalcContentHeight()
 {
@@ -981,23 +977,17 @@ function awCreateDummyCell(aParent)
     aParent.appendChild(cell);
 
   return cell;
 }
 
 function awGetNextDummyRow()
 {
   // gets the next row from the top down
-  var listbox = document.getElementById("addressingWidget");
-  var kids = listbox.childNodes;
-  for (var i = 0; i < kids.length; ++i) {
-    if (kids[i].hasAttribute("_isDummyRow"))
-      return kids[i];
-  }
-  return null;
+  return document.querySelector('#addressingWidget > [_isDummyRow]');
 }
 
 function awSizerListen()
 {
   // when splitter is clicked, fill in necessary dummy rows each time the mouse is moved
   awCalcContentHeight(); // precalculate
   document.addEventListener("mousemove", awSizerMouseMove, true);
   document.addEventListener("mouseup", awSizerMouseUp, false);
@@ -1013,17 +1003,17 @@ function awSizerMouseUp()
   document.removeEventListener("mousemove", awSizerMouseMove, true);
   document.removeEventListener("mouseup", awSizerMouseUp, false);
 }
 
 function awDocumentKeyPress(event)
 {
   try {
     var id = event.target.id;
-    if (id.substr(0, 11) == 'addressCol1')
+    if (id.startsWith('addressCol1'))
       awMenulistKeyPress(event, event.target);
   } catch (e) { }
 }
 
 function awRecipientInputCommand(event, inputElement)
 {
   gContentChanged=true;
   setupAutocomplete();
@@ -1097,17 +1087,17 @@ AutomatedAutoCompleteHandler.prototype =
     this.numSessionsToSearch = 0;
     this.numSessionsSearched = 0;
     this.searchResults = new Array;
 
     if (this.indexIntoNames < this.numNamesToComplete && this.namesToComplete[this.indexIntoNames])
     {
       /* XXX This is used to work, until switching to the new toolkit broke it
          We should fix it see bug 456550.
-      if (this.namesToComplete[this.indexIntoNames].search('@') == -1) // don't autocomplete if address has an @ sign in it
+      if (!this.namesToComplete[this.indexIntoNames].contains('@')) // don't autocomplete if address has an @ sign in it
       {
         // make sure total session count is updated before we kick off ANY actual searches
         if (gAutocompleteSession)
           this.numSessionsToSearch++;
 
         if (gLDAPSession && gCurrentAutocompleteDirectory)
           this.numSessionsToSearch++;
 
--- a/mail/test/mozmill/attachment/test-attachment-events.js
+++ b/mail/test/mozmill/attachment/test-attachment-events.js
@@ -351,33 +351,33 @@ function test_attachment_renamed() {
 
   // Ensure that we saw the attachment-renamed event
   assert_equals(1, eventCount);
   // Ensure that the event mentions the right attachment
   let renamedAttachment1 = lastEvent.target.attachment;
   let originalName1 = lastEvent.detail;
   assert_true(renamedAttachment1 instanceof Ci.nsIMsgAttachment);
   assert_equals(kRenameTo1, renamedAttachment1.name);
-  assert_true(renamedAttachment1.url.indexOf("http://www.example.com/1") != -1);
+  assert_true(renamedAttachment1.url.contains("http://www.example.com/1"));
   assert_equals("www.example.com/1", originalName1);
 
   // Ok, let's try renaming the same attachment.
   gMockPromptService.reset();
   gMockPromptService.inoutValue = kRenameTo2;
   gMockPromptService.returnValue = true;
 
   select_attachments(cw, 0);
   cw.window.goDoCommand("cmd_renameAttachment");
 
   assert_equals(2, eventCount);
   let renamedAttachment2 = lastEvent.target.attachment;
   let originalName2 = lastEvent.detail;
   assert_true(renamedAttachment2 instanceof Ci.nsIMsgAttachment);
   assert_equals(kRenameTo2, renamedAttachment2.name);
-  assert_true(renamedAttachment2.url.indexOf("http://www.example.com/1") != -1);
+  assert_true(renamedAttachment2.url.contains("http://www.example.com/1"));
   assert_equals(kRenameTo1, originalName2);
 
   // Ok, let's rename another attachment
   gMockPromptService.reset();
   gMockPromptService.inoutValue = kRenameTo3;
   gMockPromptService.returnValue = true;
 
   // We'll select the second attachment this time.
@@ -386,17 +386,17 @@ function test_attachment_renamed() {
 
   // Ensure we saw the attachment-renamed event
   assert_equals(3, eventCount);
   // Ensure that the event mentions the right attachment
   let renamedAttachment3 = lastEvent.target.attachment;
   let originalName3 = lastEvent.detail;
   assert_true(renamedAttachment3 instanceof Ci.nsIMsgAttachment);
   assert_equals(kRenameTo3, renamedAttachment3.name);
-  assert_true(renamedAttachment3.url.indexOf("http://www.example.com/2") != -1);
+  assert_true(renamedAttachment3.url.contains("http://www.example.com/2"));
   assert_equals("www.example.com/2", originalName3);
 
   // Unregister the Mock Prompt service, and remove our observer.
   gMockPromptService.unregister();
   cw.e("attachmentBucket").addEventListener(kAttachmentRenamed, listener,
                                             false);
 }
 
--- a/mail/test/mozmill/attachment/test-attachment.js
+++ b/mail/test/mozmill/attachment/test-attachment.js
@@ -11,16 +11,17 @@ var MODULE_NAME = 'test-attachment';
 var RELATIVE_ROOT = '../shared-modules';
 var MODULE_REQUIRES = ['folder-display-helpers', 'compose-helpers',
                        'window-helpers'];
 
 var elib = {};
 Cu.import('resource://mozmill/modules/elementslib.js', elib);
 var EventUtils = {};
 Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
+Cu.import("resource://gre/modules/Services.jsm");
 
 var folder;
 
 const textAttachment =
   "One of these days... people like me will rise up and overthrow you, and " +
   "the end of tyranny by the homeostatic machine will have arrived. The day " +
   "of human values and compassion and simple warmth will return, and when " +
   "that happens someone like myself who has gone through an ordeal and who " +
@@ -130,19 +131,17 @@ var setupModule = function (module) {
 
 /**
  * Set the pref to ensure that the attachments pane starts out (un)expanded
  *
  * @param expand true if the attachment pane should start out expanded,
  *        false otherwise
  */
 function ensure_starts_expanded(expand) {
-  Components.classes["@mozilla.org/preferences-service;1"]
-            .getService(Components.interfaces.nsIPrefBranch2)
-            .setBoolPref("mailnews.attachments.display.start_expanded", expand);
+  Services.prefs.setBoolPref("mailnews.attachments.display.start_expanded", expand);
 }
 
 function test_attachment_view_collapsed() {
   be_in_folder(folder);
 
   select_click_row(0);
   assert_selected_and_displayed(0);
 
--- a/mail/test/mozmill/composition/test-attachment.js
+++ b/mail/test/mozmill/composition/test-attachment.js
@@ -222,17 +222,17 @@ function test_rename_attachment() {
 
   let url = filePrefix + "some/file/here.txt";
   let size = 1234;
 
   add_attachment(cwc, url, size);
 
   // Now, rename the attachment.
   let bucket = cwc.e("attachmentBucket");
-  let node = bucket.getElementsByTagName("attachmentitem")[0];
+  let node = bucket.querySelector("attachmentitem");
   cwc.click(new elib.Elem(node));
   plan_for_modal_dialog("commonDialog", subtest_rename_attachment);
   cwc.window.RenameSelectedAttachment();
   wait_for_modal_dialog("commonDialog");
 
   assert_equals(node.getAttribute("name"), "renamed.txt");
 
   check_attachment_size(cwc, 0, size);
@@ -255,17 +255,17 @@ function test_open_attachment() {
                             .QueryInterface(Ci.nsIFileProtocolHandler);
   let url = fileHandler.getURLSpecFromFile(file);
   let size = file.fileSize;
 
   add_attachment(cwc, url, size);
 
   // Now, open the attachment.
   let bucket = cwc.e("attachmentBucket");
-  let node = bucket.getElementsByTagName("attachmentitem")[0];
+  let node = bucket.querySelector("attachmentitem");
   plan_for_modal_dialog("unknownContentType", subtest_open_attachment);
   cwc.doubleClick(new elib.Elem(node));
   wait_for_modal_dialog("unknownContentType");
 
   close_compose_window(cwc);
 }
 
 function test_forward_raw_attachment() {
--- a/mail/test/mozmill/composition/test-eml-actions.js
+++ b/mail/test/mozmill/composition/test-eml-actions.js
@@ -102,41 +102,41 @@ function test_reply_to_base64_eml() {
   // Open an .eml file.
   let file = os.getFileForPath(
     os.abspath("./base64-encoded-msg.eml", os.getFileForPath(__file__)));
   let msgc = open_message_from_file(file);
 
   let compWin = open_compose_with_reply(msgc);
 
   let bodyText = compWin.e("content-frame").contentDocument
-                        .getElementsByTagName("body")[0].textContent;
+                        .querySelector("body").textContent;
 
   const message = "You have decoded this text from base64.";
-  if (bodyText.indexOf(message) == -1)
+  if (!bodyText.contains(message))
     throw new Error("body text didn't contain the decoded text; message=" +
                     message + ", bodyText=" + bodyText);
 
-  close_compose_window(compWin); 
-  close_window(msgc); 
+  close_compose_window(compWin);
+  close_window(msgc);
 }
 
 /**
  * Test that forwarding a base64 encoded .eml works.
  */
 function test_forward_base64_eml() {
   // Open an .eml file.
   let file = os.getFileForPath(
     os.abspath("./base64-encoded-msg.eml", os.getFileForPath(__file__)));
   let msgc = open_message_from_file(file);
 
   let compWin = open_compose_with_forward(msgc);
 
   let bodyText = compWin.e("content-frame").contentDocument
-                        .getElementsByTagName("body")[0].textContent;
+                        .querySelector("body").textContent;
 
   const message = "You have decoded this text from base64.";
-  if (bodyText.indexOf(message) == -1)
+  if (!bodyText.contains(message))
     throw new Error("body text didn't contain the decoded text; message=" +
                     message + ", bodyText=" + bodyText);
 
-  close_compose_window(compWin); 
-  close_window(msgc); 
+  close_compose_window(compWin);
+  close_window(msgc);
 }
--- a/mail/test/mozmill/composition/test-forwarded-content.js
+++ b/mail/test/mozmill/composition/test-forwarded-content.js
@@ -44,17 +44,17 @@ function test_forwarded_subj() {
   be_in_folder(folder);
 
   let msg = select_click_row(0);
   assert_selected_and_displayed(mc, msg);
 
   let fwdWin = open_compose_with_forward();
 
   let headerTableText  = fwdWin.e("content-frame").contentDocument
-                          .getElementsByTagName("table")[0].textContent;
-  if (headerTableText.indexOf(msg.mime2DecodedSubject) == -1) {
-    throw new Error("Subject not set correctly in header table: subject=" + 
+                          .querySelector("table").textContent;
+  if (!headerTableText.contains(msg.mime2DecodedSubject)) {
+    throw new Error("Subject not set correctly in header table: subject=" +
                     msg.mime2DecodedSubject + ", header table text=" +
                     headerTableText);
   }
   close_compose_window(fwdWin);
 }
 
--- a/mail/test/mozmill/composition/test-forwarded-eml-actions.js
+++ b/mail/test/mozmill/composition/test-forwarded-eml-actions.js
@@ -94,28 +94,28 @@ function setupWindowAndTest(hotkeyToHit,
 
   plan_for_new_window("mail:messageWindow");
   mc.click(mc.eid("attachmentName"));
   let msgWin = wait_for_new_window("mail:messageWindow");
 
   plan_for_new_window("msgcompose");
   msgWin.keypress(null, hotkeyToHit, hotkeyModifiers);
   let compWin = wait_for_compose_window(msgWin);
-  
+
   let bodyText= compWin.e("content-frame").contentDocument
-                        .getElementsByTagName("body")[0].textContent;
-  if (bodyText.indexOf("html") != -1)
+                       .querySelector("body").textContent;
+  if (bodyText.contains("html"))
     throw new Error("body text contains raw html; bodyText=" + bodyText);
 
-  if (bodyText.indexOf(msgbodyA) == -1)
+  if (!bodyText.contains(msgbodyA))
     throw new Error("body text didn't contain the body text; msgbodyA=" +
                     msgbodyB + ", bodyText=" + bodyText);
 
   let subjectText = compWin.e("msgSubject").value;
-  if (subjectText.indexOf(msgsubject) == -1)
+  if (!subjectText.contains(msgsubject))
     throw new Error("subject text didn't contain the original subject; " +
                     "msgsubject=" +  msgsubject + ", subjectText=" + subjectText);
 
   close_compose_window(compWin, false);
   close_window(msgWin);
 }
 
 /**
--- a/mail/test/mozmill/composition/test-image-insertion-dialog.js
+++ b/mail/test/mozmill/composition/test-image-insertion-dialog.js
@@ -76,17 +76,17 @@ function test_image_insertion_dialog_per
     mwc.window.document.documentElement.cancelDialog();
   });
   cwc.click(cwc.eid("insertImage"));
   wh.wait_for_modal_dialog();
   wait_for_window_close();
 
   // Get the inserted image, double-click it, make sure we switch to "no alt
   // text", despite the persisted value being "use alt text"
-  let img = cwc.e("content-frame").contentDocument.getElementsByTagName("img")[0];
+  let img = cwc.e("content-frame").contentDocument.querySelector("img");
   wh.plan_for_modal_dialog("imageDlg", function insert_image(mwc) {
     assert_true(mwc.window.document.getElementById("noAltTextRadio").selected,
       "We shouldn't use the persisted value because the insert image has no alt text");
     mwc.window.document.documentElement.cancelDialog();
   });
   cwc.doubleClick(new elib.Elem(img));
   wh.wait_for_modal_dialog();
   wait_for_window_close();
@@ -104,17 +104,17 @@ function test_image_insertion_dialog_per
     // Accept the dialog
     mwc.window.document.documentElement.acceptDialog();
   });
   cwc.doubleClick(new elib.Elem(img));
   wh.wait_for_modal_dialog();
   wait_for_window_close();
 
   // Make sure next time we edit it, we still have "use alt text" selected.
-  let img = cwc.e("content-frame").contentDocument.getElementsByTagName("img")[0];
+  let img = cwc.e("content-frame").contentDocument.querySelector("img");
   wh.plan_for_modal_dialog("imageDlg", function insert_image(mwc) {
     assert_true(mwc.window.document.getElementById("altTextRadio").selected,
       "We edited the image to make it have alt text, we should keep it selected");
     // Accept the dialog
     mwc.window.document.documentElement.cancelDialog();
   });
   cwc.doubleClick(new elib.Elem(img));
   wh.wait_for_modal_dialog();
--- a/mail/test/mozmill/composition/test-signature-updating.js
+++ b/mail/test/mozmill/composition/test-signature-updating.js
@@ -17,21 +17,20 @@
 const MODULE_NAME = "test-signature-updating";
 
 const RELATIVE_ROOT = "../shared-modules";
 const MODULE_REQUIRES = ["folder-display-helpers", "compose-helpers", "window-helpers"];
 var jumlib = {};
 Components.utils.import("resource://mozmill/modules/jum.js", jumlib);
 var elib = {};
 Components.utils.import("resource://mozmill/modules/elementslib.js", elib);
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 var composeHelper = null;
 var cwc = null; // compose window controller
-var prefBranch = Cc["@mozilla.org/preferences-service;1"]
-                   .getService(Ci.nsIPrefService).getBranch(null);
 
 var setupModule = function (module) {
   let fdh = collector.getModule("folder-display-helpers");
   fdh.installInto(module);
   composeHelper = collector.getModule("compose-helpers");
   composeHelper.installInto(module);
   let wh = collector.getModule("window-helpers");
   wh.installInto(module);
@@ -51,22 +50,22 @@ function setupComposeWin(toAddr, subj, b
   cwc.type(cwc.eid("content-frame"), body);
 }
 
 /**
  * Test that the plaintext compose window has a signature initially,
  * and has the correct signature after switching to another identity.
  */
 function plaintextComposeWindowSwitchSignatures(suppressSigSep) {
-  prefBranch.setBoolPref("mail.identity.id1.compose_html", false);
+  Services.prefs.setBoolPref("mail.identity.id1.compose_html", false);
   cwc = composeHelper.open_compose_new_mail();
-  prefBranch.setBoolPref("mail.identity.id1.suppress_signature_separator",
-                         suppressSigSep);
-  prefBranch.setBoolPref("mail.identity.id2.suppress_signature_separator",
-                         suppressSigSep);
+  Services.prefs.setBoolPref("mail.identity.id1.suppress_signature_separator",
+                             suppressSigSep);
+  Services.prefs.setBoolPref("mail.identity.id2.suppress_signature_separator",
+                             suppressSigSep);
 
   let contentFrame = cwc.e("content-frame");
   let mailBody = contentFrame.contentDocument.body;
 
   // The first node in the body should be a BR node, which allows the user
   // to insert text before / outside of the signature.
   assert_equals(mailBody.firstChild.localName, "br");
 
@@ -152,21 +151,21 @@ function testPlaintextComposeWindowSwitc
 //function testPlaintextComposeWindowSwitchSignaturesWithSuppressedSeparator() {
 //  plaintextComposeWindowSwitchSignatures(true);
 //}
 
 /**
  * Same test, but with an HTML compose window
  */
 function HTMLComposeWindowSwitchSignatures(suppressSigSep) {
-  prefBranch.setBoolPref("mail.identity.id1.compose_html", true);
-  prefBranch.setBoolPref("mail.identity.id1.suppress_signature_separator",
-                         suppressSigSep);
-  prefBranch.setBoolPref("mail.identity.id2.suppress_signature_separator",
-                         suppressSigSep);
+  Services.prefs.setBoolPref("mail.identity.id1.compose_html", true);
+  Services.prefs.setBoolPref("mail.identity.id1.suppress_signature_separator",
+                             suppressSigSep);
+  Services.prefs.setBoolPref("mail.identity.id2.suppress_signature_separator",
+                             suppressSigSep);
   cwc = composeHelper.open_compose_new_mail();
 
   setupComposeWin("", "HTML compose window", "Body, first line.");
 
   let contentFrame = cwc.e("content-frame");
   let node = contentFrame.contentDocument.body.lastChild;
 
   // In html compose, the signature is inside the last node, which has a
--- a/mail/test/mozmill/shared-modules/test-compose-helpers.js
+++ b/mail/test/mozmill/shared-modules/test-compose-helpers.js
@@ -222,17 +222,17 @@ function close_compose_window(aControlle
  *         that is augmented using augment_controller.
  */
 function wait_for_compose_window(aController) {
   if (aController === undefined)
     aController = mc;
 
   let replyWindow = windowHelper.wait_for_new_window("msgcompose");
 
-  let editor = replyWindow.window.document.getElementsByTagName("editor")[0];
+  let editor = replyWindow.window.document.querySelector("editor");
 
   if (editor.webNavigation.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) {
     let editorObserver = {
       editorLoaded: false,
 
       observe: function eO_observe(aSubject, aTopic, aData) {
         if (aTopic == "obs_documentCreated") {
           this.editorLoaded = true;
--- a/mailnews/compose/content/mailComposeEditorOverlay.xul
+++ b/mailnews/compose/content/mailComposeEditorOverlay.xul
@@ -80,27 +80,27 @@
         if (mozDoNotSend == null)
         {
           // We haven't yet set the moz-do-not-send attribute, let's figure out the best setting
           // the rule should be in sync with to the one in nsMsgComposeAndSend::GetEmbeddedObjectInfo
 
           if (gMsgCompProcessLink)
           {
             //is it a Windows remote file?
-            if (/^\s*file:\/\/\/\/\//i.test(gMsgCompInputElement.value))
+            if (gMsgCompInputElement.value.trimLeft().toLowerCase().startsWith("file://///"))
             {
               try {
                 let dontAttachPref =
                   "mail.compose.dont_attach_source_of_local_network_links";
                 if (Services.prefs.getBoolPref(dontAttachPref))
                   attach = false;
               } catch(ex) {};
             }
             //is it not a file: location at all?
-            else if (!/^\s*file:\/\//i.test(gMsgCompInputElement.value))
+            else if (!gMsgCompInputElement.value.trimLeft().toLowerCase().startsWith("file://"))
               attach = false;
           }
         }
         else
           attach = (mozDoNotSend != "true");
 
         gMsgCompAttachSourceElement.checked = attach;
       }
--- a/mailnews/compose/test/unit/test_attachment.js
+++ b/mailnews/compose/test/unit/test_attachment.js
@@ -80,17 +80,17 @@ function checkAttachment(expectedCD, exp
   let pos = msgData.indexOf("Content-Disposition:");
   do_check_neq(pos, -1);
   let contentDisposition = msgData.substr(pos);
   pos = 0;
   do {
     pos = contentDisposition.indexOf("\n", pos);
     do_check_neq(pos, -1);
     pos++;
-  } while (contentDisposition.substr(pos, 1) == " ");
+  } while (contentDisposition.startsWith(" ", pos));
   contentDisposition = contentDisposition.substr(0, pos);
   do_check_eq(contentDisposition, expectedCD);
 
   pos = msgData.indexOf("Content-Type:"); // multipart
   do_check_neq(pos, -1);
   msgData = msgData.substr(pos + 13);
   pos = msgData.indexOf("Content-Type:"); // body
   do_check_neq(pos, -1);
@@ -98,17 +98,17 @@ function checkAttachment(expectedCD, exp
   pos = msgData.indexOf("Content-Type:"); // first attachment
   do_check_neq(pos, -1);
   var contentType = msgData.substr(pos);
   pos = 0;
   do {
     pos = contentType.indexOf("\n", pos);
     do_check_neq(pos, -1);
     pos++;
-  } while (contentType.substr(pos, 1) == " ");
+  } while (contentType.startsWith(" ", pos));
   contentType = contentType.substr(0, pos);
   do_check_eq(contentType, expectedCT);
 }
 
 function testInput0() {
   for (let folding in ParamFoldingPref) {
     Services.prefs.setIntPref("mail.strictly_mime.parm_folding", ParamFoldingPref[folding]);
     yield async_run({ func: createMessage, args: [input0] });