Skip to content

Instantly share code, notes, and snippets.

@paulirish
Forked from anonymous/gist:d83c3cf7d1c685389f08
Last active January 11, 2021 21:26
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save paulirish/ac138a480ac971a0b500 to your computer and use it in GitHub Desktop.
Save paulirish/ac138a480ac971a0b500 to your computer and use it in GitHub Desktop.
examples for devtoolsFormatter for custom object display in Chrome DevTools
// see examples in https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U/edit#
Formatter = function(simpleFormatter)
{
this._simpleFormatter = simpleFormatter;
}
Formatter.prototype = {
header: function(object)
{
if ((object instanceof Node))
return null;
var header = new JsonMLElement("span");
header.createTextChild(this._simpleFormatter.description(object));
return header.toJsonML();
},
hasBody: function(object)
{
if (object instanceof Array)
return false;
return this._simpleFormatter.hasChildren(object);
},
body: function(object)
{
var body = new JsonMLElement("ol");
body.setStyle("list-style-type:none; padding-left: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 12px");
var children = this._simpleFormatter.children(object);
for (var i = 0; i < children.length; ++i) {
var child = children[i];
var li = body.createChild("li");
var objectTag;
if (typeof child.value === "object")
objectTag = li.createObjectTag(child.value);
else
objectTag = li.createChild("span");
var nameSpan = objectTag.createChild("span");
nameSpan.createTextChild(child.key + ": ");
nameSpan.setStyle("color: rgb(136, 19, 145);");
if (child.value instanceof Node) {
var node = child.value;
objectTag.createTextChild(node.nodeName.toLowerCase());
if (node.id)
objectTag.createTextChild("#" + node.id)
else
objectTag.createTextChild("." + node.className)
}
if (typeof child.value !== "object")
objectTag.createTextChild("" + child.value);
}
return body.toJsonML();
},
_arrayFormatter: function(array)
{
var j = new JsonMLElement();
j.createTextChild("[");
for (var i = 0; i < array.length; ++i) {
if (i != 0)
j.createTextChild(", ")
j.createObjectTag(array[i]);
}
j.createTextChild("]");
return j;
}
}
JsonMLElement = function(tagName)
{
this._attributes = {};
this._jsonML = [tagName, this._attributes];
}
JsonMLElement.prototype = {
createChild: function(tagName)
{
var c = new JsonMLElement(tagName);
this._jsonML.push(c.toJsonML());
return c;
},
createObjectTag: function(object)
{
var tag = this.createChild("object");
tag.addAttribute("object", object);
return tag;
},
setStyle: function(style)
{
this._attributes["style"] = style;
},
addAttribute: function(key, value)
{
this._attributes[key] = value;
},
createTextChild: function(text)
{
this._jsonML.push(text + "");
},
toJsonML: function()
{
return this._jsonML;
}
}
function SimpleFormatter()
{
}
SimpleFormatter.prototype = {
description: function(object)
{
if ((typeof object === "object") && object)
return object.constructor.name;
return object;
},
hasChildren: function(object)
{
return (typeof object === "object");
},
children: function(object)
{
var result = [];
for (var key in object)
result.push({key: key, value: object[key]});
return result;
}
}
window["devtoolsFormatter"] = new Formatter(new SimpleFormatter());
// see examples in https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335T3U/edit#
JsonMLFormatter = function(simpleFormatter)
{
this._simpleFormatter = simpleFormatter;
}
JsonMLFormatter.prototype = {
header: function(object)
{
var c = this._simpleFormatter.preview(object);
if (c === null)
return null;
var header = new JsonMLElement('span');
header.createTextChild(c);
return header.toJsonML();
},
hasBody: function(object)
{
return this._simpleFormatter.hasChildren(object);
},
body: function(object)
{
var body = new JsonMLElement('ol');
body.setStyle('list-style-type:none; padding-left: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 12px');
var children = this._simpleFormatter.children(object);
for (var i = 0; i < children.length; ++i) {
var child = children[i];
var li = body.createChild('li');
var nameSpan = new JsonMLElement('span');
nameSpan.createTextChild(child.name + ': ');
nameSpan.setStyle('color: rgb(136, 19, 145);');
if (typeof child.value === 'object') {
var objectTag = li.createObjectTag(child.value);
objectTag.appendChild(nameSpan);
if (!this._simpleFormatter.hasChildren(child.value))
li.setStyle("padding-left: 13px;");
} else {
li.setStyle("padding-left: 13px;");
var objectTag = li.createChild('span');
objectTag.appendChild(nameSpan);
objectTag.createTextChild('' + child.value);
}
}
return body.toJsonML();
}
}
JsonMLElement = function(tagName)
{
this._attributes = {};
this._jsonML = [tagName, this._attributes];
}
JsonMLElement.prototype = {
appendChild: function(element)
{
this._jsonML.push(element.toJsonML());
},
createChild: function(tagName)
{
var c = new JsonMLElement(tagName);
this._jsonML.push(c.toJsonML());
return c;
},
createObjectTag: function(object)
{
var tag = this.createChild('object');
tag.addAttribute('object', object);
return tag;
},
setStyle: function(style)
{
this._attributes['style'] = style;
},
addAttribute: function(key, value)
{
this._attributes[key] = value;
},
createTextChild: function(text)
{
this._jsonML.push(text + '');
},
toJsonML: function()
{
return this._jsonML;
}
}
GwtSimpleFormatter = function ()
{
this._formatters = [new MapFormatter(), new SetFormatter(), new ArrayFormatter(), new EntryFormatter(), new ObjectFormatter()];
}
GwtSimpleFormatter.__INTERNAL_TYPE = '__formatter_internal_type';
GwtSimpleFormatter.__INTERNAL_TYPES = {
Entry: 'entry'
};
GwtSimpleFormatter.prototype = {
preview: function(object)
{
if (typeof object === 'undefined')
return 'undefined';
if (typeof object === 'number')
return object + '';
if (typeof object === 'string')
return object;
if (!object)
return 'null';
for (var i = 0; i < this._formatters.length; ++i) {
var formatter = this._formatters[i];
if (formatter.accept(object))
return formatter.preview(object);
}
return null;
},
hasChildren: function(object)
{
if (!object)
return false;
for (var i = 0; i < this._formatters.length; ++i) {
var formatter = this._formatters[i];
if (formatter.accept(object))
return formatter.hasChildren(object);
}
return false;
},
children: function(object)
{
if (!object)
return [];
for (var i = 0; i < this._formatters.length; ++i) {
var formatter = this._formatters[i];
if (formatter.accept(object))
return formatter.children(object);
}
return [];
}
};
ObjectFormatter = function() {};
ObjectFormatter.prototype = {
accept: function(object)
{
return !!object.getClass$
},
preview: function(object)
{
var type = object.getClass$().compoundName_1_g$;
return type;
},
hasChildren: function(object)
{
return !!Object.keys(object).length;
},
children: function(object)
{
var keys= Object.keys(object);
var properties = [];
for (var i = 0; i < keys.length; ++i)
properties.push(this._createPropertyPreview(keys[i], object[keys[i]]));
return properties;
},
_createPropertyPreview: function(key, value)
{
var result = {};
result.name = this._tryToCutKey(key) || key;
result.value = value;
return result;
},
_tryToCutKey: function(key)
{
var ind = key.lastIndexOf('_');
if (ind === -1)
return null;
var len = key.lastIndexOf('_', ind - 1);
if (len === -1)
return null;
return key.substring(0, len);
}
};
MapFormatter = function() {};
MapFormatter.prototype = {
accept: function(object)
{
if (!object.getClass$)
return false;
var clazz = object.getClass$();
return clazz.compoundName_1_g$ === 'HashMap';
},
hasChildren: function(object)
{
return !!object.size_2_g$;
},
preview: function(object)
{
var type = object.getClass$().compoundName_1_g$;
var size = object.size_2_g$;
return type + ' size = ' + size;
},
children: function(object)
{
var stringChildren = this._retrieveStringEntries(object);
if (stringChildren.length)
return stringChildren;
return this._retrieveObjectEntries(object);
},
_retrieveStringEntries: function(object)
{
var mapObject = object.stringMap_0_g$.backingMap_2_g$;
var entries = [];
var keys = Object.keys(mapObject);
for (var i = 0; i < keys.length; ++i) {
var entry = {name: keys[i], value: mapObject[keys[i]]};
entries.push(entry);
}
return entries;
},
_retrieveObjectEntries: function(object)
{
var mapObject = object.hashCodeMap_0_g$.backingMap_1_g$
var entries = [];
var keys = Object.keys(mapObject);
for (var i = 0; i < keys.length; ++i) {
var bucket = mapObject[keys[i]];
for (var j = 0; j < bucket.length; ++j) {
var entry = bucket[j];
var entryWrapper = {key: entry.key_1_g$, value: entry.value_15_g$};
entryWrapper[GwtSimpleFormatter.__INTERNAL_TYPE] = 'entry';
entries.push({name: entries.length + '', value: entryWrapper});
}
}
return entries;
}
}
ArrayFormatter = function() {};
ArrayFormatter.prototype = {
accept: function(object)
{
if (!object.___clazz$ || !(object instanceof Array))
return false;
return true;
},
preview: function(object)
{
var type = object.___clazz$.componentType_1_g$.compoundName_1_g$;
return type + '[] size = ' + object.length;
},
hasChildren: function(object)
{
return !!object.length;
},
children: function(object)
{
var result = [];
for (var i = 0; i < object.length; ++i) {
result.push({name: i + '', value: object[i]});
}
return result;
}
}
EntryFormatter = function() {};
EntryFormatter.prototype = {
accept: function(object)
{
return object[GwtSimpleFormatter.__INTERNAL_TYPE] === GwtSimpleFormatter.__INTERNAL_TYPES.Entry;
},
preview: function(object)
{
var keyPreview = window.devtoolsFormatter._simpleFormatter.preview(object.key);
var valuePreview = window.devtoolsFormatter._simpleFormatter.preview(object.value);
return keyPreview + ' => ' + valuePreview;
},
hasChildren: function(object)
{
return true;
},
children: function(object)
{
var keyProperty = {name: 'key', value: object.key};
var valueProperty = {name: 'value', value: object.value};
return [keyProperty, valueProperty];
}
};
SetFormatter = function() {};
SetFormatter.prototype = {
accept: function(object)
{
if (!object.getClass$)
return false;
var clazz = object.getClass$();
return clazz.compoundName_1_g$ === 'HashSet';
},
preview: function(object)
{
var type = object.getClass$().compoundName_1_g$;
var size = object.map_1_g$.size_2_g$;
return type + ' size = ' + size;
},
hasChildren: function(object)
{
return !!object.map_1_g$.size_2_g$;
},
children: function(object)
{
var map = object.map_1_g$;
var mapObject = map.stringMap_0_g$.backingMap_2_g$;
var entries = [];
var keys = Object.keys(mapObject);
for (var i = 0; i < keys.length; ++i) {
var entry = {name: i + '', value: keys[i]};
entries.push(entry);
}
return entries;
}
};
window['devtoolsFormatter'] = new JsonMLFormatter(new GwtSimpleFormatter());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment