armo-breadboard
Version:
Edit a live React component's source in real time.
160 lines (143 loc) • 3.92 kB
JavaScript
(function(){
'use strict';
/**
* Check circular references.
* Copyright (c) 2014 Freeform Systems
* https://github.com/tmpfs/circular
*
* @param ref A function that returns an alternative reference.
* @param methods A boolean that indicates functions should be
* coerced to strings.
*/
function circular() {
var seen = [];
return function (key, val) {
if(typeof val === 'function') {
val = val.toString();
}
if(!val || typeof (val) !== 'object') {
return val;
}
if(~seen.indexOf(val)) {
return '[Circular]';
}
seen.push(val);
return val;
};
}
function stringify(obj) {
return JSON.stringify(obj, circular());
}
if (typeof __BREADBOARD_SETTINGS !== 'object') {
window.top.postMessage({
type: 'breadboard-host/source-required',
mountpointId: parseInt(window.location.hash.substr(1)),
}, '*')
}
else {
init(__BREADBOARD_SETTINGS);
const oldOnLoad = window.onload;
window.onload = function(e) {
if (oldOnLoad) {
oldOnLoad(e);
}
sendLoad();
}
}
window.addEventListener("message", handleMessage, false);
function init(settings) {
/* TODO: show error message and bail if window.Proxy doesn't exist */
const windowLocation = settings.location;
const windowProxy = new Proxy(window, {
get: function(target, name) {
return name === 'location' ? windowLocation : target[name];
},
});
window.__BREADBOARD = {
window: windowProxy,
location: windowLocation,
};
sendInit();
}
function sendMessage(type, config={}) {
window.top.postMessage(Object.assign({}, config, {
type: 'breadboard-host/'+type,
mountpointId: __BREADBOARD_SETTINGS.mountpointId,
}), '*');
}
function sendInit() {
sendMessage('init');
}
function sendLoad() {
sendMessage('load');
}
function sendConsole(level, file, args) {
sendMessage('console', {
level: level,
file: file,
args: args,
});
}
function handleMessage(e) {
const data = e.data;
if (!data || !/^breadboard-mountpoint\/[\w-]+$/.test(data.type)) {
return;
}
const type = data.type.replace(/^breadboard-mountpoint\//, '');
switch (type) {
case 'source':
window.__BREADBOARD_SETTINGS = e.data.settings;
init(window.__BREADBOARD_SETTINGS);
document.open();
document.write(e.data.source);
document.close();
sendLoad();
break
}
}
/* Add overrides */
var unwrapped = {
console: {
log: console.log,
debug: console.debug,
info: console.info,
warn: console.warn,
error: console.error,
},
window: {
onerror: window.onerror,
},
};
function getFile(stack) {
const i = stack.indexOf('breadboard://');
if (i > -1) {
const x = stack.slice(i + 'breadboard://'.length);
const j = x.indexOf(':');
return j > -1 ? x.slice(0, j) : x;
}
}
Object.keys(unwrapped.console).forEach(function(level) {
if (unwrapped.console[level]) {
console[level] = function() {
sendConsole(level, getFile(new Error().stack), Array.prototype.slice.call(arguments).map(stringify));
unwrapped.console[level].apply(this, arguments);
}
}
});
window.onerror = function(message, url, lineNumber, columnNumber, error) {
var string = message.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1){
sendConsole('onerror', null, null);
} else {
sendConsole('onerror', getFile(error.stack), {
message: message,
error: error.stack,
});
}
if (unwrapped.window.onerror) {
return unwrapped.window.onerror(message, url, lineNumber, columnNumber, error);
}
}
})();
//# sourceURL=breadboard-host.js