mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-29 16:10:41 +00:00
ported from UXP: Issue #2790 - Part 4: Working non persistent autofill highlight (bf8cfcc9)
This commit is contained in:
@@ -2780,16 +2780,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3525,7 +3520,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)
|
||||
@@ -8464,13 +8470,16 @@ HTMLInputElement::InitializeKeyboardEventListeners()
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, CallerType::System);
|
||||
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);
|
||||
@@ -8503,6 +8512,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)
|
||||
{
|
||||
|
||||
@@ -162,6 +162,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; }
|
||||
@@ -1133,7 +1135,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.
|
||||
@@ -1659,6 +1661,7 @@ protected:
|
||||
bool mNumberControlSpinnerSpinsUp : 1;
|
||||
bool mPickerRunning : 1;
|
||||
bool mSelectionCached : 1;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
|
||||
@@ -367,16 +367,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,6 +600,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)
|
||||
{
|
||||
@@ -594,6 +637,9 @@ HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
}
|
||||
|
||||
UpdateState(true);
|
||||
|
||||
// Defensive: re-apply autofill state if value is still autofilled value
|
||||
EnsureAutofillState();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -1200,6 +1246,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 {
|
||||
@@ -1242,6 +1293,8 @@ HTMLTextAreaElement::IntrinsicState() const
|
||||
state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
|
||||
}
|
||||
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -1642,30 +1695,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()
|
||||
{
|
||||
@@ -1681,11 +1710,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
|
||||
|
||||
@@ -70,6 +70,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.
|
||||
@@ -303,6 +305,7 @@ public:
|
||||
{
|
||||
return mState.GetEditor();
|
||||
}
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTextAreaElement() {}
|
||||
@@ -334,6 +337,7 @@ protected:
|
||||
void FireChangeEventIfNeeded();
|
||||
|
||||
nsString mFocusedValue;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
/** The state of the text editor (selection controller and the editor) **/
|
||||
nsTextEditorState mState;
|
||||
@@ -407,6 +411,7 @@ protected:
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
void EnsureAutofillState();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -164,6 +164,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();
|
||||
|
||||
@@ -349,6 +350,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();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user