Adopt panel system for plugins

Change-Id: I54f520382fb4a26c05ccb2cf0cd3cb48737933ac
diff --git a/dev/demo/plugin-server.html b/dev/demo/plugin-server.html
index 15a69d2..5065d41 100644
--- a/dev/demo/plugin-server.html
+++ b/dev/demo/plugin-server.html
@@ -14,10 +14,21 @@
     <main>
       <div id="search">
         <ol>
-          <li class="active">
-            <div id="match"></div>
-            <div id="buttons"></div>
-          </li>
+          <li data-corpus-id="WPD"
+	            data-doc-id="FFF"
+	            data-text-id="01460"
+	            data-match-id="p119-120"
+	            data-available-info="base/s=spans corenlp/c=spans corenlp/ne=tokens corenlp/p=tokens corenlp/s=spans glemm/l=tokens mate/l=tokens mate/m=tokens mate/p=tokens opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans xip/c=spans malt/d=rels"
+	            id="WPD-FFF.01460-p119-120"
+	            tabindex="6">
+	          <div class="meta">WPD/III/78432</div>
+            <div class="match-main">
+              <div class="match-wrap">
+	              <div class="snippet startMore endMore"><span class="context-left">Der Fehler unterläuft häufig bei der direkten Übersetzung aus dem Englischen, wenn im originalen Ausdruck die beiden Wortteile verschiedene Wörter sind und sich das Adjektiv wahlweise auf das erste oder zweite Wort bezieht. Ein Beispiel ist multiples Testproblem für multiple </span><span class="match">test</span><span class="context-right"> problem.</span></div>
+	            </div>
+            </div>
+	          <p class="ref"><strong>Fehlbezogenes Adjektiv</strong> by Joni2,Peterlustig,BWBot; published on 2005-03-28 as FFF.01460 (WPD)</p>
+	        </li>
         </ol>
       </div>
     </main>
diff --git a/dev/demo/plugin-serverdemo.js b/dev/demo/plugin-serverdemo.js
index 92c4611..e66dfd5 100644
--- a/dev/demo/plugin-serverdemo.js
+++ b/dev/demo/plugin-serverdemo.js
@@ -5,11 +5,18 @@
   }
 });
 
-define(['app/en','buttongroup', 'plugin/server','lib/domReady','init','hint/foundries/cnx'], function (lang, buttonGroupClass, pluginClass, domReady) {
+define(['app/en','match', 'panel/match', 'plugin/server','lib/domReady','init'], function (lang, matchClass, matchPanelClass, pluginClass, domReady) {
   domReady(function () {
 
+    // Initialize match
+    matchClass.create(
+      document.getElementById('WPD-FFF.01460-p119-120')
+    );
+
+    // Load plugin server
     KorAP.Plugin = pluginClass.create();
 
+    // Register match plugin
     KorAP.Plugin.register({
       'name' : 'Example New',
       'desc' : 'Some content about cats',
@@ -25,18 +32,5 @@
       }]
     });
 
-    
-    var btns = buttonGroupClass.create();
-    document.getElementById('buttons').appendChild(btns.element());
-
-    // Are there plugin buttons defined
-    var matchButtons = KorAP.Plugin.buttonGroup("match");
-    if (matchButtons) {
-
-      // Add all matchbuttons in order
-      for (i in matchButtons) {
-        btns.add.apply(btns, matchButtons[i]);
-      }
-    };  
   });
 });
diff --git a/dev/js/src/init.js b/dev/js/src/init.js
index 54dc713..5d19cbd 100644
--- a/dev/js/src/init.js
+++ b/dev/js/src/init.js
@@ -259,7 +259,7 @@
     // There is more than 0 matches and there is a resultButton
     if (i > 0) {
 
-      if (resultPanel !== null) {
+      if (resultPanel) {
         /**
          * Toggle the alignment (left <=> right)
          */
diff --git a/dev/js/src/match.js b/dev/js/src/match.js
index 66def11..d5b365e 100644
--- a/dev/js/src/match.js
+++ b/dev/js/src/match.js
@@ -185,7 +185,8 @@
       // No reference found
       if (!refLine)
         return;
-      
+
+      // Create panel
       this.panel = matchPanelClass.create(this);
 
       this._element.insertBefore(
diff --git a/dev/js/src/panel/match.js b/dev/js/src/panel/match.js
index 2b220d3..7058a9a 100644
--- a/dev/js/src/panel/match.js
+++ b/dev/js/src/panel/match.js
@@ -78,7 +78,19 @@
           tm.button(this.button);
           tm.focus();
         }
-      )
+      );
+
+      // If plugins are enabled, add all buttons for the match panel
+      if (KorAP.Plugin) {
+        var matchButtons = KorAP.Plugin.buttonGroup("match");
+        if (matchButtons) {
+
+          // Add all matchbuttons in order
+          for (i in matchButtons) {
+            a.add.apply(a, matchButtons[i]);
+          }
+        };
+      };
 
       return this;
     },
