Work in progress on embeddable CEs

This commit is contained in:
Matt Godbolt 2016-10-26 16:39:42 -05:00 committed by Matt Godbolt
parent a5c268cbb8
commit 0cda1b839a
11 changed files with 220 additions and 23 deletions

4
.idea/watcherTasks.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions" suppressed-tasks="Less" />
</project>

10
app.js
View File

@ -463,6 +463,15 @@ function shortUrlHandler(req, res, next) {
});
}
// TODO: write the info here directly instead of redirecting...
function embeddedHandler(req, res, next) {
res.writeHead(301, {
Location: 'embed.html',
'Cache-Control': 'public'
});
res.end();
}
var clientOptionsHandler = new ClientOptionsHandler(fileSources);
var apiHandler = new ApiHandler();
var compileHandler = new CompileHandler();
@ -515,6 +524,7 @@ findCompilers().then(function (compilers) {
.use('/source', getSource)
.use('/api', apiHandler.handler)
.use('/g', shortUrlHandler)
.use('/e', embeddedHandler)
.post('/compile', compileHandler.handler) // used inside static/compiler.js
.post('/diff', diffHandler); // used inside static/compiler.js

View File

@ -61,6 +61,7 @@ define(function (require) {
}
function initialise() {
if (options.embedded) return;
$(function () {
function create_script_element(id, url) {
var el = document.createElement('script');

View File

@ -173,7 +173,7 @@ define(function (require) {
Editor.prototype.maybeEmitChange = function (force) {
var source = this.getSource();
if (!force && source == this.lastChangeEmitted) return;
this.lastChangeEmitted = this.getSource();
this.lastChangeEmitted = source;
this.eventHub.emit('editorChange', this.id, this.lastChangeEmitted);
};

85
static/embed.html Normal file
View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Compiler Explorer</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="explorer.css" rel="stylesheet">
<script data-main="main" src="ext/requirejs/require.js"></script>
</head>
<body class="embedded">
<a href="/" class="float-link link" target="_blank">
Compiler Explorer &dash; <span class="language-name"></span>
<span class="glyphicon glyphicon-new-window"></span><br/>
</a>
<div id="root"></div>
<div class="gl_keep template">
<div id="codeEditor">
<div class="top-bar btn-toolbar hidden">
<div class="btn-group btn-group-sm options" role="group">
<button title="Colourise lines so one can see how the source maps to the output"
class="btn btn-default btn-sm active" data-bind="colouriseAsm">
<span class="glyphicon glyphicon-adjust"></span>
</button>
<button title="Run the compilers automatically as you type"
class="btn btn-default btn-sm active" data-bind="compileOnChange">
<span class="glyphicon glyphicon-play-circle"></span>
</button>
</div>
</div>
<textarea>// Type your code here, or load an example.</textarea>
</div>
<div id="compiler">
<div class="top-bar">
<table>
<tr>
<td><select class="compiler-picker" placeholder="Select a compiler..."></select></td>
<td><input class="options form-control" type="text" placeholder="compiler options..."
size="256"></td>
</tr>
</table>
<div class="btn-group btn-group-sm filters hidden" data-toggle="buttons">
<button class="btn btn-sm" title="Compile to binary and disassemble the output"
data-bind="binary">
<span>11010</span>
</button>
<button class="btn btn-sm active nonbinary" title="Filter unused labels from the output"
data-bind="labels">
<span>.LX0:</span>
</button>
<button class="btn btn-sm active nonbinary" title="Filter all assembler directives from the output"
data-bind="directives">
<span>.text</span>
</button>
<button class="btn btn-sm active nonbinary"
title="Remove all lines which are only comments from the output"
data-bind="commentOnly">
<span>//</span>
</button>
<button class="btn btn-sm active" title="Output disassembly in Intel syntax"
data-bind="intel">
<span>Intel</span>
</button>
</div>
</div>
<textarea>[Waiting...]</textarea>
<div class="bottom-bar"></div>
</div>
<div id="compiler-output">
<pre class="content"></pre>
</div>
<div class="inline-msg">
<span class="compiler"></span><span class="icon">!!</span><span class="msg"></span>
</div>
</div>
</body>
</html>

View File

@ -5,9 +5,28 @@
@import url("ext/selectize/dist/css/selectize.bootstrap2.css");
.navbar {
border-radius: 0px;
border-radius: 0;
margin-bottom: 5px;
}
.float-link {
z-index: 100;
position: absolute;
bottom: 0.5em;
right: 0.5em;
display: inline-block;
padding: 0.25em;
font-size: x-small;
font-weight: bold;
text-align: center;
background-color: rgba(128,128,128,0.5);
border-radius: 5px;
}
.float-link:hover {
background-color: rgba(128,128,128,0.9);
}
.template {
display: none;
}

View File

@ -19,6 +19,7 @@
<ul class="nav navbar-nav navbar-left">
<li><a href="#" id="get-short-link">Short link</a></li>
<li><a href="#" id="get-full-link">Full link</a></li>
<li><a href="#" id="get-embed-link">Embed</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="if-github-enabled">

View File

@ -65,6 +65,36 @@ define(function (require) {
var shortenURL = require('urlshorten-google');
var Raven = require('raven-js');
function contentFromEmbedded(embeddedUrl) {
var params = url.unrisonify(embeddedUrl);
var filters = _.chain((params.filters || "").split(','))
.map(function (o) {
return [o, true];
})
.object()
.value();
return [
{
type: 'row',
content: [
editor.getComponentWith(1, params.source, filters),
compiler.getComponentWith(1, filters, params.options, params.compiler)
]
}
];
}
function getEmbeddedUrl(layout) {
window.layout = layout;
return window.location.origin + '/e#' + url.risonify({
filters: "",
source: "",
compiler: "",
options: ""
});
}
function start() {
analytics.initialise();
sharing.initialise();
@ -78,28 +108,44 @@ define(function (require) {
settings: {showPopoutIcon: false},
content: [{type: 'row', content: [editor.getComponent(1), compiler.getComponent(1)]}]
};
var root = $("#root");
var config = url.deserialiseState(window.location.hash.substr(1));
if (config) {
// replace anything in the default config with that from the hash
config = _.extend(defaultConfig, config);
}
$(window).bind('hashchange', function () {
// punt on hash events and just reload the page if there's a hash
if (window.location.hash.substr(1))
window.location.reload();
});
if (!config) {
var savedState = null;
try {
savedState = window.localStorage.getItem('gl');
} catch (e) {
// Some browsers in secure modes can throw exceptions here...
var config;
if (!options.embedded) {
config = url.deserialiseState(window.location.hash.substr(1));
if (config) {
// replace anything in the default config with that from the hash
config = _.extend(defaultConfig, config);
}
config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
if (!config) {
var savedState = null;
try {
savedState = window.localStorage.getItem('gl');
} catch (e) {
// Some browsers in secure modes can throw exceptions here...
}
config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
}
} else {
config = _.extend(defaultConfig,
{
settings: {
showMaximiseIcon: false,
showCloseIcon: false,
hasHeaders: false
},
content: contentFromEmbedded(window.location.hash.substr(1))
});
}
var root = $("#root");
var layout;
try {
layout = new GoldenLayout(config, root);
@ -110,11 +156,17 @@ define(function (require) {
new Hub(layout, defaultSrc);
}
layout.on('stateChanged', function () {
var state = JSON.stringify(layout.toConfig());
try {
window.localStorage.setItem('gl', state);
} catch (e) {
// Some browsers in secure modes may throw
var config = layout.toConfig();
// Only preserve state in localStorage in non-embedded mode.
if (!options.embedded) {
var state = JSON.stringify(config);
try {
window.localStorage.setItem('gl', state);
} catch (e) {
// Some browsers in secure modes may throw
}
} else {
$('a.link').attr('href', '/#' + url.serialiseState(config));
}
});
@ -173,6 +225,12 @@ define(function (require) {
initPopover($("#get-short-link"), function (done) {
shortenURL(permalink(), done);
});
initPopover($("#get-embed-link"), function (done) {
done(function () {
return '<iframe width="800px" height="200px" src="' +
getEmbeddedUrl(layout) + '"></iframe>';
});
});
}
$(start);

View File

@ -26,6 +26,7 @@
define(function (require) {
"use strict";
var $ = require('jquery');
var options = $.ajax({type: "GET", url: 'client-options.json', async: false});
return options.responseJSON;
var options = $.ajax({type: "GET", url: 'client-options.json', async: false}).responseJSON;
options.embedded = window.location.pathname === "/embed.html";
return options;
});

View File

@ -117,6 +117,8 @@ define(function (require) {
return {
deserialiseState: deserialiseState,
serialiseState: serialiseState
serialiseState: serialiseState,
unrisonify: unrisonify,
risonify: risonify
};
});

16
test/embedding.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Embedding test</title>
</head>
<body>
<div>
Test; here's some inline Compiler Explorer stuff:
</div>
<iframe width="800px" height="200px"
src="http://lud-ldnmg01:10240/e#source:'int+main()%7B%7D',compiler:g44,options:'-O2',filters:'colouriseAsm,intel,commentOnly,directives,labels,compileOnChange'"></iframe>
</body>
<div>And here's some text after</div>
</html>