Bug 1012662 - Updates to clipboard command controllers to match cut/copy action spec. r=ehsan

This commit is contained in:
Michael Layzell 2015-05-13 08:51:00 +02:00
parent fd0fb16611
commit 6456704cff
6 changed files with 80 additions and 36 deletions

View File

@ -620,8 +620,13 @@ IsSelectionInsideRuby(nsISelection* aSelection)
}
bool
nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection)
nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell,
nsISelection* aSelection, bool* aActionTaken)
{
if (aActionTaken) {
*aActionTaken = false;
}
NS_ASSERTION(aType == NS_CUT || aType == NS_COPY || aType == NS_PASTE,
"Invalid clipboard event type");
@ -646,14 +651,6 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// retrieve the event target node from the start of the selection
nsresult rv;
if (sel) {
// Only cut or copy when there is an uncollapsed selection
if (aType == NS_CUT || aType == NS_COPY) {
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed)
return false;
}
nsCOMPtr<nsIDOMRange> range;
rv = sel->GetRangeAt(0, getter_AddRefs(range));
if (NS_SUCCEEDED(rv) && range) {
@ -696,7 +693,7 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// If the event was cancelled, don't do the clipboard operation
doDefault = (status != nsEventStatus_eConsumeNoDefault);
}
// No need to do anything special during a paste. Either an event listener
// took care of it and cancelled the event, or the caller will handle it.
// Return true to indicate that the event wasn't cancelled.
@ -708,6 +705,9 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
clipboardData->SetReadOnly();
}
if (aActionTaken) {
*aActionTaken = true;
}
return doDefault;
}
@ -721,20 +721,43 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// use the data added to the data transfer and copy that instead.
uint32_t count = 0;
if (doDefault) {
// get the data from the selection if any
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed) {
return false;
// find the focused node
nsCOMPtr<nsIContent> srcNode = content;
if (content->IsInNativeAnonymousSubtree()) {
srcNode = content->FindFirstNonChromeOnlyAccessContent();
}
// XXX Code which decides whether we should copy text with ruby
// annotation is currenct depending on whether each range of the
// selection is inside a same ruby container. But we really should
// expose the full functionality in browser. See bug 1130891.
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
// call the copy code
rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
if (NS_FAILED(rv)) {
// check if we are looking at a password input
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(srcNode);
if (formControl) {
if (formControl->GetType() == NS_FORM_INPUT_PASSWORD) {
return false;
}
}
// when cutting non-editable content, do nothing
// XXX this is probably the wrong editable flag to check
if (aType != NS_CUT || content->IsEditable()) {
// get the data from the selection if any
bool isCollapsed;
sel->GetIsCollapsed(&isCollapsed);
if (isCollapsed) {
if (aActionTaken) {
*aActionTaken = true;
}
return false;
}
// XXX Code which decides whether we should copy text with ruby
// annotation is currenct depending on whether each range of the
// selection is inside a same ruby container. But we really should
// expose the full functionality in browser. See bug 1130891.
bool withRubyAnnotation = IsSelectionInsideRuby(sel);
// call the copy code
rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation);
if (NS_FAILED(rv)) {
return false;
}
} else {
return false;
}
} else if (clipboardData) {
@ -763,5 +786,8 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"), nullptr, 0);
}
if (aActionTaken) {
*aActionTaken = true;
}
return doDefault;
}

View File

@ -83,12 +83,16 @@ class nsCopySupport
*
* aClipboardType specifies which clipboard to use, from nsIClipboard.
*
* If aActionTaken is non-NULL, it will be set to true if an action was
* taken, whether it be the default action or the default being prevented.
*
* If the event is cancelled or an error occurs, false will be returned.
*/
static bool FireClipboardEvent(int32_t aType,
int32_t aClipboardType,
nsIPresShell* aPresShell,
nsISelection* aSelection);
nsISelection* aSelection,
bool* aActionTaken = nullptr);
};
#endif

View File

@ -500,7 +500,8 @@ nsClipboardCommand::IsCommandEnabled(const char* aCommandName, nsISupports *aCon
nsresult
nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
{
if (strcmp(aCommandName, "cmd_copy") &&
if (strcmp(aCommandName, "cmd_cut") &&
strcmp(aCommandName, "cmd_copy") &&
strcmp(aCommandName, "cmd_copyAndCollapseToEnd"))
return NS_OK;
@ -513,7 +514,13 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
nsCopySupport::FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, presShell, nullptr);
int32_t eventType = NS_COPY;
if (strcmp(aCommandName, "cmd_cut") == 0) {
eventType = NS_CUT;
}
bool actionTaken = false;
nsCopySupport::FireClipboardEvent(eventType, nsIClipboard::kGlobalClipboard, presShell, nullptr, &actionTaken);
if (!strcmp(aCommandName, "cmd_copyAndCollapseToEnd")) {
dom::Selection *sel =
@ -522,7 +529,10 @@ nsClipboardCommand::DoCommand(const char *aCommandName, nsISupports *aContext)
sel->CollapseToEnd();
}
return NS_OK;
if (actionTaken) {
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP

View File

@ -150,7 +150,7 @@ function test_dom_oncut() {
content.oncut = function() { oncut_fired = true; };
try {
synthesizeKey("x", {accelKey: 1});
ok(!oncut_fired, "cut event firing on DOM element")
ok(oncut_fired, "cut event firing on DOM element")
is(getClipboardText(), clipboardInitialValue,
"cut on DOM element did not modify clipboard");
} finally {

View File

@ -1168,7 +1168,7 @@ nsPlaintextEditor::CanCutOrCopy(PasswordFieldAllowed aPasswordFieldAllowed)
}
bool
nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType)
nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType, bool* aActionTaken)
{
if (aType == NS_PASTE)
ForceCompositionEnd();
@ -1181,7 +1181,7 @@ nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType)
return false;
}
if (!nsCopySupport::FireClipboardEvent(aType, aSelectionType, presShell, selection))
if (!nsCopySupport::FireClipboardEvent(aType, aSelectionType, presShell, selection, aActionTaken))
return false;
// If the event handler caused the editor to be destroyed, return false.
@ -1191,9 +1191,11 @@ nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType)
NS_IMETHODIMP nsPlaintextEditor::Cut()
{
if (FireClipboardEvent(NS_CUT, nsIClipboard::kGlobalClipboard))
return DeleteSelection(eNone, eStrip);
return NS_OK;
bool actionTaken = false;
if (FireClipboardEvent(NS_CUT, nsIClipboard::kGlobalClipboard, &actionTaken)) {
DeleteSelection(eNone, eStrip);
}
return actionTaken ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut)
@ -1205,8 +1207,10 @@ NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut)
NS_IMETHODIMP nsPlaintextEditor::Copy()
{
FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard);
return NS_OK;
bool actionTaken = false;
FireClipboardEvent(NS_COPY, nsIClipboard::kGlobalClipboard, &actionTaken);
return actionTaken ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsPlaintextEditor::CanCopy(bool *aCanCopy)

View File

@ -207,7 +207,7 @@ protected:
ePasswordFieldNotAllowed
};
bool CanCutOrCopy(PasswordFieldAllowed aPasswordFieldAllowed);
bool FireClipboardEvent(int32_t aType, int32_t aSelectionType);
bool FireClipboardEvent(int32_t aType, int32_t aSelectionType, bool* aActionTaken = nullptr);
bool UpdateMetaCharset(nsIDOMDocument* aDocument,
const nsACString& aCharacterSet);