Bug 485701 - Add sort markers/arrows to Password Manager and keep sort direction when clearing filter. r=dolske

This commit is contained in:
Jens Hatlak 2009-08-20 15:17:30 -07:00
parent ef0be5285c
commit db69081524
6 changed files with 306 additions and 9 deletions

View File

@ -115,7 +115,11 @@ function LoadSignons() {
// sort and display the table
signonsTree.treeBoxObject.view = signonsTreeView;
SignonColumnSort('hostname');
// The sort column didn't change. SortTree (called by
// SignonColumnSort) assumes we want to toggle the sort
// direction but here we don't so we have to trick it
lastSignonSortAscending = !lastSignonSortAscending;
SignonColumnSort(lastSignonSortColumn);
// disable "remove all signons" button if there are no signons
var element = document.getElementById("removeAllSignons");
@ -238,15 +242,37 @@ function HandleSignonKeyPress(e) {
}
}
var lastSignonSortColumn = "";
var lastSignonSortAscending = false;
function getColumnByName(column) {
switch (column) {
case "hostname":
return document.getElementById("siteCol");
case "username":
return document.getElementById("userCol");
case "password":
return document.getElementById("passwordCol");
}
}
var lastSignonSortColumn = "hostname";
var lastSignonSortAscending = true;
function SignonColumnSort(column) {
// clear out the sortDirection attribute on the old column
var lastSortedCol = getColumnByName(lastSignonSortColumn);
lastSortedCol.removeAttribute("sortDirection");
// sort
lastSignonSortAscending =
SortTree(signonsTree, signonsTreeView,
signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons,
column, lastSignonSortColumn, lastSignonSortAscending);
lastSignonSortColumn = column;
// set the sortDirection attribute to get the styling going
// first we need to get the right element
var sortedCol = getColumnByName(column);
sortedCol.setAttribute("sortDirection", lastSignonSortAscending ?
"ascending" : "descending");
}
function SignonClearFilter() {
@ -258,8 +284,6 @@ function SignonClearFilter() {
signonsTreeView._filterSet = [];
// Just reload the list to make sure deletions are respected
lastSignonSortColumn = "";
lastSignonSortAscending = false;
LoadSignons();
// Restore selection

View File

@ -81,7 +81,8 @@
onselect="SignonSelected();">
<treecols>
<treecol id="siteCol" label="&treehead.site.label;" flex="5"
onclick="SignonColumnSort('hostname');" persist="width"/>
onclick="SignonColumnSort('hostname');" persist="width"
sortDirection="ascending"/>
<splitter class="tree-splitter"/>
<treecol id="userCol" label="&treehead.username.label;" flex="2"
onclick="SignonColumnSort('username');" persist="width"/>

View File

@ -82,7 +82,7 @@ function LoadRejects() {
// sort and display the table
rejectsTree.treeBoxObject.view = rejectsTreeView;
RejectColumnSort('host');
RejectColumnSort(lastRejectSortColumn);
var element = document.getElementById("removeAllRejects");
if (rejects.length == 0) {
@ -126,7 +126,7 @@ function HandleRejectKeyPress(e) {
}
}
var lastRejectSortColumn = "";
var lastRejectSortColumn = "host";
var lastRejectSortAscending = false;
function RejectColumnSort(column) {
@ -134,4 +134,9 @@ function RejectColumnSort(column) {
SortTree(rejectsTree, rejectsTreeView, rejects,
column, lastRejectSortColumn, lastRejectSortAscending);
lastRejectSortColumn = column;
// set the sortDirection attribute to get the styling going
var sortedCol = document.getElementById("rejectCol");
sortedCol.setAttribute("sortDirection", lastRejectSortAscending ?
"ascending" : "descending");
}

View File

@ -64,7 +64,7 @@
onselect="RejectSelected();">
<treecols>
<treecol id="rejectCol" label="&treehead.site.label;" flex="5"
onclick="RejectColumnSort('host');"/>
onclick="RejectColumnSort('host');" sortDirection="ascending"/>
</treecols>
<treechildren/>
</tree>

View File

@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_passwordmgrdlg.js \
browser_passwordmgr_sort.js \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -0,0 +1,266 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Ehsan Akhgari.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
* Jens Hatlak <jh@junetz.de>
*
* 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 ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
function test() {
waitForExplicitFinish();
let pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
pwmgr.removeAllLogins();
// Add some initial logins
let urls = [
"http://example.com/",
"http://example.org/",
"http://mozilla.com/",
"http://mozilla.org/",
"http://spreadfirefox.com/",
"http://planet.mozilla.org/",
"https://developer.mozilla.org/",
"http://hg.mozilla.org/",
"http://mxr.mozilla.org/",
"http://feeds.mozilla.org/",
];
let users = [
"user",
"username",
"ehsan",
"ehsan",
"john",
"what?",
"really?",
"you sure?",
"my user name",
"my username",
];
let pwds = [
"password",
"password",
"mypass",
"mypass",
"smith",
"very secret",
"super secret",
"absolutely",
"mozilla",
"mozilla.com",
];
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
for (let i = 0; i < 10; i++)
pwmgr.addLogin(new nsLoginInfo(urls[i], urls[i], null, users[i], pwds[i],
"u"+(i+1), "p"+(i+1)));
// Detect when the password manager window is opened
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let obs = {
observe: function(aSubject, aTopic, aData) {
// unregister ourself
ww.unregisterNotification(this);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function() {
win.removeEventListener("load", arguments.callee, true);
setTimeout(doTest, 0);
}, true);
}
};
ww.registerNotification(obs);
// Open the password manager dialog
const PWMGR_DLG = "chrome://passwordmgr/content/passwordManager.xul";
let pwmgrdlg = window.openDialog(PWMGR_DLG, "Toolkit:PasswordManager", "");
// the meat of the test
function doTest() {
let doc = pwmgrdlg.document;
let win = doc.defaultView;
let sTree = doc.getElementById("signonsTree");
let filter = doc.getElementById("filter");
let siteCol = doc.getElementById("siteCol");
let userCol = doc.getElementById("userCol");
let passwordCol = doc.getElementById("passwordCol");
let toggleCalls = 0;
function toggleShowPasswords(func) {
let toggleButton = doc.getElementById("togglePasswords");
let showMode = (toggleCalls++ % 2) == 0;
// only watch for a confirmation dialog every other time being called
if (showMode) {
let obs = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == "domwindowclosed")
ww.unregisterNotification(this);
else if (aTopic == "domwindowopened") {
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function() {
win.removeEventListener("load", arguments.callee, true);
setTimeout(function() {
EventUtils.synthesizeKey("VK_RETURN", {}, win)
}, 0);
}, true);
}
}
};
ww.registerNotification(obs);
}
let obsSvc = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
obsSvc.addObserver({
observe: function(aSubject, aTopic, aData) {
if (aTopic == "passwordmgr-password-toggle-complete") {
obsSvc.removeObserver(this, "passwordmgr-password-toggle-complete", false);
func();
}
}
}, "passwordmgr-password-toggle-complete", false);
EventUtils.synthesizeMouse(toggleButton, 1, 1, {}, win);
}
function clickCol(col) {
EventUtils.synthesizeMouse(col, 20, 1, {}, win);
setTimeout(runNextTest, 0);
}
function setFilter(string) {
filter.value = string;
filter.doCommand();
setTimeout(runNextTest, 0);
}
function checkSortMarkers(activeCol) {
let isOk = true;
let col = null;
let hasAttr = false;
let treecols = activeCol.parentNode;
for (let i = 0; i < treecols.childNodes.length; i++) {
col = treecols.childNodes[i];
if (col.nodeName != "treecol")
continue;
hasAttr = col.hasAttribute("sortDirection");
isOk &= col == activeCol ? hasAttr : !hasAttr;
}
ok(isOk, "Only " + activeCol.id + " has a sort marker");
}
function checkSortDirection(col, ascending) {
checkSortMarkers(col);
let direction = ascending ? "ascending" : "descending";
is(col.getAttribute("sortDirection"), direction,
col.id + ": sort direction is " + direction);
}
function checkColumnEntries(aCol, expectedValues) {
let actualValues = getColumnEntries(aCol);
is(actualValues.length, expectedValues.length, "Checking length of expected column");
for (let i = 0; i < expectedValues.length; i++)
is(actualValues[i], expectedValues[i], "Checking column entry #"+i);
}
function getColumnEntries(aCol) {
let entries = [];
let column = sTree.columns[aCol];
let numRows = sTree.view.rowCount;
for (let i = 0; i < numRows; i++)
entries.push(sTree.view.getCellText(i, column));
return entries;
}
let testCounter = 0;
let expectedValues;
function runNextTest() {
switch (testCounter++) {
case 0:
expectedValues = urls.slice().sort();
checkColumnEntries(0, expectedValues);
checkSortDirection(siteCol, true);
// Toggle sort direction on Host column
clickCol(siteCol);
break;
case 1:
expectedValues.reverse();
checkColumnEntries(0, expectedValues);
checkSortDirection(siteCol, false);
// Sort by Username
clickCol(userCol);
break;
case 2:
expectedValues = users.slice().sort();
checkColumnEntries(1, expectedValues);
checkSortDirection(userCol, true);
// Sort by Password
clickCol(passwordCol);
break;
case 3:
expectedValues = pwds.slice().sort();
checkColumnEntries(2, expectedValues);
checkSortDirection(passwordCol, true);
// Set filter
setFilter("moz");
break;
case 4:
expectedValues = [ "absolutely", "mozilla", "mozilla.com",
"mypass", "mypass", "super secret",
"very secret" ];
checkColumnEntries(2, expectedValues);
checkSortDirection(passwordCol, true);
// Reset filter
setFilter("");
break;
case 5:
expectedValues = pwds.slice().sort();
checkColumnEntries(2, expectedValues);
checkSortDirection(passwordCol, true);
// cleanup
pwmgrdlg.close();
pwmgr.removeAllLogins();
finish();
}
}
// Toggle Show Passwords to display Password column, then start tests
toggleShowPasswords(runNextTest);
}
}