mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1698315 - Manage placeholder and autofill preview visibility using CSS rather than custom code. r=masayuki
Should be much simpler and doesn't need to deal with the different stuff. We already have pseudo-classes for this, :autofill and :placeholder-shown. I initially wrote this because this is the only limitation that forces us to have the placeholder text as a direct child of the text control frame. In the end I kept that as-is, but this simplification is still worth it. We remove dom.placeholder.show_on_focus because it doesn't behave correctly (it doesn't match the :placeholder-shown pseudo-class and it should). It was introduced in bug 807613 and never turned to false by default. I suspect nobody will miss this, but if somebody complains about it we can reintroduce it properly (handling the pref in DOM instead, changing the right state bits). Differential Revision: https://phabricator.services.mozilla.com/D108304
This commit is contained in:
parent
81b14e2ac7
commit
678b10493d
@ -1093,11 +1093,9 @@ nsresult HTMLInputElement::Clone(dom::NodeInfo* aNodeInfo,
|
||||
nsAutoString value;
|
||||
GetNonFileValueInternal(value);
|
||||
// SetValueInternal handles setting the VALUE_CHANGED bit for us
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
rv = it->SetValueInternal(
|
||||
value,
|
||||
{ValueSetterOption::
|
||||
UpdateOverlayTextVisibilityAndInvalidateFrame})))) {
|
||||
if (NS_WARN_IF(
|
||||
NS_FAILED(rv = it->SetValueInternal(
|
||||
value, {ValueSetterOption::SetValueChanged})))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -1616,8 +1614,7 @@ void HTMLInputElement::SetValue(const nsAString& aValue, CallerType aCallerType,
|
||||
// get the unsanitized value?
|
||||
nsresult rv = SetValueInternal(
|
||||
aValue, SanitizesOnValueGetter() ? nullptr : ¤tValue,
|
||||
{ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
{ValueSetterOption::ByContentAPI, ValueSetterOption::SetValueChanged,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
@ -1630,8 +1627,7 @@ void HTMLInputElement::SetValue(const nsAString& aValue, CallerType aCallerType,
|
||||
} else {
|
||||
nsresult rv = SetValueInternal(
|
||||
aValue,
|
||||
{ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
{ValueSetterOption::ByContentAPI, ValueSetterOption::SetValueChanged,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
@ -2246,9 +2242,9 @@ void HTMLInputElement::SetUserInput(const nsAString& aValue,
|
||||
GetValueMode() == VALUE_MODE_VALUE && IsSingleLineTextControl(false);
|
||||
|
||||
nsresult rv = SetValueInternal(
|
||||
aValue, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
aValue,
|
||||
{ValueSetterOption::BySetUserInputAPI, ValueSetterOption::SetValueChanged,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
if (!isInputEventDispatchedByTextControlState) {
|
||||
@ -2335,22 +2331,6 @@ nsresult HTMLInputElement::CreateEditor() {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void HTMLInputElement::UpdateOverlayTextVisibility(bool aNotify) {
|
||||
TextControlState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->UpdateOverlayTextVisibility(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
bool HTMLInputElement::GetPlaceholderVisibility() {
|
||||
TextControlState* state = GetEditorState();
|
||||
if (!state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return state->GetPlaceholderVisibility();
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetPreviewValue(const nsAString& aValue) {
|
||||
TextControlState* state = GetEditorState();
|
||||
if (state) {
|
||||
@ -2378,15 +2358,6 @@ void HTMLInputElement::EnablePreview() {
|
||||
|
||||
bool HTMLInputElement::IsPreviewEnabled() { return mIsPreviewEnabled; }
|
||||
|
||||
bool HTMLInputElement::GetPreviewVisibility() {
|
||||
TextControlState* state = GetEditorState();
|
||||
if (!state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return state->GetPreviewVisibility();
|
||||
}
|
||||
|
||||
void HTMLInputElement::GetDisplayFileName(nsAString& aValue) const {
|
||||
MOZ_ASSERT(mFileData);
|
||||
|
||||
@ -2667,8 +2638,8 @@ nsresult HTMLInputElement::SetValueInternal(
|
||||
}
|
||||
// else DoneCreatingElement calls us again once mDoneCreating is true
|
||||
|
||||
const bool setValueChanged = aOptions.contains(
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame);
|
||||
const bool setValueChanged =
|
||||
aOptions.contains(ValueSetterOption::SetValueChanged);
|
||||
if (setValueChanged) {
|
||||
SetValueChanged(true);
|
||||
}
|
||||
@ -3381,10 +3352,8 @@ void HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent) {
|
||||
mInputType->ConvertNumberToString(mRangeThumbDragStartValue, val);
|
||||
// TODO: What should we do if SetValueInternal fails? (The allocation
|
||||
// is small, so we should be fine here.)
|
||||
SetValueInternal(
|
||||
val,
|
||||
{ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame});
|
||||
SetValueInternal(val, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
frame->UpdateForValueChange();
|
||||
@ -3404,9 +3373,8 @@ void HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue) {
|
||||
mInputType->ConvertNumberToString(aValue, val);
|
||||
// TODO: What should we do if SetValueInternal fails? (The allocation
|
||||
// is small, so we should be fine here.)
|
||||
SetValueInternal(
|
||||
val, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame});
|
||||
SetValueInternal(val, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
frame->UpdateForValueChange();
|
||||
@ -3496,10 +3464,8 @@ void HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection) {
|
||||
mInputType->ConvertNumberToString(newValue, newVal);
|
||||
// TODO: What should we do if SetValueInternal fails? (The allocation
|
||||
// is small, so we should be fine here.)
|
||||
SetValueInternal(
|
||||
newVal,
|
||||
{ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame});
|
||||
SetValueInternal(newVal, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
}
|
||||
|
||||
static bool SelectTextFieldOnFocus() {
|
||||
@ -5452,10 +5418,8 @@ void HTMLInputElement::GetValueFromSetRangeText(nsAString& aValue) {
|
||||
}
|
||||
|
||||
nsresult HTMLInputElement::SetValueFromSetRangeText(const nsAString& aValue) {
|
||||
return SetValueInternal(
|
||||
aValue,
|
||||
{ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame});
|
||||
return SetValueInternal(aValue, {ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
}
|
||||
|
||||
Nullable<uint32_t> HTMLInputElement::GetSelectionStart(ErrorResult& aRv) {
|
||||
@ -6040,9 +6004,8 @@ bool HTMLInputElement::RestoreState(PresState* aState) {
|
||||
// TODO: What should we do if SetValueInternal fails? (The allocation
|
||||
// may potentially be big, but most likely we've failed to allocate
|
||||
// before the type change.)
|
||||
SetValueInternal(
|
||||
inputState.get_TextContentData().value(),
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame);
|
||||
SetValueInternal(inputState.get_TextContentData().value(),
|
||||
ValueSetterOption::SetValueChanged);
|
||||
if (inputState.get_TextContentData().lastValueChangeWasInteractive()) {
|
||||
mLastValueChangeWasInteractive = true;
|
||||
UpdateState(true);
|
||||
|
@ -224,13 +224,10 @@ class HTMLInputElement final : public TextControlElement,
|
||||
MOZ_CAN_RUN_SCRIPT virtual void UnbindFromFrame(
|
||||
nsTextControlFrame* aFrame) override;
|
||||
MOZ_CAN_RUN_SCRIPT virtual nsresult CreateEditor() override;
|
||||
virtual void UpdateOverlayTextVisibility(bool aNotify) override;
|
||||
virtual void SetPreviewValue(const nsAString& aValue) override;
|
||||
virtual void GetPreviewValue(nsAString& aValue) override;
|
||||
virtual void EnablePreview() override;
|
||||
virtual bool IsPreviewEnabled() override;
|
||||
virtual bool GetPlaceholderVisibility() override;
|
||||
virtual bool GetPreviewVisibility() override;
|
||||
virtual void InitializeKeyboardEventListeners() override;
|
||||
virtual void OnValueChanged(ValueChangeKind) override;
|
||||
virtual void GetValueFromSetRangeText(nsAString& aValue) override;
|
||||
|
@ -120,10 +120,9 @@ nsresult HTMLTextAreaElement::Clone(dom::NodeInfo* aNodeInfo,
|
||||
GetValueInternal(value, true);
|
||||
|
||||
// SetValueInternal handles setting mValueChanged for us
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
rv = it->SetValueInternal(
|
||||
value, ValueSetterOption::
|
||||
UpdateOverlayTextVisibilityAndInvalidateFrame)))) {
|
||||
if (NS_WARN_IF(
|
||||
NS_FAILED(rv = it->SetValueInternal(
|
||||
value, {ValueSetterOption::SetValueChanged})))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -236,16 +235,6 @@ nsresult HTMLTextAreaElement::CreateEditor() {
|
||||
return mState->PrepareEditor();
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::UpdateOverlayTextVisibility(bool aNotify) {
|
||||
MOZ_ASSERT(mState);
|
||||
mState->UpdateOverlayTextVisibility(aNotify);
|
||||
}
|
||||
|
||||
bool HTMLTextAreaElement::GetPlaceholderVisibility() {
|
||||
MOZ_ASSERT(mState);
|
||||
return mState->GetPlaceholderVisibility();
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::SetPreviewValue(const nsAString& aValue) {
|
||||
MOZ_ASSERT(mState);
|
||||
mState->SetPreviewText(aValue, true);
|
||||
@ -269,21 +258,14 @@ void HTMLTextAreaElement::EnablePreview() {
|
||||
|
||||
bool HTMLTextAreaElement::IsPreviewEnabled() { return mIsPreviewEnabled; }
|
||||
|
||||
bool HTMLTextAreaElement::GetPreviewVisibility() {
|
||||
MOZ_ASSERT(mState);
|
||||
return mState->GetPreviewVisibility();
|
||||
}
|
||||
|
||||
nsresult HTMLTextAreaElement::SetValueInternal(
|
||||
const nsAString& aValue, const ValueSetterOptions& aOptions) {
|
||||
MOZ_ASSERT(mState);
|
||||
|
||||
// Need to set the value changed flag here if our value has in fact changed
|
||||
// (i.e. if ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame
|
||||
// is in aOptions), so that nsTextControlFrame::UpdateValueDisplay retrieves
|
||||
// the correct value if needed.
|
||||
if (aOptions.contains(
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame)) {
|
||||
// (i.e. if ValueSetterOption::SetValueChanged is in aOptions), so that
|
||||
// retrieves the correct value if needed.
|
||||
if (aOptions.contains(ValueSetterOption::SetValueChanged)) {
|
||||
SetValueChanged(true);
|
||||
}
|
||||
|
||||
@ -307,9 +289,9 @@ void HTMLTextAreaElement::SetValue(const nsAString& aValue,
|
||||
GetValueInternal(currentValue, true);
|
||||
|
||||
nsresult rv = SetValueInternal(
|
||||
aValue, {ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
aValue,
|
||||
{ValueSetterOption::ByContentAPI, ValueSetterOption::SetValueChanged,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aError.Throw(rv);
|
||||
return;
|
||||
@ -322,10 +304,9 @@ void HTMLTextAreaElement::SetValue(const nsAString& aValue,
|
||||
|
||||
void HTMLTextAreaElement::SetUserInput(const nsAString& aValue,
|
||||
nsIPrincipal& aSubjectPrincipal) {
|
||||
SetValueInternal(
|
||||
aValue, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
SetValueInternal(aValue, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged,
|
||||
ValueSetterOption::MoveCursorToEndIfValueChanged});
|
||||
}
|
||||
|
||||
nsresult HTMLTextAreaElement::SetValueChanged(bool aValueChanged) {
|
||||
@ -660,10 +641,8 @@ void HTMLTextAreaElement::GetValueFromSetRangeText(nsAString& aValue) {
|
||||
|
||||
nsresult HTMLTextAreaElement::SetValueFromSetRangeText(
|
||||
const nsAString& aValue) {
|
||||
return SetValueInternal(
|
||||
aValue,
|
||||
{ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame});
|
||||
return SetValueInternal(aValue, {ValueSetterOption::ByContentAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
}
|
||||
|
||||
nsresult HTMLTextAreaElement::Reset() {
|
||||
|
@ -91,9 +91,6 @@ class HTMLTextAreaElement final : public TextControlElement,
|
||||
MOZ_CAN_RUN_SCRIPT virtual void UnbindFromFrame(
|
||||
nsTextControlFrame* aFrame) override;
|
||||
MOZ_CAN_RUN_SCRIPT virtual nsresult CreateEditor() override;
|
||||
virtual void UpdateOverlayTextVisibility(bool aNotify) override;
|
||||
virtual bool GetPlaceholderVisibility() override;
|
||||
virtual bool GetPreviewVisibility() override;
|
||||
virtual void SetPreviewValue(const nsAString& aValue) override;
|
||||
virtual void GetPreviewValue(nsAString& aValue) override;
|
||||
virtual void EnablePreview() override;
|
||||
|
@ -174,22 +174,6 @@ class TextControlElement : public nsGenericHTMLFormElementWithState {
|
||||
*/
|
||||
virtual void InitializeKeyboardEventListeners() = 0;
|
||||
|
||||
/**
|
||||
* Update the visibility of both the placholder and preview text based on the
|
||||
* element's state.
|
||||
*/
|
||||
virtual void UpdateOverlayTextVisibility(bool aNotify) = 0;
|
||||
|
||||
/**
|
||||
* Returns the current expected placeholder visibility state.
|
||||
*/
|
||||
virtual bool GetPlaceholderVisibility() = 0;
|
||||
|
||||
/**
|
||||
* Returns the current expected preview visibility state.
|
||||
*/
|
||||
virtual bool GetPreviewVisibility() = 0;
|
||||
|
||||
enum class ValueChangeKind {
|
||||
Internal,
|
||||
Script,
|
||||
|
@ -1017,12 +1017,10 @@ TextInputListener::HandleEvent(Event* aEvent) {
|
||||
|
||||
nsresult TextInputListener::OnEditActionHandled(TextEditor& aTextEditor) {
|
||||
if (mFrame) {
|
||||
// XXX Do we still need this or can we just remove the mFrame and
|
||||
// frame.IsAlive() conditions below?
|
||||
AutoWeakFrame weakFrame = mFrame;
|
||||
|
||||
nsITextControlFrame* frameBase = do_QueryFrame(mFrame);
|
||||
nsTextControlFrame* frame = static_cast<nsTextControlFrame*>(frameBase);
|
||||
NS_ASSERTION(frame, "Where is our frame?");
|
||||
//
|
||||
// Update the undo / redo menus
|
||||
//
|
||||
size_t numUndoItems = aTextEditor.NumberOfUndoItems();
|
||||
@ -1037,23 +1035,18 @@ nsresult TextInputListener::OnEditActionHandled(TextEditor& aTextEditor) {
|
||||
}
|
||||
|
||||
if (weakFrame.IsAlive()) {
|
||||
HandleValueChanged(frame);
|
||||
HandleValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
return mTextControlState ? mTextControlState->OnEditActionHandled() : NS_OK;
|
||||
}
|
||||
|
||||
void TextInputListener::HandleValueChanged(nsTextControlFrame* aFrame) {
|
||||
void TextInputListener::HandleValueChanged() {
|
||||
// Make sure we know we were changed (do NOT set this to false if there are
|
||||
// no undo items; JS could change the value and we'd still need to save it)
|
||||
if (mSetValueChanged) {
|
||||
if (!aFrame) {
|
||||
nsITextControlFrame* frameBase = do_QueryFrame(mFrame);
|
||||
aFrame = static_cast<nsTextControlFrame*>(frameBase);
|
||||
NS_ASSERTION(aFrame, "Where is our frame?");
|
||||
}
|
||||
aFrame->SetValueChanged(true);
|
||||
mTxtCtrlElement->SetValueChanged(true);
|
||||
}
|
||||
|
||||
if (!mSettingValue) {
|
||||
@ -1223,8 +1216,8 @@ class MOZ_STACK_CLASS AutoTextControlHandlingState {
|
||||
// mTextInputListener by ourselves since TextEditor users special path
|
||||
// for the performance.
|
||||
mTextInputListener->SettingValue(true);
|
||||
mTextInputListener->SetValueChanged(mValueSetterOptions.contains(
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame));
|
||||
mTextInputListener->SetValueChanged(
|
||||
mValueSetterOptions.contains(ValueSetterOption::SetValueChanged));
|
||||
mEditActionHandled = false;
|
||||
// Even if falling back to `TextControlState::SetValueWithoutTextEditor()`
|
||||
// due to editor destruction, it shouldn't dispatch "beforeinput" event
|
||||
@ -1255,13 +1248,6 @@ class MOZ_STACK_CLASS AutoTextControlHandlingState {
|
||||
mTextInputListener->SetValueChanged(true);
|
||||
mTextInputListener->SettingValue(
|
||||
mParent && mParent->IsHandling(TextControlAction::SetValue));
|
||||
if (!mValueSetterOptions.contains(
|
||||
ValueSetterOption::
|
||||
UpdateOverlayTextVisibilityAndInvalidateFrame)) {
|
||||
// Listener doesn't update frame, but it is required for
|
||||
// placeholder
|
||||
mTextControlState.ValueWasChanged();
|
||||
}
|
||||
}
|
||||
if (!IsOriginalTextControlFrameAlive()) {
|
||||
return SetValueWithoutTextEditorAgain() ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -1291,15 +1277,13 @@ class MOZ_STACK_CLASS AutoTextControlHandlingState {
|
||||
return true;
|
||||
}
|
||||
// XXX It's odd to drop flags except
|
||||
// ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame.
|
||||
// ValueSetterOption::SetValueChanged.
|
||||
// Probably, this intended to drop ValueSetterOption::BySetUserInputAPI
|
||||
// and ValueSetterOption::ByContentAPI, but other flags are added later.
|
||||
ErrorResult error;
|
||||
AutoTextControlHandlingState handlingSetValueWithoutEditor(
|
||||
mTextControlState, TextControlAction::SetValue, mSettingValue,
|
||||
mOldValue,
|
||||
mValueSetterOptions &
|
||||
ValueSetterOption::UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
mOldValue, mValueSetterOptions & ValueSetterOption::SetValueChanged,
|
||||
error);
|
||||
if (error.Failed()) {
|
||||
MOZ_ASSERT(error.ErrorCodeIs(NS_ERROR_OUT_OF_MEMORY));
|
||||
@ -1402,9 +1386,7 @@ TextControlState::TextControlState(TextControlElement* aOwningElement)
|
||||
mEverInited(false),
|
||||
mEditorInitialized(false),
|
||||
mValueTransferInProgress(false),
|
||||
mSelectionCached(true),
|
||||
mPlaceholderVisibility(false),
|
||||
mPreviewVisibility(false)
|
||||
mSelectionCached(true)
|
||||
// When adding more member variable initializations here, add the same
|
||||
// also to ::Construct.
|
||||
{
|
||||
@ -1424,8 +1406,6 @@ TextControlState* TextControlState::Construct(
|
||||
state->mEditorInitialized = false;
|
||||
state->mValueTransferInProgress = false;
|
||||
state->mSelectionCached = true;
|
||||
state->mPlaceholderVisibility = false;
|
||||
state->mPreviewVisibility = false;
|
||||
// When adding more member variable initializations here, add the same
|
||||
// also to the constructor.
|
||||
return state;
|
||||
@ -2850,8 +2830,8 @@ bool TextControlState::SetValueWithoutTextEditor(
|
||||
mValue.emplace();
|
||||
}
|
||||
|
||||
// We can't just early-return here, because ValueWasChanged and
|
||||
// OnValueChanged below still need to be called.
|
||||
// We can't just early-return here, because OnValueChanged below still need to
|
||||
// be called.
|
||||
if (!mValue->Equals(aHandlingSetValue.GetSettingValue()) ||
|
||||
!StaticPrefs::dom_input_skip_cursor_move_for_same_value_set()) {
|
||||
bool handleSettingValue = true;
|
||||
@ -2979,7 +2959,6 @@ bool TextControlState::SetValueWithoutTextEditor(
|
||||
}
|
||||
}
|
||||
|
||||
ValueWasChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3013,8 +2992,6 @@ void TextControlState::InitializeKeyboardEventListeners() {
|
||||
mSelCon->SetScrollableFrame(mBoundFrame->GetScrollTargetFrame());
|
||||
}
|
||||
|
||||
void TextControlState::ValueWasChanged() { UpdateOverlayTextVisibility(true); }
|
||||
|
||||
void TextControlState::SetPreviewText(const nsAString& aValue, bool aNotify) {
|
||||
// If we don't have a preview div, there's nothing to do.
|
||||
Element* previewDiv = GetPreviewNode();
|
||||
@ -3027,8 +3004,6 @@ void TextControlState::SetPreviewText(const nsAString& aValue, bool aNotify) {
|
||||
nsContentUtils::RemoveNewlines(previewValue);
|
||||
MOZ_ASSERT(previewDiv->GetFirstChild(), "preview div has no child");
|
||||
previewDiv->GetFirstChild()->AsText()->SetText(previewValue, aNotify);
|
||||
|
||||
UpdateOverlayTextVisibility(aNotify);
|
||||
}
|
||||
|
||||
void TextControlState::GetPreviewText(nsAString& aValue) {
|
||||
@ -3045,24 +3020,6 @@ void TextControlState::GetPreviewText(nsAString& aValue) {
|
||||
text->AppendTo(aValue);
|
||||
}
|
||||
|
||||
void TextControlState::UpdateOverlayTextVisibility(bool aNotify) {
|
||||
nsAutoString value, previewValue;
|
||||
bool valueIsEmpty = !HasNonEmptyValue();
|
||||
GetPreviewText(previewValue);
|
||||
|
||||
mPreviewVisibility = valueIsEmpty && !previewValue.IsEmpty();
|
||||
mPlaceholderVisibility = valueIsEmpty && previewValue.IsEmpty();
|
||||
|
||||
if (mPlaceholderVisibility && !StaticPrefs::dom_placeholder_show_on_focus()) {
|
||||
mPlaceholderVisibility =
|
||||
!nsContentUtils::IsFocusedContent(mTextCtrlElement);
|
||||
}
|
||||
|
||||
if (mBoundFrame && aNotify) {
|
||||
mBoundFrame->InvalidateFrame();
|
||||
}
|
||||
}
|
||||
|
||||
bool TextControlState::EditorHasComposition() {
|
||||
return mTextEditor && mTextEditor->IsIMEComposing();
|
||||
}
|
||||
|
@ -183,8 +183,9 @@ class TextControlState final : public SupportsWeakPtr {
|
||||
// The value is changed by changing value attribute of the element or
|
||||
// something like setRangeText().
|
||||
ByContentAPI,
|
||||
// Whether the value change should be notified to the frame/contet nor not.
|
||||
UpdateOverlayTextVisibilityAndInvalidateFrame,
|
||||
// Whether SetValueChanged should be called as a result of this value
|
||||
// change.
|
||||
SetValueChanged,
|
||||
// Whether to move the cursor to end of the value (in the case when we have
|
||||
// cached selection offsets), in the case when the value has changed. If
|
||||
// this is not set and MoveCursorToBeginSetSelectionDirectionForward
|
||||
@ -266,15 +267,9 @@ class TextControlState final : public SupportsWeakPtr {
|
||||
}
|
||||
int32_t GetRows() { return mTextCtrlElement->GetRows(); }
|
||||
|
||||
void UpdateOverlayTextVisibility(bool aNotify);
|
||||
|
||||
// placeholder methods
|
||||
bool GetPlaceholderVisibility() { return mPlaceholderVisibility; }
|
||||
|
||||
// preview methods
|
||||
void SetPreviewText(const nsAString& aValue, bool aNotify);
|
||||
void GetPreviewText(nsAString& aValue);
|
||||
bool GetPreviewVisibility() { return mPreviewVisibility; }
|
||||
|
||||
struct SelectionProperties {
|
||||
public:
|
||||
@ -416,8 +411,6 @@ class TextControlState final : public SupportsWeakPtr {
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void UnlinkInternal();
|
||||
|
||||
void ValueWasChanged();
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void DestroyEditor();
|
||||
MOZ_CAN_RUN_SCRIPT void Clear();
|
||||
|
||||
@ -473,8 +466,6 @@ class TextControlState final : public SupportsWeakPtr {
|
||||
bool mValueTransferInProgress; // Whether a value is being transferred to the
|
||||
// frame
|
||||
bool mSelectionCached; // Whether mSelectionProperties is valid
|
||||
bool mPlaceholderVisibility;
|
||||
bool mPreviewVisibility;
|
||||
|
||||
/**
|
||||
* For avoiding allocation cost of the instance, we should reuse instances
|
||||
|
@ -19,6 +19,7 @@ class nsTextControlFrame;
|
||||
namespace mozilla {
|
||||
class TextControlElement;
|
||||
class TextControlState;
|
||||
class TextEditor;
|
||||
|
||||
namespace dom {
|
||||
class Selection;
|
||||
@ -39,7 +40,7 @@ class TextInputListener final : public nsIDOMEventListener,
|
||||
* aFrame is an optional pointer to our frame, if not passed the method will
|
||||
* use mFrame to compute it lazily.
|
||||
*/
|
||||
void HandleValueChanged(nsTextControlFrame* aFrame = nullptr);
|
||||
void HandleValueChanged();
|
||||
|
||||
/**
|
||||
* OnEditActionHandled() is called when the editor handles each edit action.
|
||||
|
@ -13,11 +13,13 @@
|
||||
#include "nsIEditor.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
@ -406,12 +408,6 @@ nsresult nsTextControlFrame::CreateAnonymousContent(
|
||||
aElements.AppendElement(mRootNode);
|
||||
CreatePlaceholderIfNeeded();
|
||||
if (mPlaceholderDiv) {
|
||||
if (!IsSingleLineTextControl()) {
|
||||
// For textareas, UpdateValueDisplay doesn't initialize the visibility
|
||||
// status of the placeholder because it returns early, so we have to
|
||||
// do that manually here.
|
||||
textControlElement->UpdateOverlayTextVisibility(true);
|
||||
}
|
||||
aElements.AppendElement(mPlaceholderDiv);
|
||||
}
|
||||
CreatePreviewIfNeeded();
|
||||
@ -738,10 +734,6 @@ void nsTextControlFrame::SetFocus(bool aOn, bool aRepaint) {
|
||||
|
||||
// If 'dom.placeholeder.show_on_focus' preference is 'false', focusing or
|
||||
// blurring the frame can have an impact on the placeholder visibility.
|
||||
if (mPlaceholderDiv) {
|
||||
textControlElement->UpdateOverlayTextVisibility(true);
|
||||
}
|
||||
|
||||
if (!aOn) {
|
||||
return;
|
||||
}
|
||||
@ -1159,21 +1151,6 @@ void nsTextControlFrame::SetInitialChildList(ChildListID aListID,
|
||||
}
|
||||
}
|
||||
|
||||
void nsTextControlFrame::SetValueChanged(bool aValueChanged) {
|
||||
auto* textControlElement = TextControlElement::FromNode(GetContent());
|
||||
MOZ_ASSERT(textControlElement);
|
||||
|
||||
if (mPlaceholderDiv) {
|
||||
AutoWeakFrame weakFrame(this);
|
||||
textControlElement->UpdateOverlayTextVisibility(true);
|
||||
if (!weakFrame.IsAlive()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
textControlElement->SetValueChanged(aValueChanged);
|
||||
}
|
||||
|
||||
nsresult nsTextControlFrame::UpdateValueDisplay(bool aNotify,
|
||||
bool aBeforeEditorInit,
|
||||
const nsAString* aValue) {
|
||||
@ -1218,12 +1195,6 @@ nsresult nsTextControlFrame::UpdateValueDisplay(bool aNotify,
|
||||
// Update the display of the placeholder value and preview text if needed.
|
||||
// We don't need to do this if we're about to initialize the editor, since
|
||||
// EnsureEditorInitialized takes care of this.
|
||||
if ((mPlaceholderDiv || mPreviewDiv) && !aBeforeEditorInit) {
|
||||
AutoWeakFrame weakFrame(this);
|
||||
textControlElement->UpdateOverlayTextVisibility(aNotify);
|
||||
NS_ENSURE_STATE(weakFrame.IsAlive());
|
||||
}
|
||||
|
||||
if (aBeforeEditorInit && value.IsEmpty()) {
|
||||
if (nsIContent* node = mRootNode->GetFirstChild()) {
|
||||
mRootNode->RemoveChildNode(node, true);
|
||||
@ -1295,9 +1266,6 @@ void nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
*/
|
||||
DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame");
|
||||
|
||||
auto* control = TextControlElement::FromNode(GetContent());
|
||||
MOZ_ASSERT(control);
|
||||
|
||||
DisplayBorderBackgroundOutline(aBuilder, aLists);
|
||||
|
||||
// Redirect all lists to the Content list so that nothing can escape, ie
|
||||
@ -1306,44 +1274,19 @@ void nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* content = aLists.Content();
|
||||
nsDisplayListSet set(content, content, content, content, content, content);
|
||||
|
||||
// Clip the placeholder and preview text to the root box, so that it doesn't,
|
||||
// e.g., overlay with our <input type="number"> spin buttons.
|
||||
//
|
||||
// For other input types, this will be a noop since we size the root via
|
||||
// ReflowTextControlChild, which sets the same available space for all
|
||||
// children.
|
||||
auto clipToRoot = [&](Maybe<DisplayListClipState::AutoSaveRestore>& aClip) {
|
||||
if (mRootNode) {
|
||||
if (auto* root = mRootNode->GetPrimaryFrame()) {
|
||||
aClip.emplace(aBuilder);
|
||||
nsRect rootBox(aBuilder->ToReferenceFrame(root), root->GetSize());
|
||||
aClip->ClipContentDescendants(rootBox);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We build the ::placeholder first so that it renders below mRootNode which
|
||||
// draws the caret and we always want that on top (bug 1637476).
|
||||
if (mPlaceholderDiv && control->GetPlaceholderVisibility() &&
|
||||
mPlaceholderDiv->GetPrimaryFrame()) {
|
||||
Maybe<DisplayListClipState::AutoSaveRestore> overlayTextClip;
|
||||
clipToRoot(overlayTextClip);
|
||||
//
|
||||
// TODO(emilio): We should consider just changing the DOM order instead.
|
||||
if (mPlaceholderDiv && mPlaceholderDiv->GetPrimaryFrame()) {
|
||||
auto* kid = mPlaceholderDiv->GetPrimaryFrame();
|
||||
MOZ_ASSERT(kid->GetParent() == this);
|
||||
BuildDisplayListForChild(aBuilder, kid, set);
|
||||
}
|
||||
|
||||
for (auto* kid : mFrames) {
|
||||
nsIContent* kidContent = kid->GetContent();
|
||||
Maybe<DisplayListClipState::AutoSaveRestore> overlayTextClip;
|
||||
if (kidContent == mPlaceholderDiv) {
|
||||
continue; // we handled mPlaceholderDiv explicitly above
|
||||
}
|
||||
if (kidContent == mPreviewDiv && !control->GetPreviewVisibility()) {
|
||||
continue;
|
||||
}
|
||||
if (kidContent == mPreviewDiv) {
|
||||
clipToRoot(overlayTextClip);
|
||||
if (kid->GetContent() == mPlaceholderDiv) {
|
||||
continue; // Handled above already.
|
||||
}
|
||||
BuildDisplayListForChild(aBuilder, kid, set);
|
||||
}
|
||||
|
@ -207,9 +207,7 @@ class nsTextControlFrame : public nsContainerFrame,
|
||||
|
||||
void ComputeBaseline(const ReflowInput&, ReflowOutput&);
|
||||
|
||||
public: // for methods who access nsTextControlFrame directly
|
||||
void SetValueChanged(bool aValueChanged);
|
||||
|
||||
public:
|
||||
Element* GetRootNode() const { return mRootNode; }
|
||||
|
||||
Element* GetPreviewNode() const { return mPreviewDiv; }
|
||||
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<link rel='stylesheet' type='text/css' href='placeholder-style.css'>
|
||||
<!-- Test: when focused, element should not placeholder when
|
||||
'dom.placeholder.show_on_focus' pref is false. -->
|
||||
<script type="text/javascript">
|
||||
function focusPlaceholder()
|
||||
{
|
||||
document.getElementById('p1').focus();
|
||||
}
|
||||
function disableReftestWait()
|
||||
{
|
||||
document.documentElement.className = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<body onload="focusPlaceholder();">
|
||||
<input type="text" id="p1" value="" placeholder="my placeholder" onfocus="disableReftestWait();">
|
||||
</body>
|
||||
</html>
|
@ -34,4 +34,3 @@ needs-focus == placeholder-10.html placeholder-visible-ref.html
|
||||
needs-focus == placeholder-21.html placeholder-blank-ref.html
|
||||
needs-focus == placeholder-22.html placeholder-blank-ref.html
|
||||
== placeholder-rtl.html placeholder-rtl-ref.html
|
||||
pref(dom.placeholder.show_on_focus,false) needs-focus == placeholder-focus-pref.html placeholder-blank-ref.html
|
||||
|
@ -155,6 +155,13 @@ textarea > scrollbar {
|
||||
scrollbar-width: inherit;
|
||||
-moz-control-character-visibility: visible;
|
||||
overflow-clip-box: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
::-moz-text-control-editing-root,
|
||||
:placeholder-shown:not(:autofill)::placeholder,
|
||||
:autofill::-moz-text-control-preview {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
input::-moz-text-control-editing-root,
|
||||
|
@ -2447,12 +2447,6 @@
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Whether we should show the placeholder when the element is focused but empty.
|
||||
- name: dom.placeholder.show_on_focus
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Is support for Element.requestPointerLock enabled?
|
||||
# This is added for accessibility purpose. When user has no way to exit
|
||||
# pointer lock (e.g. no keyboard available), they can use this pref to
|
||||
|
Loading…
Reference in New Issue
Block a user