mirror of
https://github.com/jsbin/jsbin.git
synced 2026-02-01 16:46:05 +00:00
Console commands can be posted into runner and logged out.
This commit is contained in:
parent
35506e10d5
commit
af6310ec76
@ -13,141 +13,20 @@ var keylib={left:37,up:38,right:39,down:40,space:32,
|
||||
l:76,m:77,n:78,o:79,p:80,q:81,r:82,s:83,t:84,u:85,v:86,
|
||||
w:87,x:88,y:89,z:90};
|
||||
|
||||
function sortci(a, b) {
|
||||
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
|
||||
}
|
||||
|
||||
function htmlEntities(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
// custom because I want to be able to introspect native browser objects *and* functions
|
||||
function stringify(o, simple, visited) {
|
||||
var json = '', i, vi, type = '', parts = [], names = [], circular = false;
|
||||
visited = visited || [];
|
||||
|
||||
try {
|
||||
type = ({}).toString.call(o);
|
||||
} catch (e) { // only happens when typeof is protected (...randomly)
|
||||
type = '[object Object]';
|
||||
}
|
||||
|
||||
// check for circular references
|
||||
for (vi = 0; vi < visited.length; vi++) {
|
||||
if (o === visited[vi]) {
|
||||
circular = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (circular) {
|
||||
json = '[circular ' + type.slice(1);
|
||||
if (o.outerHTML) {
|
||||
json += ":\n" + htmlEntities(o.outerHTML);
|
||||
}
|
||||
} else if (type == '[object String]') {
|
||||
json = '"' + htmlEntities(o.replace(/"/g, '\\"')) + '"';
|
||||
} else if (type == '[object Array]') {
|
||||
visited.push(o);
|
||||
|
||||
json = '[';
|
||||
for (i = 0; i < o.length; i++) {
|
||||
parts.push(stringify(o[i], simple, visited));
|
||||
}
|
||||
json += parts.join(', ') + ']';
|
||||
} else if (type == '[object Object]') {
|
||||
visited.push(o);
|
||||
|
||||
json = '{';
|
||||
for (i in o) {
|
||||
names.push(i);
|
||||
}
|
||||
names.sort(sortci);
|
||||
for (i = 0; i < names.length; i++) {
|
||||
parts.push( stringify(names[i], undefined, visited) + ': ' + stringify(o[ names[i] ], simple, visited) );
|
||||
}
|
||||
json += parts.join(', ') + '}';
|
||||
} else if (type == '[object Number]') {
|
||||
json = o+'';
|
||||
} else if (type == '[object Boolean]') {
|
||||
json = o ? 'true' : 'false';
|
||||
} else if (type == '[object Function]') {
|
||||
json = o.toString();
|
||||
} else if (o === null) {
|
||||
json = 'null';
|
||||
} else if (o === undefined) {
|
||||
json = 'undefined';
|
||||
} else if (simple === undefined) {
|
||||
visited.push(o);
|
||||
|
||||
json = type + '{\n';
|
||||
for (i in o) {
|
||||
names.push(i);
|
||||
}
|
||||
names.sort(sortci);
|
||||
for (i = 0; i < names.length; i++) {
|
||||
try {
|
||||
parts.push(names[i] + ': ' + stringify(o[names[i]], true, visited)); // safety from max stack
|
||||
} catch (e) {
|
||||
if (e.name == 'NS_ERROR_NOT_IMPLEMENTED') {
|
||||
// do nothing - not sure it's useful to show this error when the variable is protected
|
||||
// parts.push(names[i] + ': NS_ERROR_NOT_IMPLEMENTED');
|
||||
}
|
||||
}
|
||||
}
|
||||
json += parts.join(',\n') + '\n}';
|
||||
} else {
|
||||
visited.push(o);
|
||||
try {
|
||||
json = stringify(o, true, visited)+''; // should look like an object
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
function cleanse(s) {
|
||||
return (s||'').replace(/[<&]/g, function (m) { return {'&':'&','<':'<'}[m];});
|
||||
}
|
||||
|
||||
/**
|
||||
* =============================================================================
|
||||
* TODO remove, temporary
|
||||
* =============================================================================
|
||||
*/
|
||||
$document.on('console:run', function (event, cmd) {
|
||||
$document.trigger('console:response', cmd);
|
||||
});
|
||||
|
||||
/**
|
||||
* Run a console command.
|
||||
* This sets up an event listener waiting for a response to the console:run
|
||||
* event it emits. It will then call a response callback, but only once per
|
||||
* posted command.
|
||||
*/
|
||||
var run = (function () {
|
||||
|
||||
var responseCb = null;
|
||||
|
||||
// When a response comes back from whatever ran the the console command
|
||||
// call the response callback, but only once!
|
||||
$document.on('console:response', function (event, data) {
|
||||
if (!responseCb) return;
|
||||
var cb = responseCb;
|
||||
responseCb = null;
|
||||
cb.call(null, ['response', data]);
|
||||
});
|
||||
|
||||
return function (cmd, cb) {
|
||||
var internalCmd = internalCommand(cmd);
|
||||
if (internalCmd) {
|
||||
return cb(['info', internalCmd]);
|
||||
}
|
||||
responseCb = cb;
|
||||
$document.trigger('console:run', cmd);
|
||||
};
|
||||
}());
|
||||
var run = function (cmd, cb) {
|
||||
var internalCmd = internalCommand(cmd);
|
||||
if (internalCmd) {
|
||||
return cb(['info', internalCmd]);
|
||||
}
|
||||
$document.trigger('console:run', cmd);
|
||||
};
|
||||
|
||||
/**
|
||||
* Run and show response to a command fired from the console
|
||||
@ -165,7 +44,7 @@ var post = function (cmd, blind, response) {
|
||||
echo(cmd);
|
||||
|
||||
// If we were handed a response, show the response straight away – otherwise
|
||||
// runs it and pass showResponse as a callback
|
||||
// runs it
|
||||
if (response) return showResponse(response);
|
||||
run(cmd, showResponse);
|
||||
|
||||
@ -366,14 +245,14 @@ window._console = {
|
||||
log: function () {
|
||||
var l = arguments.length, i = 0;
|
||||
for (; i < l; i++) {
|
||||
log(stringify(arguments[i], true));
|
||||
log(''+arguments[i], true);
|
||||
}
|
||||
window.console.log.apply(window.console, arguments);
|
||||
},
|
||||
dir: function () {
|
||||
var l = arguments.length, i = 0;
|
||||
for (; i < l; i++) {
|
||||
log(stringify(arguments[i]));
|
||||
log(arguments[i]);
|
||||
}
|
||||
window.console.dir.apply(window.console, arguments);
|
||||
},
|
||||
@ -751,13 +630,6 @@ var jsconsole = {
|
||||
// closure scope
|
||||
sandboxframe = $live.find('iframe')[0]; //document.createElement('iframe');
|
||||
|
||||
// var oldsandbox = document.getElementById('jsconsole-sandbox');
|
||||
// if (oldsandbox) {
|
||||
// body.removeChild(oldsandbox);
|
||||
// }
|
||||
|
||||
// body.appendChild(sandboxframe);
|
||||
// sandboxframe.setAttribute('id', 'jsconsole-sandbox');
|
||||
if (sandboxframe) this.setSandbox(sandboxframe);
|
||||
|
||||
if (nohelp === undefined) post(':help', true);
|
||||
@ -772,8 +644,7 @@ var jsconsole = {
|
||||
echo(data.cmd);
|
||||
log(data.response, 'response');
|
||||
}
|
||||
},
|
||||
stringify: stringify
|
||||
}
|
||||
};
|
||||
|
||||
return jsconsole;
|
||||
@ -783,95 +654,10 @@ return jsconsole;
|
||||
var msgType = '';
|
||||
|
||||
jsconsole.init(document.getElementById('output'));
|
||||
jsconsole.queue = [];
|
||||
jsconsole.remote = {
|
||||
log: function () {
|
||||
// window.console.log('remote call');
|
||||
var cmd = 'console.log';
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (e) {
|
||||
// var trace = printStackTrace({ error: e }),
|
||||
// code = jsbin.panels.panels.javascript.getCode().split('\n'),
|
||||
// allcode = getPreparedCode().split('\n'),
|
||||
// parts = [],
|
||||
// line,
|
||||
// n;
|
||||
|
||||
// for (var i = 0; i < trace.length; i++) {
|
||||
// if (trace[i].indexOf(window.location.toString()) !== -1) {
|
||||
// parts = trace[i].split(':');
|
||||
// n = parts.pop();
|
||||
// if (isNaN(parseInt(n, 10))) {
|
||||
// n = parts.pop();
|
||||
// }
|
||||
// line = n - 2;
|
||||
// if (code[line] && code[line].indexOf('console.') !== -1) {
|
||||
// cmd = $.trim(code[line]);
|
||||
// console.log(cmd);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
var argsObj = jsconsole.stringify(arguments.length == 1 ? arguments[0] : [].slice.call(arguments, 0));
|
||||
var response = [];
|
||||
[].forEach.call(arguments, function (args) {
|
||||
response.push(jsconsole.stringify(args, true));
|
||||
});
|
||||
|
||||
var msg = { response: response, cmd: cmd, type: msgType };
|
||||
|
||||
if (jsconsole.ready) {
|
||||
jsconsole.rawMessage(msg);
|
||||
} else {
|
||||
jsconsole.queue.push(msg);
|
||||
}
|
||||
|
||||
msgType = '';
|
||||
},
|
||||
info: function () {
|
||||
msgType = 'info';
|
||||
remote.log.apply(this, arguments);
|
||||
},
|
||||
echo: function () {
|
||||
var args = [].slice.call(arguments, 0),
|
||||
plain = args.pop(),
|
||||
cmd = args.pop(),
|
||||
response = args;
|
||||
|
||||
var argsObj = jsconsole.stringify(response, plain),
|
||||
msg = { response: argsObj, cmd: cmd };
|
||||
if (jsconsole.ready) {
|
||||
jsconsole.rawMessage(msg);
|
||||
} else {
|
||||
jsconsole.queue.push(msg);
|
||||
}
|
||||
},
|
||||
error: function (error, cmd) {
|
||||
var msg = { response: error.message, cmd: cmd, type: 'error' };
|
||||
if (jsconsole.ready) {
|
||||
jsconsole.rawMessage(msg);
|
||||
} else {
|
||||
jsconsole.queue.push(msg);
|
||||
}
|
||||
},
|
||||
flush: function () {
|
||||
for (var i = 0; i < jsconsole.queue.length; i++) {
|
||||
jsconsole.rawMessage(jsconsole.queue[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// just for extra support
|
||||
jsconsole.remote.debug = jsconsole.remote.dir = jsconsole.remote.log;
|
||||
jsconsole.remote.warn = jsconsole.remote.info;
|
||||
|
||||
// window.top._console = jsconsole.remote;
|
||||
|
||||
function upgradeConsolePanel(console) {
|
||||
// console.init = function () {
|
||||
console.$el.click(function () {
|
||||
jsconsole.focus();
|
||||
});
|
||||
@ -903,9 +689,6 @@ function upgradeConsolePanel(console) {
|
||||
// $live.find('iframe').remove();
|
||||
}
|
||||
};
|
||||
// jsconsole.ready = true;
|
||||
// FIXME this line was causing errors in IE7
|
||||
// jsconsole.remote.flush();
|
||||
|
||||
$document.one('jsbinReady', function () {
|
||||
var hidebutton = function () {
|
||||
@ -919,8 +702,4 @@ function upgradeConsolePanel(console) {
|
||||
}
|
||||
|
||||
});
|
||||
// editors.console.fakeConsole = window._console
|
||||
// };
|
||||
|
||||
// console.init();
|
||||
}
|
||||
|
||||
@ -292,6 +292,11 @@ var renderLivePreview = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
// Listen for console input and post it to the iframe
|
||||
$document.on('console:run', function (event, cmd) {
|
||||
renderer.postMessage('console:run', cmd);
|
||||
});
|
||||
|
||||
// When the iframe loads, swap round the callbacks and immediately invoke
|
||||
// if renderLivePreview was called already.
|
||||
return deferCallable(renderLivePreview, function (done) {
|
||||
|
||||
98
public/js/vendor/stringify.js
vendored
Normal file
98
public/js/vendor/stringify.js
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Custom stringify that's able to inspect native browser objects and functions
|
||||
*/
|
||||
var stringify = (function () {
|
||||
|
||||
var sortci = function(a, b) {
|
||||
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
|
||||
};
|
||||
|
||||
var htmlEntities = function (str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
};
|
||||
|
||||
return function (o, simple, visited) {
|
||||
var json = '', i, vi, type = '', parts = [], names = [], circular = false;
|
||||
visited = visited || [];
|
||||
|
||||
try {
|
||||
type = ({}).toString.call(o);
|
||||
} catch (e) { // only happens when typeof is protected (...randomly)
|
||||
type = '[object Object]';
|
||||
}
|
||||
|
||||
// check for circular references
|
||||
for (vi = 0; vi < visited.length; vi++) {
|
||||
if (o === visited[vi]) {
|
||||
circular = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (circular) {
|
||||
json = '[circular ' + type.slice(1);
|
||||
if (o.outerHTML) {
|
||||
json += ":\n" + htmlEntities(o.outerHTML);
|
||||
}
|
||||
} else if (type == '[object String]') {
|
||||
json = '"' + htmlEntities(o.replace(/"/g, '\\"')) + '"';
|
||||
} else if (type == '[object Array]') {
|
||||
visited.push(o);
|
||||
|
||||
json = '[';
|
||||
for (i = 0; i < o.length; i++) {
|
||||
parts.push(stringify(o[i], simple, visited));
|
||||
}
|
||||
json += parts.join(', ') + ']';
|
||||
} else if (type == '[object Object]') {
|
||||
visited.push(o);
|
||||
|
||||
json = '{';
|
||||
for (i in o) {
|
||||
names.push(i);
|
||||
}
|
||||
names.sort(sortci);
|
||||
for (i = 0; i < names.length; i++) {
|
||||
parts.push( stringify(names[i], undefined, visited) + ': ' + stringify(o[ names[i] ], simple, visited) );
|
||||
}
|
||||
json += parts.join(', ') + '}';
|
||||
} else if (type == '[object Number]') {
|
||||
json = o+'';
|
||||
} else if (type == '[object Boolean]') {
|
||||
json = o ? 'true' : 'false';
|
||||
} else if (type == '[object Function]') {
|
||||
json = o.toString();
|
||||
} else if (o === null) {
|
||||
json = 'null';
|
||||
} else if (o === undefined) {
|
||||
json = 'undefined';
|
||||
} else if (simple === undefined) {
|
||||
visited.push(o);
|
||||
|
||||
json = type + '{\n';
|
||||
for (i in o) {
|
||||
names.push(i);
|
||||
}
|
||||
names.sort(sortci);
|
||||
for (i = 0; i < names.length; i++) {
|
||||
try {
|
||||
parts.push(names[i] + ': ' + stringify(o[names[i]], true, visited)); // safety from max stack
|
||||
} catch (e) {
|
||||
if (e.name == 'NS_ERROR_NOT_IMPLEMENTED') {
|
||||
// do nothing - not sure it's useful to show this error when the variable is protected
|
||||
// parts.push(names[i] + ': NS_ERROR_NOT_IMPLEMENTED');
|
||||
}
|
||||
}
|
||||
}
|
||||
json += parts.join(',\n') + '\n}';
|
||||
} else {
|
||||
visited.push(o);
|
||||
try {
|
||||
json = stringify(o, true, visited)+''; // should look like an object
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
return json;
|
||||
};
|
||||
}());
|
||||
@ -23,4 +23,5 @@
|
||||
<div id="sandbox-wrapper"></div>
|
||||
|
||||
<script src="/js/vendor/polyfills.js"></script>
|
||||
<script src="/js/vendor/stringify.js"></script>
|
||||
<script src="/runner/runner.js"></script>
|
||||
@ -42,6 +42,10 @@ var throttle = function (fn, delay) {
|
||||
return throttled;
|
||||
};
|
||||
|
||||
var cleanse = function (s) {
|
||||
return (s||'').replace(/[<&]/g, function (m) { return {'&':'&','<':'<'}[m];});
|
||||
};
|
||||
|
||||
/** =========================================================================
|
||||
* Console
|
||||
* Proxy console.logs out to the parent window
|
||||
@ -55,18 +59,12 @@ var proxyconsole = (function () {
|
||||
var proxyconsole = {};
|
||||
|
||||
/**
|
||||
* Replace circular/un-parsable objects from an array for proxying
|
||||
* Stringify all of the console objects from an array for proxying
|
||||
*/
|
||||
proxyconsole.replaceBadArgs = function (args) {
|
||||
var newArgs = [];
|
||||
args.forEach(function (arg) {
|
||||
var newArg = arg;
|
||||
try {
|
||||
JSON.parse(JSON.stringify(arg));
|
||||
} catch(e) {
|
||||
newArg = arg.toString();
|
||||
}
|
||||
newArgs.push(newArg);
|
||||
newArgs.push(cleanse(stringify(arg)));
|
||||
});
|
||||
return newArgs;
|
||||
};
|
||||
@ -85,10 +83,6 @@ var proxyconsole = (function () {
|
||||
method: method,
|
||||
args: JSON.stringify(args)
|
||||
});
|
||||
// If the browser has the console, use it too
|
||||
// if (supportsConsole) {
|
||||
// console[method].apply(console, originalArgs);
|
||||
// }
|
||||
};
|
||||
});
|
||||
|
||||
@ -311,6 +305,24 @@ var sandbox = (function () {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate a command against the active iframe, then use the proxy console
|
||||
* to fire information up to the parent
|
||||
*/
|
||||
sandbox.eval = function (cmd) {
|
||||
if (!sandbox.active) throw new Error("Sandbox has no active iframe.");
|
||||
var childWindow = sandbox.active.contentWindow;
|
||||
var output = null,
|
||||
type = 'log';
|
||||
try {
|
||||
output = childWindow.eval(cmd);
|
||||
} catch (e) {
|
||||
output = e.message;
|
||||
type = 'error';
|
||||
}
|
||||
return proxyconsole[type](output);
|
||||
};
|
||||
|
||||
return sandbox;
|
||||
|
||||
}());
|
||||
@ -391,6 +403,13 @@ var runner = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run console commands against the iframe's scope
|
||||
*/
|
||||
runner['console:run'] = function (cmd) {
|
||||
sandbox.eval(cmd);
|
||||
};
|
||||
|
||||
return runner;
|
||||
|
||||
}());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user