From 29ec9a330fffa9cf5ed2e35109661dee2ef8c9ab Mon Sep 17 00:00:00 2001
From: "Mark M. Florida" <mflorida@gmail.com>
Date: Mon, 2 May 2016 20:59:24 -0500
Subject: [PATCH] Many fixes and tweaks: tabs are now grouped, added special
 methods for panel-specific form elements, CSS still needs tweaking.

---
 src/main/webapp/page/admin/content.jsp        |   1 +
 .../data/config/site-admin-sample-new.yaml    |  25 ++-
 src/main/webapp/scripts/xnat/ui/input.js      |   2 +-
 src/main/webapp/scripts/xnat/ui/panel.js      |  16 +-
 src/main/webapp/scripts/xnat/ui/tabs.js       | 164 ++++++++++++++----
 src/main/webapp/scripts/xnat/ui/templates.js  | 117 +++++++++++++
 6 files changed, 275 insertions(+), 50 deletions(-)
 create mode 100644 src/main/webapp/scripts/xnat/ui/templates.js

diff --git a/src/main/webapp/page/admin/content.jsp b/src/main/webapp/page/admin/content.jsp
index fd16510e..ea2c52b7 100755
--- a/src/main/webapp/page/admin/content.jsp
+++ b/src/main/webapp/page/admin/content.jsp
@@ -30,6 +30,7 @@
 
                 </div>
 
+                <script src="${sessionScope.siteRoot}/scripts/xnat/ui/templates.js"></script>
                 <script src="${sessionScope.siteRoot}/page/admin/tabs.js"></script>
 
             </div>
diff --git a/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml b/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
index 14018dc2..20fd7829 100644
--- a/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
+++ b/src/main/webapp/page/admin/data/config/site-admin-sample-new.yaml
@@ -17,6 +17,10 @@ root:
             name: siteSetup
             label: Site Setup
             group: xnatSetup
+            active: true
+            config:
+                data:
+                    foo: bar
             contains: panels # the value for 'contains' can be a custom name for 'contents'
             panels:
                 siteInfo:
@@ -25,7 +29,7 @@ root:
                     label: Site Information
                     contents:
                         siteId:
-                            kind: input.text
+                            kind: panel.input.text
                             name: siteId
                             label: Site ID
                             validation: required id onblur
@@ -43,8 +47,7 @@ root:
                             config:
                                 html: Hello people.
                                 style:
-                                    padding: 20px
-                                    color: red
+                                    fontWeight: bold
         security:
             kind: tab
             name: security
@@ -56,24 +59,18 @@ root:
                     label: General Site Security Settings
                     contents:
                         securityChannel:
-                            kind: element
-                            tag: select
+                            kind: template.panelSelect
                             name: securityChannel
                             label: Security Channel
-                            contains: options
+                            value: https
+#                            contains: options
                             options:
                                 http:
-                                    tag: option
-                                    name: http
+                                    label: http
                                     value: http
                                 https:
-                                    tag: option
-                                    name: https
+                                    label: https
                                     value: https
                             config:
                                 id: security-channel
                                 title: Security Channel
-
-
-
-
diff --git a/src/main/webapp/scripts/xnat/ui/input.js b/src/main/webapp/scripts/xnat/ui/input.js
index 09aaca32..0120e088 100644
--- a/src/main/webapp/scripts/xnat/ui/input.js
+++ b/src/main/webapp/scripts/xnat/ui/input.js
@@ -1,5 +1,5 @@
 /*!
- * Spawn UI elements using the Spawner service
+ * Spawn form input elements
  */
 
 var XNAT = getObject(XNAT);
diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js
index c7383f78..e311ad9b 100644
--- a/src/main/webapp/scripts/xnat/ui/panel.js
+++ b/src/main/webapp/scripts/xnat/ui/panel.js
@@ -45,11 +45,13 @@ var XNAT = getObject(XNAT || {});
                 ['button.btn.btn-sm.btn-link.defaults.pull-left', 'Default Settings'],
                 ['div.clear']
             ],
