From 7839c32f285199be358cf1e3f3a1f436d5d50632 Mon Sep 17 00:00:00 2001
From: "Mark M. Florida" <markflorida@wustl.edu>
Date: Mon, 12 Sep 2016 15:14:30 -0500
Subject: [PATCH] XNAT-4512, XNAT-4400: Dialog for displaying plugin info is
 now only code editor dialog that's disabled; added options for 'noData' and
 'error' messages for 'table.dataTable' widget; added ability to transform
 table cells with an 'apply' property; also added replacement of '__VALUE__'
 string in HTML with the actual value for the cell.

---
 .../xnat/spawner/site-admin-elements.yaml     | 13 ++++-
 src/main/webapp/scripts/globals.js            |  8 ++-
 src/main/webapp/scripts/xnat/ui/table.js      | 55 ++++++++++++++++---
 3 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
index 580477dd..7e806a67 100644
--- a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
+++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
@@ -789,7 +789,15 @@ pluginTable:
         dataModelBeans:
             label: Contents
             cells:
-                html: <a href="#!" class="view-plugin-info link">View Plugin Info</a>
+                apply: JSON.stringify  # function that accepts value as sole argument
+                html: >
+                    <a href="#!" class="view-plugin-info link">View Plugin Info</a>
+                    <div class="hidden plugin-json-string">__VALUE__</div>
+    messages:
+        noData: >
+            There are no plugins installed in this XNAT. Try searching for plugins on XNAT Marketplace.
+        error: >
+            An error occurred retrieving information for installed plugins.
 
 pluginTableScript:
     tag: script
@@ -806,12 +814,13 @@ pluginTableScript:
                     language: 'json'
                 }).openEditor({
                     title: 'Plugin Info',
+                    classes: 'plugin-json',
                     footerContent: '(read-only)',
                     buttons: { close: { label: 'Close' } }
                 });
             });
         });
-        $body.on('focus', 'textarea.ace_text-input', function(){
+        $body.on('focus', '.plugin-json textarea.ace_text-input', function(){
             this.disabled = true;
         });
 
diff --git a/src/main/webapp/scripts/globals.js b/src/main/webapp/scripts/globals.js
index e909ea26..86e852b6 100644
--- a/src/main/webapp/scripts/globals.js
+++ b/src/main/webapp/scripts/globals.js
@@ -156,6 +156,12 @@ function isEmptyArray( arr ){
     return isArray(arr) && arr.length === 0;
 }
 function isEmpty( x, args ){
+    if (typeof x === 'boolean') {
+        return false;
+    }
+    if (isNumeric(x)) {
+        return false;
+    }
     if (isString(x)){
         return x === '';
     }
@@ -163,7 +169,7 @@ function isEmpty( x, args ){
         return isEmptyObject(x);
     }
     if (isArray(x)){
-        return isEmptyArray(x);
+        return !x.length;
     }
     // does a function return an 'empty' value?
     if (isFunction(x)){
diff --git a/src/main/webapp/scripts/xnat/ui/table.js b/src/main/webapp/scripts/xnat/ui/table.js
index e5033996..711a971a 100755
--- a/src/main/webapp/scripts/xnat/ui/table.js
+++ b/src/main/webapp/scripts/xnat/ui/table.js
@@ -367,6 +367,7 @@ var XNAT = getObject(XNAT);
         }
 
         opts.element = extend(true, {
+            id: opts.id || randomID('t', false),
             style: {
                 width: opts.width || '100%'
             }
@@ -375,6 +376,10 @@ var XNAT = getObject(XNAT);
         // initialize the table
         var newTable = new Table(opts.element);
 
+        // create a div to hold the table
+        // or message (if no data or error)
+        var tableContainer = spawn('div.data-table-container', [newTable.table]);
+
         function createTable(rows){
             var props = [], objRows = [];
             // convert object list to array list
@@ -422,13 +427,18 @@ var XNAT = getObject(XNAT);
                 newTable.tr();
                 props.forEach(function(name){
                     var cellObj = { className: name };
-                    var itemObj = item[name];
+                    var itemVal = item[name];
                     if (opts.items && opts.items[name].cells) {
                         extend(true, cellObj, opts.items[name].cells);
                     }
                     else {
-                        cellObj.html = itemObj;
+                        cellObj.html = itemVal;
+                    }
+                    if (cellObj.apply) {
+                        itemVal = eval(cellObj.apply).apply(item, itemVal);
                     }
+                    // special __VALUE__ string gets replaced
+                    cellObj.html = cellObj.html.replace(/__VALUE__/, itemVal);
                     newTable.td(cellObj);
                     if (opts.items[name] === '~') {
                         addClassName(newTable.last.td, 'hidden');
@@ -438,6 +448,26 @@ var XNAT = getObject(XNAT);
             });
         }
 
+
+        function showMessage(){
+            tableContainer.innerHTML = '';
+            return {
+                noData: function(msg){
+                    tableContainer.innerHTML = '' +
+                        '<div class="no-data">' +
+                        (msg || 'Data not available.') +
+                        '</div>';
+                },
+                error: function(msg, error){
+                    tableContainer.innerHTML = '' +
+                        '<div class="error">' +
+                        (msg || '') +
+                        (error ? '<br><br>' + error : '') +
+                        '</div>';
+                }
+            };
+        }
+
         // if 'tableData' is a string, use as the url
         if (typeof tableData == 'string') {
             opts.url = tableData;
@@ -457,7 +487,18 @@ var XNAT = getObject(XNAT);
                         // handle data returned in ResultSet.Result array
                         json = (json.ResultSet && json.ResultSet.Result) ? json.ResultSet.Result : json;
                     }
-                    createTable(json);
+                    // make sure there's data before rendering the table
+                    if (isEmpty(json)) {
+                        showMessage().noData(opts.messages ? opts.messages.noData || opts.messages.empty : '')
+                    }
+                    else {
+                        createTable(json);
+                    }
+                },
+                error: function(obj, status, message){
+                    var _msg = opts.messages ? opts.messages.error : '';
+                    var _err = 'Error: ' + message;
+                    showMessage().error(_msg);
                 }
             });
         }
@@ -467,16 +508,16 @@ var XNAT = getObject(XNAT);
         }
 
         if (opts.container) {
-            $$(opts.container).append(newTable.table);
+            $$(opts.container).append(tableContainer);
         }
 
         // add properties for Spawner compatibility
-        newTable.element = newTable.spawned = newTable.table;
+        newTable.element = newTable.spawned = tableContainer;
         newTable.get = function(){
-            return newTable.table;
+            return tableContainer;
         };
 
-        return newTable;
+        return tableContainer;
 
     };
 
-- 
GitLab