diff --git a/dev/js/src/plugin/server.js b/dev/js/src/plugin/server.js
index c8df357..934f6f3 100644
--- a/dev/js/src/plugin/server.js
+++ b/dev/js/src/plugin/server.js
@@ -37,8 +37,10 @@
 
   // TODO:
   //   It may be useful to establish a watcher that pings
-  //   all widgets every second to see if it is still alive.
+  //   all widgets every second to see if it is still alive,
+  //   otherwise kill
   
+  // Load Plugin server
   return {
 
     /**
@@ -99,6 +101,7 @@
         throw new Error("Embedding of plugin is no list");
  
       // Embed all embeddings of the plugin
+      var that = this;
       for (var i in obj["embed"]) {
         var embed = obj["embed"][i];
 
@@ -118,19 +121,20 @@
         // The embedding will open a widget
         if (!onClick["action"] || onClick["action"] == "addWidget") {
 
-          var panel = document.getElementById(panel);
-          var that = this;
           var cb = function (e) {
 
+            // "this" is bind to the panel
+
             // Get the URL of the widget
-            var url = onClick["template"]; // that._interpolateURI(onClick["template"], this.match);
+            var url = onClick["template"];
+            // that._interpolateURI(onClick["template"], this.match);
 
             // Add the widget to the panel
-            var id = that.addWidget(panel, name, url);
+            var id = that.addWidget(this, name, url);
             plugin["widgets"].push(id);
           };
 
-          buttons[pannel].push([title, embed["classes"], cb]);
+          buttons[panel].push([title, embed["classes"], cb]);
         };
       };
     },
@@ -152,9 +156,9 @@
     },
     
     /**
-     * Open a new widget as a child to a certain element
+     * Open a new widget in a certaoin panel
      */
-    addWidget : function (element, name, src) {
+    addWidget : function (panel, name, src) {
 
       // Is it the first widget?
       if (!this._listener) {
@@ -185,12 +189,8 @@
       widgets[id] = widget;
       limits[id] = maxMessages;
 
-      // Open widget in frontend
-      // TODO:
-      //   Instead of an "element" this should probably be a 'panel' object!
-      element.appendChild(
-        widget.element()
-      );
+      // Add widget to panel
+      panel.add(widget);
 
       return id;
     },
@@ -280,5 +280,5 @@
       widgets = {};
       this._removeListener();
     }
-  }
+  };
 });
diff --git a/dev/js/src/plugin/widget.js b/dev/js/src/plugin/widget.js
index 338faa3..17c1f5e 100644
--- a/dev/js/src/plugin/widget.js
+++ b/dev/js/src/plugin/widget.js
@@ -2,25 +2,22 @@
  * The plugin system is based
  * on registered widgets (iframes) from
  * foreign services.
- * The widget component represents a single iframe.
+ * The widget component represents a single iframe and is
+ * implemented as a view object.
  *
  * @author Nils Diewald
  */
 
