diff --git a/src/main/webapp/scripts/utils.js b/src/main/webapp/scripts/utils.js index eddd98e0d2d49dec2e1a5ace96b76fedd0b035c4..afd533031af01737400c998076e75ad55afdb9fb 100755 --- a/src/main/webapp/scripts/utils.js +++ b/src/main/webapp/scripts/utils.js @@ -294,8 +294,14 @@ jQuery.fn.tableSort = function(){ if ($table.hasClass('sort-ready')) return this; $table.find('tr').each(function(i){ // add a hidden 'index' cell to each row to reset sorting - $(this).prepend('<td class="index hidden" style="display:none;">' + i + '</td>'); + var $tr = $(this); + // but only if an index column is not already present + if ($tr.find('> th, > td').first().hasClass('index')) return; + $tr.prepend('<td class="index hidden" style="display:none;">' + i + '</td>'); }); + $table.find('th').not('.sort').filter(function(){ + return this.innerHTML.trim() > ''; + }).addClass('sort'); $table.find('th.sort') .append('<i> </i>') // wrapInner('<a href="#" class="nolink" title="click to sort on this column"/>'). @@ -343,9 +349,9 @@ $(function(){ // this enables sorting for ALL columns $('table.sortable, table.sort').not('.sort-ready').each(function(){ var $table = $(this); - $table.find('th').filter(function(){ - return this.innerHTML.trim() > ''; - }).addClass('sort'); + // $table.find('th').filter(function(){ + // return this.innerHTML.trim() > ''; + // }).addClass('sort'); $table.tableSort(); }); // even if it's not available on DOM ready diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js index d08f8cc8454b745093a4a9a305e07b1f5e650a40..922bc1ab12cbfa1087dad5e03612cb3a5e475e9a 100644 --- a/src/main/webapp/scripts/xnat/ui/panel.js +++ b/src/main/webapp/scripts/xnat/ui/panel.js @@ -120,11 +120,13 @@ var XNAT = getObject(XNAT || {}); opts.title = opts.title || opts.label || opts.header; opts.name = opts.name || opts.element.name || opts.id || opts.element.id || randomID('form-', false); + // data-* attributes to add to panel addDataObjects(opts, { - panel: toDashed(opts.name) + panel: toDashed(opts.name), + method: (opts.method || 'POST').toLowerCase() }); - var _target = spawn('div.panel-body', opts.element), + var _target = spawn('div.panel-body'), hideHeader = (isDefined(opts.header) && (opts.header === false || /^-/.test(opts.title))), @@ -141,10 +143,11 @@ var XNAT = getObject(XNAT || {}); ['div.clear'] ], - _formPanel = spawn('form.validate.xnat-form-panel.panel.panel-default', { + // TODO: use opts.element for the panel itself + _formPanel = spawn('form.xnat-form-panel.panel.panel-default', { id: toDashed(opts.id || opts.element.id || opts.name) + '-panel', name: opts.name, - method: opts.method || 'POST', + //method: opts.method || 'POST', action: opts.action ? XNAT.url.rootUrl(opts.action) : '#!', addClass: opts.classes || '', data: opts.data @@ -160,6 +163,12 @@ var XNAT = getObject(XNAT || {}); (hideFooter ? ['div.hidden'] : ['div.panel-footer', opts.footer || _footer]) ]); + + // if there's a 'validation' (or 'validate') property, add 'validate' class + if (opts.validation || opts.validate) { + addClassName(_formPanel, 'validate'); + addDataObjects() + } // cache a jQuery-wrapped element var $formPanel = $(_formPanel); @@ -827,6 +836,89 @@ var XNAT = getObject(XNAT || {}); }; panel.select.multi.init = panel.select.multi; + + + ////////////////////////////////////////////////// + // DATA PANELS - RETRIEVE/DISPLAY DATA + ////////////////////////////////////////////////// + + panel.data = {}; + + panel.data.table = function(opts){ + // initialize the table + opts = cloneObject(opts); + opts.element = opts.element || {}; + addClassName(opts.element, 'data-table xnat-table'); + if (opts.sortable) { + if (opts.sortable === true) { + addClassName(opts.element, 'sortable'); + } + else { + opts.sortable = opts.sortable.split(',').map(function(item){return item.trim()}); + } + } + opts.element.style = { + width: opts.width || '100%' + }; + var dataTable = XNAT.table(opts.element); + // request data for table rows + XNAT.xhr.get({ + url: XNAT.url.rootUrl(opts.load||opts.url), + dataType: opts.dataType || 'json', + success: function(data){ + var props = []; + if (opts.items) { + dataTable.tr(); + forOwn(opts.items, function(name, val){ + props.push(name); + dataTable.th(val); + if (opts.sortable === true || opts.sortable.indexOf(name) !== -1) { + addClassName(dataTable.last.th, 'sort'); + } + }); + } + else { + forOwn(data[0], function(name, val){ + props.push(name); + }); + } + data.forEach(function(item){ + dataTable.tr(); + props.forEach(function(name){ + dataTable.td({ className: name }, item[name]); + }); + }); + if (opts.container) { + $$(opts.container).append(dataTable.table); + } + } + }); + return { + element: dataTable.table, + spawned: dataTable.table, + get: function(){ + return dataTable.table + } + }; + }; + + panel.data.list = function(opts){ + // initialize the table + opts = cloneObject(opts); + opts.element = opts.element || {}; + addClassName(opts.element, 'data-list'); + var dataList = spawn('ul', opts.element); + XNAT.xhr.get({ + url: XNAT.url.rootUrl(opts.load||opts.url), + dataType: opts.dataType || 'json', + success: function(data){ + + } + }); + + + }; + return XNAT.ui.panel = panel; @@ -844,29 +936,6 @@ var XNAT = getObject(XNAT || {}); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - function footerButton(text, type, disabled, classes){ - var button = { - type: type || 'button', - html: text || 'Submit' - }; - button.classes = [classes || '', 'btn btn-sm']; - if (type === 'link') { - button.classes.push('btn-link') - } - else if (/submit|primary/.test(type)) { - button.classes.push('btn-primary') - } - else { - button.classes.push('btn-default') - } - if (disabled) { - button.classes.push('disabled'); - button.disabled = 'disabled' - } - return spawn('button', button); - } - - /** * Panel widget with default 'Submit' and 'Revert' buttons * @param opts @@ -1057,144 +1126,6 @@ var XNAT = getObject(XNAT || {}); } - // return a single panel element - function panelElement(item){ - - var elements = [], - element, tag, - children = '', - before = [], - after = [], - kind = item.kind || '', - obj = {}; - - // input (or other) element - tag = item.tag || item.kind || 'div'; - - if (kind === 'element-group' && item.elements.length) { - element = groupElements(item.elements); - //element = spawn(tag, [radioToggle(item)]); - } - else { - if (item.name) { - obj.name = item.name - } - - if (item.type) { - obj.type = item.type; - } - } - - if (item.id) { - obj.id = item.id; - } - - if (tag === 'input' && !item.type) { - obj.type = 'text'; - } - - // 'checkbox' kind - if (kind === 'checkbox') { - tag = 'input'; - obj.type = 'checkbox'; - } - - // set a default 'size' value for text inputs - if (tag === 'input' && /text|email|url/.test(item.type || obj.type || '')) { - obj.size = '25'; - } - - if (item.label) { - obj.title = item.label; - } - - obj.data = item.data ? extend(true, {}, item.data) : {}; - - if (item.value) { - obj.value = item.value; - obj.data.value = item.value; - } - - if (item.checked) { - obj.checked = true; - obj.data.state = 'checked'; - } - - if (item.info) { - obj.data.info = item.info; - } - - if (item.attr || item.attributes) { - obj.attr = item.attr || item.attributes || {}; - } - - if (/form-table|inputTable|input-table/i.test(kind)) { - element = XNAT.ui.inputTable(item.tableData).get(); - } - else { - obj.innerHTML = [].concat(item.innerHTML || item.html || []).join('\n'); - } - - if (item.before) { - console.log('before'); - before = item.before; - //elements.push(spawn('span.before', item.before)) - } - - if (item.after) { - console.log('after'); - after = item.after; - //elements.push(spawn('span.after', item.after)) - } - - if (kind !== 'hidden') { - // enable the 'Save' and 'Discard Changes' buttons on change - obj.onchange = function(){ - var $panel = $(this).closest('.panel'); - setDisabled([$panel.find('.save'), $panel.find('.revert')], false); - }; - } - - if (kind === 'select' && item.options) { - children = item.options.map(function(option){ - var obj = {}; - obj.value = option.value; - obj.html = option.label; - if (isDefined(item.value)) { - if (item.value === obj.value) { - obj.selected = true; - } - } - return ['option', obj] - }); - } - - element = element || spawn(tag, obj, children); - - if (!elements.length) { - elements = [].concat(before, element, after); - } - // add a description if present - if (item.description) { - elements.push(spawn('div.description', item.description)) - } - - // element setup - return elements; - - } - - function elementLabel(label, id){ - var obj = { - innerHTML: label || '' - }; - if (id) { - obj.attr = { - 'for': id - } - } - return spawn('label.element-label', obj); - } // create elements that are part of an 'element-group' // returns Spawn arguments array @@ -1209,29 +1140,7 @@ var XNAT = getObject(XNAT || {}); return [tag, [].concat(label, panelElement(item))]; }); } - - // create elements from the 'elements' array - // returns Spawn arguments array - function setupElements(items){ - return items.map(function(item){ - var label = ''; - var tag = 'div.panel-element'; - switch (item.kind) { - case 'hidden': - tag = 'div.hidden'; - break; - case 'element-group': - tag += '.element-group'; - break; - } - if (item.label) { - label = elementLabel(item.label, item.id) - } - tag += '|data-name=' + item.name; - return [tag, [label, ['div.element-wrapper', panelElement(item)]]]; - }); - } - + function discardChanges(form){ var $form = $$(form); diff --git a/src/main/webapp/scripts/xnat/ui/table.js b/src/main/webapp/scripts/xnat/ui/table.js index 28a841f02a36c8e490d5eaf170c9472154ec06c8..5a645866d1561676b29942bc306b2e242645dff0 100755 --- a/src/main/webapp/scripts/xnat/ui/table.js +++ b/src/main/webapp/scripts/xnat/ui/table.js @@ -74,7 +74,7 @@ var XNAT = getObject(XNAT); }; this._rows = []; - this.cols = this.columns = []; + this._cols = 0; // how many columns? } @@ -106,59 +106,65 @@ var XNAT = getObject(XNAT); // object to set the properties // and use append or innerHTML // to add the cell content - Table.p.td = function(content){ - var td = element('td', content); + Table.p.td = function(opts, content){ + var td = element('td', opts, content); + this.last.td = td; this.last.tr.appendChild(td); return this; }; - Table.p.th = function(content){ - var th = element('th', content); + Table.p.th = function(opts, content){ + var th = element('th', opts, content); + this.last.th = th; this.last.tr.appendChild(th); return this; }; Table.p.tr = function(opts, data){ + var _this = this; var tr = element('tr', opts); //data = data || this.data || null; if (data) { + this.last.tr = tr; [].concat(data).forEach(function(item){ - tr.appendChild(element('td', item)) + _this.td(item); }); } // only add <tr> elements to <table>, <thead>, <tbody>, and <tfoot> - if (/(table|thead|tbody|tfoot)/.test(this.last.parent.tagName.toLowerCase())) { + if (/(table|thead|tbody|tfoot)/i.test(this.last.parent.tagName)) { this.last.parent.appendChild(tr); } this.last.tr = tr; //this.setLast(tr); + // nullify last <th> and <td> elements since this is a new row + this.last.th = this.last.td = null; return this; }; // create a row with <tr> and <td> elements // in the <tbody> Table.p.row = function(data, opts){ - var tr = element('tr', opts); + // var tr = element('tr', opts); data = data || []; - [].concat(data).forEach(function(item){ - tr.appendChild(element('td', item)); - }); - (this.last.tbody || this.table).appendChild(tr); + this.tr(opts, data); + // (this.last.tbody || this.table).appendChild(tr); + // nullify last <th> and <td> elements since this is a new row + // this.last.th = this.last.td = null; return this; }; // create *multiple* <td> elements Table.p.tds = function(items, opts){ - var last_tr = this.last.tr; + var _this = this; + // var last_tr = this.last.tr; [].concat(items).forEach(function(item){ - var td; - if (isPlainObject(item)) { - td = element('td', '', extend(true, item, opts)); + if (stringable(item)) { + _this.td(opts, item); } + // if 'item' isn't stringable, it will be an object else { - td = element('td', item, opts); + _this.td(extend(true, {}, opts, item)); } - last_tr.appendChild(td); }); // don't reset 'last' so we // keep using the parent <tr> @@ -167,9 +173,11 @@ var XNAT = getObject(XNAT); Table.p.rows = function(data, opts){ var _this = this, - rows = []; + rows = [], + cols = data[0].length; // first array length determines how many columns data = data || []; data.forEach(function(row){ + row = row.slice(0, cols); rows.push(_this.tr(opts, row)) }); this._rows = rows; @@ -285,6 +293,7 @@ var XNAT = getObject(XNAT); // set the number of columns based on // the header or first row of data cols = (header) ? header.length : (obj.data[0] || []).length; + this._cols = cols; // add the header if (header) { @@ -344,7 +353,7 @@ var XNAT = getObject(XNAT); tableData = opts; opts = data; } - addClassName(opts, 'data-table'); + addClassName(opts, 'xnat-table data-table'); var newTable = new Table(opts); return newTable.init(tableData); };