Bug 1329628 - Part 1. Add a phishing warning text upon footer to show the additional fields that are about to be filled while a profile being selected. r=MattN
MozReview-Commit-ID: FiCzgKAbFoE
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -493,24 +493,42 @@ var FormAutofillContent = {
if (!field || !(field instanceof Ci.nsIDOMHTMLInputElement)) {
return;
}
formFillController.markAsAutofillField(field);
},
_previewProfile(doc) {
- let selectedIndex = ProfileAutocomplete._getSelectedIndex(doc.ownerGlobal);
+ let docWin = doc.ownerGlobal;
+ let selectedIndex = ProfileAutocomplete._getSelectedIndex(docWin);
let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
+ let focusedInput = formFillController.focusedInput;
+ let mm = this._messageManagerFromWindow(docWin);
if (selectedIndex === -1 ||
+ !focusedInput ||
!lastAutoCompleteResult ||
lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile") {
+ mm.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {});
+
ProfileAutocomplete._clearProfilePreview();
} else {
+ let focusedInputDetails = this.getInputDetails(focusedInput);
+ let profile = JSON.parse(lastAutoCompleteResult.getCommentAt(selectedIndex));
+ let allFieldNames = FormAutofillContent.getAllFieldNames(focusedInput);
+ let profileFields = allFieldNames.filter(fieldName => !!profile[fieldName]);
+
+ let focusedCategory = FormAutofillUtils.getCategoryFromFieldName(focusedInputDetails.fieldName);
+ let categories = FormAutofillUtils.getCategoriesFromFieldNames(profileFields);
+ mm.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {
+ focusedCategory,
+ categories,
+ });
+
ProfileAutocomplete._previewSelectedProfile(selectedIndex);
}
},
_messageManagerFromWindow(win) {
return win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -40,25 +40,29 @@ this.FormAutofillUtils = {
isAddressField(fieldName) {
return !!this._fieldNameInfo[fieldName] && !this.isCreditCardField(fieldName);
},
isCreditCardField(fieldName) {
return this._fieldNameInfo[fieldName] == "creditCard";
},
+ getCategoryFromFieldName(fieldName) {
+ return this._fieldNameInfo[fieldName];
+ },
+
getCategoriesFromFieldNames(fieldNames) {
let categories = new Set();
for (let fieldName of fieldNames) {
- let info = this._fieldNameInfo[fieldName];
+ let info = this.getCategoryFromFieldName(fieldName);
if (info) {
categories.add(info);
}
}
- return categories;
+ return Array.from(categories);
},
getAddressSeparator() {
// The separator should be based on the L10N address format, and using a
// white space is a temporary solution.
return " ";
},
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -37,16 +37,17 @@ this.ProfileAutoCompleteResult = functio
this._popupLabels = this._generateLabels(this._focusedFieldName,
this._allFieldNames,
this._matchingProfiles);
// Add an empty result entry for footer. Its content will come from
// the footer binding, so don't assign any value to it.
this._popupLabels.push({
primary: "",
secondary: "",
+ categories: FormAutofillUtils.getCategoriesFromFieldNames(allFieldNames),
});
};
ProfileAutoCompleteResult.prototype = {
// The user's query string
searchString: "",
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -53,17 +53,17 @@
<method name="_onOverflow">
<body></body>
</method>
<method name="_onUnderflow">
<body></body>
</method>
- <method name="_adjustProfileItemLayout">
+ <method name="_adjustAutofillItemLayout">
<body>
<![CDATA[
let outerBoxRect = this.parentNode.getBoundingClientRect();
// Make item fit in popup as XUL box could not constrain
// item's width
this._itemBox.style.width = outerBoxRect.width + "px";
// Use two-lines layout when width is smaller than 150px
@@ -119,72 +119,147 @@
let {AutoCompletePopup} = Cu.import("resource://gre/modules/AutoCompletePopup.jsm", {});
AutoCompletePopup.sendMessageToBrowser("FormAutofill:PreviewProfile");
return val;
]]></setter>
</property>
-
<method name="_adjustAcItem">
<body>
<![CDATA[
- this._adjustProfileItemLayout();
+ this._adjustAutofillItemLayout();
this.setAttribute("formautofillattached", "true");
let {primary, secondary} = JSON.parse(this.getAttribute("ac-value"));
this._label.textContent = primary;
this._comment.textContent = secondary;
]]>
</body>
</method>
</implementation>
</binding>
<binding id="autocomplete-profile-listitem-footer" extends="chrome://formautofill/content/formautofill.xml#autocomplete-profile-listitem-base">
<xbl:content xmlns="http://www.w3.org/1999/xhtml">
<div anonid="autofill-footer" class="autofill-item-box autofill-footer">
+ <div anonid="autofill-warning" class="autofill-footer-row autofill-warning">
+ </div>
+ <div anonid="autofill-option-button" class="autofill-footer-row autofill-option-button">
+ </div>
</div>
</xbl:content>
<handlers>
<handler event="click" button="0"><![CDATA[
window.openPreferences("panePrivacy", {origin: "autofillFooter"});
]]></handler>
</handlers>
<implementation implements="nsIDOMXULSelectControlItemElement">
<constructor>
<![CDATA[
this._itemBox = document.getAnonymousElementByAttribute(
this, "anonid", "autofill-footer"
);
+ this._optionButton = document.getAnonymousElementByAttribute(
+ this, "anonid", "autofill-option-button"
+ );
+ this._warningTextBox = document.getAnonymousElementByAttribute(
+ this, "anonid", "autofill-warning"
+ );
+
+ this.allFieldCategories = JSON.parse(this.getAttribute("ac-value")).categories;
+
+ /**
+ * Update the text on the footer.
+ *
+ * @private
+ * @param {string|string[]} categories
+ * A list of categories that used to generate the message.
+ * @param {boolean} hasExtraCategories
+ * Used to determine if it has the extra categories other than the focued category. If
+ * the value is true, we show "Also fill ...", otherwise, show "Fill ..." only.
+ */
+ this._updateText = (categories = this.allFieldCategories, hasExtraCategories = true) => {
+ let warningTextTmplKey = hasExtraCategories ? "phishingWarningMessage" : "phishingWarningMessage2";
+ let sep = this._stringBundle.GetStringFromName("fieldNameSeparator");
+ let categoriesText = categories.map(this._stringBundle.GetStringFromName).join(sep);
+
+ this._warningTextBox.textContent = this._stringBundle.formatStringFromName(warningTextTmplKey,
+ [categoriesText], 1);
+ this.parentNode.parentNode.adjustHeight();
+ };
+
+ /**
+ * A handler for updating warning message once selectedIndex has been changed.
+ *
+ * There're three different states of warning message:
+ * 1. None of addresses were selected: We show all the categories in the form.
+ * 2. An address was selested: Show the additional categories that will also be filled.
+ * 3. An address was selected, but the focused category is the same as the only all categories: Only show
+ * the exact category that we're going to fill in.
+ *
+ * @private
+ * @param {string} focusedCategory
+ * The category that the focused input's field belongs to.
+ * @param {string[]} categories
+ * The categories of all the fields contained in the selected address.
+ */
+ this._updateWarningMsgHandler = ({data: {focusedCategory, categories}} = {data: {}}) => {
+ let hasSelectedAddress = focusedCategory && categories;
+ // If the length of categories is 1, that means all the fillable fields are in the same
+ // category. We will change the way to inform user according to this flag.
+ let hasExtraCategories = hasSelectedAddress && categories.length > 1;
+ if (!hasSelectedAddress) {
+ this._updateText();
+ return;
+ }
+
+ let showCategories = hasExtraCategories ?
+ categories.filter(category => category != focusedCategory) :
+ [focusedCategory];
+ this._updateText(showCategories, hasExtraCategories);
+ };
this._adjustAcItem();
+ this._updateText();
]]>
</constructor>
+ <method name="_onCollapse">
+ <body>
+ <![CDATA[
+ /* global messageManager */
+
+ messageManager.removeMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningMsgHandler);
+ ]]>
+ </body>
+ </method>
+
<method name="_adjustAcItem">
<body>
<![CDATA[
/* global Cu */
- this._adjustProfileItemLayout();
+ this._adjustAutofillItemLayout();
this.setAttribute("formautofillattached", "true");
let {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
- let footerTextBundleKey = AppConstants.platform == "macosx" ?
+ let buttonTextBundleKey = AppConstants.platform == "macosx" ?
"autocompleteFooterOptionOSX" : "autocompleteFooterOption";
// If the popup shows up with small layout, we should use short string to
// have a better fit in the box.
if (this._itemBox.getAttribute("size") == "small") {
- footerTextBundleKey += "Short";
+ buttonTextBundleKey += "Short";
}
- let footerText = this._stringBundle.GetStringFromName(footerTextBundleKey);
- this._itemBox.textContent = footerText;
+ let buttonText = this._stringBundle.GetStringFromName(buttonTextBundleKey);
+ this._optionButton.textContent = buttonText;
+
+ messageManager.addMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningMsgHandler);
]]>
</body>
</method>
</implementation>
</binding>
</bindings>
--- a/browser/extensions/formautofill/locale/en-US/formautofill.properties
+++ b/browser/extensions/formautofill/locale/en-US/formautofill.properties
@@ -13,8 +13,21 @@ changeAutofillOptionsOSX = Change Form A
updateAddressMessage = Would you like to update your address with this new information?
createAddressLabel = Create New Address
updateAddressLabel = Update Address
openAutofillMessagePanel = Open Form Autofill message panel
autocompleteFooterOption = Form Autofill Options
autocompleteFooterOptionShort = Options
autocompleteFooterOptionOSX = Form Autofill Preferences
autocompleteFooterOptionOSXShort = Preferences
+address = address
+name = name
+organization = company
+tel = phone
+email = email
+# LOCALIZATION NOTE (fieldNameSeparator): This is used as a separator between categories.
+fieldNameSeparator = ,\u0020
+# LOCALIZATION NOTE (phishingWarningMessage, phishingWarningMessage2): The warning
+# text that is displayed for informing users what categories are about to be filled.
+# "%S" will be replaced with a list generated from the pre-defined categories.
+# The text would be e.g. Also fill company, phone, email
+phishingWarningMessage = Also fill %S
+phishingWarningMessage2 = Fill %S
--- a/browser/extensions/formautofill/skin/linux/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/linux/autocomplete-item.css
@@ -8,11 +8,15 @@
.autofill-item-box > .profile-item-col > .profile-label {
font-size: .84em;
}
.autofill-item-box > .profile-item-col > .profile-comment {
font-size: .7em;
}
-.autofill-footer {
+.autofill-footer > .autofill-warning {
+ font-size: .7em;
+}
+
+.autofill-footer > .autofill-option-button {
font-size: .77em;
}
--- a/browser/extensions/formautofill/skin/osx/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/osx/autocomplete-item.css
@@ -7,8 +7,12 @@
.autofill-item-box > .profile-item-col > .profile-label {
font-size: 1.09em;
}
.autofill-item-box > .profile-item-col > .profile-comment {
font-size: .9em;
}
+
+.autofill-footer > .autofill-warning {
+ font-size: .9em;
+}
--- a/browser/extensions/formautofill/skin/shared/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/shared/autocomplete-item.css
@@ -5,17 +5,17 @@
@namespace url("http://www.w3.org/1999/xhtml");
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
xul|richlistitem[originaltype="autofill-profile"][selected="true"] > .autofill-item-box {
background-color: #F2F2F2;
}
-xul|richlistitem[originaltype="autofill-footer"][selected="true"] > .autofill-footer {
+xul|richlistitem[originaltype="autofill-footer"][selected="true"] > .autofill-item-box > .autofill-option-button {
background-color: #DCDCDE;
}
.autofill-item-box {
--item-padding-vertical: 6px;
--item-padding-horizontal: 10px;
--col-spacer: 7px;
--item-width: calc(50% - (var(--col-spacer) / 2));
@@ -24,17 +24,19 @@ xul|richlistitem[originaltype="autofill-
.autofill-item-box[size="small"] {
--item-padding-vertical: 7px;
--col-spacer: 0px;
--row-spacer: 3px;
--item-width: 100%;
}
-.autofill-footer {
+.autofill-footer,
+.autofill-footer[size="small"] {
+ --item-width: 100%;
--item-padding-vertical: 0;
--item-padding-horizontal: 0;
}
.autofill-item-box {
box-sizing: border-box;
margin: 0;
border-bottom: 1px solid rgba(38,38,38,.15);
@@ -76,12 +78,30 @@ xul|richlistitem[originaltype="autofill-
}
.autofill-item-box[size="small"] > .profile-comment-col {
margin-top: var(--row-spacer);
text-align: start;
}
.autofill-footer {
+ flex-direction: column;
+}
+
+.autofill-footer > .autofill-footer-row {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: var(--item-width);
+}
+
+.autofill-footer > .autofill-warning {
+ padding: 2.5px 0;
+ color: #989898;
+ text-align: center;
+ background-color: rgba(248,232,28,.2);
+ border-bottom: 1px solid rgba(38,38,38,.15);
+}
+
+.autofill-footer > .autofill-option-button {
height: 41px;
background-color: #EDEDED;
- justify-content: center;
}
--- a/browser/extensions/formautofill/skin/windows/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/windows/autocomplete-item.css
@@ -5,17 +5,21 @@
@namespace url("http://www.w3.org/1999/xhtml");
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
.autofill-item-box > .profile-item-col > .profile-comment {
font-size: .83em;
}
-.autofill-footer {
+.autofill-footer > .autofill-warning {
+ font-size: .83em;
+}
+
+.autofill-footer > .autofill-option-button {
font-size: .91em;
}
@media (-moz-windows-default-theme: 0) {
xul|richlistitem[originaltype="autofill-profile"][selected="true"] > .autofill-item-box {
background-color: Highlight;
}
}
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1220,17 +1220,22 @@ extends="chrome://global/content/binding
</getter>
</property>
<method name="_collapseUnusedItems">
<body>
<![CDATA[
let existingItemsCount = this.richlistbox.childNodes.length;
for (let i = this._matchCount; i < existingItemsCount; ++i) {
- this.richlistbox.childNodes[i].collapsed = true;
+ let item = this.richlistbox.childNodes[i];
+
+ item.collapsed = true;
+ if (typeof item._onCollapse == "function") {
+ item._onCollapse();
+ }
}
]]>
</body>
</method>
<method name="adjustHeight">
<body>
<![CDATA[
@@ -1339,17 +1344,18 @@ extends="chrome://global/content/binding
originalValue = item.getAttribute("ac-value");
originalText = item.getAttribute("ac-text");
originalType = item.getAttribute("originaltype");
// All of types are reusable except for autofill-profile,
// which has different structure of <content> and overrides
// _adjustAcItem().
reusable = originalType === style ||
- (style !== "autofill-profile" && originalType !== "autofill-profile");
+ (style !== "autofill-profile" && originalType !== "autofill-profile" &&
+ style !== "autofill-footer" && originalType !== "autofill-footer");
} else {
// need to create a new item
item = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "richlistitem");
}
item.setAttribute("dir", this.style.direction);
item.setAttribute("ac-image", image);
item.setAttribute("ac-value", value);