From ee4aab26c342ab3f4b76f9539b01594a61cb3335 Mon Sep 17 00:00:00 2001 From: "reed%reedloden.com" Date: Fri, 19 Oct 2007 07:59:10 +0000 Subject: [PATCH] Bug 327048 - "support filtering in password manager via Search field" [p=ehsan.akhgari@gmail.com (Ehsan Akhgari) r+a1.9=mconnor] --- .../passwordmgr/content/passwordManager.js | 141 ++++++++++++++++-- .../passwordmgr/content/passwordManager.xul | 123 +++++++++------ .../content/passwordManagerCommon.js | 5 + .../chrome/passwordmgr/passwordManager.dtd | 11 ++ .../chrome/passwordmgr/passwordmgr.properties | 3 + toolkit/themes/pinstripe/global/jar.mn | 1 + .../themes/pinstripe/global/passwordmgr.css | 46 ++++++ toolkit/themes/winstripe/global/jar.mn | 1 + .../themes/winstripe/global/passwordmgr.css | 46 ++++++ 9 files changed, 314 insertions(+), 63 deletions(-) create mode 100644 toolkit/themes/pinstripe/global/passwordmgr.css create mode 100644 toolkit/themes/winstripe/global/passwordmgr.css diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js index eaedbda4e2e..5fa09aa1b68 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.js +++ b/toolkit/components/passwordmgr/content/passwordManager.js @@ -24,6 +24,7 @@ # Contributor(s): # Ben "Count XULula" Goodger # Brian Ryner +# Ehsan Akhgari # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -47,25 +48,33 @@ function SignonsStartup() { kSignonBundle = document.getElementById("signonBundle"); document.getElementById("togglePasswords").label = kSignonBundle.getString("showPasswords"); LoadSignons(); + FocusFilterBox(); } var signonsTreeView = { + _filterSet : [], + _lastSelectedRanges : [], + selection: null, + rowCount : 0, setTree : function(tree) {}, getImageSrc : function(row,column) {}, getProgressMode : function(row,column) {}, getCellValue : function(row,column) {}, getCellText : function(row,column) { - var rv=""; - if (column.id=="siteCol") { - rv = signons[row].hostname; - if (signons[row].httpRealm) { rv += " (" + signons[row].httpRealm + ")"; } - } else if (column.id=="userCol") { - rv = signons[row].username; - } else if (column.id=="passwordCol") { - rv = signons[row].password; + var signon = this._filterSet.length ? this._filterSet[row] : signons[row]; + switch (column.id) { + case "siteCol": + return signon.httpRealm ? + (signon.hostname + " (" + signon.httpRealm + ")"): + signon.hostname; + case "userCol": + return signon.username || ""; + case "passwordCol": + return signon.password || ""; + default: + return ""; } - return rv; }, isSeparator : function(index) { return false; }, isSorted : function() { return false; }, @@ -109,8 +118,8 @@ function SignonSelected() { function DeleteSignon() { DeleteSelectedItemFromTree(signonsTree, signonsTreeView, - signons, deletedSignons, - "removeSignon", "removeAllSignons"); + signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons, + deletedSignons, "removeSignon", "removeAllSignons"); FinalizeSignonDeletions(); } @@ -128,8 +137,8 @@ function DeleteAllSignons() { return; DeleteAllFromTree(signonsTree, signonsTreeView, - signons, deletedSignons, - "removeSignon", "removeAllSignons"); + signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons, + deletedSignons, "removeSignon", "removeAllSignons"); FinalizeSignonDeletions(); } @@ -140,6 +149,7 @@ function TogglePasswordVisible() { showingPasswords = !showingPasswords; document.getElementById("togglePasswords").label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords"); document.getElementById("passwordCol").hidden = !showingPasswords; + _filterPasswords(); } function AskUserShowPasswords() { @@ -194,7 +204,110 @@ var lastSignonSortAscending = false; function SignonColumnSort(column) { lastSignonSortAscending = - SortTree(signonsTree, signonsTreeView, signons, + SortTree(signonsTree, signonsTreeView, + signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons, column, lastSignonSortColumn, lastSignonSortAscending); lastSignonSortColumn = column; } + +function SignonClearFilter() { + var singleSelection = (signonsTreeView.selection.count == 1); + + // Clear the Filter and the Tree Display + document.getElementById("filter").value = ""; + signonsTreeView.rowCount = 0; + signonsTree.treeBoxObject.rowCountChanged(0, -signonsTreeView._filterSet.length); + signonsTreeView._filterSet = []; + + // Just reload the list to make sure deletions are respected + lastSignonSortColumn = ""; + lastSignonSortAscending = false; + LoadSignons(); + + // Restore selection + if (singleSelection) { + signonsTreeView.selection.clearSelection(); + for (i = 0; i < signonsTreeView._lastSelectedRanges.length; ++i) { + var range = signonsTreeView._lastSelectedRanges[i]; + signonsTreeView.selection.rangedSelect(range.min, range.max, true); + } + } else { + signonsTreeView.selection.select(0); + } + signonsTreeView._lastSelectedRanges = []; + + document.getElementById("signonsIntro").value = kSignonBundle.getString("passwordsAll"); + document.getElementById("clearFilter").disabled = true; + FocusFilterBox(); +} + +function FocusFilterBox() +{ + if (document.getElementById("filter").getAttribute("focused") != "true") + document.getElementById("filter").focus(); +} + +function SignonMatchesFilter(aSignon, aFilterValue) { + if (aSignon.hostname.indexOf(aFilterValue) != -1) + return true; + if (aSignon.username && aSignon.username.indexOf(aFilterValue) != -1) + return true; + if (aSignon.httpRealm && aSignon.httpRealm.indexOf(aFilterValue) != -1) + return true; + if (showingPasswords && aSignon.password && + aSignon.password.indexOf(aFilterValue) != -1) + return true; + + return false; +} + +function FilterPasswords(aFilterValue, view) { + return signons.filter(function (s) SignonMatchesFilter(s, aFilterValue)); +} + +function SignonSaveState() { + // Save selection + var seln = signonsTreeView.selection; + signonsTreeView._lastSelectedRanges = []; + var rangeCount = seln.getRangeCount(); + for (var i = 0; i < rangeCount; ++i) { + var min = {}; var max = {}; + seln.getRangeAt(i, min, max); + signonsTreeView._lastSelectedRanges.push({ min: min.value, max: max.value }); + } +} + +function _filterPasswords() +{ + var filter = document.getElementById("filter").value; + if (filter == "") { + SignonClearFilter(); + return; + } + + var newFilterSet = FilterPasswords(filter, signonsTreeView); + if (!signonsTreeView._filterSet.length) { + // Save Display Info for the Non-Filtered mode when we first + // enter Filtered mode. + SignonSaveState(); + } + signonsTreeView._filterSet = newFilterSet; + + // Clear the display + signonsTree.treeBoxObject.rowCountChanged(0, -signonsTreeView.rowCount); + // Set up the filtered display + signonsTreeView.rowCount = signonsTreeView._filterSet.length; + signonsTree.treeBoxObject.rowCountChanged(0, signonsTreeView.rowCount); + + // if the view is not empty then select the first item + if (signonsTreeView.rowCount > 0) + signonsTreeView.selection.select(0); + + document.getElementById("signonsIntro").value = kSignonBundle.getString("passwordsFiltered"); + document.getElementById("clearFilter").disabled = false; +} + +function HandleSignonFilterKeyPress(aEvent) { + if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) + SignonClearFilter(); +} diff --git a/toolkit/components/passwordmgr/content/passwordManager.xul b/toolkit/components/passwordmgr/content/passwordManager.xul index 37b1484a0bc..58712110b76 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.xul +++ b/toolkit/components/passwordmgr/content/passwordManager.xul @@ -23,6 +23,7 @@ # Contributor(s): # Ben Goodger # Brian Ryner +# Ehsan Akhgari # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,58 +40,82 @@ # ***** END LICENSE BLOCK ***** + - + - -