Skip to content

Instantly share code, notes, and snippets.

@rpl
Last active December 29, 2015 14:19
Show Gist options
  • Save rpl/7683088 to your computer and use it in GitHub Desktop.
Save rpl/7683088 to your computer and use it in GitHub Desktop.
Ember Inspector - Firefox Port Code Fragments
import BasicAdapter from "adapters/basic";
var FirefoxAdapter = BasicAdapter.extend({
// send messages from the target tag to devtool panel
sendMessage: function(options) {
options = options || {};
var event = document.createEvent("CustomEvent");
event.initCustomEvent("ember-extension-send", true, true, options);
document.documentElement.dispatchEvent(event);
},
// receive messages for the target tag from devtool panel
_connect: function() {
var self = this;
window.addEventListener("ember-extension-receive", function(evt) {
// We clone the object so that Ember prototype extensions
// are applied.
self._messageReceived(Ember.$.extend(true, {}, evt.detail));
}, false);
}.on('init')
});
export default FirefoxAdapter;
...
// DevTool Panel Definition
exports.devtoolTabDefinition = {
id: "ember-inspector",
ordinal: 7,
icon: self.data.url("images/icon16.png"),
url: self.data.url("devtool-panel.html"),
label: "Ember",
tooltip: "Ember Inspector",
isTargetSupported: function(target) {
return target.isLocalTab;
},
build: function(iframeWindow, toolbox) {
// init devtool tab
EmberInspector.initialize(iframeWindow, toolbox);
return Promise.resolve(EmberInspector);
}
};
...
...
// request ember_debug inject into the target tab
this._sendToTargetTab({ emberDebugUrl: self.data.url("ember_debug/ember_debug.js") });
...
...
_inspectDOMElement: function(selector) {
log("activating inspector devtool panel...");
let target = this.toolbox._target;
return gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
log("inspector devtool panel activated");
let sel = toolbox.getCurrentPanel().selection;
log("selecting ", selector);
sel.setNode(sel.document.querySelector(selector), "ember-inspector");
}.bind(this));
}
...
// handler for messages from devtool panel to target tab
function onEmberInspectorMessage(message) {
console.debug("content-script: ember debug receive", message);
handleEmberDebugUrl(message) || routeToEmberDebug(message);
}
// handler for messages from target tab to devtool panel
function onEmberDebugEvent(event) {
console.debug("content-script: ember debug send", event.detail);
self.port.emit("message", event.detail);
}
// handle ember_debug inject request
function handleEmberDebugUrl(message) {
if (message.emberDebugUrl) {
console.debug("ember_debug.js url received: ", message);
var script = document.createElement("script");
script.type = "text/javascript";
script.onload = function() {
console.log("EMBER DEBUG LOADED");
script.onload = null;
};
var head = document.querySelector("head");
if (head) {
head.appendChild( script );
script.src = message.emberDebugUrl;
return true;
}
}
return false;
}
// dispatch received messages to the target tab
function routeToEmberDebug(message) {
let event = document.createEvent("CustomEvent");
event.initCustomEvent("ember-debug-receive", true, true, message);
document.documentElement.dispatchEvent(event);
}
// register the handler for messages from devtool panel to target tab
self.port.on("message", onEmberInspectorMessage);
let contentWindow = document.defaultView;
console.log("EXECUTING EMBER DEBUG BRIDGE on: ", contentWindow.location.toString());
// register the handler for messages from target tab to the devtool panel
document.addEventListener("ember-debug-send", onEmberDebugEvent, false);
// let ember-debug know that content script has been executed
if (document.body) {
document.body.dataset.emberExtension = 1;
}
let contentWindow = document.defaultView;
console.log("EXECUTING EMBER DEVTOOL BRIDGE on: ", contentWindow.location.toString());
document.addEventListener("ember-extension-send", function onEmberExtensionEvent(event) {
console.debug("devtool-content-script: send", event.detail);
self.port.emit("message", event.detail);
}, false);
self.port.on("message", function onEmberDebugMessage(message) {
console.debug("devtool-content-script: receive", message);
if (message.reload) {
window.location.reload(true);
} else {
let event = document.createEvent("CustomEvent");
event.initCustomEvent("ember-extension-receive", true, true, message);
if (document.documentElement) {
document.documentElement.dispatchEvent(event);
}
}
});
// importing gDevTools javascript module
Cu.import("resource:///modules/devtools/gDevTools.jsm");
// get the panel definition from an another module
let devtoolTabDefinition = require("./devtool-panel").devtoolTabDefinition;
// register panel on startup
function startup() {
gDevTools.registerTool(devtoolTabDefinition);
}
// unregister panel on startup
function shutdown() {
gDevTools.unregisterTool(devtoolTabDefinition);
}
startup();
exports.onUnload = function() {
shutdown();
};
...
// attach DevtoolPanel worker
worker = workers.Worker({
window: this.iframeWindow.contentWindow,
contentScriptFile: self.data.url("devtool-content-script.js")
});
worker.port.on("message", this._handleDevtoolPanelMessage.bind(this));
...
// attach target tab
worker = tabs.activeTab.attach({
window: tabs.activeTab._contentWindow,
contentScriptFile: self.data.url("content-script.js")
});
worker.port.on("message", this._handleTargetTabMessage.bind(this));
import BasicAdapter from "adapters/basic";
var FirefoxAdapter = BasicAdapter.extend({
init: function() {
this._super();
this._connect();
},
// send a message from the devtool panel to the target tab
sendMessage: function(options) {
options = options || {};
var event = document.createEvent("CustomEvent");
event.initCustomEvent("ember-debug-send", true, true, options);
document.documentElement.dispatchEvent(event);
},
// devtool panel asks firefox to open a defined DOM element in the DOM Inspector
inspectElement: function(elem) {
this.sendMessage({
type: 'view:devtools:inspectDOMElement',
elementSelector: "#" + elem.getAttribute('id')
});
},
// connect to receive messages for the devtool panel from the target tag
_connect: function() {
var self = this;
window.addEventListener('ember-debug-receive', function(event) {
var message = event.detail;
Ember.run(function() {
self._messageReceived(message);
});
});
}
});
export default FirefoxAdapter;
{
"from" : "inspectedWindow",
"name" : "<App.SearchResultController:ember329>",
"objectId" : "ember329",
"type" : "objectInspector:updateObject",
"details" : [
{
"expand" : true,
"name" : "Own Properties",
"properties" : [
{
"isMandatorySetter" : true,
"value" : {
"inspect" : "null",
"type" : "type-null"
},
"name" : "from"
},
{
"isMandatorySetter" : false,
"value" : {
"inspect" : "{_direction: fwd, _from: controllers.search.from_value, _to: from, _directionMap: [object Object], _readyToSync: true}",
"type" : "type-object"
},
"name" : "fromBinding"
},
...
]
},
{
"name" : "App.SearchResultController",
"properties" : [
{
...
}
]
}
]
}
{
"from" : "inspectedWindow",
"type" : "view:viewTree",
"tree" : {
"treeId" : "ember408",
"value" : {
"controller" : {
"objectId" : "ember315",
"name" : "App.ApplicationController"
},
"template" : "application",
"name" : "application",
"objectId" : "ember245",
"isComponent" : false,
"viewClass" : "App.ApplicationView",
"tagName" : "div"
},
"children" : [
{
"value" : {
"template" : "search_result",
"model" : {
"name" : "{jsonrpc: 2.0, id: ID5, result: [object Object]}",
"type" : "type-object"
},
"name" : "search_result",
"objectId" : "ember336",
"viewClass" : "App.SearchResultView",
"tagName" : "div",
"controller" : {
"objectId" : "ember329",
"name" : "App.SearchResultController"
},
"isComponent" : false
},
"children" : [
...
]
}
]
}
}
grunt.registerTask('build_xpi', [
'mozilla-addon-sdk',
'mozilla-cfx-xpi'
]);
grunt.registerTask('run_xpi', ['build', 'build_xpi',
'mozilla-cfx:run']);
grunt.registerTask('build_and_upload', [
'build',
'compress:main',
'build_xpi',
'ember-s3'
]);
{
...
"devDependencies": {
...
"grunt-contrib-compress": "~0.5.2",
"grunt-ember-s3": "~1.0.4",
"grunt-mozilla-addon-sdk": "~0.3.1",
"grunt-wrap": "~0.3.0"
}
}
{
"objectId":"ember329",
"type":"objectInspector:inspectById",
"from":"devtools"
}
{
"objectId": "ember329",
"type": "objectInspector:sendToConsole",
"from": "devtools"
}
// tasks/options/mozilla-addon-sdk.js
module.exports = {
"1_14": {
options: {
revision: "1.14"
}
}
};
// tasks/options/mozilla-cfx-xpi.js
module.exports = {
"stable": {
options: {
"mozilla-addon-sdk": "1_14",
extension_dir: "dist_firefox",
dist_dir: "tmp/xpi"
}
}
};
// tasks/options/mozilla-cfx.js
module.exports = {
"run": {
options: {
"mozilla-addon-sdk": "1_14",
extension_dir: "dist_firefox",
command: "run"
}
}
};
module.exports = {
"1_14": {
options: {
revision: "1.14"
}
}
};
module.exports = {
"run": {
options: {
"mozilla-addon-sdk": "1_14",
extension_dir: "dist_firefox",
command: "run"
}
}
};
module.exports = {
"stable": {
options: {
"mozilla-addon-sdk": "1_14",
extension_dir: "dist_firefox",
dist_dir: "tmp/xpi"
}
}
};
## to build ember-extension sources, download Firefox Addon SDK and build 'tmp/xpi/ember-inspector.xpi':
$ grunt build build_xpi
...
Running "mozilla-addon-sdk:1_14" (mozilla-addon-sdk) task
Downloading: https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/addon-sdk-1.14.tar.gz
Running "mozilla-cfx-xpi:stable" (mozilla-cfx-xpi) task
Creating dist dir '/home/rpl/PROJECTS/2013/MOZILLA/DEVTOOLS-EXT/ember-extension/tmp/xpi'...
Creating xpi...
Generated XPI: /home/rpl/PROJECTS/2013/MOZILLA/DEVTOOLS-EXT/ember-extension/tmp/xpi/ember-inspector.xpi
Done, without errors.
## to run it on a temporary new profile
$ grunt run_xpi
...
Running "mozilla-cfx:run" (mozilla-cfx) task
Done, without errors.
## to run it using a specific Firefox binary and profile directory
$ FIREFOX_BIN=/path/to/firefox FIREFOX_PROFILE=/path/to/profile grunt run_xpi
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment