in suite/base/content/nsContextMenu.js [587:868]
setTarget: function(aNode, aRangeParent, aRangeOffset) {
// Currently "isRemote" is always false.
//this.isRemote = gContextMenuContentData && gContextMenuContentData.isRemote;
const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
// Initialize contextual info.
this.onImage = false;
this.onLoadedImage = false;
this.onCompletedImage = false;
this.onStandaloneImage = false;
this.onCanvas = false;
this.onVideo = false;
this.onAudio = false;
this.onMetaDataItem = false;
this.onTextInput = false;
this.onNumeric = false;
this.onKeywordField = false;
this.mediaURL = "";
this.onLink = false;
this.onMailtoLink = false;
this.onSaveableLink = false;
this.inDirList = false;
this.link = null;
this.linkURL = "";
this.linkURI = null;
this.linkProtocol = "";
this.linkHasNoReferrer = false;
this.onMathML = false;
this.inFrame = false;
this.inSyntheticDoc = false;
this.hasBGImage = false;
this.bgImageURL = "";
this.autoDownload = false;
this.isTextSelected = false;
this.isContentSelected = false;
this.onEditableArea = false;
this.canSpellCheck = false;
this.onPassword = false;
// Remember the node that was clicked.
this.target = aNode;
if (aNode.nodeType == Node.DOCUMENT_NODE ||
// Not display on XUL element but relax for <label class="text-link">
(aNode.namespaceURI == xulNS && !isXULTextLinkLabel(aNode))) {
this.shouldDisplay = false;
return;
}
let editFlags = SpellCheckHelper.isEditable(this.target, window);
this.browser = this.target.ownerDocument.defaultView
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
this.principal = this.target.ownerDocument.nodePrincipal;
this.autoDownload = Services.prefs.getBoolPref("browser.download.useDownloadDir");
// Check if we are in a synthetic document (stand alone image, video, etc.).
this.inSyntheticDoc = this.target.ownerDocument.mozSyntheticDocument;
// First, do checks for nodes that never have children.
if (this.target.nodeType == Node.ELEMENT_NODE) {
// See if the user clicked on an image.
if (this.target instanceof Ci.nsIImageLoadingContent &&
this.target.currentURI) {
this.onImage = true;
var request =
this.target.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
if (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE))
this.onLoadedImage = true;
if (request &&
(request.imageStatus & request.STATUS_LOAD_COMPLETE) &&
!(request.imageStatus & request.STATUS_ERROR)) {
this.onCompletedImage = true;
}
this.mediaURL = this.target.currentURI.spec;
if (this.target.ownerDocument instanceof ImageDocument)
this.onStandaloneImage = true;
}
else if (this.target instanceof HTMLCanvasElement) {
this.onCanvas = true;
}
else if (this.target instanceof HTMLVideoElement) {
// Gecko always creates a HTMLVideoElement when loading an ogg file
// directly. If the media is actually audio, be smarter and provide
// a context menu with audio operations.
if (this.target.readyState >= this.target.HAVE_METADATA &&
(this.target.videoWidth == 0 || this.target.videoHeight == 0))
this.onAudio = true;
else
this.onVideo = true;
this.mediaURL = this.target.currentSrc || this.target.src;
}
else if (this.target instanceof HTMLAudioElement) {
this.onAudio = true;
this.mediaURL = this.target.currentSrc || this.target.src;
}
else if (editFlags & (SpellCheckHelper.INPUT | SpellCheckHelper.TEXTAREA)) {
this.onTextInput = (editFlags & SpellCheckHelper.TEXTINPUT) !== 0;
this.onNumeric = (editFlags & SpellCheckHelper.NUMERIC) !== 0;
this.onEditableArea = (editFlags & SpellCheckHelper.EDITABLE) !== 0;
this.onPassword = (editFlags & SpellCheckHelper.PASSWORD) !== 0;
if (this.onEditableArea) {
InlineSpellCheckerUI.init(this.target.editor);
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
}
this.onKeywordField = (editFlags & SpellCheckHelper.KEYWORD);
}
else if ( this.target instanceof HTMLHtmlElement ) {
// pages with multiple <body>s are lame. we'll teach them a lesson.
var bodyElt = this.target.ownerDocument.body;
if (bodyElt) {
var computedURL = this.getComputedURL(bodyElt, "background-image");
if (computedURL) {
this.hasBGImage = true;
this.bgImageURL = makeURLAbsolute(bodyElt.baseURI, computedURL);
}
}
}
else if ("HTTPIndex" in content &&
content.HTTPIndex instanceof Ci.nsIHTTPIndex) {
this.inDirList = true;
// Bubble outward till we get to an element with URL attribute
// (which should be the href).
var root = this.target;
while (root && !this.link) {
if (root.tagName == "tree") {
// Hit root of tree; must have clicked in empty space;
// thus, no link.
break;
}
if (root.getAttribute("URL")) {
// Build pseudo link object so link-related functions work.
this.onLink = true;
this.link = {href: root.getAttribute("URL"),
getAttribute: function(attr) {
if (attr == "title") {
return root.firstChild.firstChild.getAttribute("label");
} else {
return "";
}
}
};
this.linkURL = this.getLinkURL();
this.linkURI = this.getLinkURI();
this.linkProtocol = this.getLinkProtocol();
this.onMailtoLink = (this.linkProtocol == "mailto");
// If element is a directory, then you can't save it.
this.onSaveableLink = root.getAttribute("container") != "true";
}
else {
root = root.parentNode;
}
}
}
this.canSpellCheck = this._isSpellCheckEnabled(this.target);
}
else if (this.target.nodeType == Node.TEXT_NODE) {
// For text nodes, look at the parent node to determine the spellcheck attribute.
this.canSpellCheck = this.target.parentNode &&
this._isSpellCheckEnabled(this.target);
}
// We have meta data on images.
this.onMetaDataItem = this.onImage;
// Bubble out, looking for items of interest
const NS_MathML = "http://www.w3.org/1998/Math/MathML";
const XMLNS = "http://www.w3.org/XML/1998/namespace";
var elem = this.target;
while (elem) {
if (elem.nodeType == Node.ELEMENT_NODE) {
// Link?
if (!this.onLink &&
(isXULTextLinkLabel(elem) ||
(elem instanceof HTMLAnchorElement && elem.href) ||
(elem instanceof HTMLAreaElement && elem.href) ||
elem instanceof HTMLLinkElement ||
(elem.namespaceURI == NS_MathML && elem.hasAttribute("href")) ||
elem.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple")) {
// Clicked on a link.
this.onLink = true;
this.onMetaDataItem = true;
// Remember corresponding element.
this.link = elem;
this.linkURL = this.getLinkURL();
this.linkURI = this.getLinkURI();
this.linkProtocol = this.getLinkProtocol();
this.onMailtoLink = (this.linkProtocol == "mailto");
// Remember if it is saveable.
this.onSaveableLink = this.isLinkSaveable();
this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem);
}
// Text input?
if (!this.onTextInput) {
// Clicked on a link.
this.onTextInput = this.isTargetATextBox(elem);
}
// Metadata item?
if (!this.onMetaDataItem) {
// We currently display metadata on anything which fits
// the below test.
if ((elem instanceof HTMLQuoteElement && elem.cite) ||
(elem instanceof HTMLTableElement && elem.summary) ||
(elem instanceof HTMLModElement && (elem.cite || elem.dateTime)) ||
(elem instanceof HTMLElement && (elem.title || elem.lang)) ||
elem.getAttributeNS(XMLNS, "lang")) {
dump("On metadata item.\n");
this.onMetaDataItem = true;
}
}
// Background image? Don't bother if we've already found a
// background image further down the hierarchy. Otherwise,
// we look for the computed background-image style.
if (!this.hasBGImage) {
var bgImgUrl = this.getComputedURL(elem, "background-image");
if (bgImgUrl) {
this.hasBGImage = true;
this.bgImageURL = makeURLAbsolute(elem.baseURI, bgImgUrl);
}
}
}
elem = elem.parentNode;
}
// See if the user clicked on MathML
if ((this.target.nodeType == Node.TEXT_NODE &&
this.target.parentNode.namespaceURI == NS_MathML) ||
(this.target.namespaceURI == NS_MathML))
this.onMathML = true;
// See if the user clicked in a frame.
var docDefaultView = this.target.ownerDocument.defaultView;
if (docDefaultView != docDefaultView.top)
this.inFrame = true;
// if the document is editable, show context menu like in text inputs
if (!this.onEditableArea) {
if (editFlags & SpellCheckHelper.CONTENTEDITABLE) {
// If this.onEditableArea is false but editFlags is CONTENTEDITABLE,
// then the document itself must be editable.
this.onTextInput = true;
this.onKeywordField = false;
this.onImage = false;
this.onLoadedImage = false;
this.onCompletedImage = false;
this.onMathML = false;
this.inFrame = false;
this.hasBGImage = false;
this.onEditableArea = true;
var win = this.target.ownerDocument.defaultView;
var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
InlineSpellCheckerUI.init(editingSession.getEditorForWindow(win));
InlineSpellCheckerUI.initFromEvent(aRangeParent, aRangeOffset);
var canSpell = InlineSpellCheckerUI.canSpellCheck && this.canSpellCheck;
this.showItem("spell-check-enabled", canSpell);
this.showItem("spell-separator", canSpell);
}
}
function isXULTextLinkLabel(node) {
return node.namespaceURI == xulNS &&
node.tagName == "label" &&
node.classList.contains('text-link') &&
node.href;
}
},