-define(["util"], function () {
+define(["view","util"], function (viewClass) {
   "use strict";
 
-  // Localization values
-  const loc   = KorAP.Locale;
-  loc.CLOSE     = loc.CLOSE     || 'Close';
-
   return {
 
     /**
      * Create new widget
      */
     create : function (name, src, id) {
-      return Object.create(this)._init(name, src, id);
+      return Object.create(viewClass)._init(['widget']).upgradeTo(this)._init(name, src, id);
     },
 
     // Initialize widget
@@ -32,68 +29,46 @@
     },
 
     /**
-     * The element of the widget
+     * The element of the widget as embedded in the view
      */
-    element : function () {
+    show : function () {
 
-      if (this._element)
-        return this._element;
-
-      var div = document.createElement('div');
-      div.classList.add('widget');
+      if (this._show)
+        return this._show;
 
       // Spawn new iframe
-      var i = div.addE('iframe');
+      var i = document.createElement('iframe');
       i.setAttribute('allowTransparency',"true");
       i.setAttribute('frameborder', 0);
       i.setAttribute('sandbox','allow-scripts');
       i.style.height = '0px';
       i.setAttribute('name', this.id);
       i.setAttribute('src', this.src);
-      this._iframe = i;
 
-      var ul = div.addE('ul');
-      ul.classList.add('action','right');
+      // Per default there should at least be a button
+      // for settings, if the plugin requires settings.
+      // Otherwise a button indicating this is a plugin
+      // is a nice idea as well.
 
-      // Add close button
-      var close = ul.addE('li');
-      close.addE('span').addT(loc.CLOSE);
-      close.classList.add('close');
-      close.setAttribute('title', loc.CLOSE);
+      this.actions.add(
+        this.name, ['button-icon', 'plugin'], function (e) {
 
-      // Add info button on plugin
-      var plugin = ul.addE('li');
-      plugin.addE('span').addT(this.name);
-      plugin.classList.add('plugin');
-      plugin.setAttribute('title', this.name);
-      
-      // Close match
-      close.addEventListener('click', function (e) {
-        e.halt();
-        this.shutdown()
+          // Temporary
+          window.alert("Basic information about this plugin");
       }.bind(this));
       
-      this._element = div;
-
-      return div;
-    },
-
-    // Return iframe of widget
-    iframe : function () {
-      if (this._iframe)
-        return this._iframe;
-      this.element();
-      return this._iframe;
+      this._show = i;
+      return i;
     },
 
     // Resize iframe
     resize : function (data) {
-      this.iframe().style.height = data.height + 'px';
+      this.show().style.height = data.height + 'px';
     },
 
     // Shutdown suspicious iframe
     shutdown : function () {
-      this._element.parentNode.removeChild(this._element);
+      this.element().parentNode.removeChild(this.element());
     }
   }
 });
diff --git a/dev/js/src/util.js b/dev/js/src/util.js
index 27c3d8d..cb60c2a 100644
--- a/dev/js/src/util.js
+++ b/dev/js/src/util.js
@@ -83,9 +83,6 @@
   KorAP.API = KorAP.API || {};
   KorAP.Locale = KorAP.Locale || {};
 
-  // This should load plugin/server
-  KorAP.Plugin = KorAP.Plugin || {};
-
   const loc = KorAP.Locale;
   loc.OR  = loc.OR  || 'or';
   loc.AND = loc.AND || 'and';
diff --git a/dev/scss/main/buttongroup.scss b/dev/scss/main/buttongroup.scss
index 7d0031a..3e9ce00 100644
--- a/dev/scss/main/buttongroup.scss
+++ b/dev/scss/main/buttongroup.scss
@@ -64,14 +64,16 @@
       font-style: normal;
       
       &.download::after {
-	      font-family: 'FontAwesome';
 	      content: $fa-download;
       }
       
       &.close::after {
-	      font-family: 'FontAwesome';
 	      content: $fa-close;
       }
+
+      &.plugin::after {
+	      content: $fa-plugin;        
+      }
     }
   }
 }
@@ -81,7 +83,6 @@
   color: $nearly-white;
 }
 
-
 ul.menu.button-group-list {
   border-top-right-radius: 8px;
   font-size: 10pt;
diff --git a/dev/scss/main/panel.scss b/dev/scss/main/panel.scss
index 40ce48a..44d84a8 100644
--- a/dev/scss/main/panel.scss
+++ b/dev/scss/main/panel.scss
@@ -1,4 +1,3 @@
-@charset "utf-8";
 @import "../util";
 
 div.panel {
diff --git a/dev/scss/main/plugin.scss b/dev/scss/main/plugin.scss
index 6b2b715..d8c26a2 100644
--- a/dev/scss/main/plugin.scss
+++ b/dev/scss/main/plugin.scss
@@ -1,11 +1,10 @@
 @import "../util";
 
-div.widget {
-  margin-right: $right-match-distance;
-
+div.view.widget {
+  padding-right: $right-match-distance;
   > iframe {
-    box-sizing: border-box;
     margin: 0;
+    box-sizing: border-box;
     padding: 0;
     width: 100%;
     overflow-x: auto;