Bug 964014 - Adds copy-image-data-uri option to images in the markup-view, r=harth
This commit is contained in:
@@ -549,11 +549,13 @@ InspectorPanel.prototype = {
|
|||||||
* Disable the delete item if needed. Update the pseudo classes.
|
* Disable the delete item if needed. Update the pseudo classes.
|
||||||
*/
|
*/
|
||||||
_setupNodeMenu: function InspectorPanel_setupNodeMenu() {
|
_setupNodeMenu: function InspectorPanel_setupNodeMenu() {
|
||||||
|
let isSelectionElement = this.selection.isElementNode();
|
||||||
|
|
||||||
// Set the pseudo classes
|
// Set the pseudo classes
|
||||||
for (let name of ["hover", "active", "focus"]) {
|
for (let name of ["hover", "active", "focus"]) {
|
||||||
let menu = this.panelDoc.getElementById("node-menu-pseudo-" + name);
|
let menu = this.panelDoc.getElementById("node-menu-pseudo-" + name);
|
||||||
|
|
||||||
if (this.selection.isElementNode()) {
|
if (isSelectionElement) {
|
||||||
let checked = this.selection.nodeFront.hasPseudoClassLock(":" + name);
|
let checked = this.selection.nodeFront.hasPseudoClassLock(":" + name);
|
||||||
menu.setAttribute("checked", checked);
|
menu.setAttribute("checked", checked);
|
||||||
menu.removeAttribute("disabled");
|
menu.removeAttribute("disabled");
|
||||||
@@ -575,8 +577,7 @@ InspectorPanel.prototype = {
|
|||||||
let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
|
let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
|
||||||
let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
|
let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
|
||||||
let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
|
let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
|
||||||
let selectionIsElement = this.selection.isElementNode();
|
if (isSelectionElement) {
|
||||||
if (selectionIsElement) {
|
|
||||||
unique.removeAttribute("disabled");
|
unique.removeAttribute("disabled");
|
||||||
copyInnerHTML.removeAttribute("disabled");
|
copyInnerHTML.removeAttribute("disabled");
|
||||||
copyOuterHTML.removeAttribute("disabled");
|
copyOuterHTML.removeAttribute("disabled");
|
||||||
@@ -586,12 +587,24 @@ InspectorPanel.prototype = {
|
|||||||
copyOuterHTML.setAttribute("disabled", "true");
|
copyOuterHTML.setAttribute("disabled", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable the "edit HTML" item if the selection is an element and the root
|
||||||
|
// actor has the appropriate trait (isOuterHTMLEditable)
|
||||||
let editHTML = this.panelDoc.getElementById("node-menu-edithtml");
|
let editHTML = this.panelDoc.getElementById("node-menu-edithtml");
|
||||||
if (this.isOuterHTMLEditable && selectionIsElement) {
|
if (this.isOuterHTMLEditable && isSelectionElement) {
|
||||||
editHTML.removeAttribute("disabled");
|
editHTML.removeAttribute("disabled");
|
||||||
} else {
|
} else {
|
||||||
editHTML.setAttribute("disabled", "true");
|
editHTML.setAttribute("disabled", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable the "copy image data-uri" item if the selection is previewable
|
||||||
|
// which essentially checks if it's an image or canvas tag
|
||||||
|
let copyImageData = this.panelDoc.getElementById("node-menu-copyimagedatauri");
|
||||||
|
let markupContainer = this.markup.getContainer(this.selection.nodeFront);
|
||||||
|
if (markupContainer && markupContainer.isPreviewable()) {
|
||||||
|
copyImageData.removeAttribute("disabled");
|
||||||
|
} else {
|
||||||
|
copyImageData.setAttribute("disabled", "true");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_resetNodeMenu: function InspectorPanel_resetNodeMenu() {
|
_resetNodeMenu: function InspectorPanel_resetNodeMenu() {
|
||||||
@@ -717,7 +730,19 @@ InspectorPanel.prototype = {
|
|||||||
this._copyLongStr(this.walker.outerHTML(this.selection.nodeFront));
|
this._copyLongStr(this.walker.outerHTML(this.selection.nodeFront));
|
||||||
},
|
},
|
||||||
|
|
||||||
_copyLongStr: function(promise) {
|
/**
|
||||||
|
* Copy the data-uri for the currently selected image in the clipboard.
|
||||||
|
*/
|
||||||
|
copyImageDataUri: function InspectorPanel_copyImageDataUri()
|
||||||
|
{
|
||||||
|
let container = this.markup.getContainer(this.selection.nodeFront);
|
||||||
|
if (container && container.isPreviewable()) {
|
||||||
|
container.copyImageDataUri();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_copyLongStr: function InspectorPanel_copyLongStr(promise)
|
||||||
|
{
|
||||||
return promise.then(longstr => {
|
return promise.then(longstr => {
|
||||||
return longstr.string().then(toCopy => {
|
return longstr.string().then(toCopy => {
|
||||||
longstr.release().then(null, console.error);
|
longstr.release().then(null, console.error);
|
||||||
|
|||||||
@@ -52,6 +52,9 @@
|
|||||||
label="&inspectorCopyUniqueSelector.label;"
|
label="&inspectorCopyUniqueSelector.label;"
|
||||||
accesskey="&inspectorCopyUniqueSelector.accesskey;"
|
accesskey="&inspectorCopyUniqueSelector.accesskey;"
|
||||||
oncommand="inspector.copyUniqueSelector()"/>
|
oncommand="inspector.copyUniqueSelector()"/>
|
||||||
|
<menuitem id="node-menu-copyimagedatauri"
|
||||||
|
label="&inspectorCopyImageDataUri.label;"
|
||||||
|
oncommand="inspector.copyImageDataUri()"/>
|
||||||
<menuseparator/>
|
<menuseparator/>
|
||||||
<menuitem id="node-menu-delete"
|
<menuitem id="node-menu-delete"
|
||||||
label="&inspectorHTMLDelete.label;"
|
label="&inspectorHTMLDelete.label;"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
|||||||
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
|
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
|
||||||
Cu.import("resource://gre/modules/devtools/Templater.jsm");
|
Cu.import("resource://gre/modules/devtools/Templater.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
loader.lazyGetter(this, "DOMParser", function() {
|
loader.lazyGetter(this, "DOMParser", function() {
|
||||||
return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
|
return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
|
||||||
@@ -1279,20 +1280,27 @@ MarkupContainer.prototype = {
|
|||||||
return "[MarkupContainer for " + this.node + "]";
|
return "[MarkupContainer for " + this.node + "]";
|
||||||
},
|
},
|
||||||
|
|
||||||
_prepareImagePreview: function() {
|
isPreviewable: function() {
|
||||||
if (this.node.tagName) {
|
if (this.node.tagName) {
|
||||||
let tagName = this.node.tagName.toLowerCase();
|
let tagName = this.node.tagName.toLowerCase();
|
||||||
let srcAttr = this.editor.getAttributeElement("src");
|
let srcAttr = this.editor.getAttributeElement("src");
|
||||||
let isImage = tagName === "img" && srcAttr;
|
let isImage = tagName === "img" && srcAttr;
|
||||||
let isCanvas = tagName === "canvas";
|
let isCanvas = tagName === "canvas";
|
||||||
|
|
||||||
|
return isImage || isCanvas;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_prepareImagePreview: function() {
|
||||||
|
if (this.isPreviewable()) {
|
||||||
// Get the image data for later so that when the user actually hovers over
|
// Get the image data for later so that when the user actually hovers over
|
||||||
// the element, the tooltip does contain the image
|
// the element, the tooltip does contain the image
|
||||||
if (isImage || isCanvas) {
|
|
||||||
let def = promise.defer();
|
let def = promise.defer();
|
||||||
|
|
||||||
this.tooltipData = {
|
this.tooltipData = {
|
||||||
target: isImage ? srcAttr : this.editor.tag,
|
target: this.editor.getAttributeElement("src") || this.editor.tag,
|
||||||
data: def.promise
|
data: def.promise
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1308,7 +1316,18 @@ MarkupContainer.prototype = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
copyImageDataUri: function() {
|
||||||
|
// We need to send again a request to gettooltipData even if one was sent for
|
||||||
|
// the tooltip, because we want the full-size image
|
||||||
|
this.node.getImageData().then(data => {
|
||||||
|
if (data) {
|
||||||
|
data.data.string().then(str => {
|
||||||
|
clipboardHelper.copyString(str, this.markup.doc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_buildTooltipContent: function(target, tooltip) {
|
_buildTooltipContent: function(target, tooltip) {
|
||||||
@@ -2068,3 +2087,8 @@ function parseAttributeValues(attr, doc) {
|
|||||||
loader.lazyGetter(MarkupView.prototype, "strings", () => Services.strings.createBundle(
|
loader.lazyGetter(MarkupView.prototype, "strings", () => Services.strings.createBundle(
|
||||||
"chrome://browser/locale/devtools/inspector.properties"
|
"chrome://browser/locale/devtools/inspector.properties"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
|
||||||
|
return Cc["@mozilla.org/widget/clipboardhelper;1"].
|
||||||
|
getService(Ci.nsIClipboardHelper);
|
||||||
|
});
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ skip-if = true
|
|||||||
[browser_inspector_markup_subset.js]
|
[browser_inspector_markup_subset.js]
|
||||||
[browser_inspector_markup_765105_tooltip.js]
|
[browser_inspector_markup_765105_tooltip.js]
|
||||||
[browser_inspector_markup_950732.js]
|
[browser_inspector_markup_950732.js]
|
||||||
|
[browser_inspector_markup_964014_copy_image_data.js]
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@ const Cu = Components.utils;
|
|||||||
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||||
let TargetFactory = devtools.TargetFactory;
|
let TargetFactory = devtools.TargetFactory;
|
||||||
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||||
|
let promise = devtools.require("sdk/core/promise");
|
||||||
|
|
||||||
// Clear preferences that may be set during the course of tests.
|
// Clear preferences that may be set during the course of tests.
|
||||||
function clearUserPrefs() {
|
function clearUserPrefs() {
|
||||||
@@ -27,3 +28,38 @@ function getContainerForRawNode(markupView, rawNode) {
|
|||||||
let container = markupView.getContainer(front);
|
let container = markupView.getContainer(front);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the toolbox, with the inspector tool visible.
|
||||||
|
* @return a promise that resolves when the inspector is ready
|
||||||
|
*/
|
||||||
|
function openInspector() {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
|
||||||
|
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||||
|
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||||
|
let inspector = toolbox.getCurrentPanel();
|
||||||
|
inspector.once("inspector-updated", () => {
|
||||||
|
deferred.resolve(inspector, toolbox);
|
||||||
|
});
|
||||||
|
}).then(null, console.error);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the inspector's current selection to the first match of the given css
|
||||||
|
* selector
|
||||||
|
* @return a promise that resolves when the inspector is updated with the new
|
||||||
|
* node
|
||||||
|
*/
|
||||||
|
function selectNode(selector, inspector) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let node = content.document.querySelector(selector);
|
||||||
|
ok(node, "A node was found for selector " + selector + ". Selecting it now");
|
||||||
|
inspector.selection.setNode(node, "test");
|
||||||
|
inspector.once("inspector-updated", () => {
|
||||||
|
deferred.resolve(node);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,3 +17,5 @@
|
|||||||
|
|
||||||
<!ENTITY inspectorSearchHTML.label "Search HTML">
|
<!ENTITY inspectorSearchHTML.label "Search HTML">
|
||||||
<!ENTITY inspectorSearchHTML.key "F">
|
<!ENTITY inspectorSearchHTML.key "F">
|
||||||
|
|
||||||
|
<!ENTITY inspectorCopyImageDataUri.label "Copy Image Data-URL">
|
||||||
|
|||||||
Reference in New Issue
Block a user