Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (204861 => 204862)
--- trunk/Source/WebInspectorUI/ChangeLog 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/ChangeLog 2016-08-23 22:23:26 UTC (rev 204862)
@@ -1,5 +1,38 @@
2016-08-23 Devin Rousso <[email protected]>
+ Web Inspector: resource tree elements should provide "Download File" context menu items
+ https://bugs.webkit.org/show_bug.cgi?id=158035
+
+ Reviewed by Joseph Pecoraro.
+
+ Add a context menu item to elements representing resources that
+ initiates a download of that resource.
+
+ * Localizations/en.lproj/localizedStrings.js:
+
+ * UserInterface/Base/Main.js:
+ (WebInspector.saveDataToFile):
+ Add support for saving base64 objects.
+
+ * UserInterface/Base/MIMETypeUtilities.js:
+ (WebInspector.fileExtensionForMIMEType):
+ Returns a file extension for the given MIME type if able.
+
+ * UserInterface/Views/FrameTreeElement.js:
+ (WebInspector.FrameTreeElement.prototype.onattach):
+ Add contextmenu event listener since superclass onattach call is explicitly not used.
+
+ * UserInterface/Views/ResourceTimelineDataGridNode.js:
+ (WebInspector.ResourceTimelineDataGridNode.prototype.appendContextMenuItems):
+ Add Save File context menu item.
+
+ * UserInterface/Views/ResourceTreeElement.js:
+ (WebInspector.ResourceTreeElement.prototype.onattach):
+ (WebInspector.ResourceTreeElement.prototype._handleContextMenuEvent):
+ Add contextmenu event listener and Save File context menu item.
+
+2016-08-23 Devin Rousso <[email protected]>
+
Web Inspector: No open/copy src resource in context menu
https://bugs.webkit.org/show_bug.cgi?id=159028
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -613,6 +613,7 @@
localizedStrings["Role"] = "Role";
localizedStrings["Rule"] = "Rule";
localizedStrings["Samples"] = "Samples";
+localizedStrings["Save File"] = "Save File";
localizedStrings["Save configuration"] = "Save configuration";
localizedStrings["Scheme"] = "Scheme";
localizedStrings["Scope"] = "Scope";
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/MIMETypeUtilities.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/UserInterface/Base/MIMETypeUtilities.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/MIMETypeUtilities.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -78,3 +78,47 @@
return extensionToMIMEType[extension] || null;
};
+
+WebInspector.fileExtensionForMIMEType = function(mimeType)
+{
+ const mimeTypeToExtension = {
+ // Document types.
+ "text/html": "html",
+ "application/xhtml+xml": "xhtml",
+ "text/xml": "xml",
+
+ // Script types.
+ "text/_javascript_": "js",
+ "application/json": "json",
+ "text/x-clojure": "clj",
+ "text/x-coffeescript": "coffee",
+ "text/x-livescript": "ls",
+ "text/typescript": "ts",
+
+ // Stylesheet types.
+ "text/css": "css",
+ "text/x-less": "less",
+ "text/x-sass": "sass",
+ "text/x-scss": "scss",
+
+ // Image types.
+ "image/bmp": "bmp",
+ "image/gif": "gif",
+ "image/jpeg": "jpeg",
+ "image/jpeg": "jpg",
+ "application/pdf": "pdf",
+ "image/png": "png",
+ "image/tiff": "tif",
+ "image/tiff": "tiff",
+
+ // Font types and Media types are ignored for now.
+
+ // Miscellaneous types.
+ "image/svg+xml": "svg",
+ "text/plain": "txt",
+ "text/xsl": "xsl",
+ };
+
+ let extension = mimeTypeToExtension[mimeType];
+ return extension ? `.${extension}` : null;
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -806,11 +806,32 @@
}
console.assert(saveData.url);
- console.assert(typeof saveData.content === "string");
- if (!saveData.url || typeof saveData.content !== "string")
+ console.assert(saveData.content);
+ if (!saveData.url || !saveData.content)
return;
- InspectorFrontendHost.save(saveData.url, saveData.content, false, forceSaveAs || saveData.forceSaveAs);
+ let suggestedName = parseURL(saveData.url).lastPathComponent;
+ if (!suggestedName) {
+ suggestedName = WebInspector.UIString("Untitled");
+ let dataURLTypeMatch = /^data:([^;]+)/.exec(saveData.url);
+ if (dataURLTypeMatch)
+ suggestedName += WebInspector.fileExtensionForMIMEType(dataURLTypeMatch[1]) || "";
+ }
+
+ if (typeof saveData.content === "string") {
+ const base64Encoded = false;
+ InspectorFrontendHost.save(suggestedName, saveData.content, base64Encoded, forceSaveAs || saveData.forceSaveAs);
+ return;
+ }
+
+ let fileReader = new FileReader;
+ fileReader.readAsDataURL(saveData.content);
+ fileReader.addEventListener("loadend", () => {
+ let dataURLComponents = parseDataURL(fileReader.result);
+
+ const base64Encoded = true;
+ InspectorFrontendHost.save(suggestedName, dataURLComponents.data, base64Encoded, forceSaveAs || saveData.forceSaveAs);
+ });
};
WebInspector.isConsoleFocused = function()
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/FrameTreeElement.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/UserInterface/Views/FrameTreeElement.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/FrameTreeElement.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -142,6 +142,8 @@
{
// Immediate superclasses are skipped, since Frames handle their own SourceMapResources.
WebInspector.GeneralTreeElement.prototype.onattach.call(this);
+
+ this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
}
// Overrides from FolderizedTreeElement (Protected).
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -148,6 +148,15 @@
appendContextMenuItems(contextMenu)
{
+ contextMenu.appendItem(WebInspector.UIString("Save File"), () => {
+ this._resource.requestContent().then(() => {
+ WebInspector.saveDataToFile({
+ url: this._resource.url,
+ content: this._resource.content
+ });
+ });
+ });
+
if (this._resource.urlComponents.scheme !== "data")
contextMenu.appendItem(WebInspector.UIString("Copy as cURL"), () => { this._resource.generateCURLCommand(); });
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js (204861 => 204862)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js 2016-08-23 22:16:46 UTC (rev 204861)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js 2016-08-23 22:23:26 UTC (rev 204862)
@@ -87,6 +87,13 @@
return {text: [urlComponents.lastPathComponent, urlComponents.path, this._resource.url]};
}
+ onattach()
+ {
+ super.onattach();
+
+ this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));
+ }
+
ondblclick()
{
InspectorFrontendHost.openInNewTab(this._resource.url);
@@ -151,6 +158,20 @@
this.callFirstAncestorFunction("descendantResourceTreeElementMainTitleDidChange", [this, oldMainTitle]);
}
+ _handleContextMenuEvent(event)
+ {
+ let contextMenu = WebInspector.ContextMenu.createFromEvent(event);
+
+ contextMenu.appendItem(WebInspector.UIString("Save File"), () => {
+ this._resource.requestContent().then(() => {
+ WebInspector.saveDataToFile({
+ url: this._resource.url,
+ content: this._resource.content
+ });
+ });
+ });
+ }
+
// Private
_updateStatus()