mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 13:58:49 +00:00
Issue #2790 - Part 4: Working non persistent autofill highlight
This commit is contained in:
@@ -2835,16 +2835,11 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
|
||||
void
|
||||
HTMLInputElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
printf("🔍 AUTOFILL C++: SetAutofilled called with aAutofilled=%s\n", aAutofilled ? "true" : "false");
|
||||
|
||||
|
||||
if (aAutofilled) {
|
||||
printf("🔍 AUTOFILL C++: Adding NS_EVENT_STATE_AUTOFILL state\n");
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: State added successfully\n");
|
||||
} else {
|
||||
printf("🔍 AUTOFILL C++: Removing NS_EVENT_STATE_AUTOFILL state\n");
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: State removed successfully\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3578,7 +3573,18 @@ HTMLInputElement::Blur(ErrorResult& aError)
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::Blur(aError);
|
||||
}
|
||||
|
||||
if (State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
// Force a complete restyle to ensure autofill pseudo-classes are processed
|
||||
if (nsIDocument* doc = GetComposedDoc()) {
|
||||
if (nsIPresShell* shell = doc->GetShell()) {
|
||||
if (nsIFrame* frame = GetPrimaryFrame()) {
|
||||
shell->FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::Focus(ErrorResult& aError)
|
||||
@@ -8521,13 +8527,16 @@ HTMLInputElement::InitializeKeyboardEventListeners()
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// Clear autofilled state if this was an interactive user change
|
||||
// Only remove autofilled state if the value actually changed from autofilled value
|
||||
if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
printf("🔍 AUTOFILL C++: User changed autofilled input, clearing state\n");
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: Autofill state cleared from input\n");
|
||||
if (mAutofilledValue != value) {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAllValidityStates(aNotify);
|
||||
@@ -8560,6 +8569,24 @@ HTMLInputElement::HasCachedSelection()
|
||||
return isCached;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::BeginProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::EndProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::FieldSetDisabledChanged(bool aNotify)
|
||||
{
|
||||
|
||||
@@ -160,6 +160,8 @@ public:
|
||||
}
|
||||
|
||||
NS_IMETHOD SetUserInput(const nsAString& aInput) override;
|
||||
NS_IMETHOD BeginProgrammaticValueSet() override;
|
||||
NS_IMETHOD EndProgrammaticValueSet() override;
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return mType; }
|
||||
@@ -1113,7 +1115,7 @@ protected:
|
||||
bool MinOrMaxLengthApplies() const { return IsSingleLineTextControl(false, mType); }
|
||||
|
||||
void FreeData();
|
||||
nsTextEditorState *GetEditorState() const;
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
/**
|
||||
* Manages the internal data storage across type changes.
|
||||
@@ -1639,6 +1641,7 @@ protected:
|
||||
bool mNumberControlSpinnerSpinsUp : 1;
|
||||
bool mPickerRunning : 1;
|
||||
bool mSelectionCached : 1;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
|
||||
@@ -369,16 +369,46 @@ HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
|
||||
void
|
||||
HTMLTextAreaElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
printf("🔍 AUTOFILL C++: HTMLTextAreaElement::SetAutofilled called with aAutofilled=%s\n", aAutofilled ? "true" : "false");
|
||||
|
||||
if (aAutofilled) {
|
||||
printf("🔍 AUTOFILL C++: Adding NS_EVENT_STATE_AUTOFILL state to textarea\n");
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: State added successfully to textarea\n");
|
||||
GetValueInternal(mAutofilledValue, true); // Store the autofilled value
|
||||
} else {
|
||||
printf("🔍 AUTOFILL C++: Removing NS_EVENT_STATE_AUTOFILL state from textarea\n");
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: State removed successfully from textarea\n");
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, true);
|
||||
// printf("[TextArea] OnValueChanged: aWasInteractiveUserChange=%d, value='%s', autofilled='%s', autofill state=%d\n",
|
||||
// aWasInteractiveUserChange,
|
||||
// NS_ConvertUTF16toUTF8(value).get(),
|
||||
// NS_ConvertUTF16toUTF8(mAutofilledValue).get(),
|
||||
// State().HasState(NS_EVENT_STATE_AUTOFILL));
|
||||
|
||||
// Only remove autofilled state if the value actually changed from autofilled value
|
||||
if (State().HasState(NS_EVENT_STATE_AUTOFILL) || !mAutofilledValue.IsEmpty()) {
|
||||
if (aWasInteractiveUserChange && mAutofilledValue != value) {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
} else if (aWasInteractiveUserChange && mAutofilledValue == value) {
|
||||
// Defensive: re-add the autofill state if it was removed by something else
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the validity state
|
||||
bool validBefore = IsValid();
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
if (validBefore != IsValid() ||
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +602,19 @@ HTMLTextAreaElement::FireChangeEventIfNeeded()
|
||||
false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTextAreaElement::EnsureAutofillState()
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, true);
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue == value) {
|
||||
if (!State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
UpdateState(true); // Force style system to re-evaluate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
@@ -596,6 +639,9 @@ HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
}
|
||||
|
||||
UpdateState(true);
|
||||
|
||||
// Defensive: re-apply autofill state if value is still autofilled value
|
||||
EnsureAutofillState();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -1202,6 +1248,11 @@ HTMLTextAreaElement::IntrinsicState() const
|
||||
{
|
||||
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
||||
|
||||
// PATCH: Persist autofill state if autofilled
|
||||
if (!mAutofilledValue.IsEmpty()) {
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
}
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
||||
state |= NS_EVENT_STATE_REQUIRED;
|
||||
} else {
|
||||
@@ -1244,6 +1295,8 @@ HTMLTextAreaElement::IntrinsicState() const
|
||||
state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
|
||||
}
|
||||
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1644,30 +1697,6 @@ HTMLTextAreaElement::InitializeKeyboardEventListeners()
|
||||
mState.InitializeKeyboardEventListeners();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// Clear autofilled state if this was an interactive user change
|
||||
if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
printf("🔍 AUTOFILL C++: User changed autofilled textarea, clearing state\n");
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
printf("🔍 AUTOFILL C++: Autofill state cleared from textarea\n");
|
||||
}
|
||||
|
||||
// Update the validity state
|
||||
bool validBefore = IsValid();
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
if (validBefore != IsValid() ||
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLTextAreaElement::HasCachedSelection()
|
||||
{
|
||||
@@ -1683,11 +1712,33 @@ HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify)
|
||||
nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::BeginProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::EndProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLTextAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLTextAreaElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsTextEditorState* HTMLTextAreaElement::GetEditorState() const {
|
||||
return const_cast<nsTextEditorState*>(&mState);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
return nsGenericHTMLElement::GetEditor(aEditor);
|
||||
}
|
||||
NS_IMETHOD SetUserInput(const nsAString& aInput) override;
|
||||
NS_IMETHOD BeginProgrammaticValueSet() override;
|
||||
NS_IMETHOD EndProgrammaticValueSet() override;
|
||||
|
||||
/**
|
||||
* Sets or clears the autofilled state of this textarea element.
|
||||
@@ -302,6 +304,7 @@ public:
|
||||
{
|
||||
return mState.GetEditor();
|
||||
}
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTextAreaElement() {}
|
||||
@@ -333,6 +336,7 @@ protected:
|
||||
void FireChangeEventIfNeeded();
|
||||
|
||||
nsString mFocusedValue;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
/** The state of the text editor (selection controller and the editor) **/
|
||||
nsTextEditorState mState;
|
||||
@@ -406,6 +410,7 @@ protected:
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
void EnsureAutofillState();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -163,6 +163,7 @@ public:
|
||||
// or reconsider fixing bug 597525 to remove these.
|
||||
void EmptyValue() { if (mValue) mValue->Truncate(); }
|
||||
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
|
||||
void SettingValue(bool aValue) { mSettingValue = aValue; }
|
||||
|
||||
nsresult CreatePlaceholderNode();
|
||||
|
||||
@@ -348,6 +349,7 @@ private:
|
||||
mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
|
||||
bool mPlaceholderVisibility;
|
||||
bool mIsCommittingComposition;
|
||||
bool mSettingValue;
|
||||
};
|
||||
|
||||
inline void
|
||||
|
||||
@@ -25,4 +25,10 @@ interface nsIDOMNSEditableElement : nsISupports
|
||||
// 'change' event for example will be dispatched when focusing out the
|
||||
// element.
|
||||
[noscript] void setUserInput(in DOMString input);
|
||||
/**
|
||||
* Call this before and after programmatically setting the value to prevent
|
||||
* OnValueChanged from treating it as a user edit.
|
||||
*/
|
||||
void beginProgrammaticValueSet();
|
||||
void endProgrammaticValueSet();
|
||||
};
|
||||
|
||||
@@ -1270,6 +1270,14 @@ ComputeSelectorStateDependence(nsCSSSelector& aSelector)
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- BEGIN PATCH: Explicit autofill state dependence ---
|
||||
if (pseudoClass->mType == CSSPseudoClassType::autofill ||
|
||||
pseudoClass->mType == CSSPseudoClassType::mozAutofillHighlight) {
|
||||
states |= NS_EVENT_STATE_AUTOFILL;
|
||||
continue;
|
||||
}
|
||||
// --- END PATCH ---
|
||||
|
||||
auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
|
||||
states |= nsCSSPseudoClasses::sPseudoClassStateDependences[idx];
|
||||
}
|
||||
|
||||
@@ -576,6 +576,16 @@ nsCSSRuleUtils::StateSelectorMatches(Element* aElement,
|
||||
for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
|
||||
pseudoClass;
|
||||
pseudoClass = pseudoClass->mNext) {
|
||||
// --- Autofill explicit matching ---
|
||||
if (pseudoClass->mType == CSSPseudoClassType::autofill ||
|
||||
pseudoClass->mType == CSSPseudoClassType::mozAutofillHighlight) {
|
||||
// Match if the element has the autofill state, regardless of focus
|
||||
if (!aElement->State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
return false;
|
||||
}
|
||||
continue; // This pseudo-class matches
|
||||
}
|
||||
// --- End autofill explicit matching ---
|
||||
auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
|
||||
EventStates statesToCheck = nsCSSPseudoClasses::sPseudoClassStates[idx];
|
||||
if (!statesToCheck.IsEmpty() && !StateSelectorMatches(aElement,
|
||||
|
||||
@@ -1152,6 +1152,11 @@ input[type="time"] {
|
||||
|
||||
/* Autofill highlight for internal-only pseudo-class */
|
||||
input:-moz-autofill-highlight,
|
||||
select:-moz-autofill-highlight,
|
||||
textarea:-moz-autofill-highlight {
|
||||
background-color: #ffff99 !important;
|
||||
}
|
||||
|
||||
.custom-autofill-highlight {
|
||||
background: yellow !important;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
* See the nsIFormAutofillContentService documentation for details.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
console.log('🔍 AUTOFILL: FormAutofillContentService.js loaded');
|
||||
"use strict"
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
@@ -34,15 +32,11 @@ function FormHandler(aForm, aWindow) {
|
||||
|
||||
// Add a reset event listener to clear autofill state
|
||||
this.form.addEventListener("reset", () => {
|
||||
console.log('Form reset detected, clearing autofill state');
|
||||
for (let element of this.form.elements) {
|
||||
if (typeof element.setAutofilled === "function") {
|
||||
element.setAutofilled(false);
|
||||
console.log('setAutofilled(false) called on', element);
|
||||
}
|
||||
}
|
||||
// Optionally, clear fieldDetails if you want to force re-collection
|
||||
// this.fieldDetails = [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -145,9 +139,7 @@ FormHandler.prototype = {
|
||||
return "cancel";
|
||||
}
|
||||
|
||||
console.log('🔍 AUTOFILL: About to call autofillFormFields with result:', result);
|
||||
this.autofillFormFields(result);
|
||||
console.log('🔍 AUTOFILL: autofillFormFields completed');
|
||||
|
||||
return "success";
|
||||
}),
|
||||
@@ -243,10 +235,8 @@ FormHandler.prototype = {
|
||||
* }
|
||||
*/
|
||||
autofillFormFields: function (aAutofillResult) {
|
||||
console.log('🔍 AUTOFILL: autofillFormFields called with', aAutofillResult);
|
||||
|
||||
for (let field of aAutofillResult.fields) {
|
||||
console.log('🔍 AUTOFILL: Processing field', field);
|
||||
|
||||
// Get the field details, if it was processed by the user interface.
|
||||
let fieldDetail = this.fieldDetails
|
||||
@@ -255,26 +245,36 @@ FormHandler.prototype = {
|
||||
f.contactType == field.contactType &&
|
||||
f.fieldName == field.fieldName);
|
||||
|
||||
console.log('🔍 AUTOFILL: Found fieldDetail?', !!fieldDetail, fieldDetail);
|
||||
|
||||
if (!fieldDetail) {
|
||||
console.log('🔍 AUTOFILL: No fieldDetail found, skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log('🔍 AUTOFILL: Setting value on element', fieldDetail.element);
|
||||
fieldDetail.element.value = field.value;
|
||||
|
||||
// Set the autofilled state on the element
|
||||
console.log('🔍 AUTOFILL: Checking if setAutofilled exists on element');
|
||||
console.log('🔍 AUTOFILL: setAutofilled type:', typeof fieldDetail.element.setAutofilled);
|
||||
// Add event listeners for debugging
|
||||
// try {
|
||||
// fieldDetail.element.addEventListener('focus', () => console.log('[JS] input focused'));
|
||||
// fieldDetail.element.addEventListener('blur', () => console.log('[JS] input blurred'));
|
||||
// fieldDetail.element.addEventListener('input', () => console.log('[JS] input event, value:', fieldDetail.element.value));
|
||||
// } catch (e) {
|
||||
// console.log('[JS] Could not add event listeners:', e);
|
||||
// }
|
||||
|
||||
// if (typeof fieldDetail.element.setAutofilled === 'function') {
|
||||
// if (field.value) {
|
||||
// console.log('AUTOFILL: Calling setAutofilled(true) on element');
|
||||
// fieldDetail.element.setAutofilled(true);
|
||||
// console.log('AUTOFILL: setAutofilled(true) called successfully');
|
||||
// } else {
|
||||
// console.log('AUTOFILL: Calling setAutofilled(false) on element (empty value)');
|
||||
// fieldDetail.element.setAutofilled(false);
|
||||
// }
|
||||
// } else {
|
||||
// console.log('AUTOFILL: setAutofilled is not a function on this element');
|
||||
// }
|
||||
|
||||
// Highlight: Set autofilled state for all autofilled fields
|
||||
if (typeof fieldDetail.element.setAutofilled === 'function') {
|
||||
console.log('🔍 AUTOFILL: Calling setAutofilled(true) on element');
|
||||
fieldDetail.element.setAutofilled(true);
|
||||
console.log('🔍 AUTOFILL: setAutofilled(true) called successfully');
|
||||
} else {
|
||||
console.log('🔍 AUTOFILL: setAutofilled is not a function on this element');
|
||||
fieldDetail.element.setAutofilled(!!field.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1189,7 +1189,7 @@ var LoginManagerContent = {
|
||||
// Fill the form
|
||||
|
||||
if (usernameField) {
|
||||
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
|
||||
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
|
||||
let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
|
||||
|
||||
let userNameDiffers = selectedLogin.username != usernameField.value;
|
||||
@@ -1202,6 +1202,10 @@ var LoginManagerContent = {
|
||||
if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) {
|
||||
usernameField.setUserInput(selectedLogin.username);
|
||||
}
|
||||
//Set autofilled state if value is present
|
||||
if (typeof usernameField.setAutofilled === "function" && usernameField.value) {
|
||||
usernameField.setAutofilled(true);
|
||||
}
|
||||
}
|
||||
|
||||
let doc = form.ownerDocument;
|
||||
@@ -1216,6 +1220,10 @@ var LoginManagerContent = {
|
||||
};
|
||||
log("Saving autoFilledLogin", autoFilledLogin.guid, "for", form.rootElement);
|
||||
this.stateForDocument(doc).fillsByRootElement.set(form.rootElement, autoFilledLogin);
|
||||
// Patch: Set autofilled state if value is present
|
||||
if (typeof passwordField.setAutofilled === "function" && passwordField.value) {
|
||||
passwordField.setAutofilled(true);
|
||||
}
|
||||
}
|
||||
|
||||
log("_fillForm succeeded");
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@@ -541,9 +542,21 @@ nsFormFillController::SetTextValue(const nsAString & aTextValue)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(mFocusedInput);
|
||||
if (editable) {
|
||||
editable->BeginProgrammaticValueSet();
|
||||
mSuppressOnInput = true;
|
||||
editable->SetUserInput(aTextValue);
|
||||
mSuppressOnInput = false;
|
||||
editable->EndProgrammaticValueSet();
|
||||
|
||||
if (mFocusedInput) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
|
||||
if (content) {
|
||||
mozilla::dom::HTMLInputElement* htmlInput = mozilla::dom::HTMLInputElement::FromContentOrNull(content);
|
||||
if (htmlInput) {
|
||||
htmlInput->SetAutofilled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1332,7 +1345,8 @@ nsFormFillController::StopControllingInput()
|
||||
nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
|
||||
do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
|
||||
if (formAutoComplete) {
|
||||
formAutoComplete->StopControllingInput(mFocusedInput);
|
||||
// PATCH: Do NOT call StopControllingInput here, so autofill state is NOT cleared on blur/focus.
|
||||
// formAutoComplete->StopControllingInput(mFocusedInput);
|
||||
}
|
||||
|
||||
mFocusedInputNode = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user