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 old mode 100755 new mode 100644 index 2b5f0b381790ac3461beff36267bfac7bc806d4c..3bdd2557d1d0e24f0918e8a40385c5a18c8474de --- a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml +++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml @@ -24,7 +24,7 @@ siteDescriptionPage: type: text id: siteDescriptionPage name: siteDescriptionPage - size: 50 + size: 30 after: "<p>Specify a velocity template file to display on the login page</p>" siteDescriptionText: @@ -206,7 +206,7 @@ siteInfo: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: ${siteId} @@ -224,7 +224,7 @@ adminInfo: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: ${adminEmail} @@ -236,7 +236,7 @@ generalSecuritySettings: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: securityChannel: @@ -245,7 +245,7 @@ generalSecuritySettings: name: security.channel label: Security Channel options: - any: + any: label: Any value: any http: @@ -270,7 +270,7 @@ userLoginsSessionControls: label: User Logins / Session Controls method: POST action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contentType: json contents: @@ -370,7 +370,7 @@ passwords: method: POST action: /xapi/siteConfig/batch contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: passwordComplexity: @@ -444,7 +444,7 @@ csrf: method: POST action: /xapi/siteConfig/batch contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: enableCsrfToken: @@ -467,7 +467,7 @@ securityServices: action: /xapi/siteConfig/batch method: POST contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: securityServicesFeatureDefault: @@ -490,13 +490,13 @@ securityServices: id: securityServicesRoleRepositoryDefault name: security.services.roleRepository.default label: Role Repository Default - + emailServerSettings: kind: panel.form method: POST action: /xapi/notifications/batchMail contentType: json - load: ?? XNAT.data.notifications + load: XNAT.data.notifications refresh: /xapi/notifications name: emailServerSettings label: Mail Server Settings @@ -561,7 +561,7 @@ notifications: action: /xapi/notifications/batch method: POST contentType: json - load: ?? XNAT.data.notifications + load: XNAT.data.notifications refresh: /xapi/notifications contents: helpContactInfo: @@ -726,7 +726,7 @@ authenticationMethods: method: POST action: /xapi/siteConfig/batch contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: xnatInternal: @@ -751,7 +751,7 @@ genericAuthenticationProvider: method: POST action: /xapi/siteConfig/batch contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: providerDbName: @@ -777,7 +777,7 @@ ldapAuthentication: method: POST action: /xapi/siteConfig/batch contentType: json - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: ldapName: @@ -840,7 +840,7 @@ registrationOptions: label: Registration Options method: POST action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig contentType: json contents: requireEmailVerificationToRegister: @@ -898,7 +898,7 @@ manageDataTypes: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: displayNameForGenericImageSessionSingular: @@ -919,7 +919,7 @@ anonymization: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: enableSitewideAnonymizationScript: @@ -942,7 +942,7 @@ seriesImportFilter: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: enableSitewideSeriesImportFilter: @@ -981,7 +981,7 @@ sessionUploadMethod: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: selectUploadMethod: @@ -991,11 +991,11 @@ sessionUploadMethod: label: "Session Upload Method" # options: # don't know where to populate this from # http: -# label: -# value: +# label: +# value: # https: -# label: -# value: +# label: +# value: showApplet: kind: panel.input.checkbox id: showApplet @@ -1028,13 +1028,72 @@ sessionUploadMethod: label: Session Xml Rebuilder Interval dicomScpReceivers: - kind: panel.form + kind: panel name: dicomScpReceivers + label: Manage DICOM SCP Receivers + footer: false + contents: + message: + tag: div.message.bold + content: > + Caution: Changes to this setting will take effect immediately. + Before disabling the receiver, verify that there are no + transmissions currently in progress. + dicomScpEditorTemplate: + tag: "div#dicom-scp-editor-template.html-template" + contents: + dicomScpEditor: + kind: panel.form + name: dicomScpEditor + id: dicom-scp-editor + header: false + footer: false + method: PUT + action: /xapi/dicomscp + contentType: json + contents: + scpId: + kind: panel.input.text + id: scp-id + name: scpId + label: SCP ID + validation: required + aeTitle: + kind: panel.input.text + name: aeTitle + label: AE Title + validation: required + port: + kind: panel.input.number + name: port + label: Port + validation: required naturalNoZero + fileNamer: + kind: panel.input.text + name: fileNamer + label: File Namer + identifier: + kind: panel.input.text + name: identifier + label: Identifier + enabled: + kind: panel.input.checkbox + name: enabled + dicomScpManager: + tag: "div#dicom-scp-manager" + dicomScpManagerScript: + tag: script + element: + src: /scripts/xnat/admin/dicomScpManager.js + +dicomScpReceiversOld: + kind: panel.form + name: dicomScpReceiversOld label: DICOM SCP Receivers method: POST action: /xapi/dicomscp contentType: json - load: $? /xapi/dicomscp + load: /xapi/dicomscp contents: enableDicomReceiver: kind: panel.input.checkbox @@ -1083,7 +1142,7 @@ dicomScpReceivers: name: receivedFileUser label: "Default DICOM Receiver: User" description: "User account for default DICOM receiver" - + fileSystem: kind: panel.form name: fileSystem @@ -1091,7 +1150,7 @@ fileSystem: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig contents: ${archivePath} ${cachePath} @@ -1110,7 +1169,7 @@ misc: method: POST contentType: json action: /xapi/siteConfig/batch - load: ?? XNAT.data.siteConfig + load: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: scanTypeMapping: @@ -1130,7 +1189,7 @@ misc: element: href: ~/page/admin/spawner/ target: _blank - html: Manage The Spawner + html: Manage Spawner Elements swagger: kind: panel.element description: View the Swagger page. diff --git a/src/main/webapp/page/admin/style.css b/src/main/webapp/page/admin/style.css index 946b2f1f34bd6c48b04502031733291ffde74aea..28dc92c624b8c22fcfaad92d9c7770e06f90c851 100644 --- a/src/main/webapp/page/admin/style.css +++ b/src/main/webapp/page/admin/style.css @@ -72,11 +72,12 @@ body.xnat .panel { margin-bottom: 30px; background: /* #f8f8f8 */ inherit; borde body.xnat .panel-default { border: 1px solid #c8c8c8; } .panel-default .panel-heading { padding: 12px 16px; - color: #222; /background: /* #e9e9e9 */ inherit; + color: #fff; background: #1A75BB; } -.panel-default .panel-body { padding: 12px 30px; } +body.xnat .xmodal .panel { border: none; } +.panel-default .panel-body { padding: 20px; } .panel-default .panel-footer { padding: 12px; background: #f0f0f0; border-top: #c8c8c8; } -.panel-title { font-weight: normal; font-size: 20px; line-height: inherit; } +.panel-title { font-weight: normal; font-size: 18px; line-height: inherit; } /* PANEL ELEMENTS */ .panel .panel-element { margin: 15px 0; clear: both; overflow: auto; } @@ -244,4 +245,4 @@ embedded base-64 image fallbacks } .affix { position: fixed; -} \ No newline at end of file +} diff --git a/src/main/webapp/scripts/lib/spawn/spawn.js b/src/main/webapp/scripts/lib/spawn/spawn.js index f5b425155a9c359128479b8f865122d0b4fc616a..51d020e2a95934f4d72f0730c29c3ff154dcfeef 100644 --- a/src/main/webapp/scripts/lib/spawn/spawn.js +++ b/src/main/webapp/scripts/lib/spawn/spawn.js @@ -148,7 +148,7 @@ var el, $el, parts, id, classes, tagParts, attrs, isVoid, // property names to skip later skip = [ - 'innerHTML', 'html', 'attr', 'append', 'appendTo', + 'innerHTML', 'html', 'attr', 'prepend', 'append', 'appendTo', 'classes', 'className', 'style', 'data', 'fn' ], errors = []; // collect errors @@ -370,18 +370,18 @@ var frag = document.createDocumentFragment(); - if (opts.after){ - frag.appendChild(el); - appendChildren(frag, opts.after, spawn); - el = frag; - } - if (opts.before){ appendChildren(frag, opts.before, spawn); frag.appendChild(el); el = frag; } + if (opts.after){ + frag.appendChild(el); + appendChildren(frag, opts.after, spawn); + el = frag; + } + if (errors.length){ if (hasConsole) console.log(errors); } diff --git a/src/main/webapp/scripts/xmodal-v1/xmodal.js b/src/main/webapp/scripts/xmodal-v1/xmodal.js index b967f12a01bfb4554617974f15dd5da671c36bf0..84af5f4a47a5ad8da7396adbb2d2f45b2007f020 100644 --- a/src/main/webapp/scripts/xmodal-v1/xmodal.js +++ b/src/main/webapp/scripts/xmodal-v1/xmodal.js @@ -35,27 +35,37 @@ if (typeof jQuery == 'undefined') { // can't decide on a prefix for selection by id // use ONE of these: // id= | id: | @id= | @# | @= | @: | @ | #= | #: | #/ - var ALL_PREFIX = /^\*!/, // $$('*!div.foo') --> return all 'div.foo' elements as an array - RAW_ID = /^#!/, // $$('#!foo') --> return (one) element with id 'foo' - RAW_PREFIX = /^!/, // $$('!div.foo') --> return FIRST 'div.foo' element - ID_PREFIX = /^(id=|id:|@id=|@#|@=|@:|@|#=|#:|#\/)/; + var ALL_PREFIX = /^!\*/, // $$('!*div.foo') --> return raw 'div.foo' elements as an array + RAW_ID = /^!#/, // $$('!#foo') --> return (one) raw element with id 'foo' + NAME_RAW = /^!\?/, // $$('!?foo') --> return raw elements with [name="foo"] + NAME_$ = /^\?/, // $$('?foo') --> return wrapped elements with [name="foo"] + RAW_PREFIX = /^!/, // $$('!div.foo') --> return FIRST raw 'div.foo' element + ID_PREFIX = /^(id=|id:|@id=|@#|@=|@:|@|#=|#:|#\/)/; if (!el || el.jquery){ return el; } - if (el.search(ALL_PREFIX) === 0){ - return document.querySelectorAll(el.replace(ALL_PREFIX, '')); - } - // pass empty string or null as the second argument - // to get the bare element by id (no jQuery) - if (id_prefix === '' || id_prefix === null || el.search(RAW_ID) === 0){ - return document.getElementById(el.replace(RAW_ID,'')); - } - if (el.search(RAW_PREFIX) === 0){ - return document.querySelector(el.replace(RAW_PREFIX,'')); - } - id_prefix = id_prefix || ID_PREFIX; - if (el.search(id_prefix) === 0){ - return $(document.getElementById(el.replace(id_prefix,''))); + if (typeof el == 'string'){ + if (el.search(ALL_PREFIX) === 0){ + return document.querySelectorAll(el.replace(ALL_PREFIX, '')); + } + // pass empty string or null as the second argument + // to get the bare element by id (no jQuery) + if (id_prefix === '' || id_prefix === null || el.search(RAW_ID) === 0){ + return document.getElementById(el.replace(RAW_ID,'')); + } + if (el.search(NAME_RAW) === 0){ + return document.getElementsByName(el.replace(NAME_RAW, '')); + } + if (el.search(NAME_$) === 0){ + return $(document.getElementsByName(el.replace(NAME_$, ''))); + } + if (el.search(RAW_PREFIX) === 0){ + return document.querySelector(el.replace(RAW_PREFIX,'')); + } + id_prefix = id_prefix || ID_PREFIX; + if (el.search(id_prefix) === 0){ + return $(document.getElementById(el.replace(id_prefix,''))); + } } return $(el); } diff --git a/src/main/webapp/scripts/xnat/admin/dicomScpManager.js b/src/main/webapp/scripts/xnat/admin/dicomScpManager.js new file mode 100644 index 0000000000000000000000000000000000000000..29aee2bea8f28180c48d6c634e6a9a2f4bc51867 --- /dev/null +++ b/src/main/webapp/scripts/xnat/admin/dicomScpManager.js @@ -0,0 +1,283 @@ +/*! + * Manage DICOM SCP Receivers + */ + +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 dicomScpManager, undefined, + rootUrl = XNAT.url.rootUrl; + + XNAT.admin = + getObject(XNAT.admin || {}); + + XNAT.admin.dicomScpManager = dicomScpManager = + getObject(XNAT.admin.dicomScpManager || {}); + + dicomScpManager.samples = [ + { + "aeTitle": "Bogus", + "enabled": true, + "fileNamer": "string", + "identifier": "string", + "port": 0, + "scpId": "BOGUS" + }, + { + "enabled": true, + "fileNamer": "string", + "identifier": "string", + "port": 8104, + "scpId": "XNAT", + "aeTitle": "XNAT" + } + ]; + + function spacer(width){ + return spawn('i.spacer', { + style: { + display: 'inline-block', + width: width + 'px' + } + }) + } + + // keep track of used ports to help prevent port conflicts + dicomScpManager.usedPorts = []; + + // get the list of DICOM SCP Receivers + dicomScpManager.getReceivers = dicomScpManager.getAll = function(callback){ + callback = isFunction(callback) ? callback : function(){}; + return XNAT.xhr.get({ + url: rootUrl('/xapi/dicomscp'), + dataType: 'json', + success: function(data){ + // refresh the 'usedPorts' array every time this function is called + dicomScpManager.usedPorts = data.map(function(item){ + return item.port; + }); + callback.apply(this, arguments); + } + }); + }; + + dicomScpManager.getReceiver = dicomScpManager.getOne = function(id, callback){ + if (!id) return null; + callback = isFunction(callback) ? callback : function(){}; + return XNAT.xhr.get({ + url: rootUrl('/xapi/dicomscp/' + id), + dataType: 'json', + success: callback + }); + }; + + dicomScpManager.get = function(id){ + if (!id) { + return dicomScpManager.getAll(); + } + return dicomScpManager.getOne(id); + }; + + // dialog to create/edit receivers + dicomScpManager.dialog = function(item, opts){ + var tmpl = $('#dicom-scp-editor-template'); + var doWhat = !item ? 'New' : 'Edit'; + item = item || {}; + xmodal.open({ + title: doWhat + ' DICOM SCP Receiver', + template: tmpl.clone(), + height: 500, + padding: '0', + beforeShow: function(obj){ + var $form = obj.$modal.find('#dicom-scp-editor-panel'); + if (item && item.scpId) { + forOwn(item, function(prop, val){ + $form.find('[name="'+prop+'"]').val(val); + }); + } + }, + okClose: false, + okLabel: 'Save', + okAction: function(obj){ + var $form = obj.$modal.find('#dicom-scp-editor-panel'); + var id = $form.find('#scp-id').val(); + XNAT.xhr.form($form, { + method: 'PUT', + url: '/xapi/dicomscp/' + id, + contentType: 'application/json' + }); + } + }); + }; + + // create table for DICOM SCP receivers + dicomScpManager.table = function(container, callback){ + + // initialize the table - we'll add to it below + var scpTable = XNAT.table({ + className: 'dicom-scp-receivers xnat-table', + style: { + width: '100%', + marginTop: '15px', + marginBottom: '15px' + } + }); + + // add table header row + scpTable.tr() + .th({ addClass: 'left', html: '<b>ID</b>' }) + .th({ addClass: 'left', html: '<b>AE Title</b>' }) + .th('<b>Port</b>') + .th('<b>Enabled</b>') + //.th('<b>Default?</b>') // if this is enabled, enable the radio button(s) too (below) + .th('<b>Actions</b>'); + + // TODO: move event listeners to parent elements - events will bubble up + // ^-- this will reduce the number of event listeners + function enabledCheckbox(item){ + return spawn('div.center', [ + ['input.enabled', { + type: 'checkbox', + checked: !!item.enabled, + onclick: function(){ + // save the status when clicked + var enabled = this.checked; + XNAT.xhr.put({ + url: rootUrl('/xapi/dicomscp/' + item.scpId + '/enabled/' + enabled), + success: function(){ + console.log(item.scpId + (enabled ? ' enabled' : ' disabled')) + } + }); + } + }] + ]); + } + + function editButton(item){ + return spawn('button.btn.sm.edit', { + onclick: function(){ + dicomScpManager.dialog(item); + //alert('(feature not yet enabled)') + } + }, 'Edit'); + } + + function deleteButton(item){ + return spawn('button.btn.sm.delete', { + onclick: function(){ + xmodal.confirm({ + content: "" + + "Are you sure you'd like to delete the '" + item.aeTitle + "' DICOM Receiver? " + + "<b>This action cannot be undone.</b>", + okAction: function(){ + XNAT.xhr.delete({ + url: rootUrl('/xapi/dicomscp/' + item.scpId), + success: function(){ + console.log('"'+ item.scpId + '" deleted') + } + }); + } + }) + } + }, 'Delete'); + } + + dicomScpManager.getAll().done(function(data){ + data.forEach(function(item){ + scpTable.tr({title:item.scpId}) + .td(item.scpId) + .td(item.aeTitle) + .td([['div.mono.center', item.port]]) + .td([enabledCheckbox(item)]) + .td([['div.center', [editButton(item), spacer(10), deleteButton(item)]]]); + // scpTable.row([ + // item.aeTitle, + // [['div.mono.center', item.port]], + // [enabledCheckbox(item)], + // //[['div.center', [['input|type=radio;name=defaultReceiver']] ]], // how do we know which one is 'default' + // [['div.center', [editButton(item), spacer(10), deleteButton(item)]]] + // ]); + }); + + if (container){ + $$(container).append(scpTable.table); + } + + if (isFunction(callback)) { + callback(); + } + + }); + + return scpTable.table; + + }; + + dicomScpManager.init = function(container){ + + var $manager = $$(container||'div#dicom-scp-manager'); + + $manager.append(dicomScpManager.table()); + // dicomScpManager.table($manager); + + var newReceiver = spawn('button.new-dicomscp-receiver.btn.btn-sm.submit.pull-right', { + html: 'New DICOM SCP Receiver', + onclick: function(){ + dicomScpManager.dialog(); + } + }); + + var startAll = spawn('button.start-receivers.btn.btn-sm', { + html: 'Start All', + onclick: function(){ + XNAT.xhr.put({ + url: XNAT.url.rootUrl('/xapi/dicomscp/start'), + success: function(){ + console.log('DICOM SCP Receivers started') + } + }) + } + }); + + var stopAll = spawn('button.stop-receivers.btn.btn-sm', { + html: 'Stop All', + onclick: function(){ + XNAT.xhr.put({ + url: XNAT.url.rootUrl('/xapi/dicomscp/stop'), + success: function(){ + console.log('DICOM SCP Receivers stopped') + } + }) + } + }); + + // add the start, stop, and 'add new' buttons at the bottom + $manager.append(spawn('div', [ + startAll, spacer(10), stopAll, newReceiver, ['div.clear.clearfix'] + ])); + + return { + element: $manager[0], + spawned: $manager[0], + get: function(){ + return $manager[0] + } + }; + }; + + dicomScpManager.init(); + + return XNAT.admin.dicomScpManager = dicomScpManager; + +})); diff --git a/src/main/webapp/scripts/xnat/app/siteSetup.js b/src/main/webapp/scripts/xnat/app/siteSetup.js index 997b6fa9c50897208026669e99c67d932d8cc989..00262b57338167bf4de5774863d8518c3959a7a7 100644 --- a/src/main/webapp/scripts/xnat/app/siteSetup.js +++ b/src/main/webapp/scripts/xnat/app/siteSetup.js @@ -60,7 +60,7 @@ var XNAT = getObject(XNAT); resetBtn = spawn('button', { type: 'button', - classes: 'btn btn-sm btn-default revert pull-right', + classes: 'btn revert pull-right', html: 'Discard Changes', onclick: function(e){ e.preventDefault(); diff --git a/src/main/webapp/scripts/xnat/element.js b/src/main/webapp/scripts/xnat/element.js index e908f25f76efae07e88169ed91b17983d81e8bc0..6cddc1386c9f0adb6fbecf21fb68e6368f33cead 100644 --- a/src/main/webapp/scripts/xnat/element.js +++ b/src/main/webapp/scripts/xnat/element.js @@ -215,7 +215,7 @@ var XNAT = getObject(XNAT||{}); 's small sub sup u b i em strong pre ' + 'form fieldset button input textarea ' + 'label select option optgroup ' + - 'img map area embed object script' + + 'img map area embed object' + '').split(/\s+/); tagNames.forEach(function(tag, i){ @@ -257,10 +257,45 @@ var XNAT = getObject(XNAT||{}); // -> <div>Foo</div> element[tag] = function(opts, content){ var args = setOpts(opts, content); - return spawn.element(tag, args[0], args[1]); + return spawn(tag, args[0], args[1]); } }); + + + // insert items into <head> element + element.head = { + append: function(opts){ + opts = cloneObject(opts); + opts.tagName = opts.tagName || opts.tag; + if (!opts.tagName) return; + delete opts.tag; + var el = spawn(opts.tagName, opts); + document.head.appendChild(el); + return { + element: el, + spawned: el + } + } + }; + element.head.insert = element.head.append; + + + // special handling of <script> elements + // add them to the <head> + element.script = function(opts){ + opts = cloneObject(opts); + var el; + if (opts.src) { + opts.html = ''; + } + el = spawn('script', opts); + document.head.appendChild(el); + return { + element: el, + spawned: el + } + }; ////////////////////////////////////////////////////////////////////// diff --git a/src/main/webapp/scripts/xnat/spawner.js b/src/main/webapp/scripts/xnat/spawner.js index 7faa5a4f7a8a422c473e819dd389a9394156d879..ae1ebf0327ce28a4d6a96653c80eb12283376d09 100644 --- a/src/main/webapp/scripts/xnat/spawner.js +++ b/src/main/webapp/scripts/xnat/spawner.js @@ -221,7 +221,7 @@ var XNAT = getObject(XNAT); _spawn.done = function(callback){ if (isFunction(callback)) { - callback() + callback(_spawn) } return _spawn; }; diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js index 89094323623a6b36c1b07aa4934015f8cd01296d..aeb0a31e66c4a44032936910fb85f949f26e9810 100644 --- a/src/main/webapp/scripts/xnat/ui/panel.js +++ b/src/main/webapp/scripts/xnat/ui/panel.js @@ -37,12 +37,12 @@ var XNAT = getObject(XNAT || {}); } // string that indicates to look for a namespaced object value - var doLookupString = '??'; + var lookupPrefix = '??'; - function doLookup(input){ + function lookupValue(input){ if (!input) return ''; - if (input.toString().indexOf(doLookupString) === 0){ - input = input.split(doLookupString)[1].trim(); + if (input.toString().indexOf(lookupPrefix) === 0){ + input = input.split(lookupPrefix)[1].trim(); return lookupObjectValue(window, input); } return input; @@ -57,15 +57,19 @@ var XNAT = getObject(XNAT || {}); opts = cloneObject(opts); opts.element = opts.element || opts.config || {}; + opts.title = opts.title || opts.label || opts.header; var _target = spawn('div.panel-body', opts.element), + + hideHeader = (isDefined(opts.header) && (opts.header === false || /^-/.test(opts.title))), hideFooter = (isDefined(opts.footer) && (opts.footer === false || /^-/.test(opts.footer))), _panel = spawn('div.panel.panel-default', [ - ['div.panel-heading', [ - ['h3.panel-title', opts.title || opts.label] - ]], + + (hideHeader ? ['div.hidden'] : ['div.panel-heading', [ + ['h3.panel-title', opts.title] + ]]), // target is where the next spawned item will render _target, @@ -88,17 +92,23 @@ var XNAT = getObject(XNAT || {}); } } }; + + panel.formSampleConfig = { + + }; // creates a panel that's a form that can be submitted panel.form = function panelForm(opts, callback){ opts = cloneObject(opts); opts.element = opts.element || opts.config || {}; - - opts.name = opts.name || opts.element.name || opts.id || opts.element.id || randomID('form-', false) + opts.title = opts.title || opts.label || opts.header; + opts.name = opts.name || opts.element.name || opts.id || opts.element.id || randomID('form-', false); var _target = spawn('div.panel-body', opts.element), + hideHeader = (isDefined(opts.header) && (opts.header === false || /^-/.test(opts.title))), + hideFooter = (isDefined(opts.footer) && (opts.footer === false || /^-/.test(opts.footer))), _resetBtn = spawn('button.btn.btn-sm.btn-default.revert.pull-right|type=button', 'Discard Changes'), @@ -114,13 +124,14 @@ var XNAT = getObject(XNAT || {}); _formPanel = spawn('form.validate.xnat-form-panel.panel.panel-default', { name: opts.name, method: opts.method || 'POST', - action: opts.action ? XNAT.url.rootUrl(opts.action) : '#!' + action: opts.action ? XNAT.url.rootUrl(opts.action) : '#!', + addClass: opts.classes || '' }, [ - ['div.panel-heading', [ - ['h3.panel-title', opts.title || opts.label] - ]], - + (hideHeader ? ['div.hidden'] : ['div.panel-heading', [ + ['h3.panel-title', opts.title] + ]]), + // target is where this form's "contents" will be inserted _target, @@ -171,37 +182,57 @@ var XNAT = getObject(XNAT || {}); obj = cloneObject(obj); - xmodal.loading.open('#load-data'); - // need a form to put the data into! - if (!form) { + // and a 'load' property too + if (!form || !obj.load) { xmodal.loading.close('#load-data'); return; } - // if 'load' starts with ??, do lookup - var doLookup = '??'; + xmodal.loading.open('#load-data'); - if (obj.load && obj.load.toString().indexOf(doLookup) === 0) { - obj.load = (obj.load.split(doLookup)[1]||'').trim().split('|')[0]; - obj.prop = obj.prop || obj.load.split('|')[1] || ''; - setValues(form, lookupObjectValue(window, obj.load, obj.prop)); - xmodal.loading.close('#load-data'); - return form; + obj.load = obj.load.toString().trim(); + + // if 'load' starts with '$?', '~/', or just '/' + // then values need to load via REST + var ajaxPrefix = /^(\$\?|~\/|\/)/; + var doAjax = ajaxPrefix.test(obj.load); - } - // if 'load' starts with '!?' do an eval() - var doEval = '!?'; + var evalPrefix = '!?'; + + // if 'load' starts with ?? (or NOT evalPrefix or ajaxPrefix), do lookup + var lookupPrefix = '??'; + + if (!doAjax) { + + var doLookup = obj.load.indexOf(lookupPrefix) === 0; + if (doLookup) { + obj.load = (obj.load.split(lookupPrefix)[1]||'').trim().split('|')[0]; + obj.prop = obj.prop || obj.load.split('|')[1] || ''; + setValues(form, lookupObjectValue(window, obj.load, obj.prop)); + xmodal.loading.close('#load-data'); + return form; + } + + var doEval = obj.load.indexOf(evalPrefix) === 0; + if (doEval) { + obj.load = (obj.load.split(evalPrefix)[1]||'').trim(); + } + + // lastly try to eval the 'load' value + try { + setValues(form, eval(obj.load)); + } + catch (e) { + console.log(e); + } - if (obj.load && obj.load.toString().indexOf(doEval) === 0) { - obj.load = (obj.load.split(doEval)[1]||'').trim(); - setValues(form, eval(obj.load)); xmodal.loading.close('#load-data'); return form; - + } - + ////////// // REST ////////// @@ -209,12 +240,13 @@ var XNAT = getObject(XNAT || {}); var ajaxUrl = obj.refresh || ''; // if 'load' starts with $?, do ajax request - var ajaxPrefix = '$?'; + //var ajaxPrefix = '$?'; var ajaxProp = ''; // value: $? /path/to/data | obj:prop:name - if (obj.load && obj.load.toString().indexOf(ajaxPrefix) === 0) { - ajaxUrl = (obj.load.split(ajaxPrefix)[1]||'').trim().split('|')[0]; + // value: ~/path/to/data|obj.prop.name + if (doAjax) { + ajaxUrl = (obj.load.split(ajaxPrefix)[2]||'').trim().split('|')[0]; ajaxProp = ajaxUrl.split('|')[1] || ''; } @@ -268,6 +300,7 @@ var XNAT = getObject(XNAT || {}); opts.onload = opts.onload || callback; + // custom event for reloading data (refresh) $formPanel.on('reload-data', function(){ loadData(this, { refresh: opts.refresh || opts.load || opts.url @@ -712,7 +745,7 @@ var XNAT = getObject(XNAT || {}); opts.text || opts.html || ''; - opts.element.html = doLookup(opts.element.html); + opts.element.html = lookupValue(opts.element.html); opts.element.rows = 6; diff --git a/src/main/webapp/scripts/xnat/ui/table.js b/src/main/webapp/scripts/xnat/ui/table.js index 5d78860113588cbace0f1d5ffe14415662a05411..28a841f02a36c8e490d5eaf170c9472154ec06c8 100755 --- a/src/main/webapp/scripts/xnat/ui/table.js +++ b/src/main/webapp/scripts/xnat/ui/table.js @@ -25,7 +25,7 @@ var XNAT = getObject(XNAT); }(function(XNAT, $){ var table, - element = spawn.element, + element = window.spawn, undefined; // add new element class without destroying existing class