blob: 454c001ad0d9adb8ac4f5886b51f9cad103c1326 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="https://cdn.metroui.org.ua/v4.4.3/css/metro-all.min.css">
<link rel="stylesheet" href="custom.css">
<title>Epsilon Playground</title>
<link rel="shortcut icon" href="../assets/images/favicon.png">
<script>
var programPanelButtons;
var secondModelPanelButtons;
var thirdModelPanelButtons;
var modelPanelButtons = [{
html: buttonHtml("help", "Flexmi language reference"),
cls: "sys-button",
onclick: "window.open('https://www.eclipse.org/epsilon/doc/flexmi');"
},{
html: buttonHtml("refresh", "Render the model object diagram"),
cls: "sys-button",
onclick: "refreshModelDiagram()"
},{
html: buttonHtml("diagram", "Show/hide the model object diagram"),
cls: "sys-button",
onclick: "toggle('modelDiagram', function(){refreshModelDiagram();})"
}];
var metamodelPanelButtons = [{
html: buttonHtml("help", "Emfatic language reference"),
cls: "sys-button",
onclick: "window.open('https://www.eclipse.org/emfatic');"
},{
html: buttonHtml("refresh", "Render the metamodel class diagram"),
cls: "sys-button",
onclick: "refreshMetamodelDiagram()"
},{
html: buttonHtml("diagram", "Show/hide the metamodel class diagram"),
cls: "sys-button",
onclick: "toggle('metamodelDiagram', function(){refreshMetamodelDiagram();})"
}];
var secondMetamodelPanelButtons = [{
html: buttonHtml("help", "Emfatic language reference"),
cls: "sys-button",
onclick: "window.open('https://www.eclipse.org/emfatic');"
},{
html: buttonHtml("refresh", "Render the metamodel class diagram"),
cls: "sys-button",
onclick: "refreshSecondMetamodelDiagram()"
},{
html: buttonHtml("diagram", "Show/hide the metamodel class diagram"),
cls: "sys-button",
onclick: "toggle('secondMetamodelDiagram', function(){refreshSecondMetamodelDiagram();})"
}];
var consolePanelButtons = [{
html: buttonHtml("clear", "Clear the console"),
cls: "sys-button",
onclick: "consoleEditor.setValue('')"
}];
function buttonHtml(icon, hint) {
return "<span class='mif-" + icon + "' data-role='hint' data-hint-text='" + hint + "' data-hint-position='bottom'></span>";
}
</script>
</head>
<body class="h-100" onresize="fit()">
<div id="navview" data-role="navview" style="display:none">
<div class="navview-pane">
<button class="pull-button">
<span class="default-icon-menu"></span>
</button>
<ul class="navview-menu">
<li class="item-header">Epsilon Playground</li>
<li class="item-separator"></li>
<li>
<a href="?eol" id="eolExampleLink">
<span class="icon"><span class="mif-example-16 mif-eol"></span></span>
<span class="caption">Query Project Plan</span>
</a>
</li>
<li>
<a href="?evl">
<span class="icon"><span class="mif-example-16 mif-evl"></span></span>
<span class="caption">Validate Project Plan</span>
</a>
</li>
<li>
<a href="?etl">
<span class="icon"><span class="mif-example-16 mif-etl"></span></span>
<span class="caption">Transform to Deliverables</span>
</a>
</li>
<li>
<a href="?egl">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">Generate Gantt Chart</span>
</a>
</li>
<li>
<a href="?psl2graphviz">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">Generate Effort Graph</span>
</a>
</li>
<li>
<a href="?psl2html">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">Generate Effort Table</span>
</a>
</li>
<li>
<a href="?psl2pie">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">Generate Task Pie Chart</span>
</a>
</li>
<li>
<a href="?epl">
<span class="icon"><span class="mif-example-16 mif-epl"></span></span>
<span class="caption">Pattern Match Project Plan</span>
</a>
</li>
<li>
<a href="?tree2graph">
<span class="icon"><span class="mif-example-16 mif-etl"></span></span>
<span class="caption">Transform Tree to Graph</span>
</a>
</li>
<li>
<a href="?oo2db">
<span class="icon"><span class="mif-example-16 mif-etl"></span></span>
<span class="caption">Transform OO to DB</span>
</a>
</li>
<li>
<a href="?stm2java">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">State Machine to Java</span>
</a>
</li>
<li>
<a href="?stm2graphviz">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">State Machine Graph</span>
</a>
</li>
<li>
<a href="?stmvalidate">
<span class="icon"><span class="mif-example-16 mif-evl"></span></span>
<span class="caption">Validate State Machine</span>
</a>
</li>
<li>
<a href="?filegrams">
<span class="icon"><span class="mif-example-16 mif-egl"></span></span>
<span class="caption">Filegrams</span>
</a>
</li>
<li class="item-separator"></li>
<li>
<a href="#" onclick="copyShortenedLink(event)" id="exampleLink">
<span class="icon"><span class="mif-example-16 mif-link"></span></span>
<span class="caption">Share</span>
</a>
<a href="#" onclick="about(event)">
<span class="icon"><span class="mif-example-16 mif-info"></span></span>
<span class="caption">About</span>
</a>
</li>
</ul>
</div>
<div class="navview-content">
<div id="splitter" data-role="splitter" class="h-100" style="min-height:800px">
<div data-role="splitter" data-split-mode="vertical">
<div id="programPanel" data-role="panel" data-title-caption="Program (EOL)" data-title-icon="<span class='mif-apps'></span>" data-custom-buttons="">
<div class="editor" id="programEditor"></div>
</div>
<div data-role="panel" data-title-caption="Console" data-title-icon="<span class='mif-16 mif-console'></span>" data-custom-buttons="consolePanelButtons">
<div class="editor" id="console"></div>
</div>
</div>
<div data-role="splitter" data-split-mode="vertical">
<div id="modelPanel" data-role="panel" data-title-caption="Model" data-title-icon="<span class='mif-16 mif-flexmi'></span>" data-custom-buttons="modelPanelButtons" class="modelPanel">
<div data-role="splitter" class="h-100">
<div id="flexmiEditor" class="editor"></div>
<div id="modelDiagram" class="diagram"></div>
</div>
</div>
<div id="metamodelPanel" data-role="panel" data-title-caption="Metamodel" data-title-icon="<span class='mif-16 mif-emfatic'></span>" data-custom-buttons="metamodelPanelButtons" class="modelPanel">
<div data-role="splitter" class="h-100">
<div id="emfaticEditor" class="editor"></div>
<div id="metamodelDiagram" class="diagram"></div>
</div>
</div>
</div>
<div data-role="splitter" data-split-mode="vertical" id="secondModelSplitter">
<div id="secondModelPanel" data-role="panel" data-title-caption="Second Model" data-title-icon="<span class='mif-16 mif-flexmi'></span>" data-custom-buttons="secondModelPanelButtons" class="modelPanel">
<div data-role="splitter" class="h-100">
<div id="secondFlexmiEditor" class="editor"></div>
<div id="secondModelDiagram" class="diagram"></div>
</div>
</div>
<div id="secondMetamodelPanel" data-role="panel" data-title-caption="Second Metamodel" data-title-icon="<span class='mif-16 mif-emfatic'></span>" data-custom-buttons="secondMetamodelPanelButtons" class="modelPanel">
<div data-role="splitter" class="h-100">
<div id="secondEmfaticEditor" class="editor"></div>
<div id="secondMetamodelDiagram" class="diagram"></div>
</div>
</div>
</div>
<div data-role="splitter" data-split-mode="vertical" id="thirdModelSplitter">
<div id="thirdModelPanel" data-role="panel" data-title-caption="Model" data-title-icon="<span class='mif-16 mif-flexmi'></span>" data-custom-buttons="thirdModelPanelButtons" class="modelPanel">
<div class="diagram" id="thirdModelDiagram"></div>
<div id="outputEditor" class="editor" style="display:none"></div>
</div>
</div>
</div>
</div>
<div id="about-info-box" class="info-box" data-role="infobox" data-width="80%" style="overflow-y: auto;">
<span class="button square closer"></span>
<div class="info-box-content">
<h3>About the Epsilon Playground</h3>
<p>The Epsilon Playground is a web application for fiddling with metamodelling, modelling and automated model management using <a href="https://eclipse.org/emfatic">Emfatic</a>, <a href="https://eclipse.org/epsilon/doc/flexmi">Flexmi</a> and the languages of the <a href="https://eclipse.org/epsilon">Epsilon</a> platform. Its back-end is implemented using <a href="https://cloud.google.com/functions">Google Cloud Platform Functions</a> and the front-end builds heavily on the <a href="https://metroui.org.ua">Metro 4</a> framework. Diagrams are rendered using the <a href="https://github.com/magjac/d3-graphviz">d3-grapvhiz</a> Javascript library.</p>
<h4>Saving and sharing your work</h4>
<p>
To save or share your work, please click the "Share" button. This will create a short link that you can copy to your clipboard. Please note that the contents of your editors <b>will be stored in the back-end of the Epsilon Playground</b> so that they can be retrieved when you visit that link again later.
</p>
<h4>Fair usage policy</h4>
<p>
The cost of running Epsilon Playground is proportional to the number of requests made to its Google Cloud Platform back-end (i.e. execution of programs and rendering of diagrams). With fair usage we can comfortably afford this cost and keep the Playground operational, but in case of excessive use we may have to take it down with no notice. To keep costs down, server-side operations that take more than 60 seconds to complete are automatically terminated. For extensive use, large models, or complex programs, please use the <a href="http://eclipse.org/epsilon/download">development tools / Java libraries</a> provided on the Epsilon website instead.
</p>
<h4>Reporting bugs and requesting help</h4>
<p>
Please submit bug reports in the <a href="https://bugs.eclipse.org/bugs/enter_bug.cgi?product=epsilon">Eclipse Bugzilla</a> and ask for help in <a href="https://eclise.org/forum">Epsilon's forum</a>. You can submit feature requests too but please keep in mind that the Playground is not a replacement for Epsilon's <a href="https://eclipse.org/epsilon/download">Eclipse-based development tools</a>. The Playground has been cursorily tested on recent versions of Firefox and Chrome. It's unlikely that we'll be able to invest too much effort in making it compatible with older/other browsers but any patches you may be able to contribute are always welcome.
</p>
</div>
</div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"></script>
<script src="https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.js"></script>
<script src="https://cdn.metroui.org.ua/v4.4.3/js/metro.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js" type="text/javascript" charset="utf-8"></script>
<script src="eol.js" type="text/javascript"></script>
<script src="etl.js" type="text/javascript"></script>
<script src="evl.js" type="text/javascript"></script>
<script src="epl.js" type="text/javascript"></script>
<script src="egl.js" type="text/javascript"></script>
<script src="emfatic.js" type="text/javascript"></script>
<script>
var language = "eol";
var outputType = "text";
var outputLanguage = "text";
var json;
var languageName;
var secondModelEditable;
var url = window.location + "";
var questionMark = url.indexOf("?");
var editors;
var programEditor;
var flexmiEditor;
var emfaticEditor;
var secondFlexmiEditor;
var secondEmfaticEditor;
var consoleEditor;
var contentHref = document.getElementById("eolExampleLink").href;
var content = "";
if (questionMark > -1) {
content = url.substring(questionMark+1, url.length);
if (content.length == 8 && !content.startsWith("psl") && !content.startsWith("stm")) {
var xhr = new XMLHttpRequest();
var url = "https://europe-west2-epsilon-live-gcp.cloudfunctions.net/short-url";
//var url = "http://localhost:8080";
xhr.open("POST", url, false);
xhr.setRequestHeader("Content-Type", "application/json");
var data = JSON.stringify({"shortened": content});
xhr.send(data);
if (xhr.status === 200) {
var json2 = JSON.parse(xhr.responseText);
content = json2.content;
setup();
}
}
else {
var json2 = fetchExample(content);
content = btoa(JSON.stringify(json2));
setup();
}
}
else {
var json2 = fetchExample("eol");
content = btoa(JSON.stringify(json2));
setup();
}
function fetchExample(name) {
var xhr = new XMLHttpRequest();
var url = "examples/" + name + ".json";
xhr.open("GET", url, false);
xhr.send(data);
if (xhr.status === 200) {
var json2 = JSON.parse(xhr.responseText);
if (json2.program != null) json2.program = fetchFile(json2.program);
if (json2.flexmi != null) json2.flexmi = fetchFile(json2.flexmi);
if (json2.emfatic != null) json2.emfatic = fetchFile(json2.emfatic);
if (json2.secondFlexmi != null) json2.secondFlexmi = fetchFile(json2.secondFlexmi);
if (json2.secondEmfatic != null) json2.secondEmfatic = fetchFile(json2.secondEmfatic);
return json2;
}
}
function fetchFile(name) {
var xhr = new XMLHttpRequest();
var url = "examples/" + name;
xhr.open("GET", url, false);
xhr.send(data);
if (xhr.status === 200) {
return xhr.responseText;
}
}
function setup() {
json = JSON.parse(atob(content));
if (json.eol != null) { json.program = json.eol; language = "eol";}
else {language = json.language};
if (json.outputType != null) {outputType = json.outputType;}
if (json.outputLanguage != null) {outputLanguage = json.outputLanguage;}
languageName = (language == "flock" ? "Flock" : language.toUpperCase());
secondModelEditable = !(language == "etl" || language == "flock");
if (language == "etl") {
document.getElementById("thirdModelSplitter").remove();
}
else if (language == "evl" || language == "epl") {
document.getElementById("secondModelSplitter").remove();
}
else if (language == "eol" || language == "egl") {
document.getElementById("secondModelSplitter").remove();
if (outputType == "text" ) {
document.getElementById("thirdModelSplitter").remove();
}
}
Array.from(document.querySelectorAll('.editor')).forEach(function(e) {
var editor = ace.edit(e);
editor.setTheme("ace/theme/eclipse");
editor.renderer.setShowGutter(false);
editor.setFontSize("1rem");
editor.setOptions({
// fontFamily: "monospace",
fontSize: "11pt",
useSoftTabs: true
});
});
programEditor = ace.edit(document.getElementById('programEditor'));
flexmiEditor = ace.edit(document.getElementById('flexmiEditor'));
emfaticEditor = ace.edit(document.getElementById('emfaticEditor'));
secondFlexmiEditor = ace.edit(document.getElementById('secondFlexmiEditor'));
secondEmfaticEditor = ace.edit(document.getElementById('secondEmfaticEditor'));
outputEditor = ace.edit(document.getElementById('outputEditor'));
consoleEditor = ace.edit(document.getElementById('console'));
editors = [programEditor, flexmiEditor, emfaticEditor, secondFlexmiEditor, secondEmfaticEditor, consoleEditor, outputEditor];
editors.forEach(e => e.setShowPrintMargin(false));
emfaticEditor.getSession().setMode("ace/mode/emfatic");
flexmiEditor.getSession().setMode("ace/mode/xml");
flexmiEditor.getSession().on('change', function() {
updateFlexmiEditorSyntaxHighlighting(flexmiEditor);
});
updateFlexmiEditorSyntaxHighlighting(flexmiEditor);
secondEmfaticEditor.getSession().setMode("ace/mode/emfatic");
secondFlexmiEditor.getSession().setMode("ace/mode/xml");
consoleEditor.setReadOnly(true);
arrangePanels();
programPanelButtons = getProgramPanelButtons();
$('#programPanel')[0].dataset.customButtons = "programPanelButtons";
secondModelPanelButtons = getSecondModelPanelButtons();
if (language == "etl") {
$('#secondModelPanel')[0].dataset.customButtons = "secondModelPanelButtons";
}
thirdModelPanelButtons = getThirdModelPanelButtons();
//if (language == "egl") {
// $('#thirdModelPanel')[0].dataset.customButtons = "thirdModelPanelButtons";
//}
//TODO: Fix "undefined" when fields are empty
programEditor.getSession().setMode("ace/mode/" + language);
setEditorValue(programEditor, json.program);
setEditorValue(flexmiEditor, json.flexmi);
setEditorValue(emfaticEditor, json.emfatic);
setEditorValue(secondFlexmiEditor, json.secondFlexmi);
setEditorValue(secondEmfaticEditor, json.secondEmfatic);
consoleEditor.setValue("",1);
//document.getElementById("secondModelSplitter").style.display = "none";
//document.getElementById("secondMetamodelDiagram").style.display = "none";
//toggle("secondModelPanel", function(){window.alert();});
document.getElementById("navview").style.display = "block";
setInterval(fit, 100);
$(window).keydown(function(event) {
if ((event.metaKey && event.keyCode == 83) || (event.ctrlKey && event.keyCode == 83)) {
runProgram();
event.preventDefault();
}
});
}
function setEditorValue(editor, value) {
editor.setValue((value+""), 1);
}
function updateFlexmiEditorSyntaxHighlighting(editor) {
var val = editor.getSession().getValue();
if ((val.trim()+"").startsWith("<")) {
editor.getSession().setMode("ace/mode/xml");
}
else {
editor.getSession().setMode("ace/mode/yaml");
}
}
function about(event) {
event.preventDefault();
$('#about-info-box').data('infobox').open();
}
function setOutputLanguage() {
Metro.dialog.create({
title: "Set Generated Text Language",
content: "<p>You can set the language of the generated text to <a href='https://github.com/ajaxorg/ace/tree/master/lib/ace/mode'>any language</a> supported by the <a href='https://ace.c9.io/'>ACE editor</a>. </p><br><input type='text' id='language' data-role='input' value='" + outputLanguage + "'>",
actions: [
{
caption: "OK",
cls: "js-dialog-close success",
onclick: function(){
outputLanguage = document.getElementById("language").value;
setOutputEditorLanguage();
}
},
{
caption: "Cancel",
cls: "js-dialog-close"
}
]
});
/*
var selectedLanguage = prompt("Syntax higlhigthing language (any language supported by the ACE editor)", outputLanguage);
if (selectedLanguage != null) {
outputLanguage = selectedLanguage;
setOutputEditorLanguage();
}*/
}
function setOutputEditorLanguage() {
outputEditor.getSession().setMode("ace/mode/" + outputLanguage.toLowerCase());
}
function copyShortenedLink(event) {
event.preventDefault();
var content = btoa(editorsToJson());
var xhr = new XMLHttpRequest();
var url = "https://europe-west2-epsilon-live-gcp.cloudfunctions.net/short-url";
//var url = "http://localhost:8080";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
if (questionMark > 0) {
var baseUrl = (window.location+"").substring(0, questionMark);
}
else {
baseUrl = window.location;
}
Metro.notify.killAll();
Metro.dialog.create({
title: "Share link",
content: "<p>The link below contains a snapshot of the contents of all the editors in the playground. Anyone who visits this link should be able to view and run your example.</p><br/> <input style='width:100%' value='" + baseUrl + "?" + json.shortened + "'>",
closeButton: true,
actions: [
{
caption: "Copy to clipboard",
cls: "js-dialog-close success",
onclick: function(){
copyToClipboard(baseUrl + "?" + json.shortened);
}
}]
});
}
Metro.notify.killAll();
}
};
var data = JSON.stringify({"content": content});
xhr.send(data);
longNotification("Generating short link");
return false;
}
function getProgramPanelButtons() {
return [{
html: buttonHtml("help", languageName + " language reference"),
cls: "sys-button",
onclick: "window.open('https://www.eclipse.org/epsilon/doc/'+language);"
},{
html: buttonHtml("run", "Run the program (Ctrl/Cmd+S)"),
cls: "sys-button",
onclick: "runProgram()"
}];
}
function getThirdModelPanelButtons() {
return (outputType == "code") ? [{
html: buttonHtml("highlight", "Set generated text language"),
cls: "sys-button",
onclick: "setOutputLanguage()"
}] : [];
}
function getSecondModelPanelButtons() {
return secondModelEditable ? [{
html: buttonHtml("help", "Flexmi language reference"),
cls: "sys-button",
onclick: "window.open('https://www.eclipse.org/epsilon/doc/flexmi');"
},{
html: buttonHtml("refresh", "Render the model object diagram"),
cls: "sys-button",
onclick: "refreshSecondModelDiagram()"
},{
html: buttonHtml("diagram", "Show/hide the model object diagram"),
cls: "sys-button",
onclick: "toggle('secondModelDiagram', function(){})"
}] : [];
}
function copyToClipboard(str) {
var el = document.createElement('textarea');
el.value = str;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
}
function arrangePanels() {
console.log("Language: " + language);
if (language == "eol") {
toggle("secondModelSplitter");
toggle("thirdModelSplitter");
setPanelTitle("programPanel", "Program (EOL)");
}
else if (language == "egl") {
if (outputType == "dot") {
toggle("secondModelSplitter");
$("#thirdModelDiagram").show();
setPanelTitle("thirdModelPanel", "Graphviz");
setPanelIcon("thirdModelPanel", "diagram");
}
else if (outputType == "html") {
toggle("secondModelSplitter");
$("#thirdModelDiagram").show();
setPanelTitle("thirdModelPanel", "HTML");
setPanelIcon("thirdModelPanel", "html");
}
else if (outputType == "code") {
toggle("secondModelSplitter");
$("#thirdModelDiagram").hide();
$("#outputEditor").show();
setOutputEditorLanguage();
setPanelTitle("thirdModelPanel", "Generated Text");
setPanelIcon("thirdModelPanel", "editor");
}
else {
toggle("secondModelSplitter");
toggle("thirdModelSplitter");
}
setPanelTitle("programPanel", "Template (EGL)");
}
else if (language == "etl" || language == "flock") {
$("#thirdModelSplitter").hide();
$("#secondModelDiagram").show();
$("#secondFlexmiEditor").hide();
setPanelTitle("programPanel", "Transformation (ETL)");
setPanelTitle("modelPanel", "Source Model");
setPanelTitle("metamodelPanel", "Source Metamodel");
setPanelTitle("secondModelPanel", "Target Model");
setPanelTitle("secondMetamodelPanel", "Target Metamodel");
setPanelIcon("secondModelPanel", "diagram");
}
else if (language == "evl" || language == "epl") {
toggle("secondModelSplitter");
$("#thirdModelDiagram").show();
if (language == "evl") {
setPanelTitle("programPanel", "Constraints (EVL)");
setPanelTitle("thirdModelPanel", "Problems");
setPanelIcon("thirdModelPanel", "problems");
}
else {
setPanelTitle("programPanel", "Patterns (EPL)");
setPanelTitle("thirdModelPanel", "Pattern Matches");
setPanelIcon("thirdModelPanel", "diagram");
}
}
else if (language == "ecl") {
// Hide nothing; we need everything
}
setPanelIcon("programPanel", language);
}
function emptyButtons() {
return [];
}
function setPanelTitle(panelId, title) {
$("#" + panelId)[0].dataset.titleCaption = title;
}
function setPanelIcon(panelId, icon) {
$("#" + panelId)[0].dataset.titleIcon = "<span class='mif-16 mif-" + icon + "'></span>";
}
function editorsToJson() {
return JSON.stringify(
{
"language": language,
"outputType": outputType,
"outputLanguage": outputLanguage,
"program": programEditor.getValue(),
"emfatic": emfaticEditor.getValue(),
"flexmi": flexmiEditor.getValue(),
"secondEmfatic": secondEmfaticEditor.getValue(),
"secondFlexmi": secondFlexmiEditor.getValue()
}
);
}
function modelToJson(modelEditor, metamodelEditor) {
return JSON.stringify(
{
"flexmi": modelEditor.getValue(),
"emfatic": metamodelEditor.getValue()
}
);
}
function fit() {
document.getElementById("splitter").style.minHeight = window.innerHeight + "px";
var editorParentStyle = "flex-basis: calc(100% - 4px);";
var modelEditorParentStyle = editorParentStyle + ";padding:0px";
document.getElementById("programEditor").parentNode.style = editorParentStyle;
document.getElementById("console").parentNode.style = editorParentStyle;
document.getElementById("flexmiEditor").parentNode.parentNode.style = modelEditorParentStyle;
document.getElementById("emfaticEditor").parentNode.parentNode.style = modelEditorParentStyle;
if (document.getElementById("secondFlexmiEditor") != null) {
document.getElementById("secondFlexmiEditor").parentNode.parentNode.style = modelEditorParentStyle;
}
if (document.getElementById("secondEmfaticEditor") != null) {
document.getElementById("secondEmfaticEditor").parentNode.parentNode.style = modelEditorParentStyle;
}
editors.forEach(e => e.resize());
}
function setConsoleOutput(str) {
document.getElementById("console").style.color = "black";
consoleEditor.getSession().setUseWrapMode(false);
consoleEditor.setValue(str, 1);
}
function setConsoleError(str) {
document.getElementById("console").style.color = "#CD352C";
consoleEditor.getSession().setUseWrapMode(true);
consoleEditor.setValue(str, 1);
}
function runProgram() {
var xhr = new XMLHttpRequest();
var url = "https://europe-west2-epsilon-live-gcp.cloudfunctions.net/run-epsilon";
//var url = "http://localhost:8080";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
if (json.hasOwnProperty("error")) {
setConsoleError(json.error);
}
else {
setConsoleOutput(json.output);
if (language == "etl") {
renderDiagram("secondModelDiagram", json.targetModelDiagram, 'dot');
}
else if (language == "evl") {
renderDiagram("thirdModelDiagram", json.validatedModelDiagram, 'dot');
}
else if (language == "epl") {
renderDiagram("thirdModelDiagram", json.patternMatchedModelDiagram, 'dot');
}
else if (language == "egl") {
if (outputType == "dot") {
renderDiagram("thirdModelDiagram", json.generatedText, 'dot');
setConsoleOutput(json.output);
}
else if (outputType == "code") {
outputEditor.getSession().setUseWrapMode(false);
outputEditor.setValue(json.generatedText, 1);
setConsoleOutput(json.output);
}
else if (outputType == "html") {
setConsoleOutput(json.output);
var iframe = document.getElementById("htmlIframe");
if (iframe == null) {
iframe = document.createElement("iframe");
iframe.id = "htmlIframe"
iframe.style.height = "100%";
iframe.style.width = "100%";
document.getElementById("thirdModelDiagram").appendChild(iframe);
}
iframe.srcdoc = json.generatedText;
}
else {
setConsoleOutput(json.output + json.generatedText);
}
}
}
}
Metro.notify.killAll();
}
};
var data = editorsToJson();
xhr.send(data);
longNotification("Executing program");
}
function longNotification(title, cls="light") {
Metro.notify.create(/*"This may take a few seconds to complete.",*/ "<b>" + title + "...</b><br>This may take a few seconds to complete if the back end is not warmed up.", null, {keepOpen: true, cls: cls, width: 300});
}
function refreshModelDiagram() {
refreshDiagram("https://europe-west2-epsilon-live-gcp.cloudfunctions.net/flexmi-to-graphviz",
"modelDiagram", "model", "dot", flexmiEditor, emfaticEditor);
}
function refreshMetamodelDiagram() {
refreshDiagram("https://europe-west2-epsilon-live-gcp.cloudfunctions.net/emfatic-to-graphviz",
"metamodelDiagram", "metamodel", "fdp", flexmiEditor, emfaticEditor);
}
function refreshSecondModelDiagram() {
refreshDiagram("https://europe-west2-epsilon-live-gcp.cloudfunctions.net/flexmi-to-graphviz",
"secondModelDiagram", "model", "dot", secondFlexmiEditor, secondEmfaticEditor);
}
function refreshSecondMetamodelDiagram() {
refreshDiagram("https://europe-west2-epsilon-live-gcp.cloudfunctions.net/emfatic-to-graphviz",
"secondMetamodelDiagram", "metamodel", "fdp", secondFlexmiEditor, secondEmfaticEditor);
}
function toggle(elementId, onEmpty) {
var element = document.getElementById(elementId);
if (element == null) return;
if (getComputedStyle(element).display == "none") {
element.style.display = "block";
if (element.innerHTML.length == 0) {
onEmpty();
}
}
else element.style.display = "none";
}
function refreshDiagram(url, diagramId, diagramName, engine, modelEditor, metamodelEditor) {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
var t = d3.transition().ease(d3.easeLinear);
// FIXME: Make both functions return the Graphviz diagram in a "diagram" field
var jsonField = "modelDiagram";
if (diagramId.endsWith("etamodelDiagram")) jsonField = "metamodelDiagram";
if (json.hasOwnProperty("error")) {
var dot = "digraph G { \n node [ shape=box, style=filled, fillcolor=mistyrose, fontname=Arial ] \n t1[label=<<table border='0' cellborder='0'><tr><td>" + wrap(escapeHtml("The diagram could not be rendered due to the following error. " + json.error)) + "<br align='left'/></td></tr></table>>] \n}";
renderDiagram(diagramId, dot, engine);
}
else {
renderDiagram(diagramId, json[jsonField], engine);
}
Metro.notify.killAll();
}
}
};
var data = modelToJson(modelEditor, metamodelEditor);
xhr.send(data);
longNotification("Rendering " + diagramName + " diagram");
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
}
function wrap(str) {
return str.replace(/(?![^\n]{1,40}$)([^\n]{1,40})\s/g, '$1<br align="left"/>');
}
function renderDiagram(diagramId, graphviz, engine) {
// Commented out transitions because they don't work well with dashed edges in Graphviz
//var t = d3.transition().ease(d3.easeLinear);
d3.select("#" + diagramId).graphviz({fit: true, height: "100%", width:"100%", engine: engine})
.renderDot(graphviz);
}
</script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-184785655-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-184785655-1');
</script>
<script src="https://w.appzi.io/w.js?token=jlv6W"></script>
</body>
</html>