mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1920647 - part 1: Make HTMLEditor
won't show Gecko specific editing UI in contenteditable=plaintext-only
r=m_kato
Depends on D223277 Differential Revision: https://phabricator.services.mozilla.com/D223669
This commit is contained in:
parent
d47496686e
commit
ef73f35608
@ -135,6 +135,12 @@ NS_IMETHODIMP HTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HTMLEditor::GetIsAbsolutePositioningActive(bool* aIsActive) {
|
||||
MOZ_ASSERT(aIsActive);
|
||||
*aIsActive = !!mAbsolutelyPositionedObject;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Result<int32_t, nsresult> HTMLEditor::AddZIndexWithTransaction(
|
||||
nsStyledElement& aStyledElement, int32_t aChange) {
|
||||
if (!aChange) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/PresShellInlines.h"
|
||||
#include "mozilla/dom/BindContext.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsAString.h"
|
||||
@ -292,31 +293,44 @@ void HTMLEditor::HideAnonymousEditingUIs() {
|
||||
void HTMLEditor::HideAnonymousEditingUIsIfUnnecessary() {
|
||||
// XXX Perhaps, this is wrong approach to hide multiple UIs because
|
||||
// hiding one UI may causes overwriting existing UI with newly
|
||||
// created one. In such case, we will leak ovewritten UI.
|
||||
if (!IsAbsolutePositionEditorEnabled() && mAbsolutelyPositionedObject) {
|
||||
// XXX If we're moving something, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideGrabberInternal();
|
||||
NS_ASSERTION(!mAbsolutelyPositionedObject,
|
||||
"HTMLEditor::HideGrabberInternal() failed, but ignored");
|
||||
// created one. In such case, we will leak overwritten UI.
|
||||
if (mAbsolutelyPositionedObject) {
|
||||
const Element* const editingHost =
|
||||
mAbsolutelyPositionedObject->GetEditingHost();
|
||||
if (!IsAbsolutePositionEditorEnabled() || !editingHost ||
|
||||
editingHost->IsContentEditablePlainTextOnly()) {
|
||||
// XXX If we're moving something, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideGrabberInternal();
|
||||
NS_ASSERTION(!mAbsolutelyPositionedObject,
|
||||
"HTMLEditor::HideGrabberInternal() failed, but ignored");
|
||||
}
|
||||
}
|
||||
if (!IsInlineTableEditorEnabled() && mInlineEditedCell) {
|
||||
// XXX If we're resizing a table element, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideInlineTableEditingUIInternal();
|
||||
NS_ASSERTION(
|
||||
!mInlineEditedCell,
|
||||
"HTMLEditor::HideInlineTableEditingUIInternal() failed, but ignored");
|
||||
if (mInlineEditedCell) {
|
||||
const Element* const editingHost = mInlineEditedCell->GetEditingHost();
|
||||
if (!IsInlineTableEditorEnabled() || !editingHost ||
|
||||
editingHost->IsContentEditablePlainTextOnly()) {
|
||||
// XXX If we're resizing a table element, we need to cancel or commit the
|
||||
// operation now.
|
||||
HideInlineTableEditingUIInternal();
|
||||
NS_ASSERTION(
|
||||
!mInlineEditedCell,
|
||||
"HTMLEditor::HideInlineTableEditingUIInternal() failed, but ignored");
|
||||
}
|
||||
}
|
||||
if (!IsObjectResizerEnabled() && mResizedObject) {
|
||||
// XXX If we're resizing something, we need to cancel or commit the
|
||||
// operation now.
|
||||
DebugOnly<nsresult> rvIgnored = HideResizersInternal();
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"HTMLEditor::HideResizersInternal() failed, but ignored");
|
||||
NS_ASSERTION(!mResizedObject,
|
||||
"HTMLEditor::HideResizersInternal() failed, but ignored");
|
||||
if (mResizedObject) {
|
||||
const Element* const editingHost = mResizedObject->GetEditingHost();
|
||||
if (!IsObjectResizerEnabled() || !editingHost ||
|
||||
editingHost->IsContentEditablePlainTextOnly()) {
|
||||
// XXX If we're resizing something, we need to cancel or commit the
|
||||
// operation now.
|
||||
DebugOnly<nsresult> rvIgnored = HideResizersInternal();
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"HTMLEditor::HideResizersInternal() failed, but ignored");
|
||||
NS_ASSERTION(!mResizedObject,
|
||||
"HTMLEditor::HideResizersInternal() failed, but ignored");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,6 +375,13 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const RefPtr<Element> editingHost =
|
||||
ComputeEditingHost(LimitInBodyElement::No);
|
||||
if (editingHost && editingHost->IsContentEditablePlainTextOnly()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(editingHost == selectionContainerElement->GetEditingHost());
|
||||
|
||||
// what's its tag?
|
||||
RefPtr<Element> focusElement = std::move(selectionContainerElement);
|
||||
nsAtom* focusTagAtom = focusElement->NodeInfo()->NameAtom();
|
||||
@ -443,11 +464,9 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||
}
|
||||
|
||||
// now, let's display all contextual UI for good
|
||||
nsIContent* hostContent = ComputeEditingHost();
|
||||
|
||||
if (IsObjectResizerEnabled() && focusElement &&
|
||||
HTMLEditUtils::IsSimplyEditableNode(*focusElement) &&
|
||||
focusElement != hostContent) {
|
||||
focusElement != editingHost) {
|
||||
if (nsGkAtoms::img == focusTagAtom) {
|
||||
mResizedObjectIsAnImage = true;
|
||||
}
|
||||
@ -468,7 +487,7 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||
|
||||
if (IsAbsolutePositionEditorEnabled() && absPosElement &&
|
||||
HTMLEditUtils::IsSimplyEditableNode(*absPosElement) &&
|
||||
absPosElement != hostContent) {
|
||||
absPosElement != editingHost) {
|
||||
if (mAbsolutelyPositionedObject) {
|
||||
nsresult rv = RefreshGrabberInternal();
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -487,7 +506,7 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||
// XXX Shouldn't we check whether the `<table>` element is editable or not?
|
||||
if (IsInlineTableEditorEnabled() && cellElement &&
|
||||
HTMLEditUtils::IsSimplyEditableNode(*cellElement) &&
|
||||
cellElement != hostContent) {
|
||||
cellElement != editingHost) {
|
||||
if (mInlineEditedCell) {
|
||||
nsresult rv = RefreshInlineTableEditingUIInternal();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -1481,6 +1481,12 @@ NS_IMETHODIMP HTMLEditor::SetObjectResizingEnabled(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HTMLEditor::GetIsObjectResizingActive(bool* aIsActive) {
|
||||
MOZ_ASSERT(aIsActive);
|
||||
*aIsActive = !!mResizedObject;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#undef kTopLeft
|
||||
#undef kTop
|
||||
#undef kTopRight
|
||||
|
@ -31,6 +31,12 @@ NS_IMETHODIMP HTMLEditor::GetInlineTableEditingEnabled(bool* aIsEnabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP HTMLEditor::GetIsInlineTableEditingActive(bool* aIsActive) {
|
||||
MOZ_ASSERT(aIsActive);
|
||||
*aIsActive = !!mInlineEditedCell;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::ShowInlineTableEditingUIInternal(Element& aCellElement) {
|
||||
if (NS_WARN_IF(!HTMLEditUtils::IsTableCell(&aCellElement))) {
|
||||
return NS_OK;
|
||||
|
@ -444,6 +444,8 @@ skip-if = ["os == 'android'"] # Needs interaction with the scrollbar
|
||||
|
||||
["test_dragend_target.html"]
|
||||
|
||||
["test_editing_UI_in_plaintext-only.html"]
|
||||
|
||||
["test_execCommandPaste_noTarget.html"]
|
||||
|
||||
["test_focus_caret_navigation_between_nested_editors.html"]
|
||||
|
@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(async () => {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.element.contenteditable.plaintext-only.enabled", true]],
|
||||
});
|
||||
function waitForTick() {
|
||||
return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
|
||||
}
|
||||
await (async () => {
|
||||
const editingHost = document.getElementById("testAbs");
|
||||
editingHost.contentEditable = "plaintext-only";
|
||||
editingHost.focus();
|
||||
document.execCommand("enableAbsolutePositionEditing", false, "true");
|
||||
const target = editingHost.querySelector("div[style]");
|
||||
synthesizeMouseAtCenter(target, {});
|
||||
await waitForTick();
|
||||
is(
|
||||
getHTMLEditor().isAbsolutePositioningActive,
|
||||
false,
|
||||
"The absolutely positioned element positioner UI should not be visible"
|
||||
);
|
||||
document.execCommand("enableAbsolutePositionEditing", false, "false");
|
||||
editingHost.remove();
|
||||
await waitForTick();
|
||||
})();
|
||||
await (async () => {
|
||||
const editingHost = document.getElementById("testTable");
|
||||
editingHost.contentEditable = "plaintext-only";
|
||||
editingHost.focus();
|
||||
document.execCommand("enableInlineTableEditing", false, "true");
|
||||
const target = editingHost.querySelector("td");
|
||||
synthesizeMouseAtCenter(target, {});
|
||||
await waitForTick();
|
||||
is(
|
||||
getHTMLEditor().isInlineTableEditingActive,
|
||||
false,
|
||||
"The inline table editing UI should not be visible"
|
||||
);
|
||||
document.execCommand("enableInlineTableEditing", false, "false");
|
||||
editingHost.remove();
|
||||
await waitForTick();
|
||||
})();
|
||||
await (async () => {
|
||||
const editingHost = document.getElementById("testResizer");
|
||||
editingHost.contentEditable = "plaintext-only";
|
||||
editingHost.focus();
|
||||
document.execCommand("enableObjectResizing", false, "true");
|
||||
const target = editingHost.querySelector("img");
|
||||
synthesizeMouseAtCenter(target, {});
|
||||
await waitForTick();
|
||||
is(
|
||||
getHTMLEditor().isObjectResizingActive,
|
||||
false,
|
||||
"The image resizer UI should not be visible"
|
||||
);
|
||||
document.execCommand("enableObjectResizing", false, "false");
|
||||
editingHost.remove();
|
||||
await waitForTick();
|
||||
})();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function getHTMLEditor() {
|
||||
const Ci = SpecialPowers.Ci;
|
||||
const editingSession = SpecialPowers.wrap(window).docShell.editingSession;
|
||||
return editingSession.getEditorForWindow(window)
|
||||
.QueryInterface(Ci.nsIHTMLAbsPosEditor)
|
||||
.QueryInterface(Ci.nsIHTMLInlineTableEditor)
|
||||
.QueryInterface(Ci.nsIHTMLObjectResizer);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="testAbs" style="position: absolute; width: 150px; height: 150px">
|
||||
<div style="position: absolute; width: 100px; height: 100px"><br></div>
|
||||
</div>
|
||||
<div id="testTable">
|
||||
<table><td><br></td></table>
|
||||
</div>
|
||||
<div id="testResizer">
|
||||
<img src="green.png">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -15,6 +15,11 @@ interface nsIHTMLAbsPosEditor : nsISupports
|
||||
[setter_can_run_script]
|
||||
attribute boolean absolutePositioningEnabled;
|
||||
|
||||
/**
|
||||
* true if the grabber to drag the absolutly positioned element is visible.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isAbsolutePositioningActive;
|
||||
|
||||
|
||||
/* Utility methods */
|
||||
|
||||
|
@ -17,4 +17,9 @@ interface nsIHTMLInlineTableEditor : nsISupports
|
||||
*/
|
||||
[setter_can_run_script]
|
||||
attribute boolean inlineTableEditingEnabled;
|
||||
|
||||
/**
|
||||
* true if the inline table editing UI is visible.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isInlineTableEditingActive;
|
||||
};
|
||||
|
@ -29,6 +29,11 @@ interface nsIHTMLObjectResizer : nsISupports
|
||||
[setter_can_run_script]
|
||||
attribute boolean objectResizingEnabled;
|
||||
|
||||
/**
|
||||
* true if the object resizing UI is visible.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isObjectResizingActive;
|
||||
|
||||
/**
|
||||
* Hide resizers if they are visible. If this is called while there is no
|
||||
* visible resizers, this does not throw exception, just does nothing.
|
||||
|
Loading…
Reference in New Issue
Block a user