Bug 327048 - "support filtering in password manager via Search field" [p=ehsan.akhgari@gmail.com (Ehsan Akhgari) r+a1.9=mconnor]

This commit is contained in:
reed%reedloden.com 2007-10-19 07:59:10 +00:00
Родитель efed250ef1
Коммит ee4aab26c3
9 изменённых файлов: 314 добавлений и 63 удалений

Просмотреть файл

@ -24,6 +24,7 @@
# Contributor(s):
# Ben "Count XULula" Goodger
# Brian Ryner <bryner@brianryner.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# 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();
}

Просмотреть файл

@ -23,6 +23,7 @@
# Contributor(s):
# Ben Goodger
# Brian Ryner <bryner@brianryner.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# 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 *****
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/passwordmgr.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://passwordmgr/locale/passwordManager.dtd" >
<prefwindow id="SignonViewerDialog"
windowtype="Toolkit:PasswordManager"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
buttons="accept"
buttonlabelaccept="&closebutton.label;"
onload="Startup(); SignonsStartup();"
onunload="Shutdown();"
title="&rememberPasswords.title;"
persist="width height screenX screenY">
<window id="SignonViewerDialog"
windowtype="Toolkit:PasswordManager"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="Startup(); SignonsStartup();"
onunload="Shutdown();"
title="&rememberPasswords.title;"
persist="width height screenX screenY">
<prefpane id="SignonViewerDialogPane" flex="1">
<script src="chrome://passwordmgr/content/passwordManagerCommon.js"/>
<script src="chrome://passwordmgr/content/passwordManager.js"/>
<script src="chrome://passwordmgr/content/passwordManagerCommon.js"/>
<script src="chrome://passwordmgr/content/passwordManager.js"/>
<stringbundle id="signonBundle"
src="chrome://passwordmgr/locale/passwordmgr.properties"/>
<stringbundle id="signonBundle"
src="chrome://passwordmgr/locale/passwordmgr.properties"/>
<!-- saved signons -->
<vbox id="savedsignons" flex="1">
<description control="signonsTree">&spiel.signonsstored.label;</description>
<separator class="thin"/>
<tree id="signonsTree" flex="1" style="height: 20em;" hidecolumnpicker="true"
onkeypress="HandleSignonKeyPress(event)"
onselect="SignonSelected();">
<treecols>
<treecol id="siteCol" label="&treehead.site.label;" flex="5"
onclick="SignonColumnSort('hostname');" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="userCol" label="&treehead.username.label;" flex="2"
onclick="SignonColumnSort('username');" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="passwordCol" label="&treehead.password.label;" flex="2"
onclick="SignonColumnSort('password');" persist="width"
hidden="true"/>
</treecols>
<treechildren/>
</tree>
<separator class="thin"/>
<hbox id="SignonViewerButtons">
<button id="removeSignon" disabled="true" icon="remove"
label="&remove.label;" accesskey="&remove.accesskey;"
oncommand="DeleteSignon();"/>
<button id="removeAllSignons" icon="clear"
label="&removeall.label;" accesskey="&removeall.accesskey;"
oncommand="DeleteAllSignons();"/>
<spacer flex="1"/>
<button id="togglePasswords"
oncommand="TogglePasswordVisible();"/>
</hbox>
</vbox>
</prefpane>
</prefwindow>
<keyset>
<key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
<key key="&focusSearch1.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
<key key="&focusSearch2.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
</keyset>
<!-- saved signons -->
<vbox id="savedsignons" class="contentPane" flex="1">
<!-- filter -->
<hbox align="center">
<label accesskey="&filter.accesskey;" control="filter">&filter.label;</label>
<textbox id="filter" flex="1" type="timed" timeout="500"
oncommand="_filterPasswords();"
onkeypress="HandleSignonFilterKeyPress(event);"/>
<button id="clearFilter" icon="clear" label="&clear.label;"
accesskey="&clear.accesskey;"
oncommand="SignonClearFilter();" disabled="true"/>
</hbox>
<description control="signonsTree" id="signonsIntro">&spiel.signonsstored.label;</description>
<separator class="thin"/>
<tree id="signonsTree" flex="1" style="height: 20em;" hidecolumnpicker="true"
onkeypress="HandleSignonKeyPress(event)"
onselect="SignonSelected();">
<treecols>
<treecol id="siteCol" label="&treehead.site.label;" flex="5"
onclick="SignonColumnSort('hostname');" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="userCol" label="&treehead.username.label;" flex="2"
onclick="SignonColumnSort('username');" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="passwordCol" label="&treehead.password.label;" flex="2"
onclick="SignonColumnSort('password');" persist="width"
hidden="true"/>
</treecols>
<treechildren/>
</tree>
<separator class="thin"/>
<hbox id="SignonViewerButtons">
<button id="removeSignon" disabled="true" icon="remove"
label="&remove.label;" accesskey="&remove.accesskey;"
oncommand="DeleteSignon();"/>
<button id="removeAllSignons" icon="clear"
label="&removeall.label;" accesskey="&removeall.accesskey;"
oncommand="DeleteAllSignons();"/>
<spacer flex="1"/>
<button id="togglePasswords"
oncommand="TogglePasswordVisible();"/>
</hbox>
</vbox>
<hbox align="end">
<hbox class="actionButtons" flex="1">
<spacer flex="1"/>
#ifndef XP_MACOSX
<button oncommand="close();" icon="close"
label="&closebutton.label;" accesskey="&closebutton.accesskey;"/>
#endif
</hbox>
<resizer dir="bottomright"/>
</hbox>
</window>

