Bug 1692673 - Avoid enabling Cut/Copy menu commands in text editor context when there's no selection, unless a listener is present. r=masayuki

Differential Revision: https://phabricator.services.mozilla.com/D107480
This commit is contained in:
Jonathan Kew 2021-03-11 10:27:04 +00:00
parent 2093b6b5e7
commit 24a5b45445
2 changed files with 52 additions and 6 deletions

View File

@ -13,9 +13,11 @@
#include "PlaceholderTransaction.h"
#include "gfxFontUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/ContentEvents.h"
#include "mozilla/ContentIterator.h"
#include "mozilla/EditAction.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/LookAndFeel.h"
@ -54,6 +56,7 @@
#include "nsIWeakReferenceUtils.h"
#include "nsNameSpaceManager.h"
#include "nsLiteralString.h"
#include "nsPresContext.h"
#include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
@ -1214,17 +1217,52 @@ bool TextEditor::AreClipboardCommandsUnconditionallyEnabled() const {
return document && document->AreClipboardCommandsUnconditionallyEnabled();
}
bool TextEditor::CheckForClipboardCommandListener(
nsAtom* aCommand, EventMessage aEventMessage) const {
RefPtr<Document> document = GetDocument();
if (!document) {
return false;
}
RefPtr<PresShell> presShell = document->GetObservingPresShell();
if (!presShell) {
return false;
}
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
if (!presContext) {
return false;
}
RefPtr<EventTarget> et = GetDOMEventTarget();
while (et) {
EventListenerManager* elm = et->GetOrCreateListenerManager();
if (elm && elm->HasListenersFor(aCommand)) {
return true;
}
InternalClipboardEvent event(true, aEventMessage);
EventChainPreVisitor visitor(presContext, &event, nullptr,
nsEventStatus_eIgnore, false, et);
et->GetEventTargetParent(visitor);
et = visitor.GetParentTarget();
}
return false;
}
bool TextEditor::IsCutCommandEnabled() const {
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
if (NS_WARN_IF(!editActionData.CanHandle())) {
return false;
}
if (AreClipboardCommandsUnconditionallyEnabled()) {
if (IsModifiable() && IsCopyToClipboardAllowedInternal()) {
return true;
}
return IsModifiable() && IsCopyToClipboardAllowedInternal();
// If there's an event listener for "cut", we always enable the command
// as we don't really know what the listener may want to do in response.
// We look up the event target chain for a possible listener on a parent
// in addition to checking the immediate target.
return CheckForClipboardCommandListener(nsGkAtoms::oncut, eCut);
}
NS_IMETHODIMP TextEditor::Copy() {
@ -1246,11 +1284,12 @@ bool TextEditor::IsCopyCommandEnabled() const {
return false;
}
if (AreClipboardCommandsUnconditionallyEnabled()) {
if (IsCopyToClipboardAllowedInternal()) {
return true;
}
return IsCopyToClipboardAllowedInternal();
// Like "cut", always enable "copy" if there's a listener.
return CheckForClipboardCommandListener(nsGkAtoms::oncopy, eCopy);
}
bool TextEditor::CanDeleteSelection() const {

View File

@ -96,7 +96,7 @@ class TextEditor : public EditorBase, public nsITimerCallback, public nsINamed {
* disabled. This always returns true if we're in non-chrome HTML/XHTML
* document. Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
*/
bool IsCutCommandEnabled() const;
MOZ_CAN_RUN_SCRIPT bool IsCutCommandEnabled() const;
NS_IMETHOD Copy() override;
@ -105,7 +105,7 @@ class TextEditor : public EditorBase, public nsITimerCallback, public nsINamed {
* This always returns true if we're in non-chrome HTML/XHTML document.
* Otherwise, same as the result of `IsCopyToClipboardAllowed()`.
*/
bool IsCopyCommandEnabled() const;
MOZ_CAN_RUN_SCRIPT bool IsCopyCommandEnabled() const;
/**
* IsCopyToClipboardAllowed() returns true if the selected content can
@ -786,6 +786,13 @@ class TextEditor : public EditorBase, public nsITimerCallback, public nsINamed {
bool aNotify,
bool aForceStartMasking);
/**
* Helper for Is{Cut|Copy}CommandEnabled.
* Look for a listener for the given command, including up the target chain.
*/
MOZ_CAN_RUN_SCRIPT bool CheckForClipboardCommandListener(
nsAtom* aCommand, EventMessage aEventMessage) const;
protected:
mutable nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;