Bug 1132203 - Load JSON viewer dynamically on demand; r=jryans

This commit is contained in:
Jan Odvarko 2015-09-28 13:34:03 +02:00
parent 44cfe0bcf1
commit 608cbebbbc
6 changed files with 183 additions and 72 deletions

View File

@ -6,26 +6,23 @@
"use strict";
const Cu = Components.utils;
const Ci = Components.interfaces;
const Cc = Components.classes;
const {devtools} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
let require = devtools.require;
const {Cu, Cc, Ci, components} = require("chrome");
const {Class} = require("sdk/core/heritage");
const {Unknown} = require("sdk/platform/xpcom");
const xpcom = require("sdk/platform/xpcom");
const Events = require("sdk/dom/events");
const Clipboard = require("sdk/clipboard");
const NetworkHelper = require("devtools/shared/webconsole/network-helper");
const JsonViewUtils = require("devtools/client/jsonview/utils");
loader.lazyRequireGetter(this, "NetworkHelper",
"devtools/shared/webconsole/network-helper");
loader.lazyRequireGetter(this, "JsonViewUtils",
"devtools/client/jsonview/utils");
let childProcessMessageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender);
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
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.
@ -117,10 +114,6 @@ var Converter = Class({
request: []
}
if (!(aRequest instanceof Ci.nsIHttpChannel)) {
return;
}
let win = NetworkHelper.getWindowForRequest(aRequest);
let Locale = {
@ -141,17 +134,21 @@ var Converter = Class({
});
})
aRequest.visitResponseHeaders({
visitHeader: function(name, value) {
headers.response.push({name: name, value: value});
}
});
// The request doesn't have to be always nsIHttpChannel
// (e.g. in case of data: URLs)
if (aRequest instanceof Ci.nsIHttpChannel) {
aRequest.visitResponseHeaders({
visitHeader: function(name, value) {
headers.response.push({name: name, value: value});
}
});
aRequest.visitRequestHeaders({
visitHeader: function(name, value) {
headers.request.push({name: name, value: value});
}
});
aRequest.visitRequestHeaders({
visitHeader: function(name, value) {
headers.request.push({name: name, value: value});
}
});
}
let outputDoc = "";
@ -276,28 +273,37 @@ var Converter = Class({
}
});
// Stream converter component registration
const JSON_TYPE = "application/json";
const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" + JSON_TYPE + "&to=*/*";
// Stream converter component definition
const CONTRACT_ID = "@mozilla.org/streamconv;1?from=application/json&to=*/*";
const CLASS_ID = "{d8c9acee-dec5-11e4-8c75-1681e6b88ec1}";
const GECKO_VIEWER = "Gecko-Content-Viewers";
var service = xpcom.Service({
id: Components.ID(CLASS_ID),
id: components.ID(CLASS_ID),
contract: CONTRACT_ID,
Component: Converter,
register: false,
unregister: false
});
if (!xpcom.isRegistered(service)) {
xpcom.register(service);
function register() {
if (!xpcom.isRegistered(service)) {
xpcom.register(service);
return true;
}
return false;
}
// Remove native Gecko viewer
var categoryManager = Cc["@mozilla.org/categorymanager;1"].
getService(Ci.nsICategoryManager);
categoryManager.deleteCategoryEntry(GECKO_VIEWER, JSON_TYPE, false);
function unregister() {
if (xpcom.isRegistered(service)) {
xpcom.unregister(service);
return true;
}
categoryManager.addCategoryEntry("ext-to-type-mapping", "json",
JSON_TYPE, false, true);
return false;
}
exports.JsonViewService = {
register: register,
unregister: unregister
}

View File

@ -0,0 +1,111 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
"use strict";
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
// Load JsonView service module (converter-child.js) as soon as required.
XPCOMUtils.defineLazyGetter(this, "JsonViewService", function() {
const {devtools} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
const {JsonViewService} = devtools.require("devtools/client/jsonview/converter-child");
return JsonViewService;
});
const JSON_TYPE = "application/json";
const GECKO_VIEWER = "Gecko-Content-Viewers";
const JSON_VIEW_PREF = "devtools.jsonview.enabled";
const GECKO_TYPE_MAPPING = "ext-to-type-mapping";
/**
* Listen for 'devtools.jsonview.enabled' preference changes and
* register/unregister the JSON View XPCOM service as appropriate.
*/
function ConverterObserver() {
}
ConverterObserver.prototype = {
initialize: function() {
this.geckoViewer = categoryManager.getCategoryEntry(GECKO_VIEWER, JSON_TYPE);
// Only the DevEdition has this feature available by default.
// Users need to manually flip 'devtools.jsonview.enabled' preference
// to have it available in other distributions.
if (this.isEnabled()) {
this.register();
}
Services.prefs.addObserver(JSON_VIEW_PREF, this, false);
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(subject, topic, data) {
switch (topic) {
case "xpcom-shutdown":
this.onShutdown();
break;
case "nsPref:changed":
this.onPrefChanged();
break;
};
},
onShutdown: function() {
Services.prefs.removeObserver(JSON_VIEW_PREF, observer);
Services.obs.removeObserver(observer, "xpcom-shutdown");
},
onPrefChanged: function() {
if (this.isEnabled()) {
this.register();
} else {
this.unregister();
}
},
register: function() {
if (JsonViewService.register()) {
// Delete default JSON viewer (text)
categoryManager.deleteCategoryEntry(GECKO_VIEWER, JSON_TYPE, false);
// Append new *.json -> application/json type mapping
this.geckoMapping = categoryManager.addCategoryEntry(GECKO_TYPE_MAPPING,
"json", JSON_TYPE, false, true);
}
},
unregister: function() {
if (JsonViewService.unregister()) {
categoryManager.addCategoryEntry(GECKO_VIEWER, JSON_TYPE,
this.geckoViewer, false, false);
if (this.geckoMapping) {
categoryManager.addCategoryEntry(GECKO_TYPE_MAPPING, "json",
this.geckoMapping, false, true);
} else {
categoryManager.deleteCategoryEntry(GECKO_TYPE_MAPPING,
JSON_TYPE, false)
}
}
},
isEnabled: function() {
return Services.prefs.getBoolPref(JSON_VIEW_PREF);
},
};
// Listen to JSON View 'enable' pref and perform dynamic
// registration or unregistration of the main application
// component.
var observer = new ConverterObserver();
observer.initialize();

View File

@ -6,20 +6,12 @@
"use strict";
const { Cu, Ci, Cc } = require("chrome");
const {Cu, Ci, Cc} = require("chrome");
const JsonViewUtils = require("devtools/client/jsonview/utils");
Cu.import("resource://gre/modules/Services.jsm");
const { makeInfallible } = require("devtools/shared/DevToolsUtils");
const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIMessageListenerManager);
const parentProcessMessageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"].
getService(Ci.nsIMessageBroadcaster);
// Constants
const JSON_VIEW_PREF = "devtools.jsonview.enabled";
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const {makeInfallible} = require("devtools/shared/DevToolsUtils");
/**
* Singleton object that represents the JSON View in-content tool.
@ -28,31 +20,24 @@ const JSON_VIEW_PREF = "devtools.jsonview.enabled";
*/
var JsonView = {
initialize: makeInfallible(function() {
// Only the DevEdition has this feature available by default.
// Users need to manually flip 'devtools.jsonview.enabled' preference
// to have it available in other distributions.
if (Services.prefs.getBoolPref(JSON_VIEW_PREF)) {
// Load JSON converter module. This converter is responsible
// for handling 'application/json' documents and converting
// them into a simple web-app that allows easy inspection
// of the JSON data.
globalMessageManager.loadFrameScript(
"resource:///modules/devtools/client/jsonview/converter-child.js",
true);
// Load JSON converter module. This converter is responsible
// for handling 'application/json' documents and converting
// them into a simple web-app that allows easy inspection
// of the JSON data.
Services.ppmm.loadProcessScript(
"resource:///modules/devtools/client/jsonview/converter-observer.js",
true);
this.onSaveListener = this.onSave.bind(this);
this.onSaveListener = this.onSave.bind(this);
// Register for messages coming from the child process.
parentProcessMessageManager.addMessageListener(
"devtools:jsonview:save", this.onSaveListener);
}
// Register for messages coming from the child process.
Services.ppmm.addMessageListener(
"devtools:jsonview:save", this.onSaveListener);
}),
destroy: makeInfallible(function() {
if (this.onSaveListener) {
parentProcessMessageManager.removeMessageListener(
"devtools:jsonview:save", this.onSaveListener);
}
Services.ppmm.removeMessageListener(
"devtools:jsonview:save", this.onSaveListener);
}),
// Message handlers for events from child processes

View File

@ -12,6 +12,7 @@ DIRS += [
DevToolsModules(
'converter-child.js',
'converter-observer.js',
'json-viewer.js',
'main.js',
'utils.js',

View File

@ -8,6 +8,15 @@
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/head.js", this);
const JSON_VIEW_PREF = "devtools.jsonview.enabled";
// Enable JSON View for the test
Services.prefs.setBoolPref(JSON_VIEW_PREF, true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(JSON_VIEW_PREF);
});
// XXX move some API into devtools/framework/test/shared-head.js
/**

View File

@ -28,7 +28,6 @@ user_pref("javascript.options.showInConsole", true);
user_pref("devtools.browsertoolbox.panel", "jsdebugger");
user_pref("devtools.errorconsole.enabled", true);
user_pref("devtools.debugger.remote-port", 6023);
user_pref("devtools.jsonview.enabled", true);
user_pref("browser.EULA.override", true);
user_pref("gfx.color_management.force_srgb", true);
user_pref("network.manage-offline-status", false);