Created
July 6, 2015 07:28
-
-
Save jonasfj/d0d22890514ea37e17b4 to your computer and use it in GitHub Desktop.
Initial hack for interactive tutorials...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var util = require('util'); | |
var slugid = require('slugid'); | |
var ace = require('brace'); | |
require('brace/mode/javascript'); | |
require('brace/theme/ambiance'); | |
var babel = require('babel-core/lib/babel/api/browser'); | |
// Babel runtime part we use | |
require('babel-runtime/regenerator'); | |
require('babel-runtime/core-js/promise'); | |
// Modules for use in code examples | |
require('taskcluster-client'); | |
require('url'); | |
require('querystring'); | |
var preClass = document.currentScript.dataset.preClass; | |
// Not sure how to create scoped <style>, so instead we'll just | |
// include a slugid in the className that way the risk of collisions is fairly | |
// small :) | |
var btnClassId = slugid.v4(); | |
var style = document.createElement('style'); | |
style.textContent = [ | |
// Largely borrowed from http://purecss.io/buttons/ | |
// Credits to Yahoo for nice buttons released under BSD | |
".btn-" + btnClassId + "-button {", | |
" display: inline-block;", | |
" zoom: 1;", | |
" line-height: normal;", | |
" white-space: nowrap;", | |
" vertical-align: middle;", | |
" text-align: center;", | |
" cursor: pointer;", | |
" -webkit-user-drag: none;", | |
" -webkit-user-select: none;", | |
" -moz-user-select: none;", | |
" -ms-user-select: none;", | |
" user-select: none;", | |
" -webkit-box-sizing: border-box;", | |
" -moz-box-sizing: border-box;", | |
" box-sizing: border-box;", | |
" font-family: inherit;", | |
" font-size: 100%;", | |
" padding: 0.5em 1em;", | |
" color: #444; /* rgba not supported (IE 8) */", | |
" color: rgba(0, 0, 0, 0.80); /* rgba supported */", | |
" border: 1px solid #999; /*IE 6/7/8*/", | |
" border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/", | |
" background-color: #E6E6E6;", | |
" text-decoration: none;", | |
" border-radius: 4px;", | |
" margin-right: 5px;", | |
" color: white;", | |
" border-radius: 4px;", | |
" text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);", | |
"}", | |
".btn-" + btnClassId + "-button:hover,", | |
".btn-" + btnClassId + "-button:focus {", | |
" filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000',GradientType=0);", | |
" background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10)));", | |
" background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));", | |
" background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.10));", | |
" background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));", | |
" background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));", | |
"}", | |
".btn-" + btnClassId + "-button:focus {", | |
" outline: 0;", | |
"}", | |
".btn-" + btnClassId + "-button:active {", | |
" box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;", | |
" border-color: #000\9;", | |
"}", | |
".btn-" + btnClassId + "-button-green {", | |
" background: #1CB841;", | |
"}", | |
".btn-" + btnClassId + "-button-red {", | |
" background: #CA3C3C;", | |
"}", | |
].join('\n'); | |
document.currentScript.parentNode.insertBefore( | |
style, document.currentScript.parentNode.firstChild | |
); | |
var makeButton = function(text, color) { | |
var btn = document.createElement("a"); | |
btn.innerHTML = text; | |
btn.classList.add("btn-" + btnClassId + "-button"); | |
btn.classList.add("btn-" + btnClassId + "-button-" + color); | |
return btn; | |
}; | |
var cleanEval = function(window, require, console) { | |
return eval(arguments[3]); | |
}; | |
var evalCount = 0; | |
document.addEventListener("DOMContentLoaded", function() { | |
var nodeList = document.querySelectorAll('pre.' + preClass); | |
var preList = Array.prototype.slice.call(nodeList); | |
preList.forEach(function(pre) { | |
var initialCode = pre.textContent; | |
pre.style.width = '100%'; | |
var editor = ace.edit(pre); | |
editor.$blockScrolling = Infinity; | |
editor.setTheme('ace/theme/ambiance'); | |
editor.setValue(initialCode, 1); | |
editor.setAutoScrollEditorIntoView(true); | |
editor.setOption("maxLines", 50); | |
editor.setOption("showFoldWidgets", false); | |
editor.setHighlightActiveLine(false); | |
editor.setHighlightGutterLine(false); | |
editor.setShowPrintMargin(false); | |
editor.getSession().setMode('ace/mode/javascript'); | |
editor.getSession().setUseSoftTabs(true); | |
editor.getSession().setTabSize(2); | |
editor.getSession().setUseWorker(false); | |
// Create output | |
var output = document.createElement("pre"); | |
var outputWrap = document.createElement("div"); | |
output.style.width = '108ex'; | |
outputWrap.style.borderLeft = '8px solid #ccc'; | |
outputWrap.style.paddingLeft = '8px'; | |
outputWrap.appendChild(output); | |
var capturingConsole = Object.create(console); | |
var writeOutput = function() { | |
var args = Array.prototype.slice.call(arguments); | |
Function.prototype.apply.call(console.log, console, args); | |
var data = args.map(function(arg) { | |
if (typeof arg === 'string') { | |
return arg; | |
} else if (typeof arg === 'Function') { | |
return arg.toString(); | |
} | |
return util.inspect(arg); | |
}); | |
output.textContent += data + '\n'; | |
}; | |
capturingConsole.log = writeOutput; | |
capturingConsole.info = writeOutput; | |
capturingConsole.warn = writeOutput; | |
capturingConsole.error = writeOutput; | |
capturingConsole.debug = writeOutput; | |
capturingConsole.clear = function() { | |
output.textContent = ""; | |
}; | |
// Create buttons | |
var buttons = document.createElement("div"); | |
var run = makeButton('Run Code', 'green'); | |
var reset = makeButton('Reset', 'red'); | |
buttons.appendChild(run); | |
buttons.appendChild(reset); | |
run.onclick = function() { | |
capturingConsole.clear(); | |
var value = editor.getValue(); | |
try { | |
var code = babel.transform([ | |
"(async function example() {", | |
value, | |
"})" | |
].join('\n'), { | |
stage: 1, | |
optional: ['runtime'], | |
filename: 'eval-' + (evalCount++) + '.js', | |
sourceMaps: 'inline' | |
}).code; | |
} catch (err) { | |
capturingConsole.log("Compilation Error: " + err.message); | |
if (err.codeFrame) { | |
capturingConsole.log(err.codeFrame); | |
} | |
} | |
var f = cleanEval(window, require, capturingConsole, code); | |
var displayError = function(err) { | |
capturingConsole.log(err.stack); | |
capturingConsole.log('details: ' + util.inspect(err)); | |
}; | |
setTimeout(function run() { | |
try { | |
f().catch(displayError); | |
} catch (err) { | |
displayError(err); | |
} | |
}, 0); | |
}; | |
reset.onclick = function() { | |
editor.setValue(initialCode, 1); | |
capturingConsole.clear(); | |
}; | |
// Insert buttons and output after pre | |
var parent = pre.parentNode; | |
parent.insertBefore(buttons, pre.nextSibling); | |
parent.insertBefore(outputWrap, buttons.nextSibling); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "interactive-js-pre", | |
"version": "0.0.1", | |
"description": "Turn pre-tags into interactive JS editors", | |
"main": "main.js", | |
"scripts": { | |
"build": "browserify main.js | uglifyjs > bundle.min.js", | |
"develop": "watchify main.js -o bundle.js" | |
}, | |
"dependencies": { | |
"brace": "^0.5.1", | |
"babel-core": "^5.6.15", | |
"babel-runtime": "^5.6.15", | |
"taskcluster-client": "^0.22.4", | |
"slugid": "^1.0.3" | |
}, | |
"devDependencies": { | |
"browserify": "^10.2.4", | |
"watchify": "^3.2.3", | |
"uglify-js": "^2.4.23" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<body> | |
<script src="bundle.js" data-pre-class="test" charset="UTF-8"></script> | |
<pre class="test"> | |
console.log("test"); | |
throw new Error("test error"); | |
</pre> | |
<pre class="test"> | |
let querystring = require('querystring'); | |
let credentials = querystring.parse(window.location.search.substr(1)); | |
if (credentials.clientId && credentials.accessToken) { | |
// Store credentials on window object for use in later steps | |
window.tempCreds = { | |
clientId: credentials.clientId, | |
accessToken: credentials.accessToken, | |
certificate: credentials.certificate | |
}; | |
console.log("TaskCluster credentials loaded from query string,"); | |
console.log("You may now continue to the next step..."); | |
} else { | |
// If no credentials is present in querystring we redirect you to | |
// auth.taskcluster.net with current URL as target, so you can redirect back | |
// with temporary credentials in querystring using the "Grant Access" button | |
console.log("Redirecting to login in 3 seconds"); | |
// Wait for promise to resolve, and create promise that we resolve 3s later | |
await new Promise(resolve => setTimeout(resolve, 3000)); | |
window.location = "https://auth.taskcluster.net?" + querystring.stringify({ | |
target: window.location.href, | |
description: "Redirect back to tutorial with credentials in query string" | |
}); | |
} | |
</pre> | |
<hr> | |
<pre class="test"> | |
let taskcluster = require('taskcluster-client'); | |
let slugid = require('slugid'); | |
// Create a queue client object w. temporary credentials | |
let queue = new taskcluster.Queue({ | |
credentials: window.tempCreds | |
}); | |
// Create new taskId (Random UUID encoded as url-safe base64) | |
let taskId = slugid.v4(); | |
console.log("Generated taskId: " + taskId); | |
// Create task | |
let result = await queue.createTask(taskId, { | |
provisionerId: "aws-provisioner-v1", // Provisioner to find worker under | |
workerType: "b2gtest", // WorkerType to run task on | |
created: new Date().toJSON(), | |
deadline: taskcluster.fromNowJSON('2 hours'), | |
payload: { // docker-worker specific payload | |
image: "ubuntu:15.04", // Use the ubuntu image tag 15.04 | |
command: ["du", "/usr"], // Run the command "du" with argument "/usr" | |
maxRunTime: 600 // Run for at most 600s == 10min | |
}, | |
metadata: { | |
name: "Interactive Tutorial Task", | |
description: "Task created from **interactive tutorial**...", | |
owner: "[email protected]", // Person who caused this task | |
source: window.location.href // Source for the task definition | |
} | |
}); | |
console.log("Created task:\n" + JSON.stringify(result.status, null, 2)); | |
console.log("Inspect it at: https://tools.taskcluster.net/task-inspector/#" + taskId); | |
</pre> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment