Bug 1334663 - Add ability to copy and launch URL from password manager draft
authorSteve Jarvis <sajarvis@bu.edu>
Mon, 13 Mar 2017 17:52:26 -0600
changeset 497859 dbf72fad4fba90f572e2843e69d6509608599d10
parent 490433 1bc2ad020aee2830e0a7941f10958dbec108c254
child 549018 e904d06a5707f335bb9f635fea13bf04c44ce643
push id49042
push userbmo:sajarvis@bu.edu
push dateMon, 13 Mar 2017 23:53:02 +0000
bugs1334663
milestone54.0a1
Bug 1334663 - Add ability to copy and launch URL from password manager MozReview-Commit-ID: JApe0OhTIg8
toolkit/components/passwordmgr/content/passwordManager.js
toolkit/components/passwordmgr/content/passwordManager.xul
toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -627,16 +627,25 @@ function FilterPasswords() {
   if (signonsTreeView.rowCount > 0)
     signonsTreeView.selection.select(0);
 
   signonsIntro.textContent = kSignonBundle.getString("loginsDescriptionFiltered");
   removeAllButton.setAttribute("label", kSignonBundle.getString("removeAllShown.label"));
   removeAllButton.setAttribute("accesskey", kSignonBundle.getString("removeAllShown.accesskey"));
 }
 
+function CopySiteUrl() {
+  // Copy selected site url to clipboard
+  let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
+                  getService(Ci.nsIClipboardHelper);
+  let row = signonsTree.currentIndex;
+  let url = signonsTreeView.getCellText(row, {id: "siteCol"});
+  clipboard.copyString(url);
+}
+
 function CopyPassword() {
   // Don't copy passwords if we aren't already showing the passwords & a master
   // password hasn't been entered.
   if (!showingPasswords && !masterPasswordLogin())
     return;
   // Copy selected signon's password to clipboard
   let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
                   getService(Ci.nsIClipboardHelper);
@@ -657,16 +666,22 @@ function CopyUsername() {
 }
 
 function EditCellInSelectedRow(columnName) {
   let row = signonsTree.currentIndex;
   let columnElement = getColumnByName(columnName);
   signonsTree.startEditing(row, signonsTree.columns.getColumnFor(columnElement));
 }
 
+function LaunchSiteUrl() {
+  let row = signonsTree.currentIndex;
+  let url = signonsTreeView.getCellText(row, {id: "siteCol"});
+  window.openUILinkIn(url, "tab");
+}
+
 function UpdateContextMenu() {
   let singleSelection = (signonsTreeView.selection.count == 1);
   let menuItems = new Map();
   let menupopup = document.getElementById("signonsTreeContextMenu");
   for (let menuItem of menupopup.querySelectorAll("menuitem")) {
     menuItems.set(menuItem.id, menuItem);
   }
 
@@ -674,23 +689,32 @@ function UpdateContextMenu() {
     for (let menuItem of menuItems.values()) {
       menuItem.setAttribute("disabled", "true");
     }
     return;
   }
 
   let selectedRow = signonsTree.currentIndex;
 
+  // Don't display "Launch Site URL" if we're not a browser.
+  if (window.openUILinkIn) {
+    menuItems.get("context-launchsiteurl").removeAttribute("disabled");
+  } else {
+    menuItems.get("context-launchsiteurl").setAttribute("disabled", "true");
+    menuItems.get("context-launchsiteurl").setAttribute("hidden", "true");
+  }
+
   // Disable "Copy Username" if the username is empty.
   if (signonsTreeView.getCellText(selectedRow, { id: "userCol" }) != "") {
     menuItems.get("context-copyusername").removeAttribute("disabled");
   } else {
     menuItems.get("context-copyusername").setAttribute("disabled", "true");
   }
 
+  menuItems.get("context-copysiteurl").removeAttribute("disabled");
   menuItems.get("context-editusername").removeAttribute("disabled");
   menuItems.get("context-copypassword").removeAttribute("disabled");
 
   // Disable "Edit Password" if the password column isn't showing.
   if (!document.getElementById("passwordCol").hidden) {
     menuItems.get("context-editpassword").removeAttribute("disabled");
   } else {
     menuItems.get("context-editpassword").setAttribute("disabled", "true");
--- a/toolkit/components/passwordmgr/content/passwordManager.xul
+++ b/toolkit/components/passwordmgr/content/passwordManager.xul
@@ -12,31 +12,43 @@
         windowtype="Toolkit:PasswordManager"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="Startup();"
         onunload="Shutdown();"
         title="&savedLogins.title;"
         style="width: 45em;"
         persist="width height screenX screenY">
 
+#if defined(MOZ_BUILD_APP_IS_BROWSER)
+  <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
+#endif
   <script type="application/javascript" src="chrome://passwordmgr/content/passwordManager.js"/>
 
   <stringbundle id="signonBundle"
                 src="chrome://passwordmgr/locale/passwordmgr.properties"/>
 
   <keyset>
     <key keycode="VK_ESCAPE" oncommand="escapeKeyHandler();"/>
     <key key="&windowClose.key;" modifiers="accel" oncommand="escapeKeyHandler();"/>
     <key key="&focusSearch1.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
     <key key="&focusSearch2.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
   </keyset>
 
   <popupset id="signonsTreeContextSet">
     <menupopup id="signonsTreeContextMenu"
                onpopupshowing="UpdateContextMenu()">
+      <menuitem id="context-copysiteurl"
+                label="&copySiteUrlCmd.label;"
+                accesskey="&copySiteUrlCmd.accesskey;"
+                oncommand="CopySiteUrl()"/>
+      <menuitem id="context-launchsiteurl"
+                label="&launchSiteUrlCmd.label;"
+                accesskey="&launchSiteUrlCmd.accesskey;"
+                oncommand="LaunchSiteUrl()"/>
+      <menuseparator/>
       <menuitem id="context-copyusername"
                 label="&copyUsernameCmd.label;"
                 accesskey="&copyUsernameCmd.accesskey;"
                 oncommand="CopyUsername()"/>
       <menuitem id="context-editusername"
                 label="&editUsernameCmd.label;"
                 accesskey="&editUsernameCmd.accesskey;"
                 oncommand="EditCellInSelectedRow('username')"/>
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
@@ -34,42 +34,51 @@ add_task(function* test() {
     function doTest() {
         let doc = pwmgrdlg.document;
         let selection = doc.getElementById("signonsTree").view.selection;
         let menuitem = doc.getElementById("context-copyusername");
 
         function copyField() {
             info("Select all");
             selection.selectAll();
+            assertMenuitemEnabled("copysiteurl", false);
+            assertMenuitemEnabled("launchsiteurl", false);
             assertMenuitemEnabled("copyusername", false);
             assertMenuitemEnabled("editusername", false);
             assertMenuitemEnabled("copypassword", false);
             assertMenuitemEnabled("editpassword", false);
 
             info("Select the first row (with an empty username)");
             selection.select(0);
+            assertMenuitemEnabled("copysiteurl", true);
+            assertMenuitemEnabled("launchsiteurl", true);
             assertMenuitemEnabled("copyusername", false, "empty username");
             assertMenuitemEnabled("editusername", true);
             assertMenuitemEnabled("copypassword", true);
             assertMenuitemEnabled("editpassword", false, "password column hidden");
 
             info("Clear the selection");
             selection.clearSelection();
+            assertMenuitemEnabled("copysiteurl", false);
+            assertMenuitemEnabled("launchsiteurl", false);
             assertMenuitemEnabled("copyusername", false);
             assertMenuitemEnabled("editusername", false);
             assertMenuitemEnabled("copypassword", false);
             assertMenuitemEnabled("editpassword", false);
 
             info("Select the third row and making the password column visible");
             selection.select(2);
             doc.getElementById("passwordCol").hidden = false;
+            assertMenuitemEnabled("copysiteurl", true);
+            assertMenuitemEnabled("launchsiteurl", true);
             assertMenuitemEnabled("copyusername", true);
             assertMenuitemEnabled("editusername", true);
             assertMenuitemEnabled("copypassword", true);
             assertMenuitemEnabled("editpassword", true, "password column visible");
+
             menuitem.doCommand();
         }
 
         function assertMenuitemEnabled(idSuffix, expected, reason = "") {
             doc.defaultView.UpdateContextMenu();
             let actual = !doc.getElementById("context-" + idSuffix).getAttribute("disabled");
             is(actual, expected, idSuffix + " should be " + (expected ? "enabled" : "disabled") +
                (reason ? ": " + reason : ""));
@@ -80,21 +89,29 @@ add_task(function* test() {
                 Services.ww.unregisterNotification(arguments.callee);
                 Services.logins.removeAllLogins();
                 doc.getElementById("passwordCol").hidden = true;
                 resolve();
             });
             pwmgrdlg.close();
         }
 
+        function testSiteUrl() {
+            info("Testing Copy Site URL");
+            waitForClipboard("http://mozilla.org/", function copySiteUrl() {
+                menuitem = doc.getElementById("context-copysiteurl");
+                menuitem.doCommand();
+            }, cleanUp, cleanUp);
+        }
+
         function testPassword() {
             info("Testing Copy Password");
             waitForClipboard("coded", function copyPassword() {
                 menuitem = doc.getElementById("context-copypassword");
                 menuitem.doCommand();
-            }, cleanUp, cleanUp);
+            }, testSiteUrl, testSiteUrl);
         }
 
         info("Testing Copy Username");
         waitForClipboard("ehsan", copyField, testPassword, testPassword);
     }
   });
 });
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
@@ -26,19 +26,25 @@
 
 <!ENTITY      searchFilter.label              "Search">
 <!ENTITY      searchFilter.accesskey          "S">
 
 <!ENTITY      windowClose.key                 "w">
 <!ENTITY      focusSearch1.key                "f">
 <!ENTITY      focusSearch2.key                "k">
 
+<!ENTITY      copySiteUrlCmd.label            "Copy URL">
+<!ENTITY      copySiteUrlCmd.accesskey        "y">
+
 <!ENTITY      copyPasswordCmd.label           "Copy Password">
 <!ENTITY      copyPasswordCmd.accesskey       "C">
 
 <!ENTITY      copyUsernameCmd.label           "Copy Username">
 <!ENTITY      copyUsernameCmd.accesskey       "U">
 
 <!ENTITY      editPasswordCmd.label           "Edit Password">
 <!ENTITY      editPasswordCmd.accesskey       "E">
 
 <!ENTITY      editUsernameCmd.label           "Edit Username">
 <!ENTITY      editUsernameCmd.accesskey       "d">
+
+<!ENTITY      launchSiteUrlCmd.label          "Visit URL">
+<!ENTITY      launchSiteUrlCmd.accesskey      "V">