Support for 'adopted' buttongroups and anchors to prepend to

Change-Id: I2925fbc0a34cdc3e105a43669ab0082b000a4178
diff --git a/Changes b/Changes
index 35169bd..74689e9 100755
--- a/Changes
+++ b/Changes
@@ -15,6 +15,8 @@
           direct childNodes aswell as a specification to test for it (lerepp)
         - Make actions private in panels and views.
         - Move pagination out of resultinfo.
+        - Add support for "adopted" button groups and anchor children
+          to prepend to.
 
 0.42 2021-06-18
         - Added GitHub based CI for perl.
diff --git a/dev/js/spec/buttongroupSpec.js b/dev/js/spec/buttongroupSpec.js
index 3d018e0..80a9e8f 100644
--- a/dev/js/spec/buttongroupSpec.js
+++ b/dev/js/spec/buttongroupSpec.js
@@ -227,5 +227,62 @@
       expect(s.get()).toBeTruthy();
       expect(e.firstChild.firstChild.classList.contains("checked")).toBeTruthy();
     });
+
+    it('should allow adoption', function () {
+
+      const el = document.createElement('div');
+      
+      const group = buttonGroupClass.adopt(el);
+
+      group.add('Meta', {'cls':['meta', 'top']}, function (e) {});
+      group.add('Mate', {'cls':['mate']}, function (e) {});
+
+      var btn = group.element().children[0];
+      expect(btn.tagName).toEqual('SPAN');
+      expect(btn.classList.contains('meta')).toBeTruthy();
+      expect(btn.classList.contains('top')).toBeTruthy();
+      expect(btn.innerText).toEqual('Meta');
+
+      btn = group.element().children[1];
+      expect(btn.tagName).toEqual('SPAN');
+      expect(btn.classList.contains('mate')).toBeTruthy();
+      expect(btn.classList.contains('top')).toBeFalsy();
+      expect(btn.innerText).toEqual('Mate');
+    });
+
+    it('should make anchor element definable', function () {
+
+      const el = document.createElement('div');
+      const c1 = el.appendChild(document.createElement('c1'));
+      const c2 = el.appendChild(document.createElement('c2'));
+      const c3 = el.appendChild(document.createElement('c3'));
+      
+      const group = buttonGroupClass.adopt(el);
+      expect(group.anchor(c3)).toBeTruthy();
+
+      group.add('Meta', {'cls':['meta', 'top']}, function (e) {});
+      group.add('Mate', {'cls':['mate']}, function (e) {});
+
+      let btn = group.element().children[0];
+      expect(btn.tagName).toEqual('C1');
+
+      btn = group.element().children[1];
+      expect(btn.tagName).toEqual('C2');
+      
+      btn = group.element().children[2];
+      expect(btn.tagName).toEqual('SPAN');
+      expect(btn.classList.contains('meta')).toBeTruthy();
+      expect(btn.classList.contains('top')).toBeTruthy();
+      expect(btn.innerText).toEqual('Meta');
+
+      btn = group.element().children[3];
+      expect(btn.tagName).toEqual('SPAN');
+      expect(btn.classList.contains('mate')).toBeTruthy();
+      expect(btn.classList.contains('top')).toBeFalsy();
+      expect(btn.innerText).toEqual('Mate');
+
+      btn = group.element().children[4];
+      expect(btn.tagName).toEqual('C3');
+    });
   });
 });
diff --git a/dev/js/src/buttongroup.js b/dev/js/src/buttongroup.js
index 755ad7f..040637f 100644
--- a/dev/js/src/buttongroup.js
+++ b/dev/js/src/buttongroup.js
@@ -9,7 +9,16 @@
     create : function (classes) {
       return Object.create(this)._init(classes);
     },
-    
+
+    /**
+     * Adopt existing button group element
+     */
+    adopt : function (element) {
+      const obj = Object.create(this);
+      obj._el = element;
+      return obj;
+    },
+
     // Initialize button group
     _init : function (classes) {
       const e = document.createElement('div');
@@ -21,7 +30,6 @@
       this._el = e;
       return this;
     },
-
     
     /**
      * Return main element
@@ -30,6 +38,16 @@
       return this._el;
     },
 
+    /**
+     * Define element following newly added buttons.
+     */
+    anchor : function (anchor) {
+      if (anchor.parentNode == this._el) {
+        this._anchor = anchor;
+        return true;
+      };
+      return false;
+    },
     
     /**
      * Upgrade this object to another object, 
@@ -44,6 +62,14 @@
       return this;
     },
 
+    _insert : function (tag = 'span') {
+      const span = document.createElement(tag);
+      if (this._anchor) {
+        this._el.insertBefore(span, this._anchor);
+        return span;
+      }
+      return this._el.appendChild(span);
+    },
     
     /**
      * Add button in order
@@ -51,8 +77,7 @@
      * Returns the button element
      */
     add : function (title, data, cb) {
-      
-      const b = this._el.addE('span');
+      const b = this._insert('span');
       b.setAttribute('title',title);
 
       if (data !== undefined) {
@@ -112,7 +137,7 @@
      * for use as action plugins.
      */
     addToggle : function (title, data, state) {
-      const b = this._el.addE('span');
+      const b = this._insert('span');
       b.setAttribute('title',title);
 
       if (data != undefined) {