Split service component from widgets and introduce
host->plugin communication
Change-Id: I2377059dfc30c196a5b24d331fe60f0310694ba1
diff --git a/dev/js/src/plugin/server.js b/dev/js/src/plugin/server.js
index 163a315..1c46dbe 100644
--- a/dev/js/src/plugin/server.js
+++ b/dev/js/src/plugin/server.js
@@ -1,6 +1,6 @@
/**
* The plugin system is based
- * on registered widgets (iframes) from
+ * on registered services (iframes) from
* foreign services.
* The server component spawns new iframes and
* listens to them.
@@ -8,15 +8,15 @@
* @author Nils Diewald
*/
-define(["plugin/widget", "util"], function (widgetClass) {
+define(["plugin/widget", 'plugin/service', 'state', "util"], function (widgetClass, serviceClass, stateClass) {
"use strict";
KorAP.Panel = KorAP.Panel || {};
- // Contains all widgets to address with
+ // Contains all servicess to address with
// messages to them
- var widgets = {};
- var plugins = {};
+ var services = {};
+ var plugins = {};
// TODO:
// These should better be panels and every panel
@@ -33,7 +33,7 @@
var buttonsSingle = {
query : [],
result : []
- }
+ }
// This is a counter to limit acceptable incoming messages
// to a certain amount. For every message, this counter will
@@ -85,6 +85,17 @@
* 'action' : 'addWidget',
* 'template' : 'https://localhost:5678/?match={matchid}',
* }
+ * },{
+ * 'title' : 'glemm',
+ * 'panel' : 'query',
+ * 'onClick' : {
+ * 'action' : 'toggle',
+ * 'state' : 'glemm',
+ * 'service' : {
+ * 'id' : 'glemm',
+ * 'template' : 'https://localhost:5678/'
+ * }
+ * }
* }]
* });
*
@@ -103,7 +114,8 @@
name : name,
desc : obj["desc"],
about : obj["about"],
- widgets : []
+ widgets : [],
+ services : []
};
if (typeof obj["embed"] !== 'object')
@@ -111,37 +123,41 @@
// Embed all embeddings of the plugin
var that = this;
- for (var i in obj["embed"]) {
- var embed = obj["embed"][i];
+ for (let i in obj["embed"]) {
+ let embed = obj["embed"][i];
if (typeof embed !== 'object')
throw new Error("Embedding of plugin is no object");
- var panel = embed["panel"];
-
- if (!panel || !(buttons[panel] || buttonsSingle[panel]))
- throw new Error("Panel for plugin is invalid");
- var onClick = embed["onClick"];
-
// Needs to be localized as well
- var title = embed["title"];
+ let title = embed["title"];
+ let panel = embed["panel"];
+ let onClick = embed["onClick"];
+
+
+ if (!panel || !(buttons[panel] || buttonsSingle[panel]))
+ throw new Error("Panel for plugin is invalid");
// The embedding will open a widget
if (!onClick["action"] || onClick["action"] == "addWidget") {
- var cb = function (e) {
+
+ let cb = function (e) {
// "this" is bind to the panel
// Get the URL of the widget
- var url = onClick["template"];
+ let url = onClick["template"];
// that._interpolateURI(onClick["template"], this.match);
// Add the widget to the panel
- var id = that.addWidget(this, name, url);
+ let id = that.addWidget(this, name, url);
plugin["widgets"].push(id);
};
+ // TODO:
+ // Create button class to be stored and loaded in button groups!
+
// Add to dynamic button list (e.g. for matches)
if (buttons[panel]) {
buttons[panel].push([title, embed["classes"], cb]);
@@ -156,11 +172,53 @@
else {
buttonsSingle[panel].push([title, embed["classes"], cb]);
}
+ }
+
+ else if (onClick["action"] == "toggle") {
+
+ // Todo: Initially false
+ let state = stateClass.create(false);
+
+ // TODO:
+ // Lazy registration (see above!)
+ KorAP.Panel[panel].actions.addToggle("Title",["title"], state);
+
+ // Get the URL of the service
+
+ // TODO:
+ // Use the "service" keyword
+ let url = onClick["template"];
+
+ // Add the service
+ let id = this.addService(name, url);
+
+ // TODO:
+ // This is a bit stupid to get the service window
+ let iframe = services[id].load();
+ let win = iframe.contentWindow;
+
+ // Create object to communicate the toggle state
+ // once the iframe is loaded.
+ iframe.onload = function () {
+ let sendToggle = {
+ setState : function (val) {
+ win.postMessage({
+ action: 'state',
+ key : onClick['state'],
+ value : val
+ }, '*'); // TODO: Fix origin
+ }
+ };
+
+ // Associate object with the state
+ state.associate(sendToggle);
+ };
+
+ plugin["services"].push(id);
};
};
},
-
// TODO:
// Interpolate URIs similar to https://tools.ietf.org/html/rfc6570
// but as simple as possible
@@ -191,17 +249,11 @@
buttonsSingle[name] = [];
}
},
-
- /**
- * Open a new widget view in a certain panel and return
- * the id.
- */
- addWidget : function (panel, name, src) {
- if (!src)
- return;
+ // Optionally initialize the service mechanism and get an ID
+ _getServiceID : function () {
- // Is it the first widget?
+ // Is it the first service?
if (!this._listener) {
/*
@@ -210,7 +262,7 @@
this._listener = this._receiveMsg.bind(this);
window.addEventListener("message", this._listener);
- // Every second increase the limits of all registered widgets
+ // Every second increase the limits of all registered services
this._timer = window.setInterval(function () {
for (var i in limits) {
if (limits[i]++ >= maxMessages) {
@@ -220,14 +272,51 @@
}, 1000);
};
- // Create a unique random ID per widget
- var id = 'id-' + this._randomID();
+ // Create a unique random ID per service
+ return 'id-' + this._randomID();
+ },
+
+ /**
+ * Add a service in a certain panel and return the id.
+ */
+ addService : function (name, src) {
+ if (!src)
+ return;
+
+ let id = this._getServiceID();
+
+ // Create a new service
+ let service = serviceClass.create(name, src, id);
+
+ // TODO!
+ // Store the service based on the identifier
+ services[id] = service;
+ limits[id] = maxMessages;
+
+ // widget._mgr = this;
+
+ // Add service to panel
+ this.element().appendChild(
+ service.load()
+ );
+
+ return id;
+ },
+
+
+ /**
+ * Open a new widget view in a certain panel and return
+ * the id.
+ */
+ addWidget : function (panel, name, src) {
+
+ let id = this._getServiceID();
// Create a new widget
var widget = widgetClass.create(name, src, id);
// Store the widget based on the identifier
- widgets[id] = widget;
+ services[id] = widget;
limits[id] = maxMessages;
widget._mgr = this;
@@ -240,14 +329,14 @@
/**
- * Get widget by identifier
+ * Get service by identifier
*/
- widget : function (id) {
- return widgets[id];
+ service : function (id) {
+ return services[id];
},
- // Receive a call from an embedded iframe.
+ // Receive a call from an embedded service.
// The handling needs to be very careful,
// as this can easily become a security nightmare.
_receiveMsg : function (e) {
@@ -268,46 +357,60 @@
if (!id)
return;
- // Get the widget
- var widget = widgets[id];
+ // Get the service
+ let service = services[id];
- // If the addressed widget does not exist - fail
- if (!widget)
+ // If the addressed service does not exist - fail
+ if (!service)
return;
// Check for message limits
if (limits[id]-- < 0) {
- // Kill widget
- KorAP.log(0, 'Suspicious action by widget', widget.src);
+ // Kill service
+ KorAP.log(0, 'Suspicious action by service', service.src);
// TODO:
// Potentially kill the whole plugin!
- // This removes all connections before closing the widget
- this._closeWidget(widget.id);
- widget.close();
+ // This removes all connections before closing the service
+ this._closeService(service.id);
+
+ // if (service.isWidget)
+ service.close();
+
return;
};
// Resize the iframe
- if (d.action === 'resize') {
- widget.resize(d);
- }
+ switch (d.action) {
+ case 'resize':
+ if (service.isWidget)
+ service.resize(d);
+ break;
// Log message from iframe
- else if (d.action === 'log') {
- KorAP.log(d.code, d.msg, widget.src);
+ case 'log':
+ KorAP.log(d.code, d.msg, service.src);
+ break;
};
// TODO:
// Close
},
- // Close the widget
- _closeWidget : function (id) {
+ // Close the service
+ _closeService : function (id) {
delete limits[id];
- delete widgets[id];
+
+ // Close the iframe
+ if (services[id] && services[id]._closeIframe) {
+ services[id]._closeIframe();
+
+ // Remove from list
+ delete services[id];
+ };
+
// Remove listeners in case no widget
// is available any longer
@@ -328,19 +431,39 @@
this._listener = undefined;
},
+ /**
+ * Return the service element.
+ */
+ element : function () {
+ if (!this._element) {
+ this._element = document.createElement('div');
+ this._element.setAttribute("id", "services");
+ }
+ return this._element;
+ },
+
// Destructor, just for testing scenarios
destroy : function () {
limits = {};
- for (let w in widgets) {
- widgets[w].close();
+ for (let s in services) {
+ services[s].close();
};
- widgets = {};
+ services = {};
for (let b in buttons) {
buttons[b] = [];
};
for (let b in buttonsSingle) {
buttonsSingle[b] = [];
};
+
+ if (this._element) {
+ let e = this._element;
+ if (e.parentNode) {
+ e.parentNode.removeChild(e);
+ };
+ this._element = null;
+ };
+
this._removeListener();
}
};