Skip to content

Instantly share code, notes, and snippets.

@cbrem
Last active June 12, 2019 09:58
Show Gist options
  • Save cbrem/4220f2ab0f24d3b60376 to your computer and use it in GitHub Desktop.
Save cbrem/4220f2ab0f24d3b60376 to your computer and use it in GitHub Desktop.
Object Formatter API Options

Simple Output Formatter

Output formatters could simply apply a apply filter to objects to display in the Object Inspecter if certain criteria are met. Changes to the display would propagate back to the object being displayed (its grip, really) via a number of propertyCallbacks. Whenever we click an object that this formatter matches, we open a new tab alongside the normal inspecter to display it in (after the given formatting has been applied).

main.js

const formatters = require('sdk/devtools/output-formatter');

var formatter = formatters.Formatter({
	/* The title to display for this formatter in the Object Inspecter tab created
	 * for it. */
	title: "DOM Element Style Editor",

	/* Display a clicked object in this formatter's view if include(obj) == true. */
	include: obj => !!obj.styles,

	/* Given a (safe, wrapped) representation of the object grip, create the
	 * object that will be sent to the view. */
	render: obj => obj.styles,

	/* Communicate changes on the properties of the view representation of the
	 * back to the devtools. Here, `obj` refers again to the (safe, wrapped) grip,
	 * while `key`, `value`, etc. are the keys and values of the object that was
	 * sent to this formatter's view. */
	propertyCallbacks: {
		onAdd: (obj, key, value) => obj.styles[key] = value,
		onDelete: (obj, key) => delete obj.styles[key],
		onChangeKey: (obj, oldKey, newKey) => {
			let oldValue = obj.styles[oldKey];
			delete obj.styles[oldKey];
			obj.styles[newKey] = oldValue;
		},
		onChangeValue: (obj, key, newValue) => obj.styles[key] = newValue,
	}

Output Formatters with React-like DOM Elements

This design would be similar to the above, except that the object that the renderer passes on the Object Inspecter tab would be a rich, DOM-like element instead of a JS Object (like in React). This would give the user some more formatting power while still allowing them to use a lot of the framework provided by VariablesView.

main.js

const formatters = require('sdk/devtools/output-formatter');

var formatter = formatters.Formatter({
	/* The title to display for this formatter in the Object Inspecter tab created
	 * for it. */
	title: "DOM Element Style Editor",

	/* Display a clicked object in this formatter's view if include(obj) == true. */
	include: obj => !!obj.styles,

	/* Given a (safe, wrapped) representation of the object grip, create a DOM-like
	 * element that will be sent to the view. The element must be composed of
	 * sdk-defined parts so that:
	 *   1. We can render it in a web-worker instead of its own iframe.
	 *   2. It can piggy-back off of the existing VariablesView styles and
	 *      tree structure it the user wishes. */
	render: obj => {
		let scope = formatter.Scope();
		for (let [key, val] of obj.styles) {
			let pair = formatters.Pair(key, val);
			scope.add(pair);
		}
		return scope;
	},

	/* Communicate changes on the properties of the view representation of the
	 * back to the devtools. Here, `obj` refers again to the (safe, wrapped) grip,
	 * while `key`, `value`, etc. are the keys and values of the DOM-like element
	 *  that was sent to this formatter's view. */
	propertyCallbacks: {
		onAdd: (obj, key, value) => obj.styles[key] = value,
		onDelete: (obj, key) => delete obj.styles[key],
		onChangeKey: (obj, oldKey, newKey) => {
			let oldValue = obj.styles[oldKey];
			delete obj.styles[oldKey];
			obj.styles[newKey] = oldValue;
		},
		onChangeValue: (obj, key, newValue) => obj.styles[key] = newValue,
	}
});

Output Formatters with HTML Pages

This is similar to both above examples, except that the user defines their own HTML page in which to render a representation of a clicked object.

main.js

const formatters = require('sdk/devtools/output-formatter');
const data = require('self').data;

var formatter = formatters.Formatter({
	/* The URL of the HTML document in which to render objects. */
	viewURL: data.url('myView.html'),

	/* Display a clicked object in this formatter's view if include(obj) == true. */
	include: obj => !!obj.styles,

	/* Given a (safe, wrapped) representation of the object grip and a representation
	 * of the document at `viewURL`, confiure the document to display information
	 * the grip. To make changes to the grip's properties from the document, use the
	 * provided `propertyCallbacks`. */
	render: (doc, obj, propertyCallbacks) => {
		let {add, delete, changeKey, changeValue} = propertyCallbacks;
		let scope = $("myScope");
		for (let [key, val] of obj.styles) {
			/* Fill `scope` with buttons and text fields formatted similarly to
			 * the VariablesView. Configure the buttons to call the
			 * `propertyCallbacks` as appropriate to alert the webconsole of changes
			 * that it should make on the object grip. */
		}
	}
});

myView.html

<html>
	<head>
		<title>DOM Element Style Editor</title>
	<body>
		<div id="myScope"></div>
	</body>
</html>
@jsantell
Copy link

Instead of propertyCallbacks, just have 'onAdd' on the main object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment