From 23e68227a2e3f3946fa4fd5589f338e6b36a6e56 Mon Sep 17 00:00:00 2001 From: yami <34216515+kn-yami@users.noreply.github.com> Date: Tue, 30 Jul 2019 15:27:59 +0200 Subject: Issue #1138 - Part 1: refactor the JSON Viewer stream converter Mozilla Bug 1367894 --- devtools/client/jsonview/converter-child.js | 332 ++++++++++++---------------- devtools/client/jsonview/css/general.css | 9 +- devtools/client/jsonview/json-viewer.js | 4 +- devtools/client/jsonview/utils.js | 2 + 4 files changed, 153 insertions(+), 194 deletions(-) (limited to 'devtools/client/jsonview') diff --git a/devtools/client/jsonview/converter-child.js b/devtools/client/jsonview/converter-child.js index 61aa0c9a3..cf93161af 100644 --- a/devtools/client/jsonview/converter-child.js +++ b/devtools/client/jsonview/converter-child.js @@ -23,10 +23,6 @@ const childProcessMessageManager = Cc["@mozilla.org/childprocessmessagemanager;1"] .getService(Ci.nsISyncMessageSender); -// Amount of space that will be allocated for the stream's backing-store. -// Must be power of 2. Used to copy the data stream in onStopRequest. -const SEGMENT_SIZE = Math.pow(2, 17); - const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view"; const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" + JSON_VIEW_MIME_TYPE + "&to=*/*"; @@ -61,9 +57,9 @@ let Converter = Class({ * 1. asyncConvertData captures the listener * 2. onStartRequest fires, initializes stuff, modifies the listener * to match our output type - * 3. onDataAvailable transcodes the data into a UTF-8 string - * 4. onStopRequest gets the collected data and converts it, - * spits it to the listener + * 3. onDataAvailable spits it back to the listener + * 4. onStopRequest spits it back to the listener and initializes + * the JSON Viewer * 5. convert does nothing, it's just the synchronous version * of asyncConvertData */ @@ -76,60 +72,52 @@ let Converter = Class({ }, onDataAvailable: function (request, context, inputStream, offset, count) { - // From https://developer.mozilla.org/en/Reading_textual_data - let is = Cc["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Ci.nsIConverterInputStream); - is.init(inputStream, this.charset, -1, - Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); - - // Seed it with something positive - while (count) { - let str = {}; - let bytesRead = is.readString(count, str); - if (!bytesRead) { - break; - } - count -= bytesRead; - this.data += str.value; - } + this.listener.onDataAvailable(...arguments); }, onStartRequest: function (request, context) { - this.data = ""; - this.uri = request.QueryInterface(Ci.nsIChannel).URI.spec; + this.channel = request; + + // Let "save as" save the original JSON, not the viewer. + // To save with the proper extension we need the original content type, + // which has been replaced by application/vnd.mozilla.json.view + let originalType; + if (request instanceof Ci.nsIHttpChannel) { + try { + let header = request.getResponseHeader("Content-Type"); + originalType = header.split(";")[0]; + } catch (err) { + // Handled below + } + } else { + let uri = request.QueryInterface(Ci.nsIChannel).URI.spec; + let match = uri.match(/^data:(.*?)[,;]/); + if (match) { + originalType = match[1]; + } + } + const JSON_TYPES = ["application/json", "application/manifest+json"]; + if (!JSON_TYPES.includes(originalType)) { + originalType = JSON_TYPES[0]; + } + request.QueryInterface(Ci.nsIWritablePropertyBag); + request.setProperty("contentType", originalType); - // Sets the charset if it is available. (For documents loaded from the - // filesystem, this is not set.) - this.charset = - request.QueryInterface(Ci.nsIChannel).contentCharset || "UTF-8"; + // Parse source as JSON. This is like text/plain, but enforcing + // UTF-8 charset (see bug 741776). + request.QueryInterface(Ci.nsIChannel); + request.contentType = JSON_TYPES[0]; + this.charset = request.contentCharset = "UTF-8"; - this.channel = request; - this.channel.contentType = "text/html"; - this.channel.contentCharset = "UTF-8"; // Because content might still have a reference to this window, // force setting it to a null principal to avoid it being same- // origin with (other) content. - this.channel.loadInfo.resetPrincipalsToNullPrincipal(); + request.loadInfo.resetPrincipalsToNullPrincipal(); - this.listener.onStartRequest(this.channel, context); + this.listener.onStartRequest(request, context); }, - /** - * This should go something like this: - * 1. Make sure we have a unicode string. - * 2. Convert it to a Javascript object. - * 2.1 Removes the callback - * 3. Convert that to HTML? Or XUL? - * 4. Spit it back out at the listener - */ onStopRequest: function (request, context, statusCode) { - let headers = { - response: [], - request: [] - }; - - let win = NetworkHelper.getWindowForRequest(request); - let Locale = { $STR: key => { try { @@ -141,12 +129,10 @@ let Converter = Class({ } }; - JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); - - Events.once(win, "DOMContentLoaded", event => { - win.addEventListener("contentMessage", - this.onContentMessage.bind(this), false, true); - }); + let headers = { + response: [], + request: [] + }; // The request doesn't have to be always nsIHttpChannel // (e.g. in case of data: URLs) @@ -156,7 +142,6 @@ let Converter = Class({ headers.response.push({name: name, value: value}); } }); - request.visitRequestHeaders({ visitHeader: function (name, value) { headers.request.push({name: name, value: value}); @@ -164,155 +149,124 @@ let Converter = Class({ }); } - let outputDoc = ""; - - try { - headers = JSON.stringify(headers); - outputDoc = this.toHTML(this.data, headers, this.uri); - } catch (e) { - console.error("JSON Viewer ERROR " + e); - outputDoc = this.toErrorPage(e, this.data, this.uri); - } - - let storage = Cc["@mozilla.org/storagestream;1"] - .createInstance(Ci.nsIStorageStream); - - storage.init(SEGMENT_SIZE, 0xffffffff, null); - let out = storage.getOutputStream(0); - - let binout = Cc["@mozilla.org/binaryoutputstream;1"] - .createInstance(Ci.nsIBinaryOutputStream); - - binout.setOutputStream(out); - binout.writeUtf8Z(outputDoc); - binout.close(); - - // We need to trim 4 bytes off the front (this could be underlying bug). - let trunc = 4; - let instream = storage.newInputStream(trunc); + let win = NetworkHelper.getWindowForRequest(request); + JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); + JsonViewUtils.exportIntoContentScope(win, headers, "headers"); - // Pass the data to the main content listener - this.listener.onDataAvailable(this.channel, context, instream, 0, - instream.available()); + win.addEventListener("DOMContentLoaded", event => { + win.addEventListener("contentMessage", + onContentMessage.bind(this), false, true); + loadJsonViewer(win.document); + }, {once: true}); this.listener.onStopRequest(this.channel, context, statusCode); - this.listener = null; - }, - - htmlEncode: function (t) { - return t !== null ? t.toString() - .replace(/&/g, "&") - .replace(/"/g, """) - .replace(//g, ">") : ""; - }, - - toHTML: function (json, headers, title) { - let themeClassName = "theme-" + JsonViewUtils.getCurrentTheme(); - let clientBaseUrl = "resource://devtools/client/"; - let baseUrl = clientBaseUrl + "jsonview/"; - let themeVarsUrl = clientBaseUrl + "themes/variables.css"; - let commonUrl = clientBaseUrl + "themes/common.css"; - let toolbarsUrl = clientBaseUrl + "themes/toolbars.css"; - - let os; - let platform = Services.appinfo.OS; - if (platform.startsWith("WINNT")) { - os = "win"; - } else if (platform.startsWith("Darwin")) { - os = "mac"; - } else { - os = "linux"; - } - - return "\n" + - "" + - "" + this.htmlEncode(title) + "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
" + - "
" + this.htmlEncode(json) + "
" + - "
" + this.htmlEncode(headers) + "
" + - ""; - }, - - toErrorPage: function (error, data, uri) { - // Escape unicode nulls - data = data.replace("\u0000", "\uFFFD"); - - let errorInfo = error + ""; - - let output = "
" + "error parsing"; - if (errorInfo.message) { - output += "
" + errorInfo.message + "
"; - } + } +}); - output += "
" + this.highlightError(data, - errorInfo.line, errorInfo.column) + "
"; +// Chrome <-> Content communication +function onContentMessage(e) { + // Do not handle events from different documents. + let win = NetworkHelper.getWindowForRequest(this.channel); + if (win != e.target) { + return; + } - return "\n" + - "" + this.htmlEncode(uri + " - Error") + "" + - "" + - "" + - output + - ""; - }, + let value = e.detail.value; + switch (e.detail.type) { + case "copy": + copyString(win, value); + break; + + case "copy-headers": + copyHeaders(win, value); + break; + + case "save": + // The window ID is needed when the JSON Viewer is inside an iframe. + let windowID = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils).outerWindowID; + childProcessMessageManager.sendAsyncMessage( + "devtools:jsonview:save", {url: value, windowID: windowID}); + } +} - // Chrome <-> Content communication +// Loads the JSON Viewer into a text/plain document +function loadJsonViewer(doc) { + function addStyleSheet(url) { + let link = doc.createElement("link"); + link.rel = "stylesheet"; + link.type = "text/css"; + link.href = url; + doc.head.appendChild(link); + } - onContentMessage: function (e) { - // Do not handle events from different documents. - let win = NetworkHelper.getWindowForRequest(this.channel); - if (win != e.target) { - return; - } + let os; + let platform = Services.appinfo.OS; + if (platform.startsWith("WINNT")) { + os = "win"; + } else if (platform.startsWith("Darwin")) { + os = "mac"; + } else { + os = "linux"; + } - let value = e.detail.value; - switch (e.detail.type) { - case "copy": - Clipboard.set(value, "text"); - break; + doc.documentElement.setAttribute("platform", os); + doc.documentElement.dataset.contentType = doc.contentType; + doc.documentElement.classList.add("theme-" + JsonViewUtils.getCurrentTheme()); + doc.documentElement.dir = Services.locale.isAppLocaleRTL ? "rtl" : "ltr"; + + let base = doc.createElement("base"); + base.href = "resource://devtools/client/jsonview/"; + doc.head.appendChild(base); + + addStyleSheet("../themes/variables.css"); + addStyleSheet("../themes/common.css"); + addStyleSheet("../themes/toolbars.css"); + addStyleSheet("css/main.css"); + + let json = doc.querySelector("pre"); + json.id = "json"; + let content = doc.createElement("div"); + content.id = "content"; + content.appendChild(json); + doc.body.appendChild(content); + + let script = doc.createElement("script"); + script.src = "lib/require.js"; + script.dataset.main = "viewer-config"; + doc.body.appendChild(script); +} - case "copy-headers": - this.copyHeaders(value); - break; +function copyHeaders(win, headers) { + let value = ""; + let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n"; - case "save": - childProcessMessageManager.sendAsyncMessage( - "devtools:jsonview:save", value); - } - }, + let responseHeaders = headers.response; + for (let i = 0; i < responseHeaders.length; i++) { + let header = responseHeaders[i]; + value += header.name + ": " + header.value + eol; + } - copyHeaders: function (headers) { - let value = ""; - let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n"; + value += eol; - let responseHeaders = headers.response; - for (let i = 0; i < responseHeaders.length; i++) { - let header = responseHeaders[i]; - value += header.name + ": " + header.value + eol; - } + let requestHeaders = headers.request; + for (let i = 0; i < requestHeaders.length; i++) { + let header = requestHeaders[i]; + value += header.name + ": " + header.value + eol; + } - value += eol; + copyString(win, value); +} - let requestHeaders = headers.request; - for (let i = 0; i < requestHeaders.length; i++) { - let header = requestHeaders[i]; - value += header.name + ": " + header.value + eol; - } +function copyString(win, string) { + win.document.addEventListener("copy", event => { + event.clipboardData.setData("text/plain", string); + event.preventDefault(); + }, {once: true}); - Clipboard.set(value, "text"); - } -}); + win.document.execCommand("copy", false, null); +} // Stream converter component definition let service = xpcom.Service({ diff --git a/devtools/client/jsonview/css/general.css b/devtools/client/jsonview/css/general.css index 0c68d65e7..89b3b3c98 100644 --- a/devtools/client/jsonview/css/general.css +++ b/devtools/client/jsonview/css/general.css @@ -28,8 +28,7 @@ pre { font-family: var(--monospace-font-family); } -#json, -#headers { +#json { display: none; } @@ -44,3 +43,9 @@ body.theme-dark { .theme-dark pre { background-color: var(--theme-body-background); } + +/******************************************************************************/ +/* Fixes for quirks mode */ +table { + font: inherit; +} diff --git a/devtools/client/jsonview/json-viewer.js b/devtools/client/jsonview/json-viewer.js index d96081da2..bf86ebbea 100644 --- a/devtools/client/jsonview/json-viewer.js +++ b/devtools/client/jsonview/json-viewer.js @@ -12,7 +12,6 @@ define(function (require, exports, module) { const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area")); const json = document.getElementById("json"); - const headers = document.getElementById("headers"); let jsonData; @@ -27,13 +26,12 @@ define(function (require, exports, module) { jsonText: json.textContent, jsonPretty: null, json: jsonData, - headers: JSON.parse(headers.textContent), + headers: window.headers, tabActive: 0, prettified: false }; json.remove(); - headers.remove(); /** * Application actions/commands. This list implements all commands diff --git a/devtools/client/jsonview/utils.js b/devtools/client/jsonview/utils.js index a70afdc68..6ab697c89 100644 --- a/devtools/client/jsonview/utils.js +++ b/devtools/client/jsonview/utils.js @@ -96,6 +96,8 @@ exports.exportIntoContentScope = function (win, obj, defineAs) { Cu.exportFunction(propValue, clone, { defineAs: propName }); + } else { + clone[propName] = Cu.cloneInto(propValue, win); } } }; -- cgit v1.2.3 From f635feec77ad32c3e1251a91a145ebee185fee31 Mon Sep 17 00:00:00 2001 From: yami <34216515+kn-yami@users.noreply.github.com> Date: Tue, 30 Jul 2019 15:42:58 +0200 Subject: Issue #1138 - Part 2: JSON Viewer should ignore BOM Mozilla Bug 1395313 --- devtools/client/jsonview/json-viewer.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'devtools/client/jsonview') diff --git a/devtools/client/jsonview/json-viewer.js b/devtools/client/jsonview/json-viewer.js index bf86ebbea..38cb6d7ec 100644 --- a/devtools/client/jsonview/json-viewer.js +++ b/devtools/client/jsonview/json-viewer.js @@ -13,24 +13,26 @@ define(function (require, exports, module) { const json = document.getElementById("json"); - let jsonData; - - try { - jsonData = JSON.parse(json.textContent); - } catch (err) { - jsonData = err + ""; - } - // Application state object. let input = { jsonText: json.textContent, jsonPretty: null, - json: jsonData, headers: window.headers, tabActive: 0, prettified: false }; + // Remove BOM, if present. + if (input.jsonText.startsWith("\ufeff")) { + input.jsonText = input.jsonText.slice(1); + } + + try { + input.json = JSON.parse(input.jsonText); + } catch (err) { + input.json = err; + } + json.remove(); /** @@ -59,7 +61,7 @@ define(function (require, exports, module) { theApp.setState({jsonText: input.jsonText}); } else { if (!input.jsonPretty) { - input.jsonPretty = JSON.stringify(jsonData, null, " "); + input.jsonPretty = JSON.stringify(input.json, null, " "); } theApp.setState({jsonText: input.jsonPretty}); } -- cgit v1.2.3 From d80d5688e6177d81513aa5b4d55cb479220c85b0 Mon Sep 17 00:00:00 2001 From: yami <34216515+kn-yami@users.noreply.github.com> Date: Tue, 30 Jul 2019 16:09:52 +0200 Subject: Issue #1138 - Part 3: avoid quirks mode in JSON Viewer Mozilla Bug 1368899 --- devtools/client/jsonview/converter-child.js | 262 +++++++++++++++------------- devtools/client/jsonview/css/general.css | 7 +- devtools/client/jsonview/css/main.css | 4 +- 3 files changed, 146 insertions(+), 127 deletions(-) (limited to 'devtools/client/jsonview') diff --git a/devtools/client/jsonview/converter-child.js b/devtools/client/jsonview/converter-child.js index cf93161af..1be342474 100644 --- a/devtools/client/jsonview/converter-child.js +++ b/devtools/client/jsonview/converter-child.js @@ -58,8 +58,7 @@ let Converter = Class({ * 2. onStartRequest fires, initializes stuff, modifies the listener * to match our output type * 3. onDataAvailable spits it back to the listener - * 4. onStopRequest spits it back to the listener and initializes - * the JSON Viewer + * 4. onStopRequest spits it back to the listener * 5. convert does nothing, it's just the synchronous version * of asyncConvertData */ @@ -76,98 +75,168 @@ let Converter = Class({ }, onStartRequest: function (request, context) { - this.channel = request; + // Set the content type to HTML in order to parse the doctype, styles + // and scripts, but later a element will switch the tokenizer + // to the plaintext state in order to parse the JSON. + request.QueryInterface(Ci.nsIChannel); + request.contentType = "text/html"; - // Let "save as" save the original JSON, not the viewer. - // To save with the proper extension we need the original content type, - // which has been replaced by application/vnd.mozilla.json.view - let originalType; - if (request instanceof Ci.nsIHttpChannel) { - try { - let header = request.getResponseHeader("Content-Type"); - originalType = header.split(";")[0]; - } catch (err) { - // Handled below - } - } else { - let uri = request.QueryInterface(Ci.nsIChannel).URI.spec; - let match = uri.match(/^data:(.*?)[,;]/); - if (match) { - originalType = match[1]; - } - } - const JSON_TYPES = ["application/json", "application/manifest+json"]; - if (!JSON_TYPES.includes(originalType)) { - originalType = JSON_TYPES[0]; - } - request.QueryInterface(Ci.nsIWritablePropertyBag); - request.setProperty("contentType", originalType); + // JSON enforces UTF-8 charset (see bug 741776). + request.contentCharset = "UTF-8"; - // Parse source as JSON. This is like text/plain, but enforcing - // UTF-8 charset (see bug 741776). - request.QueryInterface(Ci.nsIChannel); - request.contentType = JSON_TYPES[0]; - this.charset = request.contentCharset = "UTF-8"; + // Changing the content type breaks saving functionality. Fix it. + fixSave(request); // Because content might still have a reference to this window, // force setting it to a null principal to avoid it being same- // origin with (other) content. request.loadInfo.resetPrincipalsToNullPrincipal(); + // Start the request. this.listener.onStartRequest(request, context); - }, - - onStopRequest: function (request, context, statusCode) { - let Locale = { - $STR: key => { - try { - return jsonViewStrings.GetStringFromName(key); - } catch (err) { - console.error(err); - return undefined; - } - } - }; - - let headers = { - response: [], - request: [] - }; - - // The request doesn't have to be always nsIHttpChannel - // (e.g. in case of data: URLs) - if (request instanceof Ci.nsIHttpChannel) { - request.visitResponseHeaders({ - visitHeader: function (name, value) { - headers.response.push({name: name, value: value}); - } - }); - request.visitRequestHeaders({ - visitHeader: function (name, value) { - headers.request.push({name: name, value: value}); - } - }); - } + // Initialize stuff. let win = NetworkHelper.getWindowForRequest(request); - JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); - JsonViewUtils.exportIntoContentScope(win, headers, "headers"); - + exportData(win, request); win.addEventListener("DOMContentLoaded", event => { - win.addEventListener("contentMessage", - onContentMessage.bind(this), false, true); - loadJsonViewer(win.document); + win.addEventListener("contentMessage", onContentMessage, false, true); }, {once: true}); - this.listener.onStopRequest(this.channel, context, statusCode); + // Insert the initial HTML code. + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + let stream = converter.convertToInputStream(initialHTML(win.document)); + this.listener.onDataAvailable(request, context, stream, 0, stream.available()); + }, + + onStopRequest: function (request, context, statusCode) { + this.listener.onStopRequest(request, context, statusCode); this.listener = null; } }); +// Lets "save as" save the original JSON, not the viewer. +// To save with the proper extension we need the original content type, +// which has been replaced by application/vnd.mozilla.json.view +function fixSave(request) { + let originalType; + if (request instanceof Ci.nsIHttpChannel) { + try { + let header = request.getResponseHeader("Content-Type"); + originalType = header.split(";")[0]; + } catch (err) { + // Handled below + } + } else { + let uri = request.QueryInterface(Ci.nsIChannel).URI.spec; + let match = uri.match(/^data:(.*?)[,;]/); + if (match) { + originalType = match[1]; + } + } + const JSON_TYPES = ["application/json", "application/manifest+json"]; + if (!JSON_TYPES.includes(originalType)) { + originalType = JSON_TYPES[0]; + } + request.QueryInterface(Ci.nsIWritablePropertyBag); + request.setProperty("contentType", originalType); +} + +// Exports variables that will be accessed by the non-privileged scripts. +function exportData(win, request) { + let Locale = { + $STR: key => { + try { + return jsonViewStrings.GetStringFromName(key); + } catch (err) { + console.error(err); + return undefined; + } + } + }; + JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); + + let headers = { + response: [], + request: [] + }; + // The request doesn't have to be always nsIHttpChannel + // (e.g. in case of data: URLs) + if (request instanceof Ci.nsIHttpChannel) { + request.visitResponseHeaders({ + visitHeader: function (name, value) { + headers.response.push({name: name, value: value}); + } + }); + request.visitRequestHeaders({ + visitHeader: function (name, value) { + headers.request.push({name: name, value: value}); + } + }); + } + JsonViewUtils.exportIntoContentScope(win, headers, "headers"); +} + +// Serializes a qualifiedName and an optional set of attributes into an HTML +// start tag. Be aware qualifiedName and attribute names are not validated. +// Attribute values are escaped with escapingString algorithm in attribute mode +// (https://html.spec.whatwg.org/multipage/syntax.html#escapingString). +function startTag(qualifiedName, attributes = {}) { + return Object.entries(attributes).reduce(function (prev, [attr, value]) { + return prev + " " + attr + "=\"" + + value.replace(/&/g, "&amp;") + .replace(/\u00a0/g, "&nbsp;") + .replace(/"/g, "&quot;") + + "\""; + }, "<" + qualifiedName) + ">"; +} + +// Builds an HTML string that will be used to load stylesheets and scripts, +// and switch the parser to plaintext state. +function initialHTML(doc) { + let os; + let platform = Services.appinfo.OS; + if (platform.startsWith("WINNT")) { + os = "win"; + } else if (platform.startsWith("Darwin")) { + os = "mac"; + } else { + os = "linux"; + } + + let base = doc.createElement("base"); + base.href = "resource://devtools/client/jsonview/"; + + let style = doc.createElement("link"); + style.rel = "stylesheet"; + style.type = "text/css"; + style.href = "css/main.css"; + + let script = doc.createElement("script"); + script.src = "lib/require.js"; + script.dataset.main = "viewer-config"; + script.defer = true; + + let head = doc.createElement("head"); + head.append(base, style, script); + + return "<!DOCTYPE html>\n" + + startTag("html", { + "platform": os, + "class": "theme-" + JsonViewUtils.getCurrentTheme(), + "dir": Services.locale.isAppLocaleRTL ? "rtl" : "ltr" + }) + + head.outerHTML + + startTag("body") + + startTag("div", {"id": "content"}) + + startTag("plaintext", {"id": "json"}); +} + // Chrome <-> Content communication function onContentMessage(e) { // Do not handle events from different documents. - let win = NetworkHelper.getWindowForRequest(this.channel); + let win = this; if (win != e.target) { return; } @@ -191,53 +260,6 @@ function onContentMessage(e) { } } -// Loads the JSON Viewer into a text/plain document -function loadJsonViewer(doc) { - function addStyleSheet(url) { - let link = doc.createElement("link"); - link.rel = "stylesheet"; - link.type = "text/css"; - link.href = url; - doc.head.appendChild(link); - } - - let os; - let platform = Services.appinfo.OS; - if (platform.startsWith("WINNT")) { - os = "win"; - } else if (platform.startsWith("Darwin")) { - os = "mac"; - } else { - os = "linux"; - } - - doc.documentElement.setAttribute("platform", os); - doc.documentElement.dataset.contentType = doc.contentType; - doc.documentElement.classList.add("theme-" + JsonViewUtils.getCurrentTheme()); - doc.documentElement.dir = Services.locale.isAppLocaleRTL ? "rtl" : "ltr"; - - let base = doc.createElement("base"); - base.href = "resource://devtools/client/jsonview/"; - doc.head.appendChild(base); - - addStyleSheet("../themes/variables.css"); - addStyleSheet("../themes/common.css"); - addStyleSheet("../themes/toolbars.css"); - addStyleSheet("css/main.css"); - - let json = doc.querySelector("pre"); - json.id = "json"; - let content = doc.createElement("div"); - content.id = "content"; - content.appendChild(json); - doc.body.appendChild(content); - - let script = doc.createElement("script"); - script.src = "lib/require.js"; - script.dataset.main = "viewer-config"; - doc.body.appendChild(script); -} - function copyHeaders(win, headers) { let value = ""; let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n"; diff --git a/devtools/client/jsonview/css/general.css b/devtools/client/jsonview/css/general.css index 89b3b3c98..d80720f4f 100644 --- a/devtools/client/jsonview/css/general.css +++ b/devtools/client/jsonview/css/general.css @@ -30,6 +30,7 @@ pre { #json { display: none; + white-space: pre-wrap; } /******************************************************************************/ @@ -43,9 +44,3 @@ body.theme-dark { .theme-dark pre { background-color: var(--theme-body-background); } - -/******************************************************************************/ -/* Fixes for quirks mode */ -table { - font: inherit; -} diff --git a/devtools/client/jsonview/css/main.css b/devtools/client/jsonview/css/main.css index 04f3cb87c..c75d7cea0 100644 --- a/devtools/client/jsonview/css/main.css +++ b/devtools/client/jsonview/css/main.css @@ -3,7 +3,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -@import "resource://devtools/client/shared/components/reps/reps.css"; +@import "resource://devtools/client/themes/variables.css"; +@import "resource://devtools/client/themes/common.css"; +@import "resource://devtools/client/themes/toolbars.css"; @import "resource://devtools/client/shared/components/tree/tree-view.css"; @import "resource://devtools/client/shared/components/tabs/tabs.css"; -- cgit v1.2.3 From 3aeef88170dc6071f99d2351955ad4ee92bc83d1 Mon Sep 17 00:00:00 2001 From: yami <34216515+kn-yami@users.noreply.github.com> Date: Thu, 1 Aug 2019 02:18:45 +0200 Subject: Issue #1138 - Part 4: fix JSON Viewer save functionality Saving JSON from the viewer was broken, because the message passed to the `saveToFile` function contained unneeded data. This bug was introduced by 23e68227a2e3f3946fa4fd5589f338e6b36a6e56. --- devtools/client/jsonview/converter-child.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'devtools/client/jsonview') diff --git a/devtools/client/jsonview/converter-child.js b/devtools/client/jsonview/converter-child.js index 1be342474..65327c395 100644 --- a/devtools/client/jsonview/converter-child.js +++ b/devtools/client/jsonview/converter-child.js @@ -252,11 +252,8 @@ function onContentMessage(e) { break; case "save": - // The window ID is needed when the JSON Viewer is inside an iframe. - let windowID = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils).outerWindowID; childProcessMessageManager.sendAsyncMessage( - "devtools:jsonview:save", {url: value, windowID: windowID}); + "devtools:jsonview:save", value); } } -- cgit v1.2.3