зеркало из https://github.com/mozilla/gecko-dev.git
Bug 927802 - Hook up contextmenu for contenteditables, fix cut, paste handling for contenteditables. r=mbrubeck
--HG-- extra : rebase_source : 9f91350b3f578107dae958a64d65f4217a38fc72
This commit is contained in:
Родитель
a6e308d2ea
Коммит
1aba7c033f
|
@ -118,6 +118,14 @@ var ContextMenuHandler = {
|
|||
} else {
|
||||
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
|
||||
}
|
||||
} else if (this._target.isContentEditable) {
|
||||
try {
|
||||
this._target.ownerDocument.execCommand("paste",
|
||||
false,
|
||||
Ci.nsIClipboard.kGlobalClipboard);
|
||||
} catch (ex) {
|
||||
dump("ContextMenuHandler: exception pasting into contentEditable: " + ex.message + "\n");
|
||||
}
|
||||
}
|
||||
this.reset();
|
||||
},
|
||||
|
@ -134,6 +142,12 @@ var ContextMenuHandler = {
|
|||
} else {
|
||||
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
|
||||
}
|
||||
} else if (this._target.isContentEditable) {
|
||||
try {
|
||||
this._target.ownerDocument.execCommand("cut", false);
|
||||
} catch (ex) {
|
||||
dump("ContextMenuHandler: exception cutting from contentEditable: " + ex.message + "\n");
|
||||
}
|
||||
}
|
||||
this.reset();
|
||||
},
|
||||
|
@ -188,12 +202,13 @@ var ContextMenuHandler = {
|
|||
contentDisposition: "",
|
||||
string: "",
|
||||
};
|
||||
let uniqueStateTypes = new Set();
|
||||
|
||||
// Do checks for nodes that never have children.
|
||||
if (popupNode.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
|
||||
// See if the user clicked on an image.
|
||||
if (popupNode instanceof Ci.nsIImageLoadingContent && popupNode.currentURI) {
|
||||
state.types.push("image");
|
||||
uniqueStateTypes.add("image");
|
||||
state.label = state.mediaURL = popupNode.currentURI.spec;
|
||||
imageUrl = state.mediaURL;
|
||||
this._target = popupNode;
|
||||
|
@ -218,6 +233,7 @@ var ContextMenuHandler = {
|
|||
|
||||
let elem = popupNode;
|
||||
let isText = false;
|
||||
let isEditableText = false;
|
||||
|
||||
while (elem) {
|
||||
if (elem.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
|
||||
|
@ -230,7 +246,7 @@ var ContextMenuHandler = {
|
|||
continue;
|
||||
}
|
||||
|
||||
state.types.push("link");
|
||||
uniqueStateTypes.add("link");
|
||||
state.label = state.linkURL = this._getLinkURL(elem);
|
||||
linkUrl = state.linkURL;
|
||||
state.linkTitle = popupNode.textContent || popupNode.title;
|
||||
|
@ -238,49 +254,61 @@ var ContextMenuHandler = {
|
|||
// mark as text so we can pickup on selection below
|
||||
isText = true;
|
||||
break;
|
||||
} else if (Util.isTextInput(elem)) {
|
||||
}
|
||||
// is the target contentEditable (not just inheriting contentEditable)
|
||||
else if (elem.contentEditable == "true") {
|
||||
this._target = elem;
|
||||
isEditableText = true;
|
||||
isText = true;
|
||||
uniqueStateTypes.add("input-text");
|
||||
|
||||
if (elem.textContent.length) {
|
||||
uniqueStateTypes.add("selectable");
|
||||
} else {
|
||||
uniqueStateTypes.add("input-empty");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// is the target a text input
|
||||
else if (Util.isTextInput(elem)) {
|
||||
this._target = elem;
|
||||
isEditableText = true;
|
||||
uniqueStateTypes.add("input-text");
|
||||
|
||||
let selectionStart = elem.selectionStart;
|
||||
let selectionEnd = elem.selectionEnd;
|
||||
|
||||
state.types.push("input-text");
|
||||
this._target = elem;
|
||||
|
||||
// Don't include "copy" for password fields.
|
||||
if (!(elem instanceof Ci.nsIDOMHTMLInputElement) || elem.mozIsTextField(true)) {
|
||||
// If there is a selection add cut and copy
|
||||
if (selectionStart != selectionEnd) {
|
||||
state.types.push("cut");
|
||||
state.types.push("copy");
|
||||
uniqueStateTypes.add("cut");
|
||||
uniqueStateTypes.add("copy");
|
||||
state.string = elem.value.slice(selectionStart, selectionEnd);
|
||||
} else if (elem.value && elem.textLength) {
|
||||
// There is text and it is not selected so add selectable items
|
||||
state.types.push("selectable");
|
||||
uniqueStateTypes.add("selectable");
|
||||
state.string = elem.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!elem.textLength) {
|
||||
state.types.push("input-empty");
|
||||
}
|
||||
|
||||
let flavors = ["text/unicode"];
|
||||
let cb = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
|
||||
let hasData = cb.hasDataMatchingFlavors(flavors,
|
||||
flavors.length,
|
||||
Ci.nsIClipboard.kGlobalClipboard);
|
||||
if (hasData && !elem.readOnly) {
|
||||
state.types.push("paste");
|
||||
uniqueStateTypes.add("input-empty");
|
||||
}
|
||||
break;
|
||||
} else if (Util.isText(elem)) {
|
||||
}
|
||||
// is the target an element containing text content
|
||||
else if (Util.isText(elem)) {
|
||||
isText = true;
|
||||
} else if (elem instanceof Ci.nsIDOMHTMLMediaElement ||
|
||||
}
|
||||
// is the target a media element
|
||||
else if (elem instanceof Ci.nsIDOMHTMLMediaElement ||
|
||||
elem instanceof Ci.nsIDOMHTMLVideoElement) {
|
||||
state.label = state.mediaURL = (elem.currentSrc || elem.src);
|
||||
state.types.push((elem.paused || elem.ended) ?
|
||||
uniqueStateTypes.add((elem.paused || elem.ended) ?
|
||||
"media-paused" : "media-playing");
|
||||
if (elem instanceof Ci.nsIDOMHTMLVideoElement) {
|
||||
state.types.push("video");
|
||||
uniqueStateTypes.add("video");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,20 +323,37 @@ var ContextMenuHandler = {
|
|||
let selection = targetWindow.getSelection();
|
||||
if (selection && this._tapInSelection(selection, aX, aY)) {
|
||||
state.string = targetWindow.getSelection().toString();
|
||||
state.types.push("copy");
|
||||
state.types.push("selected-text");
|
||||
uniqueStateTypes.add("copy");
|
||||
uniqueStateTypes.add("selected-text");
|
||||
if (isEditableText) {
|
||||
uniqueStateTypes.add("cut");
|
||||
}
|
||||
} else {
|
||||
// Add general content text if this isn't anything specific
|
||||
if (state.types.indexOf("image") == -1 &&
|
||||
state.types.indexOf("media") == -1 &&
|
||||
state.types.indexOf("video") == -1 &&
|
||||
state.types.indexOf("link") == -1 &&
|
||||
state.types.indexOf("input-text") == -1) {
|
||||
state.types.push("content-text");
|
||||
if (!(
|
||||
uniqueStateTypes.has("image") ||
|
||||
uniqueStateTypes.has("media") ||
|
||||
uniqueStateTypes.has("video") ||
|
||||
uniqueStateTypes.has("link") ||
|
||||
uniqueStateTypes.has("input-text")
|
||||
)) {
|
||||
uniqueStateTypes.add("content-text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is paste applicable here?
|
||||
if (isEditableText) {
|
||||
let flavors = ["text/unicode"];
|
||||
let cb = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
|
||||
let hasData = cb.hasDataMatchingFlavors(flavors,
|
||||
flavors.length,
|
||||
Ci.nsIClipboard.kGlobalClipboard);
|
||||
// add paste if there's data
|
||||
if (hasData && !elem.readOnly) {
|
||||
uniqueStateTypes.add("paste");
|
||||
}
|
||||
}
|
||||
// populate position and event source
|
||||
state.xPos = offsetX + aX;
|
||||
state.yPos = offsetY + aY;
|
||||
|
@ -316,8 +361,9 @@ var ContextMenuHandler = {
|
|||
|
||||
for (let i = 0; i < this._types.length; i++)
|
||||
if (this._types[i].handler(state, popupNode))
|
||||
state.types.push(this._types[i].name);
|
||||
uniqueStateTypes.add(this._types[i].name);
|
||||
|
||||
state.types = [type for (type of uniqueStateTypes)];
|
||||
this._previousState = state;
|
||||
|
||||
sendAsyncMessage("Content:ContextMenu", state);
|
||||
|
|
Загрузка…
Ссылка в новой задаче