Filthy little hack: when the live preview is open, any calls to console.* will switch the context to the jsbin preview - NOT the actual current window. Note that this only works in Chrome due to the way the argument.callee call stack is exposed.

This commit is contained in:
remy 2011-03-20 13:38:00 +00:00
parent 46f73fbd51
commit 6a4492e1be
2 changed files with 60 additions and 0 deletions

View File

@ -0,0 +1,53 @@
function ConsoleContext(context) {
var self = this;
this.context = context;
this.executable = typeof context == 'function';
this.active = false;
this.original = window.top.console;
// yeah, lame, but we've no way to detect the console arguments support, because
// it can only be tested from the /actual/ console.
this.supported = /chrome/i.test(navigator.userAgent);
}
ConsoleContext.prototype = {
hijack: function (method, args) {
var context = this.executable ? this.context() : this.context;
var re = new RegExp('console\.' + method + '\\((.*?)\\)');
if (!/renderLivePreview/.test(arguments.callee.caller.caller.toString()) && context) {
context.eval('console.' + method + '(' + arguments.callee.caller.caller.arguments[0].toString().match(re)[1] + ')');
} else {
this.original[method].apply(this.original, args);
}
},
log: function () {
this.hijack('log', [].slice.call(arguments));
},
debug: function () {
this.hijack('debug', [].slice.call(arguments));
},
dir: function () {
this.hijack('dir', [].slice.call(arguments));
},
warn: function () {
this.hijack('warn', [].slice.call(arguments));
},
error: function () {
this.hijack('error', [].slice.call(arguments));
},
activate: function () {
if (this.supported) {
window.top.console = this;
if (console == this) this.original.log('--- console context switched to jsbin ---');
this.active = true;
}
},
deactivate: function () {
if (this.supported) {
this.active = false;
if (console == this) this.original.log('--- console context switched back to original ---');
window.top.console = this.original;
}
}
};

View File

@ -2,6 +2,11 @@ var $live = $('#live'),
$bin = $('#bin'),
throttledPreview = throttle(renderLivePreview, 100);
//= require "consoleContext"
var hijackedConsole = new ConsoleContext(function () {
return $('#live iframe').length ? $('#live iframe')[0].contentWindow : null;
});
// could chain - but it's more readable like this
$live.bind('show', function () {
$bin.addClass('live');
@ -11,10 +16,12 @@ $live.bind('show', function () {
// start timer
$(document).bind('codeChange.live', throttledPreview);
renderLivePreview();
hijackedConsole.activate();
}).bind('hide', function () {
$(document).unbind('codeChange.live');
localStorage && localStorage.removeItem('livepreview');
$bin.removeClass('live');
hijackedConsole.deactivate();
}).bind('toggle', function () {
$live.trigger($bin.is('.live') ? 'hide' : 'show');
});