зеркало из https://github.com/mozilla/gecko-dev.git
Bug 551711 - Open Link in New Tab via content panel [r=vingtetun]
This commit is contained in:
Родитель
d0b1111af9
Коммит
aa910b9900
|
@ -139,6 +139,7 @@ function InputHandler(browserViewContainer) {
|
|||
this.listenFor(browserViewContainer, "keyup");
|
||||
this.listenFor(browserViewContainer, "DOMMouseScroll");
|
||||
this.listenFor(browserViewContainer, "MozMousePixelScroll");
|
||||
this.listenFor(browserViewContainer, "contextmenu");
|
||||
|
||||
this.addModule(new MouseModule(this, browserViewContainer));
|
||||
this.addModule(new ScrollwheelModule(this, browserViewContainer));
|
||||
|
@ -418,6 +419,11 @@ function MouseModule(owner, browserViewContainer) {
|
|||
|
||||
MouseModule.prototype = {
|
||||
handleEvent: function handleEvent(evInfo) {
|
||||
// TODO: Make "contextmenu" a first class part of InputHandler
|
||||
// Bug 554639
|
||||
if (evInfo.event.type == "contextmenu")
|
||||
this._cleanClickBuffer();
|
||||
|
||||
if (evInfo.event.button !== 0) // avoid all but a clean left click
|
||||
return;
|
||||
|
||||
|
|
|
@ -108,6 +108,11 @@ let Util = {
|
|||
return null;
|
||||
},
|
||||
|
||||
makeURLAbsolute: function makeURLAbsolute(base, url) {
|
||||
// Note: makeURI() will throw if url is not a valid URI
|
||||
return makeURI(url, null, makeURI(base)).spec;
|
||||
},
|
||||
|
||||
contentIsHandheld: function contentIsHandheld(browser) {
|
||||
let doctype = browser.contentDocument.doctype;
|
||||
if (doctype && /(WAP|WML|Mobile)/.test(doctype.publicId))
|
||||
|
|
|
@ -1699,6 +1699,142 @@ var SelectHelper = {
|
|||
}
|
||||
};
|
||||
|
||||
const kXLinkNamespace = "http://www.w3.org/1999/xlink";
|
||||
|
||||
var ContextHelper = {
|
||||
popupNode: null,
|
||||
onLink: false,
|
||||
onImage: false,
|
||||
linkURL: "",
|
||||
mediaURL: "",
|
||||
|
||||
_clearState: function ch_clearState() {
|
||||
this.popupNode = null;
|
||||
this.onLink = false;
|
||||
this.onImage = false;
|
||||
this.linkURL = "";
|
||||
this.mediaURL = "";
|
||||
},
|
||||
|
||||
_getLinkURL: function ch_getLinkURL(aLink) {
|
||||
let href = aLink.href;
|
||||
if (href)
|
||||
return href;
|
||||
|
||||
href = aLink.getAttributeNS(kXLinkNamespace, "href");
|
||||
if (!href || !href.match(/\S/)) {
|
||||
// Without this we try to save as the current doc,
|
||||
// for example, HTML case also throws if empty
|
||||
throw "Empty href";
|
||||
}
|
||||
|
||||
return Util.makeURLAbsolute(aLink.baseURI, href);
|
||||
},
|
||||
|
||||
handleEvent: function ch_handleEvent(aEvent) {
|
||||
this._clearState();
|
||||
|
||||
let [elementX, elementY] = Browser.transformClientToBrowser(aEvent.clientX, aEvent.clientY);
|
||||
this.popupNode = Browser.elementFromPoint(elementX, elementY);
|
||||
|
||||
// Do checks for nodes that never have children.
|
||||
if (this.popupNode.nodeType == Node.ELEMENT_NODE) {
|
||||
// See if the user clicked on an image.
|
||||
if (this.popupNode instanceof Ci.nsIImageLoadingContent && this.popupNode.currentURI) {
|
||||
this.onImage = true;
|
||||
this.mediaURL = this.popupNode.currentURI.spec;
|
||||
}
|
||||
}
|
||||
|
||||
let elem = this.popupNode;
|
||||
while (elem) {
|
||||
if (elem.nodeType == Node.ELEMENT_NODE) {
|
||||
// Link?
|
||||
if (!this.onLink &&
|
||||
((elem instanceof HTMLAnchorElement && elem.href) ||
|
||||
(elem instanceof HTMLAreaElement && elem.href) ||
|
||||
elem instanceof HTMLLinkElement ||
|
||||
elem.getAttributeNS(kXLinkNamespace, "type") == "simple")) {
|
||||
|
||||
// Target is a link or a descendant of a link.
|
||||
this.onLink = true;
|
||||
this.linkURL = this._getLinkURL(elem);
|
||||
}
|
||||
}
|
||||
|
||||
elem = elem.parentNode;
|
||||
}
|
||||
|
||||
let first = last = null;
|
||||
let commands = document.getElementById("context-commands");
|
||||
for (let i=0; i<commands.childElementCount; i++) {
|
||||
let command = commands.children[i];
|
||||
let type = command.getAttribute("type");
|
||||
command.removeAttribute("selector");
|
||||
if (type.indexOf("image") != -1 && this.onImage) {
|
||||
first = (first ? first : command);
|
||||
last = command;
|
||||
command.hidden = false;
|
||||
continue;
|
||||
} else if (type.indexOf("link") != -1 && this.onLink) {
|
||||
first = (first ? first : command);
|
||||
last = command;
|
||||
command.hidden = false;
|
||||
continue;
|
||||
}
|
||||
command.hidden = true;
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
this._clearState();
|
||||
return;
|
||||
}
|
||||
|
||||
first.setAttribute("selector", "first-child");
|
||||
last.setAttribute("selector", "last-child");
|
||||
|
||||
let label = document.getElementById("context-hint");
|
||||
if (this.onImage)
|
||||
label.value = this.mediaURL;
|
||||
if (this.onLink)
|
||||
label.value = this.linkURL;
|
||||
|
||||
let container = document.getElementById("context-popup");
|
||||
container.hidden = false;
|
||||
|
||||
let rect = container.getBoundingClientRect();
|
||||
let height = Math.min(rect.height, 0.75 * window.innerWidth);
|
||||
let width = Math.min(rect.width, 0.75 * window.innerWidth);
|
||||
|
||||
container.height = height;
|
||||
container.width = width;
|
||||
container.top = (window.innerHeight - height) / 2;
|
||||
container.left = (window.innerWidth - width) / 2;
|
||||
|
||||
BrowserUI.pushPopup(this, [container]);
|
||||
},
|
||||
|
||||
hide: function ch_hide() {
|
||||
this._clearState();
|
||||
|
||||
let container = document.getElementById("context-popup");
|
||||
container.hidden = true;
|
||||
|
||||
BrowserUI.popPopup();
|
||||
}
|
||||
};
|
||||
|
||||
var ContextCommands = {
|
||||
openInNewTab: function cc_openInNewTab(aEvent) {
|
||||
Browser.addTab(ContextHelper.linkURL, false);
|
||||
},
|
||||
|
||||
saveImage: function cc_saveImage(aEvent) {
|
||||
let doc = ContextHelper.popupNode.ownerDocument;
|
||||
saveImageURL(ContextHelper.mediaURL, null, "SaveImageTitle", false, false, doc.documentURIObject);
|
||||
}
|
||||
}
|
||||
|
||||
function removeBookmarksForURI(aURI) {
|
||||
//XXX blargle xpconnect! might not matter, but a method on
|
||||
// nsINavBookmarksService that takes an array of items to
|
||||
|
|
|
@ -438,6 +438,9 @@ var Browser = {
|
|||
notifications.addEventListener("AlertActive", notificationHandler, false);
|
||||
notifications.addEventListener("AlertClose", notificationHandler, false);
|
||||
|
||||
// Add context helper to the content area only
|
||||
container.addEventListener("contextmenu", ContextHelper, false);
|
||||
|
||||
// initialize input handling
|
||||
ih = new InputHandler(container);
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/commandUtil.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/exceptions.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||
|
@ -481,6 +482,20 @@
|
|||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<vbox id="context-popup" hidden="true" class="dialog-dark" top="0" left="0">
|
||||
<hbox id="context-header">
|
||||
<label id="context-hint" crop="center" flex="1"/>
|
||||
</hbox>
|
||||
<richlistbox id="context-commands" onclick="ContextHelper.hide();">
|
||||
<richlistitem id="context-openinnewtab" type="link" onclick="ContextCommands.openInNewTab(event);">
|
||||
<label value="&contextOpenInNewTab.label;"/>
|
||||
</richlistitem>
|
||||
<richlistitem id="context-saveimage" type="image" onclick="ContextCommands.saveImage(event);">
|
||||
<label value="&contextSaveImage.label;"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
|
||||
<!-- alerts for content -->
|
||||
<hbox id="alerts-container" hidden="true" align="start" class="dialog-dark" top="0" left="0"
|
||||
onclick="AlertsHelper.click(event);">
|
||||
|
|
|
@ -91,3 +91,6 @@
|
|||
<!ENTITY consoleErrFile.label "Source File:">
|
||||
<!ENTITY consoleErrLine.label "Line:">
|
||||
<!ENTITY consoleErrColumn.label "Column:">
|
||||
|
||||
<!ENTITY contextOpenInNewTab.label "Open Link in New Tab">
|
||||
<!ENTITY contextSaveImage.label "Save Image">
|
||||
|
|
|
@ -1041,6 +1041,38 @@ box[type="documenttab"]:only-child .documenttab-close {
|
|||
list-style-image: url("chrome://browser/skin/images/check-30.png");
|
||||
}
|
||||
|
||||
/* context popup ----------------------------------------------------------- */
|
||||
#context-popup {
|
||||
/* Remove some dialog-dark styles */
|
||||
padding: 8px 0 0 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#context-header > label {
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#context-commands {
|
||||
border: 1px solid rgb(207,207,207);
|
||||
-moz-border-radius: 0 0 8px 8px;
|
||||
}
|
||||
|
||||
#context-commands > richlistitem {
|
||||
-moz-box-align: center;
|
||||
background-color: rgb(245,245,245);
|
||||
min-width: 200px; /* keep the command from being too narrow */
|
||||
}
|
||||
|
||||
#context-commands > richlistitem[selector="first-child"] {
|
||||
background: -moz-linear-gradient(top, rgb(255,255,255), rgb(245,245,245));
|
||||
}
|
||||
|
||||
#context-commands > richlistitem[selector="last-child"] {
|
||||
background: -moz-linear-gradient(top, rgb(245,245,245), rgb(215,215,215));
|
||||
-moz-border-radius: 0 0 8px 8px !important;
|
||||
}
|
||||
|
||||
.modal-block {
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
|
|
|
@ -708,6 +708,38 @@ box[type="documenttab"]:only-child .documenttab-close {
|
|||
min-width: 30px;
|
||||
}
|
||||
|
||||
/* context popup ----------------------------------------------------------- */
|
||||
#context-popup {
|
||||
/* Remove some dialog-dark styles */
|
||||
padding: 0.5mm 0 0 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#context-header > label {
|
||||
font-size: 8pt;
|
||||
padding: 0.25mm;
|
||||
}
|
||||
|
||||
#context-commands {
|
||||
border: 1px solid rgb(207,207,207);
|
||||
-moz-border-radius: 0 0 0.5mm 0.5mm;
|
||||
}
|
||||
|
||||
#context-commands > richlistitem {
|
||||
-moz-box-align: center;
|
||||
background-color: rgb(245,245,245);
|
||||
min-width: 200px; /* keep the command from being too narrow */
|
||||
}
|
||||
|
||||
#context-commands > richlistitem[selector="first-child"] {
|
||||
background: -moz-linear-gradient(top, rgb(255,255,255), rgb(245,245,245));
|
||||
}
|
||||
|
||||
#context-commands > richlistitem[selector="last-child"] {
|
||||
background: -moz-linear-gradient(top, rgb(245,245,245), rgb(215,215,215));
|
||||
-moz-border-radius: 0 0 8px 8px !important;
|
||||
}
|
||||
|
||||
.modal-block {
|
||||
-moz-box-align: center;
|
||||
-moz-box-pack: center;
|
||||
|
|
Загрузка…
Ссылка в новой задаче