зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1644366 - Restore behavior of selection into view to keep scrolling ancestors on focus. r=smaug
... yet keep respecting the preventScroll flag. Differential Revision: https://phabricator.services.mozilla.com/D78900
This commit is contained in:
Родитель
4af6525e90
Коммит
bbf8acf349
|
@ -24,6 +24,7 @@
|
|||
#include "nsCaret.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIAppWindow.h"
|
||||
#include "nsTextControlFrame.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsFrameSelection.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
|
@ -2675,6 +2676,15 @@ void nsFocusManager::ScrollIntoView(PresShell* aPresShell, nsIContent* aContent,
|
|||
aContent, ScrollAxis(kScrollMinimum, WhenToScroll::IfNotVisible),
|
||||
ScrollAxis(kScrollMinimum, WhenToScroll::IfNotVisible),
|
||||
ScrollFlags::ScrollOverflowHidden);
|
||||
// Scroll the input / textarea selection into view, unless focused with the
|
||||
// mouse, see bug 572649.
|
||||
if (aFlags & FLAG_BYMOUSE) {
|
||||
return;
|
||||
}
|
||||
// ScrollContentIntoView flushes layout, so no need to flush again here.
|
||||
if (nsTextControlFrame* tf = do_QueryFrame(aContent->GetPrimaryFrame())) {
|
||||
tf->ScrollSelectionIntoViewAsync(nsTextControlFrame::ScrollAncestors::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow,
|
||||
|
|
|
@ -57,6 +57,7 @@ nsIFrame* NS_NewTextControlFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
|
|||
NS_IMPL_FRAMEARENA_HELPERS(nsTextControlFrame)
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsTextControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsTextControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_ENTRY(nsITextControlFrame)
|
||||
|
@ -714,26 +715,7 @@ void nsTextControlFrame::SetFocus(bool aOn, bool aRepaint) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Scroll the current selection into view
|
||||
Selection* caretSelection = caret->GetSelection();
|
||||
const bool isFocusedRightNow = ourSel == caretSelection;
|
||||
if (!isFocusedRightNow) {
|
||||
// Don't scroll the current selection if we've been focused using the mouse.
|
||||
uint32_t lastFocusMethod = 0;
|
||||
Document* doc = GetContent()->GetComposedDoc();
|
||||
if (doc) {
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
fm->GetLastFocusMethod(doc->GetWindow(), &lastFocusMethod);
|
||||
}
|
||||
}
|
||||
if (!(lastFocusMethod & nsIFocusManager::FLAG_BYMOUSE)) {
|
||||
// NOTE(emilio): This is asynchronous, so it can't cause havoc.
|
||||
ScrollSelectionIntoViewAsync();
|
||||
}
|
||||
}
|
||||
|
||||
// tell the caret to use our selection
|
||||
// Tell the caret to use our selection
|
||||
caret->SetSelection(ourSel);
|
||||
|
||||
// mutual-exclusion: the selection is either controlled by the
|
||||
|
@ -843,18 +825,23 @@ nsresult nsTextControlFrame::SetSelectionInternal(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsTextControlFrame::ScrollSelectionIntoViewAsync() {
|
||||
void nsTextControlFrame::ScrollSelectionIntoViewAsync(
|
||||
ScrollAncestors aScrollAncestors) {
|
||||
auto* textControlElement = TextControlElement::FromNode(GetContent());
|
||||
MOZ_ASSERT(textControlElement);
|
||||
nsISelectionController* selCon = textControlElement->GetSelectionController();
|
||||
if (!selCon) {
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t flags = aScrollAncestors == ScrollAncestors::Yes
|
||||
? 0
|
||||
: nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY;
|
||||
|
||||
// Scroll the selection into view (see bug 231389).
|
||||
selCon->ScrollSelectionIntoView(
|
||||
nsISelectionController::SELECTION_NORMAL,
|
||||
nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY);
|
||||
nsISelectionController::SELECTION_FOCUS_REGION, flags);
|
||||
}
|
||||
|
||||
nsresult nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect) {
|
||||
|
|
|
@ -188,6 +188,11 @@ class nsTextControlFrame : public nsContainerFrame,
|
|||
|
||||
NS_DECL_QUERYFRAME
|
||||
|
||||
// Whether we should scroll only the current selection into view in the inner
|
||||
// scroller, or also ancestors as needed.
|
||||
enum class ScrollAncestors { No, Yes };
|
||||
void ScrollSelectionIntoViewAsync(ScrollAncestors = ScrollAncestors::No);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Launch the reflow on the child frames - see nsTextControlFrame::Reflow()
|
||||
|
@ -290,8 +295,6 @@ class nsTextControlFrame : public nsContainerFrame,
|
|||
mozilla::WritingMode aWM,
|
||||
float aFontSizeInflation) const;
|
||||
|
||||
void ScrollSelectionIntoViewAsync();
|
||||
|
||||
private:
|
||||
// helper methods
|
||||
MOZ_CAN_RUN_SCRIPT nsresult SetSelectionInternal(
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<!doctype html>
|
||||
<title>programatic focus() scrolls selection into view including ancestors</title>
|
||||
<link rel="author" href="https://mozilla.org" title="Mozilla">
|
||||
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1644366">
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<div style="overflow: auto; height: 100px">
|
||||
<textarea style="overflow: hidden; height: 200px">
|
||||
Some text
|
||||
That is surely more
|
||||
Than 100px tall
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
For sure.
|
||||
</textarea>
|
||||
</div>
|
||||
<script>
|
||||
promise_test(async function(t) {
|
||||
await new Promise(resolve => window.addEventListener("load", resolve));
|
||||
let textarea = document.querySelector("textarea");
|
||||
textarea.setSelectionRange(textarea.value.length, textarea.value.length);
|
||||
textarea.focus();
|
||||
|
||||
await new Promise(resolve => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(resolve));
|
||||
});
|
||||
|
||||
assert_not_equals(textarea.parentNode.scrollTop, 0, "Should've scrolled ancestor to show the selection");
|
||||
});
|
||||
</script>
|
Загрузка…
Ссылка в новой задаче