Support descriptions in plugin embeds (fixes #224)

Change-Id: I65f15113c08d464d6eef2af1186e1ebfa7dab225
diff --git a/Changes b/Changes
index b09ef98..f404abd 100644
--- a/Changes
+++ b/Changes
@@ -3,6 +3,8 @@
         - Fix warning on OAuth public clients (diewald)
         - Introduce navi->list helper (diewald)
         - Add border to query panel widgets (fixes #225; diewald)
+        - Add 'desc' support to embedded widgets
+          (fixes #224; diewald)
 
 0.57 2024-10-08
         - Support VCs via URL without queries (diewald)
diff --git a/dev/js/spec/buttongroupSpec.js b/dev/js/spec/buttongroupSpec.js
index d35abfe..29fb4f5 100644
--- a/dev/js/spec/buttongroupSpec.js
+++ b/dev/js/spec/buttongroupSpec.js
@@ -115,10 +115,25 @@
       var btn = group.element().firstChild;
       expect(btn.tagName).toEqual('SPAN');
       expect(btn.getAttribute('data-icon')).toEqual('metaicon');
+      expect(btn.getAttribute('title')).toEqual('Meta');
       expect(btn.classList.contains('meta')).toBeTruthy();
       expect(btn.innerText).toEqual('Meta');
     });
 
+    it('should add description', function () {
+      var group = buttonGroupClass.create();
+      expect(group.element().classList.contains('button-group')).toBeTruthy();
+
+      group.add('Meta', {'cls':['meta'], 'icon': 'metaicon', 'desc': 'MyMeta'}, function (e) {});
+
+      var btn = group.element().firstChild;
+      expect(btn.tagName).toEqual('SPAN');
+      expect(btn.getAttribute('data-icon')).toEqual('metaicon');
+      expect(btn.getAttribute('title')).toEqual('MyMeta');
+      expect(btn.classList.contains('meta')).toBeTruthy();
+      expect(btn.innerText).toEqual('Meta');
+    });
+    
     it('should open lists', function () {
       var group = buttonGroupClass.create();
       expect(group.element().classList.contains('button-group')).toBeTruthy();
@@ -228,6 +243,13 @@
       // Check state
       expect(s.get()).toBeTruthy();
       expect(e.firstChild.firstChild.classList.contains("checked")).toBeTruthy();
+
+
+      group.addToggle('example2',{'cls':["examplecls"], "desc":"Haha"}, s);
+
+      e = group.element();
+
+      expect(e.children[1].getAttribute("title")).toBe("Haha");
     });
 
     it('should allow adoption', function () {
diff --git a/dev/js/spec/pluginSpec.js b/dev/js/spec/pluginSpec.js
index acadeac..6dd31b3 100644
--- a/dev/js/spec/pluginSpec.js
+++ b/dev/js/spec/pluginSpec.js
@@ -253,6 +253,7 @@
         embed : [{
           panel : 'result',
           title : 'Glemm',
+          desc : 'Start Glemm',
           onClick : {
             state : 'check',
             template : 'about:blank',
@@ -265,7 +266,8 @@
       let b = p.actions().element().firstChild;
       expect(b.hasAttribute("data-icon")).toBeFalsy();
       expect(b.hasAttribute("cls")).toBeFalsy();
-      expect(b.getAttribute("title")).toEqual("Glemm");
+      expect(b.lastChild.innerText).toEqual("Glemm");
+      expect(b.getAttribute("title")).toEqual("Start Glemm");
       expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
       expect(b.firstChild.classList.contains('check')).toBeTruthy();
       expect(b.firstChild.classList.contains('checked')).toBeFalsy();
@@ -278,7 +280,7 @@
 
       expect(manager.states().toString()).toEqual("\"check\":true");
       
-      expect(b.getAttribute("title")).toEqual("Glemm");
+      expect(b.getAttribute("title")).toEqual("Start Glemm");
       expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
       expect(b.firstChild.classList.contains('check')).toBeTruthy();
       expect(b.firstChild.classList.contains('checked')).toBeTruthy();
@@ -401,6 +403,7 @@
         embed : [{
           panel : 'result',
           title : 'Add',
+          desc : 'Add something',
           onClick : {
             template : 'about:blank',
             action : 'addWidget',
@@ -410,6 +413,8 @@
       });
 
       let b = p.actions().element().firstChild;
+      expect(b.lastChild.innerText).toEqual("Add");
+      expect(b.getAttribute("title")).toEqual("Add something");
       b.click();
       expect(p.element().querySelectorAll("iframe").length).toEqual(1);
       expect(p.element().querySelector("iframe").getAttribute('sandbox')).toEqual('allow-forms allow-scripts');
diff --git a/dev/js/src/buttongroup.js b/dev/js/src/buttongroup.js
index 31f60c8..c6a772e 100644
--- a/dev/js/src/buttongroup.js
+++ b/dev/js/src/buttongroup.js
@@ -81,7 +81,7 @@
      */
     add : function (title, data, cb) {
       const b = this._insert('span');
-      b.setAttribute('title',title);
+      let desc = title;
 
       if (data !== undefined) {
         if (data['cls'] !== undefined) {
@@ -94,9 +94,14 @@
 
         if (data['state'] !== undefined) {
           b['state'] = data['state'];
-        }
+        };
+
+        if (data['desc'] !== undefined) {
+          desc = data['desc'];
+        };
       };
-     
+
+      b.setAttribute('title', desc);
       b.addE('span').addT(title);
 
       let that = this;
@@ -149,7 +154,7 @@
      */
     addToggle : function (title, data, state) {
       const b = this._insert('span');
-      b.setAttribute('title',title);
+      let desc = title;
 
       if (data != undefined) {
         if (data['cls'] !== undefined) {
@@ -158,8 +163,18 @@
             data['cls']
           );
         };
+
+        if (data['icon'] !== undefined) { 
+          b.setAttribute('data-icon', data['icon']);
+        };
+        
+        if (data['desc'] !== undefined) {
+          desc = data['desc'];
+        };
       };
 
+      b.setAttribute('title',desc);
+      
       // Set check marker
       const check = b.addE('span');
       check.classList.add("check", "button-icon");
diff --git a/dev/js/src/plugin/server.js b/dev/js/src/plugin/server.js
index ecf436c..c99f695 100644
--- a/dev/js/src/plugin/server.js
+++ b/dev/js/src/plugin/server.js
@@ -205,7 +205,10 @@
 
 
           // Button object
-          let obj = {'cls':embed["classes"], 'icon': icon }
+          let obj = {'cls':embed["classes"], 'icon': icon };
+
+          if (embed['desc'] != undefined)
+            obj['desc'] = embed['desc'];
 
           if (onClick["action"] && onClick["action"] == "setWidget") {
 
@@ -231,7 +234,6 @@
           }
         }
 
-        // TODO There is no possibility to add icons to a plugin toggle button right now. 
         else if (onClick["action"] == "toggle") {
 
           // TODO:
@@ -244,9 +246,14 @@
             onClick["default"]
           );
 
+          let obj = {'cls':["title"], 'icon': icon};
+
+          if (embed['desc'] != undefined)
+            obj['desc'] = embed['desc'];          
+          
           // TODO:
           //   Lazy registration (see above!)
-          KorAP.Panel[panel].actions().addToggle(title, {'cls':["title"]}, state);
+          KorAP.Panel[panel].actions().addToggle(title, obj, state);
 
           // Add the service
           let id = this.addService({