diff --git a/platform/src/Button.js b/platform/src/Button.js
new file mode 100644
index 0000000..2d817ee
--- /dev/null
+++ b/platform/src/Button.js
@@ -0,0 +1,80 @@
+
+var buttonTypes= {
+ BUTTON_ACTION: 'BUTTON_ACTION',
+ BUTTON_HELP: 'BUTTON_HELP'
+}
+
+class Button {
+ id;
+ icon;
+ hint;
+ action;
+ type;
+
+ /**
+ * Create a Button
+ * @param {object} buttonConfigObject
+ * @param {string} parentPanel
+ */
+ constructor(buttonConfigObject, parentPanel){
+ this.id= buttonConfigObject.id;
+ this.icon= buttonConfigObject.icon;
+ this.hint= buttonConfigObject.hint;
+ this.action = buttonConfigObject.action;
+
+ // Set button's onclick action
+ if (buttonConfigObject["url"] != undefined) {
+ this.type = buttonTypes.BUTTON_HELP;
+ this.action = "window.open('" + buttonConfigObject.url + "');";
+
+ } else if (buttonConfigObject["actionfunction"] != undefined) {
+ this.type = buttonTypes.BUTTON_ACTION;
+ this.action = "runAction( '" + parentPanel + "', '" + buttonConfigObject.id +"' )";
+
+ } else if (buttonConfigObject["internal"] != undefined) {
+ this.action = buttonConfigObject.internal;
+
+ } else {
+ console.log( "Button '" + buttonConfigObject.id + "' with uknown key.");
+ }
+ }
+
+
+ buttonHtml() {
+ return "";
+ }
+
+ /**
+ * Get a string representation of the button for its display
+ * @returns {String} DOM object with html, cls and onclick properties
+ */
+ getView() {
+ var buttonData={};
+
+ buttonData.html= this.buttonHtml();
+ buttonData.cls= "sys-button";
+ buttonData.onclick= this.action;
+
+ return buttonData;
+ }
+
+
+ /**
+ * Create an array of buttons from an array of configurations
+ * @param {object[]} buttonConfigs
+ * @param {string} parentPanel
+ * @returns {Button[]} the Button objects
+ */
+ static createButtons(buttonConfigs, parentPanel){
+
+ let buttons= [];
+
+ buttonConfigs.forEach((config)=>{
+ buttons.push( new Button(config, parentPanel) );
+ })
+
+ return buttons;
+ }
+}
+
+export {Button}
\ No newline at end of file
diff --git a/platform/src/ConsolePanel.js b/platform/src/ConsolePanel.js
index ddd4c13..13e82e0 100644
--- a/platform/src/ConsolePanel.js
+++ b/platform/src/ConsolePanel.js
@@ -1,5 +1,6 @@
import { Panel } from "./Panel.js";
import { define } from "ace-builds";
+import { Button } from "./Button.js";
class ConsolePanel extends Panel {
@@ -7,19 +8,22 @@ class ConsolePanel extends Panel {
super(id);
this.editor.setReadOnly(true);
this.editor.setValue("", 1);
- this.element.dataset.customButtons = JSON.stringify(this.getButtons());
+
+ let buttons = [];
+ let clearButton = new Button(
+ { id:"clear",
+ hint:"Clear the console",
+ internal: `panels.find((p) => p.id==="${this.id}").editor.setValue('')`,
+ icon: "clear" },
+ this.id
+ );
+ buttons.push(clearButton);
+ this.addButtons(buttons);
+
this.detectHyperlinks(this.editor);
this.setTitleAndIcon("Console", "console");
}
- getButtons() {
- return [{
- html: this.buttonHtml("clear", "Clear the console"),
- cls: "sys-button",
- onclick: "consolePanel.setValue('')"
- }];
- }
-
setOutput(str) {
document.getElementById(this.id + "Editor").style.color = "black";
this.editor.getSession().setUseWrapMode(false);
diff --git a/platform/src/MetamodelPanel.js b/platform/src/MetamodelPanel.js
index 918b6a7..03a1ca4 100644
--- a/platform/src/MetamodelPanel.js
+++ b/platform/src/MetamodelPanel.js
@@ -3,7 +3,6 @@ import { ModelPanel } from './ModelPanel.js';
class MetamodelPanel extends ModelPanel {
constructor(id) {
super(id, true, null);
- this.element.dataset.customButtons = JSON.stringify(this.getButtons());
this.setTitleAndIcon("Metamodel", "emfatic");
}
@@ -11,22 +10,6 @@ class MetamodelPanel extends ModelPanel {
this.editor.getSession().setMode("ace/mode/emfatic");
}
- getButtons() {
- return [{
- html: this.buttonHtml("help", "Emfatic language reference"),
- cls: "sys-button",
- onclick: "window.open('https://www.eclipse.org/epsilon/doc/articles/playground/#emfatic-metamodels-in-the-playground');"
- },{
- html: this.buttonHtml("refresh", "Render the metamodel class diagram"),
- cls: "sys-button",
- onclick: this.id + "Panel.refreshDiagram()"
- },{
- html: this.buttonHtml("diagram", "Show/hide the metamodel class diagram"),
- cls: "sys-button",
- onclick: "toggle('" + this.id + "Diagram', function(){" + this.id + "Panel.refreshDiagram();})"
- }];
- }
-
refreshDiagram() {
this.refreshDiagramImpl(backend.getEmfaticToPlantUMLService(), this.id + "Diagram", "metamodel", null, this.getEditor());
}
diff --git a/platform/src/ModelPanel.js b/platform/src/ModelPanel.js
index 2192025..968ea53 100644
--- a/platform/src/ModelPanel.js
+++ b/platform/src/ModelPanel.js
@@ -13,7 +13,6 @@ class ModelPanel extends Panel {
this.editable = editable;
this.metamodelPanel = metamodelPanel;
this.setupSyntaxHighlighting();
- this.element.dataset.customButtons = JSON.stringify(this.getButtons());
this.setTitleAndIcon("Model", "flexmi");
}
@@ -62,22 +61,6 @@ class ModelPanel extends Panel {
}
}
- getButtons() {
- return this.editable ? [{
- html: this.buttonHtml("help", "Flexmi language reference"),
- cls: "sys-button",
- onclick: "window.open('https://www.eclipse.org/epsilon/doc/flexmi');"
- }, {
- html: this.buttonHtml("refresh", "Render the model object diagram"),
- cls: "sys-button",
- onclick: this.id + "Panel.refreshDiagram()"
- }, {
- html: this.buttonHtml("diagram", "Show/hide the model object diagram"),
- cls: "sys-button",
- onclick: "toggle('" + this.id + "Diagram', function(){" + this.id + "Panel.refreshDiagram();})"
- }] : [];
- }
-
/* TODO: Rename to something more sensible */
refreshDiagramImpl(url, diagramId, diagramName, modelEditor, metamodelEditor) {
var xhr = new XMLHttpRequest();
diff --git a/platform/src/OutputPanel.js b/platform/src/OutputPanel.js
index b4beaee..a6df7c2 100644
--- a/platform/src/OutputPanel.js
+++ b/platform/src/OutputPanel.js
@@ -1,5 +1,7 @@
+
import { ModelPanel } from "./ModelPanel.js";
import { language } from "./Playground.js";
+import { Button } from "./Button.js";
class OutputPanel extends ModelPanel {
@@ -13,20 +15,25 @@ class OutputPanel extends ModelPanel {
this.outputType = outputType;
this.outputLanguage = outputLanguage;
this.language = language;
- this.element.dataset.customButtons = JSON.stringify(this.getButtons());
+
+ let buttons = [];
+ if (this.outputType == "code"){
+ let highlightButton = new Button(
+ { id:"highlight",
+ hint:"Set generated text language",
+ internal: `panels.find((p) => p.id==="${this.id}").editor.setOutputLanguage()`,
+ icon: "highlight" },
+ this.id
+ );
+ buttons.push(highlightButton);
+ }
+ this.addButtons(buttons);
+
this.getEditor().getSession().setMode("ace/mode/" + outputLanguage.toLowerCase());
- //this.getEditor().getSession().setUseWrapMode(false);
}
setupSyntaxHighlighting() {}
- getButtons() {
- return (this.outputType == "code") ? [{
- html: this.buttonHtml("highlight", "Set generated text language"),
- cls: "sys-button",
- onclick: this.id + "Panel.setOutputLanguage()"
- }] : [];
- }
getSelect() {
return Metro.getPlugin("#generatedFiles", 'select');
diff --git a/platform/src/Panel.js b/platform/src/Panel.js
index 00e95a3..af624df 100644
--- a/platform/src/Panel.js
+++ b/platform/src/Panel.js
@@ -97,32 +97,20 @@ class Panel {
return this.type;
}
- buttonHtml(icon, hint) {
- return "";
- }
-
-
/**
* Add the buttons to the page
- * @param {object[]} buttons Objects with attributes: icon, hint, action
- *
- * TODO Support image files for icon
+ * @param {Button[]} buttons - The Button objects to add.
*/
addButtons(buttons){
+ if (buttons.length > 0){
+ var buttonViewData= buttons.map( (btn) => {
+ return btn.getView();
+ });
- var buttonViewData= buttons.map( (btn) => {
- var buttonData={};
-
- buttonData.html= this.buttonHtml(btn.icon, btn.hint);
- buttonData.cls= "sys-button";
- buttonData.onclick= btn.action;
+ buttonViewData.reverse(); // So they are displayed in the order they are defined
- return buttonData;
- });
-
- buttonViewData.reverse(); // So they are displayed in the order they are defined
-
- this.element.dataset.customButtons = JSON.stringify(buttonViewData);
+ this.element.dataset.customButtons = JSON.stringify(buttonViewData);
+ }
}
diff --git a/platform/src/Playground.js b/platform/src/Playground.js
index 6c8e34a..af24dde 100644
--- a/platform/src/Playground.js
+++ b/platform/src/Playground.js
@@ -21,6 +21,7 @@ import { OutputPanel } from "./OutputPanel.js";
import { TestPanel } from './TestPanel.js';
import { BlankPanel } from './BlankPanel .js';
import { XtextEditorPanel } from './XtextEditorPanel.js';
+import { Button } from './Button.js';
import { Preloader } from './Preloader.js';
import { Backend } from './Backend.js';
@@ -262,8 +263,8 @@ function initialisePanels() {
/**
* Create a panel for a given panel config entry
*
- * @param {string} panel
- * @return {Panel}
+ * @param {Object} panel - The activity config panel definition.
+ * @return {Panel} the platform Panel
*/
function createPanelForDefinitionId(panel){
const panelDefinition = panel.ref;
@@ -278,7 +279,6 @@ function initialisePanels() {
newPanel = new ProgramPanel(newPanelId);
// Set from the tool panel definition
- newPanel.setIcon(panelDefinition.icon);
newPanel.setEditorMode(panelDefinition.language);
newPanel.setType(panelDefinition.language);
@@ -301,8 +301,6 @@ function initialisePanels() {
const panelDef = toolsManager.getPanelDefinition(newPanelId);
newPanel = new OutputPanel(newPanelId, panelDefinition.language, outputType, outputLanguage);
-
- newPanel.setIcon(panelDefinition.icon);
newPanel.hideEditor();
newPanel.showDiagram();
@@ -314,7 +312,6 @@ function initialisePanels() {
newPanel = new XtextEditorPanel(newPanelId, editorUrl, panel.extension);
- newPanel.setIcon(panelDefinition.icon);
newPanel.setType(panelDefinition.language);
break;
@@ -327,44 +324,38 @@ function initialisePanels() {
// Add elements common to all panels
newPanel.setTitle(panel.name);
- if (panelDefinition.buttons != null){
-
- var buttons = panel.ref.buttons.map( (btn) => {
- var buttonData = {};
-
- buttonData.icon = btn.icon;
- buttonData.hint = btn.hint;
- buttonData.action = generateButtonOnclickHtml(btn, panel.id);
-
- return buttonData;
+ if(panel.icon != null){
+ newPanel.setIcon(panel.icon);
+ } else {
+ newPanel.setIcon(panelDefinition.icon);
+ }
+
+ if (panel.buttons == null && panelDefinition.buttons != null){
+ // No activity defined buttons
+ newPanel.addButtons( Button.createButtons( panelDefinition.buttons, panel.id));
+
+ } else if (panel.buttons != null && panelDefinition.buttons != null) {
+ // The activity has defined the buttons
+ let resolvedButtonConfigs = panel.buttons.map(btn =>{
+ let resolvedButton;
+
+ if (btn.ref){
+ // button reference so resolve
+ resolvedButton= panelDefinition.buttons.find((pdBtn)=> pdBtn.id===btn.ref);
+ } else {
+ // activity defined button
+ resolvedButton= btn;
+ }
+ return resolvedButton;
});
-
- newPanel.addButtons(buttons);
- }
-
-
+ panel.buttons = resolvedButtonConfigs;
+ newPanel.addButtons( Button.createButtons( resolvedButtonConfigs, panel.id));
+ }
+
return newPanel;
}
-function generateButtonOnclickHtml(button, panelId){
-
- var onclickHtml;
-
- if (button["url"] != undefined) {
- onclickHtml = "window.open('" + button.url + "');";
-
- } else if (button["actionfunction"] != undefined) {
- onclickHtml = "runAction( '" + panelId + "', '" + button.id +"' )";
-
- } else {
- console.log( "Button '" + button.id + "' with uknown key.");
- }
-
- return onclickHtml;
-}
-
-
function copyToClipboard(str) {
var el = document.createElement('textarea');
el.value = str;
@@ -816,7 +807,14 @@ function runAction(source, sourceButton) {
// Get the action
var action = activityManager.getActionForCurrentActivity(source, sourceButton);
- const buttonConfig = action.source.ref.buttons.find( btn => btn.id == sourceButton );
+ let buttonConfig;
+ if(action.source.buttons){
+ //Buttons defined by activity
+ buttonConfig= action.source.buttons.find( btn => btn.id == sourceButton );
+ } else {
+ //Buttons defined by tool
+ buttonConfig= action.source.ref.buttons.find( btn => btn.id == sourceButton );
+ }
const toolActionFunction = toolsManager.getActionFunction( buttonConfig.actionfunction ); // TODO tidy up by resolving tool references
// Create map containing panel values
diff --git a/platform/test/spec/testButtonSpec.js b/platform/test/spec/testButtonSpec.js
new file mode 100644
index 0000000..405e995
--- /dev/null
+++ b/platform/test/spec/testButtonSpec.js
@@ -0,0 +1,51 @@
+
+import {Button} from "../../src/Button.js"
+
+
+describe("Button", () => {
+
+ const btnConfigAf = {
+ id: "1",
+ icon: "ico",
+ actionfunction: "af",
+ hint: "hn"
+ }
+
+ it("can be created", () => {
+ let btn = new Button(btnConfigAf, "pid");
+ expect(btn instanceof Button).toBe(true);
+ })
+
+ it("has an id set by a config object", () => {
+ let btn = new Button(btnConfigAf, "pid");
+ expect(btn.id).toBe("1");
+ })
+
+ it("has an icon set by a config object", () => {
+ let btn = new Button(btnConfigAf, "pid");
+ expect(btn.icon).toBe("ico");
+ })
+
+ it("has an hint set by a config object", () => {
+ let btn = new Button(btnConfigAf, "pid");
+ expect(btn.hint).toBe("hn");
+ })
+
+ it("getView - outputs a DOM representation for customButtons properties", () => {
+ const expectedDomObject = {
+ "html": "",
+ "cls": "sys-button",
+ "onclick": "runAction( 'pid', '1' )"
+ }
+
+ let btn = new Button(btnConfigAf, "pid");
+ expect(btn.getView()).toEqual(expectedDomObject);
+ })
+
+ it("createButtons - creates multiple buttons from an array of button objects", () => {
+ let btns = Button.createButtons([btnConfigAf, btnConfigAf, btnConfigAf, btnConfigAf], "pid");
+
+ expect(btns.length).toBe(4);
+ expect(btns[0]).toEqual(new Button(btnConfigAf, "pid"));
+ })
+})