mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-02 05:17:31 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
4c1a4a4402
31 changed files with 827 additions and 36 deletions
|
|
@ -1603,6 +1603,16 @@ private:
|
|||
|
||||
// Data members
|
||||
EventStates mState;
|
||||
|
||||
public:
|
||||
// Public helper to add or remove event states
|
||||
void SetEventState(mozilla::EventStates aState, bool aAdd) {
|
||||
if (aAdd) {
|
||||
this->AddStates(aState);
|
||||
} else {
|
||||
this->RemoveStates(aState);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RemoveFromBindingManagerRunnable : public mozilla::Runnable
|
||||
|
|
|
|||
|
|
@ -4058,3 +4058,35 @@ nsTranslationNodeList::GetLength(uint32_t* aRetVal)
|
|||
*aRetVal = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::AddElementEventState(nsIDOMElement* aElement, uint64_t aState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||
if (!content) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mozilla::dom::Element* element = static_cast<mozilla::dom::Element*>(content.get());
|
||||
if (!element) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
element->SetEventState(mozilla::EventStates(aState), true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::RemoveElementEventState(nsIDOMElement* aElement, uint64_t aState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||
if (!content) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mozilla::dom::Element* element = static_cast<mozilla::dom::Element*>(content.get());
|
||||
if (!element) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
element->SetEventState(mozilla::EventStates(aState), false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,6 +293,9 @@ private:
|
|||
// Modal <dialog> element
|
||||
#define NS_EVENT_STATE_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(54)
|
||||
|
||||
// Autofilled input element (for :autofill pseudo-class)
|
||||
#define NS_EVENT_STATE_AUTOFILL NS_DEFINE_EVENT_STATE_MACRO(55)
|
||||
|
||||
#define DIR_ATTR_STATES (NS_EVENT_STATE_HAS_DIR_ATTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_LTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_RTL | \
|
||||
|
|
|
|||
|
|
@ -2832,6 +2832,20 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (aAutofilled) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue = value;
|
||||
} else {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
nsIEditor*
|
||||
HTMLInputElement::GetEditor()
|
||||
{
|
||||
|
|
@ -3562,7 +3576,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)
|
||||
|
|
@ -7070,6 +7095,13 @@ HTMLInputElement::IntrinsicState() const
|
|||
state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
|
||||
}
|
||||
|
||||
// Autofill highlight should persist as long as the value matches the autofilled value
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (!mAutofilledValue.IsEmpty() && value == mAutofilledValue) {
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
@ -8505,8 +8537,23 @@ HTMLInputElement::InitializeKeyboardEventListeners()
|
|||
NS_IMETHODIMP_(void)
|
||||
HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// Only remove autofilled state if the value actually changed from autofilled value
|
||||
if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue != value) {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
} else if (aWasInteractiveUserChange && !State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
// If the value is changed back to the autofilled value, restore the state
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue == value) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAllValidityStates(aNotify);
|
||||
|
||||
if (HasDirAuto()) {
|
||||
|
|
@ -8537,6 +8584,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; }
|
||||
|
|
@ -845,6 +847,15 @@ public:
|
|||
void SetUserInput(const nsAString& aInput,
|
||||
nsIPrincipal& aSubjectPrincipal);
|
||||
|
||||
/**
|
||||
* Sets or clears the autofilled state of this input element.
|
||||
* When setting, also stores the autofilled value for persistence.
|
||||
* When clearing, clears the stored autofilled value.
|
||||
*
|
||||
* @param aAutofilled Whether the element should be marked as autofilled
|
||||
*/
|
||||
void SetAutofilled(bool aAutofilled);
|
||||
|
||||
// XPCOM GetPhonetic() is OK
|
||||
|
||||
/**
|
||||
|
|
@ -860,6 +871,8 @@ public:
|
|||
|
||||
void UpdateEntries(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories);
|
||||
|
||||
void SetAutofilledValue(const nsAString& aValue) { mAutofilledValue = aValue; }
|
||||
|
||||
protected:
|
||||
virtual ~HTMLInputElement();
|
||||
|
||||
|
|
@ -1103,7 +1116,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.
|
||||
|
|
@ -1629,6 +1642,11 @@ protected:
|
|||
bool mNumberControlSpinnerSpinsUp : 1;
|
||||
bool mPickerRunning : 1;
|
||||
bool mSelectionCached : 1;
|
||||
/**
|
||||
* The value that was autofilled by the browser. Used to persist the autofill
|
||||
* highlight as long as the value matches, regardless of focus/blur.
|
||||
*/
|
||||
nsString mAutofilledValue;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
|
|
@ -1772,6 +1790,8 @@ private:
|
|||
nsCOMPtr<nsIFilePicker> mFilePicker;
|
||||
RefPtr<HTMLInputElement> mInput;
|
||||
};
|
||||
|
||||
void EnsureAutofillState();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -366,6 +366,46 @@ HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
|
|||
return SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTextAreaElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
if (aAutofilled) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
GetValueInternal(mAutofilledValue, true); // Store the autofilled value
|
||||
} else {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, true);
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
|
||||
{
|
||||
|
|
@ -556,6 +596,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)
|
||||
{
|
||||
|
|
@ -580,6 +633,9 @@ HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
|||
}
|
||||
|
||||
UpdateState(true);
|
||||
|
||||
// Defensive: re-apply autofill state if value is still autofilled value
|
||||
EnsureAutofillState();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
@ -1186,6 +1242,10 @@ HTMLTextAreaElement::IntrinsicState() const
|
|||
{
|
||||
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
||||
|
||||
if (!mAutofilledValue.IsEmpty()) {
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
}
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
||||
state |= NS_EVENT_STATE_REQUIRED;
|
||||
} else {
|
||||
|
|
@ -1628,23 +1688,6 @@ HTMLTextAreaElement::InitializeKeyboardEventListeners()
|
|||
mState.InitializeKeyboardEventListeners();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// 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()
|
||||
{
|
||||
|
|
@ -1660,11 +1703,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,17 @@ 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.
|
||||
* This is used by the browser's autofill system to indicate when
|
||||
* a value has been automatically filled (e.g., from saved form data).
|
||||
*
|
||||
* @param aAutofilled Whether the element should be marked as autofilled
|
||||
*/
|
||||
void SetAutofilled(bool aAutofilled);
|
||||
|
||||
// nsIFormControl
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_TEXTAREA; }
|
||||
|
|
@ -293,6 +304,7 @@ public:
|
|||
{
|
||||
return mState.GetEditor();
|
||||
}
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTextAreaElement() {}
|
||||
|
|
@ -324,6 +336,7 @@ protected:
|
|||
void FireChangeEventIfNeeded();
|
||||
|
||||
nsString mFocusedValue;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
/** The state of the text editor (selection controller and the editor) **/
|
||||
nsTextEditorState mState;
|
||||
|
|
@ -397,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
|
||||
|
|
|
|||
|
|
@ -1944,6 +1944,20 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
const long MOUSE_BUTTONS_5TH_BUTTON = 0x10;
|
||||
// Buttons are not specified, will be calculated from |aButton|.
|
||||
const long MOUSE_BUTTONS_NOT_SPECIFIED = -1;
|
||||
|
||||
/**
|
||||
* Add an EventState bit to an element (privileged only).
|
||||
* @param element The element to modify.
|
||||
* @param state The EventState bit (see EventStates.h, e.g. NS_EVENT_STATE_AUTOFILL).
|
||||
*/
|
||||
void addElementEventState(in nsIDOMElement element, in unsigned long long state);
|
||||
|
||||
/**
|
||||
* Remove an EventState bit from an element (privileged only).
|
||||
* @param element The element to modify.
|
||||
* @param state The EventState bit.
|
||||
*/
|
||||
void removeElementEventState(in nsIDOMElement element, in unsigned long long state);
|
||||
};
|
||||
|
||||
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -200,6 +200,13 @@ partial interface HTMLInputElement {
|
|||
// for example will be dispatched when focusing out the element.
|
||||
[Func="IsChromeOrXBL", NeedsSubjectPrincipal]
|
||||
void setUserInput(DOMString input);
|
||||
|
||||
// Sets or clears the autofilled state of this input element.
|
||||
// This is used by the browser's autofill system to indicate when
|
||||
// a value has been automatically filled (e.g., from saved passwords
|
||||
// or form data).
|
||||
[ChromeOnly]
|
||||
void setAutofilled(boolean autofilled);
|
||||
};
|
||||
|
||||
partial interface HTMLInputElement {
|
||||
|
|
|
|||
|
|
@ -97,4 +97,10 @@ partial interface HTMLTextAreaElement {
|
|||
// element.
|
||||
[ChromeOnly]
|
||||
void setUserInput(DOMString input);
|
||||
|
||||
// Sets or clears the autofilled state of this textarea element.
|
||||
// This is used by the browser's autofill system to indicate when
|
||||
// a value has been automatically filled (e.g., from saved form data).
|
||||
[ChromeOnly]
|
||||
void setAutofilled(boolean autofilled);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue