Add toggle button to buttongroup

Change-Id: I8b65001ca0e39dc4a04d19ee1e8a90fdb414b35f
diff --git a/dev/demo/panel.html b/dev/demo/panel.html
index 35f78e7..5782365 100644
--- a/dev/demo/panel.html
+++ b/dev/demo/panel.html
@@ -18,21 +18,23 @@
 });
 
 
-require(['buttongroup', 'panel', 'view/result/koralquery'], function (btnClass, panelClass, kqClass) {
+require(['buttongroup', 'panel', 'view/result/koralquery', 'state'], function (btnClass, panelClass, kqClass, stateClass) {
   KorAP.koralQuery = {
     '@type' : "https://beispiel",
     'key' : 'Cool'
   };
 
-  var panel = panelClass.create();
-  var actions = panel.actions;
+  let panel = panelClass.create();
+  let actions = panel.actions;
 
+  // Add simple button
   actions.add('Meta',['meta'], function () {
     console.log(this.button.classList.contains('meta'));
     view = kqClass.create();
     panel.add(view);
   });
 
+  // Add list button
   var list = actions.addList('More', ['list']);
 
   list.readItems([
@@ -40,6 +42,23 @@
     ['very cool', 'veryCool', function (e, action) { console.log('very cool') }]
   ]);
 
+  // Add toggle button
+  let s = stateClass.create(true);
+
+  let bgChange = {
+    setState : function (val) {
+      if (val) {
+        document.body.style.backgroundColor = 'red';
+      } else {
+        document.body.style.backgroundColor = 'transparent';
+      }
+    }
+  };
+
+  s.associate(bgChange);
+
+  actions.addToggle('Background',['bg'], s);
+
   document.getElementById('mainButton').appendChild(panel.element());
 });
 
diff --git a/dev/js/spec/buttongroupSpec.js b/dev/js/spec/buttongroupSpec.js
index a25d15c..9183759 100644
--- a/dev/js/spec/buttongroupSpec.js
+++ b/dev/js/spec/buttongroupSpec.js
@@ -1,4 +1,4 @@
-define(['buttongroup'], function (buttonGroupClass) {
+define(['buttongroup','state'], function (buttonGroupClass, stateClass) {
 
   var FunObj = {
     count : 0,
@@ -109,5 +109,35 @@
     it('should open lists', function () {
       
     });
+
+    it('should support toggle buttons', function () {
+      var group = buttonGroupClass.create();
+
+      let s = stateClass.create();
+
+      expect(s.get()).toBeFalsy();
+      
+      group.addToggle('example',["examplecls"],s);
+
+      let e = group.element();
+
+      expect(e.firstChild.getAttribute("title")).toBe("example");
+      expect(e.firstChild.classList.contains("examplecls")).toBeTruthy();
+
+      expect(e.firstChild.firstChild.classList.contains("check")).toBeTruthy();
+      expect(e.firstChild.firstChild.classList.contains("button-icon")).toBeTruthy();
+      expect(e.firstChild.lastChild.textContent).toBe("example");
+
+      // Check state
+      expect(s.get()).toBeFalsy();
+      expect(e.firstChild.firstChild.classList.contains("checked")).toBeFalsy();
+
+      // Click on the button
+      e.firstChild.click();
+
+      // Check state
+      expect(s.get()).toBeTruthy();
+      expect(e.firstChild.firstChild.classList.contains("checked")).toBeTruthy();
+    });
   });
 });
diff --git a/dev/js/src/buttongroup.js b/dev/js/src/buttongroup.js
index b782754..01e5a1c 100644
--- a/dev/js/src/buttongroup.js
+++ b/dev/js/src/buttongroup.js
@@ -88,7 +88,52 @@
 
       return list;
     },
-    
+
+    /**
+     * Add button that can toggle a state.
+     * The state has to be a state object.
+     */
+    addToggle : function (title, classes, state) {
+      let b = this._element.addE('span');
+      b.setAttribute('title',title);
+      if (classes !== undefined) {
+        b.classList.add.apply(b.classList, classes);
+      };
+
+      // Set check marker
+      let check = b.addE('span');
+      check.classList.add("check", "button-icon");
+      check.addE('span');
+
+      // Associate this object to state
+      // Add setState method to object
+      check.setState = function (value) {
+        if (value) {
+          this.classList.add("checked");
+        } else {
+          this.classList.remove("checked");
+        }
+      };
+      state.associate(check);
+
+      b.addE('span').addT(title);
+      
+      let that = this;
+      b.addEventListener('click', function (e) {
+
+        // Do not bubble
+        e.halt();
+        
+        // Toggle state
+        if (state.get()) {
+          state.set(false)
+        } else {
+          state.set(true);
+        }
+      });
+
+      return b;
+    },
 
     /**
      * Bind an object to all callbacks of the button group.
diff --git a/dev/js/src/init.js b/dev/js/src/init.js
index 0b31e23..982929c 100644
--- a/dev/js/src/init.js
+++ b/dev/js/src/init.js
@@ -30,7 +30,8 @@
   'tour/tours',
   'api',
   'mailToChiffre',
-  'util'
+  'util',
+  'state'
 ], function (matchClass,
              hintClass,
              vcClass,
diff --git a/dev/scss/main/buttongroup.scss b/dev/scss/main/buttongroup.scss
index fd0866d..e0d2cba 100644
--- a/dev/scss/main/buttongroup.scss
+++ b/dev/scss/main/buttongroup.scss
@@ -7,14 +7,16 @@
 .button-group {
   > span {
     cursor: pointer;
-    &.button-icon {
-      font-family: 'FontAwesome';
-      > span {
-        @include blind;
-      }
-    }
   }
 
+
+  span.button-icon {
+    font-family: 'FontAwesome';
+    > span {
+      @include blind;
+    }
+  }
+  
   &.button-panel, &.operators {
     > span {
       box-shadow: $choose-box-shadow;
@@ -44,6 +46,24 @@
       }
     }
   }
+
+  &.button-panel {
+    > span > span.check {
+      font-family: 'FontAwesome';
+      width: 1.2em;
+      display: inline-block;
+      &:not(.checked)::after {
+        content: $fa-check;
+      }
+      &.checked::after {
+        content: $fa-checked;
+      }
+      > span {
+        @include blind;
+      }
+    }
+  }
+
   &.button-view {
     display: block;
     position: absolute;
@@ -101,4 +121,3 @@
   }
 }
 
-