jsbin/public/js/render/console.js

1080 lines
32 KiB
JavaScript

//= require "../vendor/prettyprint"
//= require "../vendor/stacktrace"
var jsconsole = (function (window) {
function sortci(a, b) {
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
// 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 {'&':'&amp;','<':'&lt;'}[m];});
}
function run(cmd) {
var rawoutput = null,
className = 'response',
internalCmd = internalCommand(cmd);
if (internalCmd) {
return ['info', internalCmd];
} else {
try {
rawoutput = sandboxframe.contentWindow.eval(cmd);
} catch (e) {
rawoutput = e.message;
className = 'error';
}
return [className, cleanse(stringify(rawoutput))];
}
}
function post(cmd, blind, response /* passed in when echoing from remote console */) {
cmd = trim(cmd);
if (blind === undefined) {
history.push(cmd);
setHistory(history);
}
if ((cmd.match(commandPresent) || []).length > 1) {
// split the command up in to blocks and internal commands and run sequentially
} else {
}
echo(cmd);
// order so it appears at the top
var el = document.createElement('div'),
li = document.createElement('li'),
span = document.createElement('span'),
parent = output.parentNode;
if (!internalCommand(cmd)) {
// Fix console not having iframe
if (!(sandboxframe && sandboxframe.contentWindow)) {
// Boo. There must be a nice way to do this.
sandboxframe = $live.find('iframe')[0];
// Only force it to render if there's no live iframe
if (!(sandboxframe && sandboxframe.contentWindow)) {
renderLivePreview(false);
sandboxframe = $live.find('iframe')[0];
}
jsconsole.setSandbox(sandboxframe);
}
}
// In a setTimeout so that renderLivePreview has time for the iframe to load
setTimeout(function () {
response = response || run(cmd);
if (response !== undefined) {
el.className = 'response';
span.innerHTML = response[1];
if (response[0] != 'info') prettyPrint([span]);
el.appendChild(span);
li.className = response[0];
li.innerHTML = '<span class="gutter"></span>';
li.appendChild(el);
appendLog(li);
exec.value = '';
if (enableCC) {
try {
// document.getElementsByTagName('a')[0].focus();
if (jsbin.panels.focused.id === 'console') {
if (!jsbin.embed) {
cursor.focus();
}
document.execCommand('selectAll', false, null);
document.execCommand('delete', false, null);
}
} catch (e) {}
}
}
pos = history.length;
}, 0);
}
function log(msg, className) {
var li = document.createElement('li'),
div = document.createElement('div');
div.innerHTML = msg;
prettyPrint([div]);
li.className = className || 'log';
li.innerHTML = '<span class="gutter"></span>';
li.appendChild(div);
appendLog(li);
}
function echo(cmd) {
var li = document.createElement('li');
li.className = 'echo';
li.innerHTML = '<span class="gutter"></span><div>' + cleanse(cmd) + '</div>';
logAfter = null;
// logAfter = $(output).find('li.echo:first')[0] || null;
// logAfter = output.querySelector('li.echo') || null;
appendLog(li, true);
}
window.info = function(cmd) {
var li = document.createElement('li');
li.className = 'info';
li.innerHTML = '<span class="gutter"></span><div>' + cleanse(cmd) + '</div>';
// logAfter = output.querySelector('li.echo') || null;
// appendLog(li, true);
appendLog(li);
};
function appendLog(el, echo) {
output.appendChild(el);
output.parentNode.scrollTop = output.parentNode.scrollHeight + 1000;
return;
if (echo) {
if (!output.firstChild) {
output.appendChild(el);
} else {
output.insertBefore(el, output.firstChild);
}
} else {
if (!output.lastChild) {
output.appendChild(el);
} else {
// console.log(output.lastChild.nextSibling);
output.insertBefore(el, logAfter ? logAfter : output.lastChild.nextSibling); // ? output.lastChild.nextSibling : output.firstChild
}
}
}
function internalCommand(cmd) {
var parts = [], c;
if (cmd.substr(0, 1) == ':') {
parts = cmd.substr(1).split(' ');
c = parts.shift();
return (commands[c] || noop).apply(this, parts);
}
}
function noop() {}
function showhelp() {
var commands = [
':reset - destroy state and start afresh',
':history - list current session history',
':load &lt;url&gt; - to inject new DOM',
':load &lt;script_url&gt; - to inject external library',
' load also supports following shortcuts: <br /> jquery, underscore, prototype, mootools, dojo, rightjs, coffeescript, yui.<br /> eg. :load jquery',
':clear - to clear contents of the console',
':about jsconsole'
];
return commands.join('\n');
}
function load(url) {
if (navigator.onLine) {
if (arguments.length > 1 || libraries[url] || url.indexOf('.js') !== -1) {
return loadScript.apply(this, arguments);
} else {
return loadDOM(url);
}
} else {
return "You need to be online to use :load";
}
}
function loadScript() {
var doc = sandboxframe.contentDocument || sandboxframe.contentWindow.document;
for (var i = 0; i < arguments.length; i++) {
(function (url) {
var script = document.createElement('script');
script.src = url;
script.onload = function () {
window.top.info('Loaded ' + url, 'http://' + window.location.hostname);
if (url == libraries.coffeescript) window.top.info('Now you can type CoffeeScript instead of plain old JS!');
};
script.onerror = function () {
log('Failed to load ' + url, 'error');
};
doc.body.appendChild(script);
})(libraries[arguments[i]] || arguments[i]);
}
return "Loading script...";
}
function loadDOM(url) {
var doc = sandboxframe.contentWindow.document,
script = document.createElement('script'),
cb = 'loadDOM' + +new Date;
script.src = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22' + encodeURIComponent(url) + '%22&format=xml&callback=' + cb;
window[cb] = function (yql) {
if (yql.results.length) {
var html = yql.results[0].replace(/type="text\/javascript"/ig,'type="x"').replace(/<body.*?>/, '').replace(/<\/body>/, '');
doc.body.innerHTML = html;
window.top.info('DOM load complete');
} else {
log('Failed to load DOM', 'error');
}
try {
window[cb] = null;
delete window[cb];
} catch (e) {}
};
document.body.appendChild(script);
return "Loading url into DOM...";
}
function trim(s) {
return (s||"").replace(/^\s+|\s+$/g,"");
}
var ccCache = {};
var ccPosition = false;
window._console = {
log: function () {
var l = arguments.length, i = 0;
for (; i < l; i++) {
log(stringify(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]));
}
window.console.dir.apply(window.console, arguments);
},
props: function (obj) {
var props = [], realObj;
try {
for (var p in obj) props.push(p);
} catch (e) {}
window.console.props.apply(window.console, arguments);
return props;
},
error: function (err) {
log(err.message, 'error');
window.console.error.apply(window.console, arguments);
}
};
function about() {
return 'Ported to JS Bin from <a target="_new" href="http://jsconsole.com">jsconsole.com</a>';
}
function setHistory(history) {
if (typeof JSON == 'undefined') return;
try {
// because FF with cookies disabled goes nuts, and because sometimes WebKit goes nuts too...
sessionStorage.setItem('history', JSON.stringify(history));
} catch (e) {}
}
function getHistory() {
var history = [''];
if (typeof JSON == 'undefined') return history;
try {
// because FF with cookies disabled goes nuts, and because sometimes WebKit goes nuts too...
history = JSON.parse(sessionStorage.getItem('history') || '[""]');
} catch (e) {}
return history;
}
function showHistory() {
var h = getHistory();
h.shift();
return h.join("\n");
}
var exec = document.getElementById('exec'),
form = exec.form || {},
output = null,
sandboxframe = null,
sandbox = null,
history = getHistory(),
codeCompleteTimer = null,
fakeConsole = 'window.parent._console',
libraries = {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js',
prototype: 'http://ajax.googleapis.com/ajax/libs/prototype/1/prototype.js',
dojo: 'http://ajax.googleapis.com/ajax/libs/dojo/1/dojo/dojo.xd.js',
mootools: 'http://ajax.googleapis.com/ajax/libs/mootools/1/mootools-yui-compressed.js',
underscore: 'http://documentcloud.github.com/underscore/underscore-min.js',
rightjs: 'http://rightjs.org/hotlink/right.js',
coffeescript: 'http://jashkenas.github.com/coffee-script/extras/coffee-script.js',
yui: 'http://yui.yahooapis.com/3.9.1/build/yui/yui-min.js'
},
body = document.getElementsByTagName('body')[0],
logAfter = null,
lastCmd = null,
wait = false,
commandPresent = /:((?:help|about|load|clear|reset|wait|history)(?:.*))\n/gi,
commands = {
history: showHistory,
help: showhelp,
about: about,
load: load,
wait: function () {
wait = true;
return '';
},
clear: function () {
setTimeout(function () { output.innerHTML = ''; }, 10);
return 'clearing...';
},
reset: function () {
output.innerHTML = '';
jsconsole.init(output, true);
return 'Context reset';
}
},
fakeInput = null,
cursor = document.getElementById('cursor'),
// I hate that I'm browser sniffing, but there's issues with Firefox and execCommand so code completion won't work
iOSMobile = navigator.userAgent.indexOf('AppleWebKit') !== -1 && navigator.userAgent.indexOf('Mobile') !== -1,
// FIXME Remy, seriously, don't sniff the agent like this, it'll bite you in the arse.
enableCC = navigator.userAgent.indexOf('AppleWebKit') !== -1 && navigator.userAgent.indexOf('Mobile') === -1 || navigator.userAgent.indexOf('OS 5_') !== -1;
if (enableCC) {
var autofocus = jsbin.embed ? '' : 'autofocus';
exec.parentNode.innerHTML = '<div ' + autofocus + ' id="exec" autocapitalize="off" spellcheck="false"><span id="cursor" spellcheck="false" autocapitalize="off" autocorrect="off"' + (iOSMobile ? '' : ' contenteditable') + '></span></div>';
exec = document.getElementById('exec');
cursor = document.getElementById('cursor');
} else {
$('#console').addClass('plain');
}
if (enableCC && iOSMobile) {
fakeInput = document.createElement('input');
fakeInput.className = 'fakeInput';
fakeInput.setAttribute('spellcheck', 'false');
fakeInput.setAttribute('autocorrect', 'off');
fakeInput.setAttribute('autocapitalize', 'off');
exec.parentNode.appendChild(fakeInput);
}
// sandbox = sandboxframe.contentDocument || sandboxframe.contentWindow.document;
// tweaks to interface to allow focus
// if (!('autofocus' in document.createElement('input'))) exec.focus();
function whichKey(event) {
var keys = {38:1, 40:1, Up:38, Down:40, Enter:10, 'U+0009':9, 'U+0008':8, 'U+0190':190, 'Right':39,
// these two are ignored
'U+0028': 57, 'U+0026': 55 };
return keys[event.keyIdentifier] || event.which || event.keyCode;
}
function setCursorTo(str) {
str = enableCC ? cleanse(str) : str;
exec.value = str;
if (enableCC) {
document.execCommand('selectAll', false, null);
document.execCommand('delete', false, null);
document.execCommand('insertHTML', false, str);
} else {
var rows = str.match(/\n/g);
exec.setAttribute('rows', rows !== null ? rows.length + 1 : 1);
}
cursor.focus();
// window.scrollTo(0,0);
}
// output.ontouchstart = output.onclick = function (event) {
// event = event || window.event;
// if (event.target.nodeName == 'A' && event.target.className == 'permalink') {
// var command = decodeURIComponent(event.target.search.substr(1));
// setCursorTo(command);
// if (liveHistory) {
// window.history.pushState(command, command, event.target.href);
// }
// return false;
// }
// };
exec.ontouchstart = function () {
window.scrollTo(0,0);
};
exec.onkeyup = function (event) {
var which = whichKey(event);
if (enableCC && which != 9 && which != 16) {
clearTimeout(codeCompleteTimer);
codeCompleteTimer = setTimeout(function () {
codeComplete(event);
}, 200);
}
};
if (enableCC) {
// disabled for now
cursor.__onpaste = function (event) {
setTimeout(function () {
// this causes the field to lose focus - I'll leave it here for a while, see how we get on.
// what I need to do is rip out the contenteditable and replace it with something entirely different
cursor.innerHTML = cursor.innerText;
// setCursorTo(cursor.innerText);
}, 10);
};
}
function findNode(list, node) {
var pos = 0;
for (var i = 0; i < list.length; i++) {
if (list[i] == node) {
return pos;
}
pos += list[i].nodeValue.length;
}
return -1;
};
exec.onkeydown = function (event) {
event = event || window.event;
var keys = {38:1, 40:1},
wide = body.className == 'large',
which = whichKey(event);
if (typeof which == 'string') which = which.replace(/\/U\+/, '\\u');
if (keys[which]) {
if (event.shiftKey) {
// changeView(event);
} else if (!wide) { // history cycle
if (enableCC && window.getSelection) {
window.selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
cursorPos = findNode(selObj.anchorNode.parentNode.childNodes, selObj.anchorNode) + selObj.anchorOffset;
var value = exec.value,
firstnl = value.indexOf('\n'),
lastnl = value.lastIndexOf('\n');
if (firstnl !== -1) {
if (which == 38 && cursorPos > firstnl) {
return;
} else if (which == 40 && cursorPos < lastnl) {
return;
}
}
}
if (which == 38) { // cycle up
pos--;
if (pos < 0) pos = 0; //history.length - 1;
} else if (which == 40) { // down
pos++;
if (pos >= history.length) pos = history.length; //0;
}
if (history[pos] != undefined && history[pos] !== '') {
removeSuggestion();
setCursorTo(history[pos])
return false;
} else if (pos == history.length) {
removeSuggestion();
setCursorTo('');
return false;
}
}
} else if ((which == 13 || which == 10) && event.shiftKey == false) { // enter (what about the other one)
removeSuggestion();
if (event.shiftKey == true || event.metaKey || event.ctrlKey || !wide) {
var command = exec.textContent || exec.value;
if (command.length) post(command);
return false;
}
} else if ((which == 13 || which == 10) && !enableCC && event.shiftKey == true) {
// manually expand the textarea when we don't have code completion turned on
var rows = exec.value.match(/\n/g);
rows = rows != null ? rows.length + 2 : 2;
exec.setAttribute('rows', rows);
} else if (which == 9 && wide) {
checkTab(event);
} else if (event.shiftKey && event.metaKey && which == 8) {
output.innerHTML = '';
} else if ((which == 39 || which == 35) && ccPosition !== false) { // complete code
completeCode();
} else if (event.ctrlKey && which == 76) {
output.innerHTML = '';
} else if (enableCC) { // try code completion
if (ccPosition !== false && which == 9) {
codeComplete(event); // cycles available completions
return false;
} else if (ccPosition !== false && cursor.nextSibling) {
removeSuggestion();
}
}
};
if (enableCC && iOSMobile) {
fakeInput.onkeydown = function (event) {
removeSuggestion();
var which = whichKey(event);
if (which == 13 || which == 10) {
post(this.value);
this.value = '';
cursor.innerHTML = '';
return false;
}
};
fakeInput.onkeyup = function (event) {
cursor.innerHTML = cleanse(this.value);
var which = whichKey(event);
if (enableCC && which != 9 && which != 16) {
clearTimeout(codeCompleteTimer);
codeCompleteTimer = setTimeout(function () {
codeComplete(event);
}, 200);
}
};
var fakeInputFocused = false;
var dblTapTimer = null,
taps = 0;
form.addEventListener('touchstart', function (event) {
// window.scrollTo(0,0);
if (ccPosition !== false) {
event.preventDefault();
clearTimeout(dblTapTimer);
taps++;
if (taps === 2) {
completeCode();
fakeInput.value = cursor.textContent;
removeSuggestion();
fakeInput.focus();
} else {
dblTapTimer = setTimeout(function () {
taps = 0;
codeComplete({ which: 9 });
}, 200);
}
}
return false;
});
}
function completeCode(focus) {
var tmp = exec.textContent, l = tmp.length;
removeSuggestion();
cursor.innerHTML = tmp;
ccPosition = false;
// daft hack to move the focus elsewhere, then back on to the cursor to
// move the cursor to the end of the text.
document.getElementsByTagName('a')[0].focus();
cursor.focus();
var range, selection;
if (document.createRange) {//Firefox, Chrome, Opera, Safari, IE 9+
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(cursor);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
} else if (document.selection) {//IE 8 and lower
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(cursor);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
form.onsubmit = function (event) {
event = event || window.event;
event.preventDefault && event.preventDefault();
removeSuggestion();
post(exec.textContent || exec.value);
return false;
};
document.onkeydown = function (event) {
event = event || window.event;
var which = event.which || event.keyCode;
if (event.shiftKey && event.metaKey && which == 8) {
output.innerHTML = '';
cursor.focus();
} else if (event.target == output.parentNode && which == 32) { // space
output.parentNode.scrollTop += 5 + output.parentNode.offsetHeight * (event.shiftKey ? -1 : 1);
}
// return changeView(event);
};
exec.onclick = function () {
cursor.focus();
}
function getProps(cmd, filter) {
var surpress = {}, props = [];
if (!ccCache[cmd]) {
try {
// surpress alert boxes because they'll actually do something when we're looking
// up properties inside of the command we're running
surpress.alert = sandboxframe.contentWindow.alert;
sandboxframe.contentWindow.alert = function () {};
// loop through all of the properties available on the command (that's evaled)
ccCache[cmd] = sandboxframe.contentWindow.eval('console.props(' + cmd + ')').sort();
// return alert back to it's former self
delete sandboxframe.contentWindow.alert;
} catch (e) {
ccCache[cmd] = [];
}
// if the return value is undefined, then it means there's no props, so we'll
// empty the code completion
if (ccCache[cmd][0] == 'undefined') ccOptions[cmd] = [];
ccPosition = 0;
props = ccCache[cmd];
} else if (filter) {
// console.log('>>' + filter, cmd);
for (var i = 0, p; i < ccCache[cmd].length, p = ccCache[cmd][i]; i++) {
if (p.indexOf(filter) === 0) {
if (p != filter) {
props.push(p.substr(filter.length, p.length));
}
}
}
} else {
props = ccCache[cmd];
}
return props;
}
function codeComplete(event) {
var cmd = cursor.textContent.split(/[;\s]+/g).pop(),
parts = cmd.split('.'),
which = whichKey(event),
cc,
props = [];
if (cmd) {
// get the command without the dot to allow us to introspect
if (cmd.substr(-1) == '.') {
// get the command without the '.' so we can eval it and lookup the properties
cmd = cmd.substr(0, cmd.length - 1);
// returns an array of all the properties from the command
props = getProps(cmd);
} else {
props = getProps(parts.slice(0, parts.length - 1).join('.') || 'window', parts[parts.length - 1]);
}
if (props.length) {
if (which == 9) { // tabbing cycles through the code completion
// however if there's only one selection, it'll auto complete
if (props.length === 1) {
ccPosition = false;
} else {
if (event.shiftKey) {
// backwards
ccPosition = ccPosition == 0 ? props.length - 1 : ccPosition-1;
} else {
ccPosition = ccPosition == props.length - 1 ? 0 : ccPosition+1;
}
}
} else {
ccPosition = 0;
}
if (ccPosition === false) {
completeCode();
} else {
// position the code completion next to the cursor
if (!cursor.nextSibling) {
cc = document.createElement('span');
cc.className = 'suggest';
exec.appendChild(cc);
}
cursor.nextSibling.innerHTML = props[ccPosition];
exec.value = exec.textContent;
}
if (which == 9) return false;
} else {
ccPosition = false;
}
} else {
ccPosition = false;
}
if (ccPosition === false && cursor.nextSibling) {
removeSuggestion();
}
exec.value = exec.textContent;
}
function removeSuggestion() {
if (!enableCC) exec.setAttribute('rows', 1);
if (enableCC && cursor.nextSibling) cursor.parentNode.removeChild(cursor.nextSibling);
}
var jsconsole = {
run: post,
clear: commands.clear,
reset: function () {
this.run(':reset');
},
focus: function () {
if (enableCC) {
cursor.focus();
} else {
$(exec).focus();
}
},
echo: echo,
setSandbox: function (newSandbox) {
// sandboxframe.parentNode.removeChild(sandboxframe);
sandboxframe = newSandbox;
sandbox = sandboxframe.contentDocument || sandboxframe.contentWindow.document;
// sandbox.open();
// stupid jumping through hoops if Firebug is open, since overwriting console throws error
// sandbox.write('<script>(function () { var fakeConsole = ' + fakeConsole + '; if (window.console != undefined) { for (var k in fakeConsole) { console[k] = fakeConsole[k]; } } else { console = fakeConsole; } })();</script>');
// sandbox.write('<script>window.print=function(){};window.alert=function(){};window.prompt=function(){};window.confirm=function(){};</script>');
// sandbox.open();
// sandbox.write(getPreparedCode(true));
sandboxframe.contentWindow.eval('(function () { var fakeConsole = ' + fakeConsole + '; if (window.console != undefined) { for (var k in fakeConsole) { console[k] = fakeConsole[k]; } } else { console = fakeConsole; } })();');
// sandbox.close();
this.sandboxframe = sandboxframe;
if (sandbox.readyState !== 'complete') {
this.ready = false;
} else {
jsconsole.onload();
}
sandbox.onreadystatechange = function () {
if (sandbox.readyState === 'complete') {
jsconsole.ready = true;
jsconsole.onload();
}
};
getProps('window'); // cache
},
_onloadQueue: [],
onload: function (fn) {
var i = 0, length = this._onloadQueue.length;
if (this.ready === false && fn) { // if not ready and callback passed - cache it
this._onloadQueue.push(fn);
} else if (this.ready === true && !fn) { // if ready and not callback - flush cache
for (; i < length; i++) {
this._onloadQueue[i].call(this);
}
this._onloadQueue = [];
} else if (fn) { // if callback and ready - run callback
fn.call(this);
}
},
init: function (outputElement, nohelp) {
output = outputElement;
// 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);
},
rawMessage: function (data) {
if (data.type && data.type == 'error') {
post(data.cmd, true, ['error', data.response]);
} else if (data.type && data.type == 'info') {
window.top.info(data.response);
} else {
if (data.cmd.indexOf('console.log') === -1) data.response = data.response.substr(1, data.response.length - 2); // fiddle to remove the [] around the repsonse
echo(data.cmd);
log(data.response, 'response');
}
},
stringify: stringify
};
return jsconsole;
})(this);
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();
});
console.reset = function () {
jsconsole.reset();
};
console.settings.render = function (withAlerts) {
var html = editors.html.render().trim();
if (html === "") {
var code = editors.javascript.render().trim();
jsconsole.run(code);
} else {
renderLivePreview(withAlerts || false);
}
};
console.settings.show = function () {
jsconsole.clear();
// renderLivePreview(true);
// setTimeout because the renderLivePreview creates the iframe after a timeout
setTimeout(function () {
// jsconsole.setSandbox($live.find('iframe')[0]);
if (editors.console.ready && !jsbin.embed) jsconsole.focus();
}, 0);
};
console.settings.hide = function () {
// Removal code is commented out so that the
// output iframe is never removed
if (!editors.live.visible) {
// $live.find('iframe').remove();
}
};
// jsconsole.ready = true;
jsconsole.remote.flush();
$document.one('jsbinReady', function () {
var hidebutton = function () {
$('#runconsole')[this.visible ? 'hide' : 'show']();
};
jsbin.panels.panels.live.on('show', hidebutton).on('hide', hidebutton);
if (jsbin.panels.panels.live.visible) {
$('#runconsole').hide();
}
});
// editors.console.fakeConsole = window._console
// };
// console.init();
}