Stack Snippets Console

Add a console to "Stack Snippets" executable code on StackExchange

As of 2014-10-10. See the latest version.

  1. // ==UserScript==
  2. // @name Stack Snippets Console
  3. // @namespace http://stackexchange.com/users/3846032/scimonster
  4. // @version 1.0.1
  5. // @description Add a console to "Stack Snippets" executable code on StackExchange
  6. // @include http://*.stackexchange.com/*
  7. // @include http://stackoverflow.com/*
  8. // @include http://*.stackoverflow.com/*
  9. // @include http://stacksnippets.net/*
  10. // @copyright 2014+, Scimonster
  11. // ==/UserScript==
  12.  
  13. if (location.hostname == 'stacksnippets.net') {
  14. (function(){
  15.  
  16. // define some functions
  17.  
  18. function isSEDomainName(dname) {
  19. return !!~["stackoverflow.com", "stackexchange.com"].indexOf(dname.split('.').slice(-2).join('.'));
  20. }
  21.  
  22. function URLparser(href) {
  23. var p = document.createElement('a');
  24. p.href = href;
  25. return p;
  26. }
  27.  
  28. // listen for the ping
  29.  
  30. this.addEventListener('message', function(ev){
  31. if (isSEDomainName(URLparser(ev.origin).hostname) && ev.data == 'console ping') {
  32. // passes the test
  33. listen(ev);
  34. }
  35. }, false);
  36.  
  37. // listen for console.log()s
  38.  
  39. function listen(ev) {
  40.  
  41. var oldLog = console.log;
  42.  
  43. function log(firstArg) {
  44. var args = [].slice.call(arguments);
  45.  
  46. oldLog.apply(console, args); // use the default console.log()
  47.  
  48. if (typeof firstArg == 'string') { // might require replacing
  49. if (~firstArg.indexOf('%s') || ~firstArg.indexOf('%d') || ~firstArg.indexOf('%i') || ~firstArg.indexOf('%f')) {
  50. // there is something to be replaced
  51. args.shift();
  52. firstArg = firstArg.replace(/%[sdif]/g, function(match){
  53. switch (match) {
  54. case '%s': return args.shift().toString();
  55. case '%d': case '%i': return parseInt(args.shift());
  56. case '%f': return parseFloat(args.shift());
  57. default: return match;
  58. }
  59. });
  60. args.unshift(firstArg);
  61. }
  62. }
  63. // replacements done, ready for concat
  64. var text = args.map(function(a){
  65. if (typeof a == 'object') {
  66. try {
  67. return JSON.strigify(a);
  68. } catch(e) {
  69. return "{bad object}";
  70. }
  71. }
  72. return a.toString();
  73. });
  74.  
  75. postMessage('log', firstArg, text.join(''));
  76. }
  77.  
  78. this.console.log = log;
  79.  
  80. function postMessage(type, message) {
  81. ev.source.postMessage({
  82. type: 'log',
  83. message: message,
  84. time: new Date,
  85. snippet: this.name // the iframe
  86. }, ev.origin);
  87. }
  88.  
  89. }
  90.  
  91. })();
  92. } else {
  93. (function(){
  94.  
  95. function padNum(num, length) {
  96. num = num.toString();
  97. return num.length < length ? padNum('0' + num, length) : num;
  98. }
  99.  
  100. $(document).on('click', 'div.snippet-result input[type=button]', function(){
  101. var container = $(this).parent().parent();
  102. container.children('.snippet-console').remove();
  103. if (!this.className) { // the run button
  104. $('<div class="snippet-console"><h6><a href="http://stackapps.com/q/4931/28683" target="_blank">Snippet Console</a> <small>v1.0.1</small></h6><ul></ul></div>').appendTo(container).css({
  105. position: 'relative',
  106. width: '100%',
  107. maxHeight: 200,
  108. borderTopWidth: 1,
  109. borderTopStyle: 'solid',
  110. borderTopColor: 'rgb(170, 170, 170)',
  111. overflow: 'auto',
  112. display: 'none'
  113. }).children('ul').css({
  114. listStyleType: 'none',
  115. fontFamily: 'monospace'
  116. });
  117.  
  118. var snippet = container.find('iframe')[0];
  119.  
  120. snippet.onload = function(){
  121. setTimeout(function(){
  122. snippet.contentWindow.postMessage('console ping', "*");
  123. // need to accept all because the iframe has no URL
  124. }, 100);
  125. };
  126. }
  127. });
  128.  
  129. window.addEventListener('message', function(ev){
  130. if (ev.origin == 'null' && ev.data.snippet) { // seems to be a snippet
  131. var time = padNum(ev.data.time.getHours(),2)+':'+padNum(ev.data.time.getMinutes(),2)+':'+padNum(ev.data.time.getSeconds(),2)+'.'+padNum(ev.data.time.getMilliseconds(),3);
  132. var li = $('<li data-type="'+ev.data.type+'"><span style="color:gray">'+time+':</span> <span></span></li>');
  133. li.find('span').last().text(ev.data.message);
  134. var snCons = $('iframe[name="'+ev.data.snippet+'"]').parent().parent().children('.snippet-console').show();
  135. snCons.children('ul').append(li);
  136. snCons.scrollTop(snCons.children('ul').height()); // scroll to bottom
  137. }
  138. }, false);
  139. })();
  140. }