diff --git a/src/main/webapp/WEB-INF/tags/page/xnat.tag b/src/main/webapp/WEB-INF/tags/page/xnat.tag index 924ed878e7c1ada7207dc064bd86d0b340210098..a2c8cbe11e18d1eeea65e3ad2656a34cc80d75d8 100644 --- a/src/main/webapp/WEB-INF/tags/page/xnat.tag +++ b/src/main/webapp/WEB-INF/tags/page/xnat.tag @@ -670,23 +670,27 @@ ${bodyTop} loadjs(scriptUrl('xnat/event.js'), function(){ + var clicker = XNAT.event.click('#header_logo, #xnat_power > a'); + // shift-click the header or footer XNAT logo to TOGGLE debug mode on/off + clicker.shiftKey(function(e){ + e.preventDefault(); + if (Cookies.get('debug') === 'on'){ + Cookies.set('debug', 'off'); + window.location.hash = 'debug=off'; + } + else { + Cookies.set('debug', 'on'); + window.location.hash = 'debug=on'; + } + window.location.reload(); + }); + // alt-shift-click to open the Swagger page in a new window - XNAT.event.click('#header_logo, #xnat_power > a') - .shiftKey(function(e){ - e.preventDefault(); - if (Cookies.get('debug') === 'on'){ - window.location.hash = 'debug=off'; - } - else { - window.location.hash = 'debug=on'; - } - window.location.reload(); - }) - .altShift(function(e){ - e.preventDefault(); - XNAT.ui.popup(XNAT.url.rootUrl('/xapi/swagger-ui.html')); - }); + clicker.altShift(function(e){ + e.preventDefault(); + XNAT.ui.popup(XNAT.url.rootUrl('/xapi/swagger-ui.html')); + }); }) diff --git a/src/main/webapp/page/admin/content.jsp b/src/main/webapp/page/admin/content.jsp index ec8aeace85c4ad74be93ae8f903027166a2da393..7f9c30cf28e45fd5dc13c285525acb7a23c8571a 100755 --- a/src/main/webapp/page/admin/content.jsp +++ b/src/main/webapp/page/admin/content.jsp @@ -44,8 +44,9 @@ delete XNAT.data.siteConfig.targetSource; - // var jsonUrl = XNAT.url.rootUrl('/page/admin/data/config/site-admin-sample-new.yaml'); +// var jsonUrl = XNAT.url.rootUrl('/page/admin/data/config/site-admin-sample-new.yaml'); var jsonUrl = XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/adminPage'); +// var jsonUrl = XNAT.url.rootUrl('/page/admin/data/site-admin-page.json'); $.get({ url: jsonUrl, diff --git a/src/main/webapp/page/admin/data/config/site-setup.yaml b/src/main/webapp/page/admin/data/config/site-setup.yaml index 547033e1307a52e15045ed9575bedc1585ce65ac..d9879a40a8f060b1ab478561c2b8ce1d2c452081 100644 --- a/src/main/webapp/page/admin/data/config/site-setup.yaml +++ b/src/main/webapp/page/admin/data/config/site-setup.yaml @@ -1,6 +1,5 @@ siteSetup: kind: app.siteSetup.form -# kind: panel.multiForm name: siteSetup label: XNAT Initial Setup # method: GET @@ -21,7 +20,7 @@ siteSetup: marginBottom: 24px html: > The settings below need to be configured before this XNAT system - can be used. Please set the properties below and submit the form continue. + can be used. Please set the properties below and submit the form to continue. # ==================== # PANEL @@ -33,9 +32,8 @@ siteSetup: method: POST action: /xapi/siteConfig/batch contentType: json - load: - lookup: XNAT.data.siteConfig - refresh: /xapi/siteConfig + load: ?? XNAT.data.siteConfig + refresh: /xapi/siteConfig contents: siteId: @@ -82,9 +80,8 @@ siteSetup: method: POST action: /xapi/siteConfig/batch contentType: json - load: - lookup: XNAT.data.siteConfig - refresh: /xapi/siteConfig + load: ?? XNAT.data.siteConfig + refresh: /xapi/siteConfig contents: archivePath: @@ -145,16 +142,16 @@ siteSetup: method: POST action: /xapi/siteConfig/smtpServer contentType: json - load: - #lookup: XNAT.data.siteConfig.smtpServer - refresh: /xapi/siteConfig/smtpServer +# load: ?? XNAT.data.siteConfig.smtpServer + refresh: /xapi/siteConfig/smtpServer contents: host: kind: panel.input.text name: host label: Host - value: ?? XNAT.data.siteConfig.smtpServer.host + value: ?? XNAT:data:siteConfig:smtpServer:host +# value: "" placeholder: localhost validation: required @@ -162,7 +159,8 @@ siteSetup: kind: panel.input.number name: port label: Port - value: ?? XNAT.data.siteConfig.smtpServer.port + value: ?? XNAT:data:siteConfig:smtpServer:port +# value: "" placeholder: 25 validation: required number @@ -170,19 +168,22 @@ siteSetup: kind: panel.input.text name: username label: Username - value: ?? XNAT.data.siteConfig.smtpServer.username + value: ?? XNAT:data:siteConfig:smtpServer:username +# value: "" password: kind: panel.input.password name: password label: Password - value: ?? XNAT.data.siteConfig.smtpServer.password + value: ?? XNAT:data:siteConfig:smtpServer:password +# value: "" protocol: kind: panel.input.text name: protocol label: Protocol - value: ?? XNAT.data.siteConfig.smtpServer.protocol + value: ?? XNAT:data:siteConfig:smtpServer:protocol +# value: "" mailServerProperties: kind: panel.subhead @@ -192,16 +193,20 @@ siteSetup: kind: panel.input.checkbox name: mail.smtp.auth label: SMTP Auth? - value: ?? XNAT.data.siteConfig.smtpServer['mail.smtp.auth'] + value: ?? XNAT:data:siteConfig:smtpServer:mail.smtp.auth +# value: "" smtpStartTls: kind: panel.input.checkbox name: mail.smtp.starttls.enable label: Smart TLS? - value: ?? XNAT.data.siteConfig.smtpServer['mail.smtp.starttls.enable'] + value: ?? XNAT:data:siteConfig:smtpServer:mail.smtp.starttls.enable +# value: "" smtpSSLTrust: kind: panel.input.text name: mail.smtp.ssl.trust label: SSL Trust - value: ?? XNAT.data.siteConfig.smtpServer['mail.smtp.ssl.trust'] + value: ?? XNAT:data:siteConfig:smtpServer:mail.smtp.ssl.trust +# value: "" + diff --git a/src/main/webapp/page/admin/spawner/spawner-admin.js b/src/main/webapp/page/admin/spawner/spawner-admin.js index 30464ee17213dbfef1eaf7cedf1b45164551ca32..7645623f608631cbedceec1a0a4d0e504f936c3c 100644 --- a/src/main/webapp/page/admin/spawner/spawner-admin.js +++ b/src/main/webapp/page/admin/spawner/spawner-admin.js @@ -123,6 +123,7 @@ XNAT.xhr.getJSON({ console.log(obj) }, okLabel: 'Save Changes', + okClose: false, okAction: function(obj){ XNAT.xhr.put({ url: elementUrl, diff --git a/src/main/webapp/scripts/xmodal-v1/xmodal.js b/src/main/webapp/scripts/xmodal-v1/xmodal.js index 117922845f2ab21c7a3661d9cadf3b48e471e166..d81ab12c7d335b17c28af83fd4e8d74a40012c66 100644 --- a/src/main/webapp/scripts/xmodal-v1/xmodal.js +++ b/src/main/webapp/scripts/xmodal-v1/xmodal.js @@ -1352,6 +1352,11 @@ if (typeof jQuery == 'undefined') { opts.id = arg3.id || arg2; } + // don't open a second loader with the same id + if (xmodal.modals._ids.indexOf(opts.id) > 0) { + return false; + } + return xmodal.open(opts); }; diff --git a/src/main/webapp/scripts/xnat/app/siteSetup.js b/src/main/webapp/scripts/xnat/app/siteSetup.js index eb0119d3a5a251e87cd4082e003bc022b131d27b..e14b12b3cc7d011db8b5716775bb60dbe49b9165 100644 --- a/src/main/webapp/scripts/xnat/app/siteSetup.js +++ b/src/main/webapp/scripts/xnat/app/siteSetup.js @@ -32,6 +32,18 @@ var XNAT = getObject(XNAT); // use app.siteSetup.form for Spawner 'kind' + // call 'test' until it returns true + function waitForIt(interval, test, callback){ + var waiting = setInterval(function(){ + if (test()) { + var called = callback(); + clearInterval(waiting); + return called; + } + }, interval || 10); + return waiting; + } + // creates a panel that submits all forms contained within siteSetup.form = function(opts, callback){ @@ -85,53 +97,118 @@ var XNAT = getObject(XNAT); var loader = xmodal.loading.open('#multi-save'); - // reset error count on new submission - multiform.errors = 0; + // reset success count on new submission + multiform.success = 0; // how many child forms are there? multiform.count = $forms.length; + // set error count to form count and subtract + // as submissions are successful + multiform.errors = 0; + // submit ALL enclosed forms $forms.each(function(){ - $(this).addClass('silent').trigger('submit'); + var $form = $(this).addClass('json silent'); + XNAT.xhr.form($form, { + contentType: 'application/json', + validate: function(){ + + var $form = $(this); + var errors = 0; + var validation = true; + + $form.dataAttr('errors', 0); + + $form.find(':input.required').each(function(){ + var $input = $(this); + $input.removeClass('invalid'); + if ($input.val() === '') { + errors++; + validation = false; + $input.addClass('invalid'); + } + }); + + $form.dataAttr('errors', errors); + + if (!validation) { + $form.dataAttr('status','error').addClass('error'); + multiform.errors++; + //don't show a dialog for each individual form + //if (!$form.hasClass('silent')) { + xmodal.message('Error','Please enter values for the required items and re-submit the form.'); + //} + } + + return validation; + + }, + //contentType: 'json', + success: function(){ + $form + .dataAttr('status', 'success') + .removeClass('error') + .addClass('success'); + multiform.success++ + }, + error: function(){ + $form + .dataAttr('status', 'error') + .removeClass('success') + .addClass('error'); + multiform.errors++ + } + }); + // $(this).addClass('silent').trigger('submit'); }); - multiform.errors = $forms.filter('.error').length; + // multiform.errors = $forms.filter('.error').length; + + function initialize(a, b, c){ + + XNAT.xhr.postJSON({ + url: XNAT.url.rootUrl('/xapi/siteConfig/batch'), + data: JSON.stringify({initialized:true}), + success: function(){ + xmodal.message({ + title: false, + esc: false, + content: 'Your XNAT site is ready to use. Click "OK" to continue to the home page.', + action: function(){ + // window.location.href = XNAT.url.rootUrl('/setup?init=true'); + window.location.href = XNAT.url.rootUrl('/'); + //$forms.each.triggerHandler('reload-data'); + } + }); + } + }).fail(function(e, txt, jQxhr){ + xmodal.message({ + title: 'Error', + content: [ + 'An error occurred during initialization', + e, + txt + ].join(': <br>') + }) + }).always(function(){ + xmodal.loading.close(loader.$modal); + }); + } - if (multiform.errors) { - xmodal.closeAll(); - xmodal.message('Error', 'Please correct the highlighted errors and re-submit the form.'); - return false; + function errorCheck(){ + return multiform.errors || multiform.success === multiform.count; } - XNAT.xhr.postJSON({ - url: XNAT.url.rootUrl('/xapi/siteConfig/batch'), - data: JSON.stringify({initialized:true}), - success: function(){ - xmodal.message({ - title: false, - esc: false, - content: 'Your XNAT site is ready to use. Click "OK" to continue to the home page.', - action: function(){ - // window.location.href = XNAT.url.rootUrl('/setup?init=true'); - window.location.href = XNAT.url.rootUrl('/'); - //$forms.each.triggerHandler('reload-data'); - } - }); + waitForIt(100, errorCheck, function(){ + if (multiform.errors) { + xmodal.closeAll(); + xmodal.message('Error', 'Please correct the highlighted errors and re-submit the form.'); + return false; } - }).fail(function(e, txt, jQxhr){ - xmodal.loading.close(loader.$modal); - xmodal.message({ - title: 'Error', - content: [ - 'An error occurred during initialization', - e, - txt - ].join(': <br>') - }) + initialize(); }); - xmodal.loading.close(loader.$modal); return false; } diff --git a/src/main/webapp/scripts/xnat/spawner.js b/src/main/webapp/scripts/xnat/spawner.js index 98a068fd5da4f6840ad2236538c2992af0296dfd..be902f8ab51016857d8cc33ec9ecad824fa94172 100644 --- a/src/main/webapp/scripts/xnat/spawner.js +++ b/src/main/webapp/scripts/xnat/spawner.js @@ -33,6 +33,10 @@ var XNAT = getObject(XNAT); // keep track of items that didn't spawn spawner.notSpawned = []; + function setRoot(url){ + url = url.replace(/^(\.\/+)/, '/'); + return XNAT.url.rootUrl(url) + } // ================================================== // MAIN FUNCTION @@ -60,6 +64,12 @@ var XNAT = getObject(XNAT); // with a fallback to a generic div kind = prop.kind || prop.type || 'div.spawned'; + // make 'href' 'src' and 'action' properties + // start at the site root if starting with './' + if (prop.config.href) { + prop.config.href = setRoot(prop.config.href) + } + // do a raw spawn() if 'kind' is 'element' // or if there's a tag property if (kind === 'element' || prop.tag) { diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js index d9220e9b5872099083387caa717f88ae3a417401..54b24abfe724ba50669b7fd12aeff1f8a6fb1447 100644 --- a/src/main/webapp/scripts/xnat/ui/panel.js +++ b/src/main/webapp/scripts/xnat/ui/panel.js @@ -35,37 +35,15 @@ var XNAT = getObject(XNAT || {}); }); return obj.data; } - - // another way to do this without using eval() - // is to loop over object string using dot notation: - // var myVal = lookupObjectValue(XNAT, 'data.siteConfig.siteId'); - // --> myVal == 'myXnatSiteId' - function lookupObjectValue(root, objStr){ - var val = ''; - if (!objStr) { - objStr = root; - root = window; - } - root = root || window; - objStr.toString().trim().split('.').forEach(function(part, i){ - // start at the root object - if (i === 0) { - val = root[part] || {}; - } - else { - val = val[part]; - } - }); - return val; - } - + // string that indicates to look for a namespaced object value var doLookupString = '??'; function doLookup(input){ if (!input) return ''; - if (input.toString().trim().indexOf(doLookupString) === 0){ - return lookupObjectValue(window, input.split(doLookupString)[1]); + if (input.toString().indexOf(doLookupString) === 0){ + input = input.split(doLookupString)[1].trim(); + return lookupObjectValue(window, input); } return input; } @@ -139,9 +117,11 @@ var XNAT = getObject(XNAT || {}); ['h3.panel-title', opts.title || opts.label] ]], - // target is where the next spawned item will render + + // target is where this form's "contents" will be inserted _target, + (hideFooter ? ['div.hidden'] : ['div.panel-footer', opts.footer || _footer]) ]); @@ -151,96 +131,117 @@ var XNAT = getObject(XNAT || {}); _formPanel.id = (opts.id || opts.element.id) + '-panel'; } + // cache a jQuery-wrapped element + var $formPanel = $(_formPanel); + // set form element values from an object map function setValues(form, dataObj){ - // pass a single argument to work with this form - if (!dataObj) { - dataObj = form; - form = _formPanel; - } // find all form inputs with a name attribute $$(form).find(':input[name]').each(function(){ - var val = ''; - if (Array.isArray(dataObj)) { - val = dataObj.join(', '); + var val = dataObj[this.name]; + if (!val) return; + if (Array.isArray(val)) { + val = val.join(', '); } else { - val = /string|number/i.test(typeof dataObj) ? dataObj : dataObj[this.name] || ''; + val = stringable(val) ? val : JSON.stringify(val); } $(this).changeVal(val); }); - if (xmodal && xmodal.loading && xmodal.loading.close){ - xmodal.loading.close(); + if (xmodal && xmodal.loading && xmodal.loading.closeAll){ + xmodal.loading.closeAll(); } } // populate the data fields if this panel is in the 'active' tab // (only getting values for the active tab should cut down on requests) - function loadData(obj){ + function loadData(form, obj){ - if (!obj) { - obj = opts.load || {}; + obj = cloneObject(obj); + + xmodal.loading.open('#load-data'); + + // need a form to put the data into! + if (!form) { + xmodal.loading.close('#load-data'); + return; } - obj = cloneObject(obj); + // if 'load' starts with ??, do lookup + var doLookup = '??'; + + 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.form = obj.form || obj.target || obj.element || _formPanel; + } + + // if 'load' starts with '!?' do an eval() + var doEval = '!?'; + 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; - // need a form to put the data into - if (!obj.form) return; + } + + ////////// + // REST + ////////// - // // if there's a 'refresh' url, make that obj.url - // if (obj.refresh) obj.url = obj.refresh; + // if 'load' starts with $?, do ajax request + var ajaxPrefix = '$?'; + var ajaxUrl = ''; + var ajaxProp = ''; - // if we pass data in a 'lookup' property, just use that - // to avoid doing a server request - if (obj.lookup && !obj.url) { - if (Array.isArray(obj.lookup)) { - obj.lookup = obj.lookup[0]; - } - else { - try { - obj.lookup = eval(obj.lookup); - } - catch (e) { - if (console && console.log) console.log(e); - obj.lookup = '' - } - } - setValues(obj.form, obj.lookup); - return obj.form; + if (obj.refresh) { + ajaxUrl = obj.refresh; + } + // value: $? /path/to/data | obj:prop:name + else if (obj.load && obj.load.toString().indexOf(ajaxPrefix) === 0) { + ajaxUrl = obj.load; } - // otherwise try to get the data values via ajax + ajaxUrl = (ajaxUrl.split(ajaxPrefix)[1]||'').trim().split('|')[0]; + ajaxProp = ajaxUrl.split('|')[1] || ''; // need a url to get the data - if (!obj.url) return obj.form; + if (!ajaxUrl || !stringable(ajaxUrl)) { + xmodal.loading.close('#load-data'); + return form; + } - obj.method = obj.method || 'GET'; + // force GET method + obj.method = 'GET'; // setup the ajax request // override values with an // 'ajax' or 'xhr' property obj.ajax = extend(true, { method: obj.method, - url: XNAT.url.restUrl(obj.url) + url: XNAT.url.rootUrl(ajaxUrl) }, obj.ajax || obj.xhr); - // allow use of 'prop' or 'root' for the root property name - obj.prop = obj.prop || obj.root; - obj.ajax.success = function(data){ - var prop = data; - // if there's a property to target, - // specify the 'prop' property - if (obj.prop){ - obj.prop.split('.').forEach(function(part){ - prop = prop[part]; - }); + if (ajaxProp){ + data = data[ajaxProp]; } - $(obj.form).dataAttr('status', 'clean'); - setValues(prop); + $(form).dataAttr('status', 'clean'); + setValues(form, data); + }; + + obj.ajax.error = function(){ + $(form).dataAttr('status', 'error'); + }; + + + obj.ajax.complete = function(){ + xmodal.loading.close('#load-data'); }; // return the ajax thing for method chaining @@ -248,11 +249,9 @@ var XNAT = getObject(XNAT || {}); } - //if (opts.load){ - // loadData(opts.load); - //} - - var $formPanel = $(_formPanel); + // if (opts.load) { + // loadData(_formPanel, opts) + // } // keep an eye on the inputs $formPanel.find(':input').on('change', function(){ @@ -262,14 +261,16 @@ var XNAT = getObject(XNAT || {}); opts.onload = opts.onload || callback; $formPanel.on('reload-data', function(){ - xmodal.loading.open(); - opts.load.url = opts.load.url || opts.load.refresh; - loadData(opts.load); + loadData(this, { + refresh: opts.refresh || opts.load || opts.url + }); }); // click 'Discard Changes' button to reload data _resetBtn.onclick = function(){ - $formPanel.triggerHandler('reload-data'); + if (!/^#/.test($formPanel.attr('action')||'#')){ + $formPanel.triggerHandler('reload-data'); + } }; opts.callback = opts.callback || callback || diddly; @@ -294,6 +295,11 @@ var XNAT = getObject(XNAT || {}); silent = $form.hasClass('silent'), multiform = {}; + // don't submit forms with 'action' starting with '#' + if (/^#/.test($form.attr('action')||'#')) { + return false; + } + $form.dataAttr('errors', 0); // validate inputs before moving on @@ -313,13 +319,12 @@ var XNAT = getObject(XNAT || {}); if (!silent) { xmodal.message('Error','Please enter values for the required items and re-submit the form.'); } - multiform.errors++; // keep track of errors for multi-form submission return false; } - // don't open loading dialog for multiform submit + // only open loading dialog for standard (non-multi) submit if (!multiform.count){ - xmodal.loading.open('#form-save'); + var saveLoader = xmodal.loading.open('#form-save'); } // var ajaxSubmitOpts = { @@ -356,29 +361,16 @@ var XNAT = getObject(XNAT || {}); var ajaxConfig = { method: opts.method, url: this.action, - success: function(data){ + success: function(){ var obj = {}; - // if a data object is returned, - // just use that - if (data) { - // HACK! - // wrap the returned data in an array so the - // loadData() function handles it properly - obj.lookup = [data]; - } - else { - obj.url = opts.refresh; - } - - // don't mess with modals for multiforms + // actually, NEVER use returned data... + // ALWAYS reload from the server + obj.refresh = opts.refresh || opts.reload || opts.url || opts.load; if (!silent){ - xmodal.loading.close('#form-save'); + xmodal.loading.close(saveLoader.$modal); xmodal.message('Data saved successfully.', { action: function(){ - loadData(obj); - if (callback && isFunction(callback)) { - - } + loadData($form, obj); } }); } @@ -401,8 +393,10 @@ var XNAT = getObject(XNAT || {}); // this object is returned to the XNAT.spawner() method return { - load: loadData, - setValues: setValues, + load: function(){ + loadData(_formPanel, opts) + }, + // setValues: setValues, target: _target, element: _formPanel, spawned: _formPanel, @@ -646,6 +640,13 @@ var XNAT = getObject(XNAT || {}); return XNAT.ui.template.panelInput(opts).spawned; }; + panel.input.date = function panelInputPassword(opts){ + opts = cloneObject(opts); + opts.type = 'date'; + addClassName(opts, 'date'); + return XNAT.ui.template.panelInput(opts).spawned; + }; + panel.input.checkbox = function panelInputCheckbox(opts){ opts = cloneObject(opts); opts.type = 'checkbox'; @@ -708,7 +709,7 @@ var XNAT = getObject(XNAT || {}); var textarea = spawn('textarea', opts.element); return XNAT.ui.template.panelDisplay(opts, textarea).spawned; }; - panel.input.textares = panel.textarea; + panel.input.textarea = panel.textarea; ////////////////////////////////////////////////// // SELECT MENU PANEL ELEMENTS diff --git a/src/main/webapp/scripts/xnat/ui/templates.js b/src/main/webapp/scripts/xnat/ui/templates.js index ca152a22485b59620076542e3b1a8651ffccb816..df5dadf4d40bc78fcda445acc23f3aa560752117 100644 --- a/src/main/webapp/scripts/xnat/ui/templates.js +++ b/src/main/webapp/scripts/xnat/ui/templates.js @@ -264,6 +264,8 @@ var XNAT = getObject(XNAT); // check buttons if value is true if (/checkbox|radio/i.test(opts.type||'')) { + element.checked = /true|checked/i.test((opts.checked || element.value).toString()); + // add a hidden input to capture the checkbox/radio value hiddenInput = spawn('input', { type: 'hidden', @@ -271,8 +273,6 @@ var XNAT = getObject(XNAT); value: element.checked }); - element.checked = /true|checked/i.test((opts.checked || element.value).toString()); - // change the value of the hidden input onclick element.onclick = function(){ hiddenInput.value = this.checked.toString(); diff --git a/src/main/webapp/scripts/xnat/xhr.js b/src/main/webapp/scripts/xnat/xhr.js index b285ff42d3d7b77cb300329ceafb0c6df96d683c..e0df7ab2fcb9b2d2efa6986dce28268c751973f6 100755 --- a/src/main/webapp/scripts/xnat/xhr.js +++ b/src/main/webapp/scripts/xnat/xhr.js @@ -72,7 +72,23 @@ var XNAT = getObject(XNAT||{}), //extend(xhr, url); xhr.$ = getObject(xhr.$||{}); - + // adding shortcut methods: put and delete AJAX calls for clarity + $.each(["put", "delete"], function(i, method) { + $[method] = function(url, data, callback, type) { + if ($.isFunction(data)) { + type = type || callback; + callback = data; + data = undefined; + } + return $.ajax({ + url: url, + type: method, + dataType: type, + data: data, + success: callback + }); + }; + }); // Direct maps to jQuery's AJAX methods. // Why use these instead of jQuery directly? // For flexibility to allow XNAT's AJAX @@ -80,9 +96,10 @@ var XNAT = getObject(XNAT||{}), xhr.$.ajax = xhr.ajax$ = $.ajax; xhr.$.get = xhr.get$ = $.get; xhr.$.post = xhr.post$ = $.post; + xhr.$.put = xhr.put$ = $.put; + xhr.$.delete = xhr.delete$ = $.delete; xhr.$.getJSON = xhr.getJSON$ = $.getJSON; xhr.$.getScript = xhr.getScript$ = $.getScript; - xhr.$.load = xhr.load$ = function(selector, url, data, success){ $$(selector).load(url, data, success); }; @@ -381,9 +398,9 @@ var XNAT = getObject(XNAT||{}), function processJSON(data, stringify){ var output = {}; - $.each(data, function(prop, val){ - prop = val.name || prop; - val = (val.value || val) || ''; + forEach(data, function(item){ + var prop = item.name; + var val = item.value; if (typeof output[prop] == 'undefined') { output[prop] = val; } @@ -420,12 +437,7 @@ var XNAT = getObject(XNAT||{}), } return $el; } - - // can the value be reasonably used as a string? - function stringable(val){ - return /string|number|boolean/.test(typeof val); - } - + // set form element values from an object map function setValues(form, dataObj){ // cache and check if form exists @@ -455,11 +467,7 @@ var XNAT = getObject(XNAT||{}), // this could be a handy jQuery method $.fn.setValues = function(dataObj){ - // only run on form or div elements - // (gotta draw the line somewhere) - if (/form|div/i.test(this.tagName||'')) { - setValues(this, dataObj); - } + setValues(this, dataObj); return this; }; @@ -467,12 +475,24 @@ var XNAT = getObject(XNAT||{}), var $form = $$(form), _form = $form[0], // raw DOM element + validation = true, callback = diddly; opts = cloneObject(opts); - opts.url = XNAT.url.restUrl(opts.url || _form.action); + opts.url = XNAT.url.rootUrl(opts.url || $form.attr('action')); opts.method = opts.method || _form.method || 'GET'; + if ($.isFunction(opts.validate)) { + validation = opts.validate.apply(_form, opts); + if (!validation) { + $form.removeClass('valid').addClass('invalid'); + return validation; + } + else { + $form.removeClass('invalid').addClass('valid'); + } + } + // set opts.callback:false to prevent the // 'standard' method callback from running if (opts.callback !== false) { @@ -490,7 +510,8 @@ var XNAT = getObject(XNAT||{}), opts.success = function(data){ callback.apply($form, arguments); // repopulate 'real' data after success - setValues($form, data); + // DON'T TRUST RETURNED DATA + //setValues($form, data); } } // populate form fields from returned @@ -498,7 +519,8 @@ var XNAT = getObject(XNAT||{}), else if (/GET/i.test(opts.method)){ opts.success = function(data){ callback.apply($form, arguments); - setValues($form, data); + // DON'T TRUST RETURNED DATA + //setValues($form, data); }; } @@ -507,11 +529,20 @@ var XNAT = getObject(XNAT||{}), }; + // $('form.foo').submitJSON(); + $.fn.submitJSON = function(opts){ + $(this).addClass('json'); + return xhr.form(this, extend(true, { + method: this.method || 'POST', + processData: false, + contentType: 'application/json' + }, opts)) + }; + // intercept form submissions with 'ajax' or 'json' class - $('body').on('submit', 'form.ajax, form.json', function(e){ - e.preventDefault(); - xhr.form(this); - return false; + // using namespaced event handler submit.json + $('body').on('submit-json, submit-ajax', 'form.ajax, form.json', function(opts){ + return xhr.form(this, opts); }); // special case for YUI 'GET' request @@ -608,3 +639,4 @@ var XNAT = getObject(XNAT||{}), xhr.loaded = true; })(XNAT, jQuery, YAHOO); + diff --git a/src/main/webapp/xdat-templates/navigations/powered_by.vm b/src/main/webapp/xdat-templates/navigations/powered_by.vm index 6c7489f99b64283d0137cbb9776221d28da0629a..f6f478e1fa74086a59e847240c26aca3bfc76e87 100644 --- a/src/main/webapp/xdat-templates/navigations/powered_by.vm +++ b/src/main/webapp/xdat-templates/navigations/powered_by.vm @@ -7,24 +7,27 @@ loadjs(scriptUrl('xnat/event.js'), function(){ - // shift-click the header or footer XNAT logo to ENABLE debug mode - // alt-shift-click to DISABLE debug mode - // ctrl-alt-click to open the Swagger page in a new window - XNAT.event.click('#header_logo, #xnat_power > a') - .shiftKey(function(e){ - e.preventDefault(); - window.location.hash = 'debug=on' - window.location.reload(); - }) - .altShift(function(e){ - e.preventDefault(); - window.location.hash = 'debug=off' - window.location.reload(); - }) - .ctrlAlt(function(e){ - e.preventDefault(); - XNAT.ui.popup('/xapi/swagger-ui.html'); - }); + var clicker = XNAT.event.click('#header_logo, #xnat_power > a'); + + // shift-click the header or footer XNAT logo to TOGGLE debug mode on/off + clicker.shiftKey(function(e){ + e.preventDefault(); + if (Cookies.get('debug') === 'on'){ + Cookies.set('debug', 'off'); + window.location.hash = 'debug=off'; + } + else { + Cookies.set('debug', 'on'); + window.location.hash = 'debug=on'; + } + window.location.reload(); + }); + + // alt-shift-click to open the Swagger page in a new window + clicker.altShift(function(e){ + e.preventDefault(); + XNAT.ui.popup(XNAT.url.rootUrl('/xapi/swagger-ui.html')); + }); })