Просмотреть файл

@ -24,6 +24,7 @@
# Contributor(s):
# Ben "Count XULula" Goodger
# Brian Ryner <bryner@brianryner.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# 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
@ -88,6 +89,10 @@ var signonReloadDisplay = {
lastSignonSortAscending = !lastSignonSortAscending; // prevents sort from being reversed
}
LoadSignons();
// apply the filter if needed
if (document.getElementById("filter") && document.getElementById("filter").value != "") {
_filterPasswords();
}
} else if (state == "rejects") {
rejects.length = 0;
if (lastRejectSortColumn == "hostname") {

Просмотреть файл

@ -21,6 +21,7 @@
#
# Contributor(s):
# Brian Ryner <bryner@brianryner.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# 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
@ -40,6 +41,7 @@
<!ENTITY rememberPasswords.title "Remember Passwords">
<!ENTITY dontRememberPasswords.title "Don't Remember Passwords">
<!ENTITY closebutton.label "Close">
<!ENTITY closebutton.accesskey "C">
<!ENTITY spiel.signonsstored.label "Password Manager has saved login information for the following sites:">
<!ENTITY spiel.signonsnotstored.label "Password Manager will never save login information for the following sites:">
@ -51,3 +53,12 @@
<!ENTITY remove.accesskey "R">
<!ENTITY removeall.label "Remove All">
<!ENTITY removeall.accesskey "A">
<!ENTITY filter.label "Search:">
<!ENTITY filter.accesskey "S">
<!ENTITY clear.label "Clear">
<!ENTITY clear.accesskey "l">
<!ENTITY windowClose.key "w">
<!ENTITY focusSearch1.key "f">
<!ENTITY focusSearch2.key "k">

Просмотреть файл

@ -20,6 +20,7 @@
#
# Contributor(s):
# Brian Ryner <bryner@brianryner.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# 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
@ -55,3 +56,5 @@ showPasswords=Show Passwords
noMasterPasswordPrompt=Are you sure you wish to show your passwords?
removeAllPasswordsPrompt=Are you sure you wish to remove all passwords?
removeAllPasswordsTitle=Remove all passwords
passwordsAll=The following passwords have been saved by the Password Manager:
passwordsFiltered=The following passwords match your search:

Просмотреть файл

@ -30,6 +30,7 @@ classic.jar:
+ skin/classic/global/netError.css
+ skin/classic/global/numberbox.css
skin/classic/global/plugins.css (/toolkit/empty-file)
+ skin/classic/global/passwordmgr.css
+ skin/classic/global/popup.css
+ skin/classic/global/preferences.css
+ skin/classic/global/progressmeter.css

Просмотреть файл

@ -0,0 +1,46 @@
/* ***** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is Login Manager code.
The Initial Developer of the Original Code is
Ehsan Akhgari <ehsan.akhgari@gmail.com>.
Portions created by the Initial Developer are Copyright (C) 2007
the Initial Developer. All Rights Reserved.
Contributor(s):
Ehsan Akhgari <ehsan.akhgari@gmail.com>
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
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK ***** */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
.contentPane {
margin: 9px 8px 5px 8px;
}
.actionButtons {
margin: 0px 3px 6px 3px !important;
}

Просмотреть файл

@ -23,6 +23,7 @@ classic.jar:
skin/classic/global/dropmarker.css
skin/classic/global/numberbox.css
skin/classic/global/notification.css
skin/classic/global/passwordmgr.css
skin/classic/global/popup.css
skin/classic/global/progressmeter.css
skin/classic/global/radio.css

Просмотреть файл

@ -0,0 +1,46 @@
/* ***** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is Login Manager code.
The Initial Developer of the Original Code is
Ehsan Akhgari <ehsan.akhgari@gmail.com>.
Portions created by the Initial Developer are Copyright (C) 2007
the Initial Developer. All Rights Reserved.
Contributor(s):
Ehsan Akhgari <ehsan.akhgari@gmail.com>
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
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK ***** */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
.contentPane {
margin: 9px 8px 5px 8px;
}
.actionButtons {
margin: 0px 3px 6px 3px !important;
}