Simplify permission handling in widgets and services

Change-Id: I5050b0dad19f84eaf62e051978f0abc5c6a22800
diff --git a/dev/js/spec/pluginSpec.js b/dev/js/spec/pluginSpec.js
index e2dab8f..2a980ad 100644
--- a/dev/js/spec/pluginSpec.js
+++ b/dev/js/spec/pluginSpec.js
@@ -11,7 +11,7 @@
     it('should add a widget', function () {
       var manager = pluginServerClass.create();
       var panel = panelClass.create();
-      var id = manager.addWidget(panel, 'Example 1', 'about:blank');
+      var id = manager.addWidget(panel, {"name": 'Example 1', "src": 'about:blank'});
       expect(id).toMatch(/^id-/);
 
       var panelE = panel.element();
@@ -39,7 +39,7 @@
       expect(e.getAttribute("id")).toBe("services");
       expect(e.children.length).toBe(0);
 
-      var id = manager.addService('Example 1', 'about:blank');
+      var id = manager.addService({"name":'Example 1', "src":'about:blank'});
       expect(id).toMatch(/^id-/);
 
       expect(e.children.length).toBe(1);
@@ -53,7 +53,7 @@
     it('should close a widget', function () {
       var manager = pluginServerClass.create();
       var panel = panelClass.create();
-      var id = manager.addWidget(panel, 'Example 2', 'about:blank');
+      var id = manager.addWidget(panel, {"name":'Example 2', "src":'about:blank'});
       expect(id).toMatch(/^id-/);
 
       var panelE = panel.element();
@@ -273,7 +273,7 @@
     it('should be initializable', function () {
       expect(function () { widgetClass.create() }).toThrow(new Error("Service not well defined"));
 
-      widget = widgetClass.create("Test", "https://example", 56);
+      widget = widgetClass.create({"name" : "Test", "src":"https://example", "id":56});
       expect(widget).toBeTruthy();
       expect(widget.id).toEqual(56);
       expect(widget.name).toEqual("Test");
@@ -281,9 +281,12 @@
     });
 
     it('should create a view element', function () {
-      var widget = widgetClass.create("Test", "https://example", 56);
-      widget.allow("allow-scripts");
-      widget.allow("allow-forms");
+      var widget = widgetClass.create({
+        "name":"Test",
+        "src":"https://example",
+        "id":56,
+        "permissions":["allow-scripts","allow-forms"]
+      });
       var we = widget.element();
 
       expect(we.tagName).toEqual("DIV");
@@ -295,10 +298,6 @@
       expect(iframe.getAttribute("sandbox")).toEqual("allow-forms allow-scripts");
       expect(iframe.getAttribute("src")).toEqual("https://example");
       expect(iframe.getAttribute("name")).toEqual("56");
-
-
-      widget.allow(["allow-downloads","allow-everything"]);
-      expect(iframe.getAttribute("sandbox")).toEqual("allow-downloads allow-everything allow-forms allow-scripts");
       
       var btn = we.lastChild;
       expect(btn.classList.contains("button-group")).toBeTruthy();
@@ -316,21 +315,9 @@
       expect(btn.lastChild.firstChild.tagName).toEqual("SPAN");
       expect(btn.lastChild.textContent).toEqual("Test");
     })
-
-    it('should have mutable permissions', function () {
-      var widget = widgetClass.create("Test", "https://example", 56);
-      var we = widget.element();
-      var iframe = we.firstChild;
-      expect(iframe.tagName).toEqual("IFRAME");
-      expect(iframe.getAttribute("sandbox")).toEqual("");
-      widget.allow("allow-scripts");
-      widget.allow("allow-forms");
-      expect(iframe.tagName).toEqual("IFRAME");
-      expect(iframe.getAttribute("sandbox")).toEqual("allow-forms allow-scripts");
-    });
     
     it('should be resizable', function () {
-      var widget = widgetClass.create("Test", "https://example", 56);
+      var widget = widgetClass.create({"name":"Test", "src":"https://example", "id":56});
       var iframe = widget.show();
       expect(iframe.style.height).toEqual('0px');
       widget.resize({ height : 9 });
@@ -338,7 +325,7 @@
     });
 
     it('should be minimizable', function () {
-      var widget = widgetClass.create("Test", "https://example", 56);
+      var widget = widgetClass.create({"name":"Test", "src":"https://example", "id":56});
       var we = widget.element();
       expect(we.classList.contains('show')).toBeTruthy();
       widget.minimize();
@@ -350,7 +337,7 @@
     it('should be initializable', function () {
       expect(function () { serviceClass.create() }).toThrow(new Error("Service not well defined"));
 
-      let service = serviceClass.create("Test", "https://example", 56);
+      let service = serviceClass.create({"name":"Test", "src":"https://example", "id":56});
       expect(service).toBeTruthy();
       expect(service.id).toEqual(56);
       expect(service.name).toEqual("Test");
@@ -358,7 +345,7 @@
     });
 
     it('should be loadable', function () {
-      let service = serviceClass.create("Test", "https://example", 56);
+      let service = serviceClass.create({"name":"Test", "src":"https://example", "id":56});
       expect(service).toBeTruthy();
 
       let i = service.load();
@@ -502,7 +489,7 @@
   describe('KorAP.Plugin communications', function () {
     it('should receive messages', function () {
       var manager = pluginServerClass.create();
-      var id = manager.addService('Example 1', 'about:blank');
+      var id = manager.addService({"name":'Example 1', "src":'about:blank'});
       expect(id).toMatch(/^id-/);
       var temp = KorAP.koralQuery;
       KorAP.koralQuery = { "@type" : "koral:test" };
@@ -526,7 +513,7 @@
       KorAP.Pipe = pipeClass.create();
       expect(KorAP.Pipe.toString()).toEqual("");
       
-      var id = manager.addService('Example 2', 'about:blank');
+      var id = manager.addService({"name":'Example 2', "src":'about:blank'});
       expect(id).toMatch(/^id-/);
       manager._receiveMsg({
         "data" : {
@@ -562,7 +549,7 @@
 
     it('should reply to query information requests', function () {
       var manager = pluginServerClass.create();
-      var id = manager.addService('Service', 'about:blank');
+      var id = manager.addService({"name":'Service', "src":'about:blank'});
       expect(id).toMatch(/^id-/);
       var temp = KorAP.vc;
       // Create form for query form information
diff --git a/dev/js/src/plugin/server.js b/dev/js/src/plugin/server.js
index 2422892..4504e56 100644
--- a/dev/js/src/plugin/server.js
+++ b/dev/js/src/plugin/server.js
@@ -149,12 +149,6 @@
             // "this".button is the button
             // "that" is the server object
 
-            // Get the URL of the widget
-            let url = onClick["template"];
-            // that._interpolateURI(onClick["template"], this.match);
-
-            let perm = onClick["permissions"];
-
             // The button has a state and the state is associated to the
             // a intermediate object to toggle the view
             if ('state' in this.button && this.button.state.associates() > 0) {
@@ -184,7 +178,11 @@
             };
 
             // Add the widget to the panel
-            let id = that.addWidget(this, name, url, perm);
+            let id = that.addWidget(this, {
+              "name": name,
+              "src": onClick["template"], // that._interpolateURI(onClick["template"], this.match);
+              "permissions": onClick["permissions"]
+            });
             plugin["widgets"].push(id);
             
             // If a state exists, associate with a mediator object
@@ -240,16 +238,14 @@
           //   Lazy registration (see above!)
           KorAP.Panel[panel].actions.addToggle(title, {'cls':["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);
-
-          let perm = onClick["permissions"];
+          let id = this.addService({
+            "name" : name,
+            // TODO:
+            //   Use the "service" keyword
+            "src" : onClick["template"],
+            "permissions" : onClick["permissions"]
+          });
 
           // TODO:
           //   This is a bit stupid to get the service window
@@ -338,17 +334,16 @@
     /**
      * Add a service in a certain panel and return the id.
      */
-    addService : function (name, src, permissions) {
-      if (!src)
+    addService : function (data) {
+      if (!data["src"])
         return;
 
       let id = this._getServiceID();
 
+      data["id"] = id;
+
       // Create a new service
-      let service = serviceClass.create(name, src, id);
-      if (permissions != undefined) {
-        service.allow(permissions);
-      };     
+      let service = serviceClass.create(data);
       
       services[id] = service;
       limits[id] = maxMessages;
@@ -366,15 +361,15 @@
      * Open a new widget view in a certain panel and return
      * the id.
      */
-    addWidget : function (panel, name, src, permissions) {
+    addWidget : function (panel, data) {
+      // panel, name, src, permissions
 
       let id = this._getServiceID();
 
+      data["id"] = id;
+      
       // Create a new widget
-      var widget = widgetClass.create(name, src, id);
-      if (permissions != undefined) {
-        widget.allow(permissions);
-      };
+      var widget = widgetClass.create(data);
 
       // Store the widget based on the identifier
       services[id] = widget;
diff --git a/dev/js/src/plugin/service.js b/dev/js/src/plugin/service.js
index 4029349..23271e5 100644
--- a/dev/js/src/plugin/service.js
+++ b/dev/js/src/plugin/service.js
@@ -2,18 +2,26 @@
   "use strict";
 
   return {
-    create : function (name, src, id) {
-      return Object.create(this)._init(name, src, id);
+    create : function (data) {
+      return Object.create(this)._init(data);
     },
 
     // Initialize service
-    _init : function (name, src, id) {
-      if (!name || !src || !id)
+    _init : function (data) {
+      if (!data || !data["name"] || !data["src"] || !data["id"])
         throw Error("Service not well defined");
-      this.name = name;
-      this.src = src;
-      this.id = id;
+
+      this.name = data["name"];
+      this.src = data["src"];
+      this.id = data["id"];
       this._perm = new Set();
+
+      let perm = data["permissions"];
+      if (perm && Array.isArray(perm)) {
+        perm.forEach(
+          p => this._perm.add(p)
+        );
+      };
       
       // There is no close method defined yet
       if (!this.close) {
@@ -43,7 +51,7 @@
       e.setAttribute('allowTransparency',"true");
       e.setAttribute('frameborder', 0);
       // Allow forms in Plugins
-      e.setAttribute('sandbox', this._permString());
+      e.setAttribute('sandbox', Array.from(this._perm).sort().join(" "));
       e.style.height = '0px';
       e.setAttribute('name', this.id);
       e.setAttribute('src', this.src);
@@ -52,25 +60,6 @@
       return e;
     },
 
-    allow : function (permission) {
-      if (Array.isArray(permission)) {
-        permission.forEach(
-          p => this._perm.add(p)
-        );
-      }
-      else {
-        this._perm.add(permission);
-      };
-
-      if (this._load) {
-        this._load.setAttribute('sandbox', this._permString());
-      }
-    },
-
-    _permString : function () {
-      return Array.from(this._perm).sort().join(" ");
-    },
-
     /**
      * Send a message to the embedded service.
      */
diff --git a/dev/js/src/plugin/widget.js b/dev/js/src/plugin/widget.js
index a845ebc..e661e6d 100644
--- a/dev/js/src/plugin/widget.js
+++ b/dev/js/src/plugin/widget.js
@@ -16,8 +16,8 @@
     /**
      * Create new widget
      */
-    create : function (name, src, id) {
-      return Object.create(viewClass)._init(['widget']).upgradeTo(serviceClass)._init(name, src, id).upgradeTo(this)._init();
+    create : function (data) {
+      return Object.create(viewClass)._init(['widget']).upgradeTo(serviceClass)._init(data).upgradeTo(this)._init();
     },
 
     // Initialize widget