зеркало из 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, "keyup");
|
||||||
this.listenFor(browserViewContainer, "DOMMouseScroll");
|
this.listenFor(browserViewContainer, "DOMMouseScroll");
|
||||||
this.listenFor(browserViewContainer, "MozMousePixelScroll");
|
this.listenFor(browserViewContainer, "MozMousePixelScroll");
|
||||||
|
this.listenFor(browserViewContainer, "contextmenu");
|
||||||
|
|
||||||
this.addModule(new MouseModule(this, browserViewContainer));
|
this.addModule(new MouseModule(this, browserViewContainer));
|
||||||
this.addModule(new ScrollwheelModule(this, browserViewContainer));
|
this.addModule(new ScrollwheelModule(this, browserViewContainer));
|
||||||
|
@ -418,6 +419,11 @@ function MouseModule(owner, browserViewContainer) {
|
||||||
|
|
||||||
MouseModule.prototype = {
|
MouseModule.prototype = {
|
||||||
handleEvent: function handleEvent(evInfo) {
|
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
|
if (evInfo.event.button !== 0) // avoid all but a clean left click
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,11 @@ let Util = {
|
||||||
return null;
|
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) {
|
contentIsHandheld: function contentIsHandheld(browser) {
|
||||||
let doctype = browser.contentDocument.doctype;
|
let doctype = browser.contentDocument.doctype;
|
||||||
if (doctype && /(WAP|WML|Mobile)/.test(doctype.publicId))
|
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) {
|
function removeBookmarksForURI(aURI) {
|
||||||
//XXX blargle xpconnect! might not matter, but a method on
|
//XXX blargle xpconnect! might not matter, but a method on
|
||||||
// nsINavBookmarksService that takes an array of items to
|
// nsINavBookmarksService that takes an array of items to
|
||||||
|
|
|
@ -438,6 +438,9 @@ var Browser = {
|
||||||
notifications.addEventListener("AlertActive", notificationHandler, false);
|
notifications.addEventListener("AlertActive", notificationHandler, false);
|
||||||
notifications.addEventListener("AlertClose", notificationHandler, false);
|
notifications.addEventListener("AlertClose", notificationHandler, false);
|
||||||
|
|
||||||
|
// Add context helper to the content area only
|
||||||
|
container.addEventListener("contextmenu", ContextHelper, false);
|
||||||
|
|
||||||
// initialize input handling
|
// initialize input handling
|
||||||
ih = new InputHandler(container);
|
ih = new InputHandler(container);
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
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/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/commandUtil.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/exceptions.js"/>
|
<script type="application/javascript" src="chrome://browser/content/exceptions.js"/>
|
||||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||||
|
@ -481,6 +482,20 @@
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</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 -->
|
<!-- alerts for content -->
|
||||||
<hbox id="alerts-container" hidden="true" align="start" class="dialog-dark" top="0" left="0"
|
<hbox id="alerts-container" hidden="true" align="start" class="dialog-dark" top="0" left="0"
|
||||||
onclick="AlertsHelper.click(event);">
|
onclick="AlertsHelper.click(event);">
|
||||||
|
|
|
@ -91,3 +91,6 @@
|
||||||
<!ENTITY consoleErrFile.label "Source File:">
|
<!ENTITY consoleErrFile.label "Source File:">
|
||||||
<!ENTITY consoleErrLine.label "Line:">
|
<!ENTITY consoleErrLine.label "Line:">
|
||||||
<!ENTITY consoleErrColumn.label "Column:">
|
<!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");
|
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 {
|
.modal-block {
|
||||||
-moz-box-align: center;
|
-moz-box-align: center;
|
||||||
-moz-box-pack: center;
|
-moz-box-pack: center;
|
||||||
|
|
|
@ -708,6 +708,38 @@ box[type="documenttab"]:only-child .documenttab-close {
|
||||||
min-width: 30px;
|
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 {
|
.modal-block {
|
||||||
-moz-box-align: center;
|
-moz-box-align: center;
|
||||||
-moz-box-pack: center;
|
-moz-box-pack: center;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче