Bug 1257078 - Implement a selection feature for showing some specific password.; r?MattN
MozReview-Commit-ID: CTGhZ9ZxbTm
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1075,16 +1075,17 @@ GK_ATOM(resizebefore, "resizebefore")
GK_ATOM(resizer, "resizer")
GK_ATOM(resolution, "resolution")
GK_ATOM(resource, "resource")
GK_ATOM(resources, "resources")
GK_ATOM(result, "result")
GK_ATOM(resultPrefix, "result-prefix")
GK_ATOM(retargetdocumentfocus, "retargetdocumentfocus")
GK_ATOM(rev, "rev")
+GK_ATOM(revealSelectedPasswords, "revealselectedpasswords")
GK_ATOM(reverse, "reverse")
GK_ATOM(reversed, "reversed")
GK_ATOM(richlistbox, "richlistbox")
GK_ATOM(richlistitem, "richlistitem")
GK_ATOM(right, "right")
GK_ATOM(rightmargin, "rightmargin")
GK_ATOM(rightpadding, "rightpadding")
GK_ATOM(role, "role")
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -3735,18 +3735,35 @@ nsTreeBodyFrame::PaintText(int32_t
NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
bool isRTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
// Now obtain the text for our cell.
nsAutoString text;
mView->GetCellText(aRowIndex, aColumn, text);
- if (aColumn->Type() == nsITreeColumn::TYPE_PASSWORD) {
- TextEditRules::FillBufWithPWChars(&text, text.Length());
+ nsCOMPtr<nsITreeSelection> selection;
+ bool isSelected = false;
+ mView->GetSelection(getter_AddRefs(selection));
+ if (selection) {
+ selection->IsSelected(aRowIndex, &isSelected);
+ }
+
+ nsIContent* baseContent = GetBaseElement();
+ bool revealSelectedPasswords = isSelected && baseContent &&
+ baseContent->HasAttr(kNameSpaceID_None, nsGkAtoms::revealSelectedPasswords);
+
+ if (aColumn->Type() == nsITreeColumn::TYPE_PASSWORD && !revealSelectedPasswords) {
+ // For the security reason, the amount of dot character should be fixed.
+ // Please see Bug 1209267 as well.
+ TextEditRules::FillBufWithPWChars(&text, 11);
+ }
+
+ if (selection) {
+ selection->InvalidateSelection();
}
// We're going to paint this text so we need to ensure bidi is enabled if
// necessary
CheckTextForBidi(text);
DrawResult result = DrawResult::SUCCESS;
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -284,20 +284,18 @@ function LoadSignons() {
// 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
if (signons.length == 0) {
removeAllButton.setAttribute("disabled", "true");
- togglePasswordsButton.setAttribute("disabled", "true");
} else {
removeAllButton.removeAttribute("disabled");
- togglePasswordsButton.removeAttribute("disabled");
}
return true;
}
function GetVisibleLogins() {
return signonsTreeView._filterSet.length ? signonsTreeView._filterSet : signons;
}
@@ -341,18 +339,20 @@ function RestoreSelections(selectedSigno
}
}
}
function SignonSelected() {
let selections = GetTreeSelections();
if (selections.length) {
removeButton.removeAttribute("disabled");
+ togglePasswordsButton.removeAttribute("disabled");
} else {
removeButton.setAttribute("disabled", true);
+ togglePasswordsButton.setAttribute("disabled", true);
}
}
function DeleteSignon() {
let syncNeeded = (signonsTreeView._filterSet.length != 0);
let tree = signonsTree;
let view = signonsTreeView;
let table = GetVisibleLogins();
@@ -436,17 +436,21 @@ function DeleteAllSignons() {
Services.telemetry.getHistogramById("PWMGR_MANAGE_DELETED_ALL").add(1);
}
function TogglePasswordVisible() {
if (showingPasswords || masterPasswordLogin(AskUserShowPasswords)) {
showingPasswords = !showingPasswords;
togglePasswordsButton.label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords");
togglePasswordsButton.accessKey = kSignonBundle.getString(showingPasswords ? "hidePasswordsAccessKey" : "showPasswordsAccessKey");
- document.getElementById("passwordCol").hidden = !showingPasswords;
+ if (showingPasswords) {
+ signonsTree.setAttribute("revealselectedpasswords", "true");
+ } else {
+ signonsTree.removeAttribute("revealselectedpasswords");
+ }
FilterPasswords();
}
// Notify observers that the password visibility toggling is
// completed. (Mostly useful for tests)
Services.obs.notifyObservers(null, "passwordmgr-password-toggle-complete", null);
Services.telemetry.getHistogramById("PWMGR_MANAGE_VISIBILITY_TOGGLED").add(showingPasswords);
}
--- a/toolkit/components/passwordmgr/content/passwordManager.xul
+++ b/toolkit/components/passwordmgr/content/passwordManager.xul
@@ -77,19 +77,18 @@
ignoreincolumnpicker="true"
sortDirection="ascending"/>
<splitter class="tree-splitter"/>
<treecol id="userCol" label="&treehead.username.label;" flex="25"
ignoreincolumnpicker="true"
data-field-name="username" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="passwordCol" label="&treehead.password.label;" flex="15"
- ignoreincolumnpicker="true"
- data-field-name="password" persist="width"
- hidden="true"/>
+ ignoreincolumnpicker="true" type="password"
+ data-field-name="password" persist="width"/>
<splitter class="tree-splitter"/>
<treecol id="timeCreatedCol" label="&treehead.timeCreated.label;" flex="10"
data-field-name="timeCreated" persist="width hidden"
hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="timeLastUsedCol" label="&treehead.timeLastUsed.label;" flex="20"
data-field-name="timeLastUsed" persist="width hidden"
hidden="true"/>
@@ -113,17 +112,17 @@
label="&removeall.label;" accesskey="&removeall.accesskey;"
oncommand="DeleteAllSignons();"/>
<spacer flex="1"/>
#if defined(MOZ_BUILD_APP_IS_BROWSER) && defined(XP_WIN)
<button accesskey="&import.accesskey;"
label="&import.label;"
oncommand="OpenMigrator();"/>
#endif
- <button id="togglePasswords"
+ <button id="togglePasswords" disabled="true"
oncommand="TogglePasswordVisible();"/>
</hbox>
</vbox>
<hbox align="end">
<hbox class="actionButtons" flex="1">
<spacer flex="1"/>
#ifndef XP_MACOSX
<button oncommand="close();" icon="close"
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
@@ -44,32 +44,32 @@ add_task(function* test() {
assertMenuitemEnabled("copypassword", false);
assertMenuitemEnabled("editpassword", false);
info("Select the first row (with an empty username)");
selection.select(0);
assertMenuitemEnabled("copyusername", false, "empty username");
assertMenuitemEnabled("editusername", true);
assertMenuitemEnabled("copypassword", true);
- assertMenuitemEnabled("editpassword", false, "password column hidden");
+ assertMenuitemEnabled("editpassword", true);
info("Clear the selection");
selection.clearSelection();
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("copyusername", true);
assertMenuitemEnabled("editusername", true);
assertMenuitemEnabled("copypassword", true);
- assertMenuitemEnabled("editpassword", true, "password column visible");
+ assertMenuitemEnabled("editpassword", true);
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 : ""));
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
@@ -90,18 +90,22 @@ add_task(function* test() {
}
Services.obs.addObserver(function(aSubject, aTopic, aData) {
if (aTopic == "passwordmgr-password-toggle-complete") {
Services.obs.removeObserver(arguments.callee, aTopic);
func();
}
}, "passwordmgr-password-toggle-complete", false);
-
- EventUtils.synthesizeMouse(toggleButton, 1, 1, {}, win);
+ function handleSelect() {
+ sTree.removeEventListener('select', handleSelect);
+ EventUtils.synthesizeMouse(toggleButton, 1, 1, {}, win);
+ }
+ sTree.addEventListener('select', handleSelect);
+ sTree.view.selection.rangedSelect(0, 9, true);
}
function clickCol(col) {
EventUtils.synthesizeMouse(col, 20, 1, {}, win);
setTimeout(runNextTest, 0);
}
function setFilter(string) {
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
@@ -148,17 +148,22 @@ add_task(function* test() {
runNextTest();
else
endFunction();
}
function runNextTest() {
let testCase = tests[testCounter++];
setFilter(testCase.filter);
- setTimeout(runOneTest, 0, testCase);
+ function handleSelect() {
+ tree.removeEventListener('select', handleSelect);
+ setTimeout(runOneTest, 0, testCase);
+ }
+ tree.addEventListener('select', handleSelect);
+ view.selection.rangedSelect(0, 9, true);
}
runNextTest();
}
function step1() {
runTests(1, step2);
}