-            _panel  = spawn('form.xnat-form-panel.panel.panel-default', [
+            _panel = spawn('form.xnat-form-panel.panel.panel-default', [
                 ['div.panel-heading', [
                     ['h3.panel-title', config.title || config.label]
                 ]],
+                
                 _target,
+                
                 ['div.panel-footer', config.footer || _footer]
             ]);
         return {
@@ -62,6 +64,18 @@ var XNAT = getObject(XNAT || {});
         }
     };
 
+    panel.input = {};
+
+    panel.input.text = function(opts){
+        return XNAT.ui.templates.panelInput(opts).spawned;
+    };
+
+    panel.input.email = function(opts){
+        opts.type = 'text';
+        opts.className = [].concat(opts.className||[], 'email').join(' ').trim();
+        return XNAT.ui.templates.panelInput(opts).spawned;
+    };
+
     function footerButton(text, type, disabled, classes){
         var button = {
             type: type || 'button',
diff --git a/src/main/webapp/scripts/xnat/ui/tabs.js b/src/main/webapp/scripts/xnat/ui/tabs.js
index d1114853..86e0d70b 100755
--- a/src/main/webapp/scripts/xnat/ui/tabs.js
+++ b/src/main/webapp/scripts/xnat/ui/tabs.js
@@ -33,22 +33,148 @@ var XNAT = getObject(XNAT || {});
         getObject(XNAT.page || {});
 
 
+    // ==================================================
+    // SET UP ONE TAB GROUP
+    // add a single tab group to the groups
+    tab.group = function(obj, container){
+        var id = toDashed(obj.id || obj.name);
+        if (!id) return; // a tab group MUST have an id
+        var group = spawn('ul.nav.tab-group', {
+            id: id,
+            html:
+                '<li class="label">' +
+                (obj.label || obj.title || obj.text || 'Tab Group') +
+                '</li>'
+        });
+        if (container) {
+            $$(container).append(group);
+        }
+        return group;
+    };
+    // ==================================================
+
+
+    // ==================================================
+    // SET UP TAB GROUPS
+    tab.groups = function(obj, container, empty){
+        var groups = [],
+            $container = $$(container);
+        $.each(obj, function(name, label){
+            groups.push(tab.group({
+                id: toDashed(name),
+                label: label
+            }));
+        });
+        if (empty){
+            $container.empty();
+        }
+        $container.append(groups);
+        return groups;
+    };
+    // ==================================================
+
+
+    // save the id of the active tab
+    XNAT.ui.tab.active = '';
+
+    function activateTab(tab, id){
+
+        var $tab  = $(tab),
+            $tabs = $(tab).closest('div.xnat-tab-container');
+
+        // first deactivate ALL tabs and panes
+        $tabs
+            .find('div.tab-pane')
+            .hide()
+            .removeClass('active');
+
+        $tabs
+            .find('li.tab')
+            .removeClass('active');
+
+        // then activate THIS tab and pane
+
+        $tab.addClass('active');
+
+        $('#'+id)
+            .show()
+            .addClass('active');
+
+        XNAT.ui.tab.active = id;
+
+    }
+
+    // ==================================================
+    // CREATE A SINGLE TAB
+    tab.init = function _tab(obj){
+
+        var _flipper, _pane;
+        
+        obj = getObject(obj);
+        obj.config = getObject(obj.config);
+        obj.config.id = obj.config.id || obj.id || (toDashed(obj.name) + '-content');
+        obj.config.data = extend({ name: obj.name }, obj.config.data);
+        
+        _flipper = spawn('li.tab', {
+            onclick: function(){
+                activateTab(this, obj.config.id)
+            }
+        }, [
+            ['a', {
+                title: obj.label,
+                //href: '#'+obj.config.id,
+                href: '#!',
+                html: obj.label
+            }]
+        ]);
+        _pane = spawn('div.tab-pane', obj.config);
+
+        if (obj.active) {
+            $(_flipper).addClass('active');
+            $(_pane).addClass('active');
+            tab.active = _pane.id;
+        }
+
+        // add all the flippers
+        $('#'+(toDashed(obj.group))+'.tab-group').append(_flipper);
+
+        function render(element){
+            $$(element).append(_pane);
+            return _pane;
+        }
+
+        function get(){
+            return _pane;
+        }
+
+        return {
+            // contents: obj.tabs||obj.contents||obj.content||'',
+            flipper: _flipper,
+            pane: _pane,
+            element: _pane,
+            spawned: _pane,
+            render: render,
+            get: get
+        }
+    };
+    // ==================================================
+
+
     // ==================================================
     // MAIN FUNCTION
     tabs.init = function _tabs(obj){
 
-        console.log('XNAT.ui.tabs.init()');
-        console.log(obj);
-
         var spawned = spawn('div.tabs');
 
+        // set up the group elements
+        tab.groups(obj.groups, '#admin-config-tabs > .xnat-nav-tabs');
+
         function render(element){
             $$(element).append(spawned);
             return spawned;
         }
 
         function get(){
-            console.log('XNAT.ui.tab.init().get()');
             return spawned;
         }
 
@@ -91,36 +217,6 @@ var XNAT = getObject(XNAT || {});
     // ==================================================
 
 
-    // ==================================================
-    // CREATE A SINGLE TAB
-    tab.init = function _tab(obj){
-
-        console.log('XNAT.ui.tab.init()');
-        console.log(obj);
-
-        var spawned = spawn('div.tab');
-
-        function render(element){
-            $$(element).append(spawned);
-            return spawned;
-        }
-
-        function get(){
-            console.log('XNAT.ui.tab.init().get()');
-            return spawned;
-        }
-
-        return {
-            // contents: obj.tabs||obj.contents||obj.content||'',
-            element: spawned,
-            spawned: spawned,
-            render: render,
-            get: get
-        }
-    };
-
-// ==================================================
-
 tabs.tab = tab;
 
 
diff --git a/src/main/webapp/scripts/xnat/ui/templates.js b/src/main/webapp/scripts/xnat/ui/templates.js
new file mode 100644
index 00000000..db56fa39
--- /dev/null
+++ b/src/main/webapp/scripts/xnat/ui/templates.js
@@ -0,0 +1,117 @@
+/*!
+ * Templates for creating UI elements with spawn.js
+ */
+
+var XNAT = getObject(XNAT);
+
+(function(factory){
+    if (typeof define === 'function' && define.amd) {
+        define(factory);
+    }
+    else if (typeof exports === 'object') {
+        module.exports = factory();
+    }
+    else {
+        return factory();
+    }
+}(function(){
+
+    var undefined, template,
+        $ = jQuery || null; // check and localize
+
+    XNAT.ui = getObject(XNAT.ui || {});
+
+    XNAT.ui.template = template = 
+        XNAT.ui.template || {};
+
+
+    // ========================================
+    // generic panel element
+    template.panelElement = function(opts, content){
+        var _templ, _spawn, _html;
+        opts.className = [].concat(opts.className||[], 'panel-element').join(' ').trim();
+        _templ = [
+            'div|data-name='+(opts.name||''),
+            { className: opts.className },
+            content
+        ];
+        _spawn = function(){
+            return spawn.apply(null, _templ);
+        };
+        _html = _spawn().outerHTML;
+        return {
+            template: _templ, // the raw template (Spawn array)
+            spawned: _spawn(), // pre-spawned
+            spawn: _spawn, // call to make a fresh spawn
+            html: _html, // pre-spawned HTML
+            get: _spawn,
+            getHTML: function(){ // call to get fresh HTML
+                return spawn(_templ).outerHTML;
+            }
+        }
+    };
+    // ========================================
+
+
+    // ========================================
+    // input element for form panels
+    template.panelInput = function(opts){
+        return template.panelElement(opts, [
+            ['label.element-label|for='+opts.id, opts.label||opts.title||opts.name],
+            ['div.element-wrapper', [
+                ['input', {
+                    type: opts.type||'text',
+                    id: opts.id,
+                    name: opts.name,
+                    className: opts.className||'',
+                    size: 25,
+                    title: opts.title||opts.name||opts.id
+                }],
+                ['div.description', opts.description||opts.body||opts.html]
+            ]]
+        ]);
+    };
+    // ========================================
+
+
+    // ========================================
+    // select element for form panels
+    template.panelSelect = function(opts){
+        opts = getObject(opts);
+        opts.name = opts.name || opts.id;
+        opts.id = opts.id || toDashed(opts.name);
+        
+        var _select = spawn('select', {
+            id: opts.id,
+            name: opts.name,
+            className: opts.className||'',
+            //size: 25,
+            title: opts.title||opts.name||opts.id||'',
+            value: opts.value||''
+        });
+        // add the options
+        $.each(opts.options||{}, function(name, prop){
+            var _option = spawn('option', {
+                html: prop.label || prop.text,
+                value: prop.value
+            });
+            // select the option if it's the select element's value
+            if (prop.value === opts.value){
+                _option.selected = true;
+            }
+            _select.appendChild(_option)    
+        });
+        return template.panelElement(opts, [
+            ['label.element-label|for='+opts.id, opts.label||opts.title||opts.name],
+            ['div.element-wrapper', [
+                _select,
+                ['div.description', opts.description||opts.body||opts.html]
+            ]]
+        ]);
+    };
+    // ========================================
+
+
+    return XNAT.ui.templates = XNAT.ui.template = template;
+
+}));
-- 
GitLab