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 84bcb3dc5c485cf07665a5e522e0b8152492207d..0a28fd6a136d56cb7fe26fb8905282827fa136c0 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 @@ -16,6 +16,7 @@ siteId: label: Site ID validation: required id onblur description: "The id used to refer to this site (also used to generate database ids). The Site ID must start with a letter and contain only letters, numbers and underscores. It should be a short, one-word name or acronym which describes your site. No spaces or non-alphanumeric characters." + siteDescriptionType: kind: panel.display # make this a radio button group id: siteDescriptionType @@ -23,46 +24,59 @@ siteDescriptionType: label: Site Description value: Select a site description option below # onchange: # some javascript that toggles display of the elements below appropriately + siteDescriptionOptionText: kind: panel.input.checkbox # make this a radio button group id: siteDescriptionOptionText label: "Text (Markdown)" + siteDescriptionOptionPage: kind: panel.input.checkbox # make this a radio button group id: siteDescriptionOptionPage label: "Page" + siteDescriptionPage: kind: panel.input.text id: siteDescriptionPage name: siteDescriptionPage label: " " description: "Specify a velocity template file to display on the login page" + siteDescriptionText: kind: panel.textarea id: siteDescriptionText name: siteDescriptionText label: " " description: "Specify a simple text description of this site" + element: + style: + width: 300px + height: 150px + siteLoginLanding: kind: panel.input.text id: siteLoginLanding name: siteLoginLanding label: Site Login Landing + siteLandingLayout: kind: panel.input.text id: siteLandingLayout name: siteLandingLayout label: Site Landing Layout + siteHome: kind: panel.input.text id: siteHome name: siteHome label: Site Home + siteHomeLayout: kind: panel.input.text id: siteHomeLayout name: siteHomeLayout label: Site Home Layout + siteUrl: kind: panel.input.text id: siteUrl @@ -70,21 +84,24 @@ siteUrl: label: Site Url validation: required id description: "" + adminEmail: kind: panel.input.email id: adminEmail name: adminEmail label: Site Administrator Email Address - url: /xapi/siteConfig/adminEmail - value: '' + value: ?? XNAT.data.siteConfig.adminEmail fileSystemSettingsWarning: someInfo: tag: div.message element: - html: "These settings must be defined during initial application configuration, and are seldom - if ever - changed." + html: > + These settings must be defined during initial application configuration, + and are seldom, if ever, changed. style: fontWeight: bold + archiveRootPath: kind: panel.input.text id: archiveRootPath @@ -92,7 +109,8 @@ archiveRootPath: label: Archive Root Path validation: required path description: "" - value: ??XNAT.data.siteConfig.archiveRootPath + value: ?? XNAT.data.siteConfig.archiveRootPath + cachePath: kind: panel.input.text id: cachePath @@ -100,7 +118,8 @@ cachePath: label: Cache Path validation: required path description: "" - value: ??XNAT.data.siteConfig.cachePath + value: ?? XNAT.data.siteConfig.cachePath + prearchivePath: kind: panel.input.text id: prearchivePath @@ -108,7 +127,8 @@ prearchivePath: label: Prearchive Path validation: required path description: "" - value: ??XNAT.data.siteConfig.prearchivePath + value: ?? XNAT.data.siteConfig.prearchivePath + ftpPath: kind: panel.input.text id: ftpPath @@ -210,41 +230,49 @@ userLoginsSessionControls: lookup: XNAT.data.siteConfig refresh: /xapi/siteConfig contents: + sessionTimeout: kind: panel.input.number id: sessionTimeout name: aliasTokenTimeout label: Session Timeout - value: 15 - description: "Interval for timing out alias tokens. Uses PostgreSQL interval notation: http://www.postgresql.org/docs/9.0/static/functions-datetime.html" + value: ?? XNAT.data.siteConfig.sessionTimeout || 15 + description: > + Interval for timing out alias tokens. Uses + <a target="_blank" href="http://www.postgresql.org/docs/9.0/static/functions-datetime.html">PostgreSQL interval notation</a> + sessionTimeoutMessage: kind: panel.input.text id: sessionTimeoutMessage name: sessionTimeoutMessage label: Session Timeout Message - value: "Your session has timed out." + value: ?? XNAT.data.siteConfig.sessionTimeoutMessage || "Your session has timed out." description: Alert message provided to users after a session timeout and logout. + allowResumeOnNextLogin: kind: panel.input.checkbox - id: allowResumeOnNextLogin + id: allow-resume-on-next-login name: allowResumeOnNextLogin label: Allow Resume On Next Login? - value: true + value: ?? XNAT.data.siteConfig.allowResumeOnNextLogin description: Allow user to resume where they left off, if logging back in after a session timeout? + maximumConcurrentSessions: kind: panel.input.number id: maximumConcurrentSessions name: security.sessions.concurrent_max label: Maximum Concurrent Sessions - value: 5 + value: ?? XNAT.data.siteConfig.maximumConcurrentSessions || 5 description: The maximum number of permitted sessions a user can have open simultaneously + loginFailureMessage: kind: panel.input.text id: loginFailureMessage name: UI.login_failure_message label: Login Failure Message - value: Login failed + value: || Login failed description: Text to show when a user fails to login + maximumFailedLogins: kind: panel.input.number id: maximumFailedLogins @@ -252,6 +280,7 @@ userLoginsSessionControls: label: Maximum Failed Logins value: -1 description: Number of failed login attempts before accounts are temporarily locked. (-1 disables feature) + failedLoginLockoutDuration: kind: panel.input.number id: failedLoginLockoutDuration @@ -259,6 +288,7 @@ userLoginsSessionControls: label: Failed Login Lockout Duration value: 0 description: Number of milliseconds to lock user accounts that have exceeded the max_failed_logins count. Select (3600000 for 1 hour, 86400000 for 24 hours) + userInactivityLockout: kind: panel.input.number id: userInactivityLockout @@ -1011,9 +1041,9 @@ misc: ################################################# #### Root Site Admin Spawner Config Object #### ################################################# -siteAdmin: +adminPage: kind: tabs - name: siteAdmin + name: adminPage label: Administer XNAT meta: ${tabGroups} diff --git a/src/main/webapp/page/admin/content.jsp b/src/main/webapp/page/admin/content.jsp index 2457534d48d6f3b8d8dffbfc9bbaf4cf99a3862e..ec8aeace85c4ad74be93ae8f903027166a2da393 100755 --- a/src/main/webapp/page/admin/content.jsp +++ b/src/main/webapp/page/admin/content.jsp @@ -32,9 +32,6 @@ </div> - <%--<script src="${sessionScope.siteRoot}/scripts/lib/jquery-plugins/jquery.form.js"></script>--%> - <%--<script src="${sessionScope.siteRoot}/scripts/lib/yamljs/dist/yaml.js"></script>--%> - <c:import url="/xapi/siteConfig" var="siteConfig"/> <script> @@ -47,8 +44,8 @@ delete XNAT.data.siteConfig.targetSource; - var jsonUrl = XNAT.url.rootUrl('/page/admin/data/config/site-admin-sample-new.yaml'); - // var jsonUrl = XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/siteAdmin'); + // var jsonUrl = XNAT.url.rootUrl('/page/admin/data/config/site-admin-sample-new.yaml'); + var jsonUrl = XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/adminPage'); $.get({ url: jsonUrl, diff --git a/src/main/webapp/page/admin/spawner/content.jsp b/src/main/webapp/page/admin/spawner/content.jsp index 11d0a5b141e0c80ea2f208fa88cc6a09cb5c9f94..a2b46a582709ec3003c4b944406a5f44a06cdb80 100644 --- a/src/main/webapp/page/admin/spawner/content.jsp +++ b/src/main/webapp/page/admin/spawner/content.jsp @@ -19,7 +19,7 @@ <div class="panel-body"> - <div data-name="spawnerElements" class="panel-element"> + <div data-name="spawnerElements" class="panel-element" style="overflow:visible;"> <%--<label class="element-label" for="!?"></label>--%> <%--<div class="element-wrapper">--%> diff --git a/src/main/webapp/page/admin/spawner/spawner-admin.js b/src/main/webapp/page/admin/spawner/spawner-admin.js index 4b63c32a39cb3e8726ff5cc2c4b46e7ce085367b..141bd1449815ecd2e99d7609491a9834660fde28 100644 --- a/src/main/webapp/page/admin/spawner/spawner-admin.js +++ b/src/main/webapp/page/admin/spawner/spawner-admin.js @@ -13,7 +13,7 @@ spawn('button|type=button', { html: 'View JSON', onclick: function(){ - XNAT.xhr.get(XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/siteAdmin'), function(data){ + XNAT.xhr.get(XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/adminPage'), function(data){ showJSON(data); }); }, @@ -73,7 +73,7 @@ XNAT.xhr.getJSON({ ]]); var idsMenu = spawn('select#spawner-ns-ids', [['option|value=!', 'Select an Element']]); - + tds.push(['td', [ idsMenu, @@ -91,22 +91,22 @@ XNAT.xhr.getJSON({ } var elementUrl = XNAT.url.rootUrl('/xapi/spawner/element/' + NS + '/' + getId); $.get(elementUrl, function(data){ - var _textarea = spawn('textarea.mono', { + var _textarea = spawn('textarea.yaml.mono', { name: getId, html: data.yaml, style: { width: '500px', height: '250px' } }); _textarea.innerHTML = (data.yaml); var _table = XNAT.table({className: 'xnat-table borderless'}).init([ + // [ [['b.label', 'Label: ']], data.label ], + // we could use spawn arg arrays (above), but HTML (below) is fine ['<b class="label">Namespace:</b> ', data.namespace], ['<b class="label">Element ID:</b> ', data.elementId], - [ [['b.label', 'Label: ']], data.label ], - //['<b class="label">Label:</b> ', data.label], - [ [['b.label', 'Created: ']], new Date(data.created).toString() ], - // ['<b class="label">Created:</b> ', new Date(data.created).toString()], + ['<b class="label">Label:</b> ', data.label], + ['<b class="label">Created:</b> ', new Date(data.created).toString()], ['<b class="label">Modified:</b> ', new Date(data.timestamp).toString()] ]); - // anothe way to add a row of data + // another way to add a row of data _table.tr().td([['b.label', 'YAML: ']]).td([_textarea]); //_table.tr().td('<b>YAML:</b> ').td([_textarea]); xmodal.open({ @@ -114,25 +114,20 @@ XNAT.xhr.getJSON({ width: 700, height: 550, maximize: true, + enter: false, + esc: false, title: 'Element ID: ' + getId, content: _table.get().outerHTML, beforeShow: function(obj){ console.log(obj) }, okLabel: 'Save Changes', - okAction: function(){ + okAction: function(obj){ XNAT.xhr.put({ - // url: XNAT.url.csrfUrl(elementUrl), - url: (elementUrl), - data: { - // namespace: data.namespace, - // elementId: data.elementId, - yaml: _textarea.value - }, - //dataType: 'text/x-yaml', - //contentType: 'application/json', + url: elementUrl, + data: obj.$modal.find('textarea.yaml').val(), contentType: 'text/x-yaml', - processData: false, + // processData: false, success: function(){ xmodal.message('Data saved.') }, @@ -150,14 +145,14 @@ XNAT.xhr.getJSON({ // spawn and push the row items.push(spawn('tr', tds)); - (function(){ - XNAT.xhr.get(XNAT.url.rootUrl('/xapi/spawner/ids/' + NS), function(ids){ - $.each(ids, function(){ - var id = this; - idsMenu.appendChild(spawn('option', { value: id, html: id })) - }); + // populate menu with spawner elements for 'NS' namespace + XNAT.xhr.get(XNAT.url.rootUrl('/xapi/spawner/ids/' + NS), function(ids){ + $.each(ids, function(){ + var id = this; + idsMenu.appendChild(spawn('option', { value: id, html: id })) }); - })() + chosenInit(idsMenu, { width: '250px' }); + }); }); @@ -165,3 +160,4 @@ XNAT.xhr.getJSON({ } }); + diff --git a/src/main/webapp/page/admin/tabs.js b/src/main/webapp/page/admin/tabs.js index 2d11966a7c1d2a6147ff18b94c7d7d2b98256636..916bf95f328bfb201aa2a91be6645cad9bba8135 100644 --- a/src/main/webapp/page/admin/tabs.js +++ b/src/main/webapp/page/admin/tabs.js @@ -19,7 +19,7 @@ // get the JSON and do the setup 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.json'); - // var jsonUrl = XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/siteAdmin'); + // var jsonUrl = XNAT.url.rootUrl('/xapi/spawner/resolve/siteAdmin/adminPage'); // get the siteConfig object first // doing this in JSP for better(?) performance diff --git a/src/main/webapp/scripts/lib/spawn/spawn.js b/src/main/webapp/scripts/lib/spawn/spawn.js index 228aa1ef5469832ce2a60732f9f6d0d15f9a11aa..f5b425155a9c359128479b8f865122d0b4fc616a 100644 --- a/src/main/webapp/scripts/lib/spawn/spawn.js +++ b/src/main/webapp/scripts/lib/spawn/spawn.js @@ -37,10 +37,22 @@ // boolean element attributes var boolAttrs = [ - 'disabled', - 'selected', 'checked', - 'multiple' + 'selected', + 'disabled', + 'hidden', + 'multiple', + 'readonly', + 'async', + 'autofocus', + 'autoplay', + 'controls', + 'defer', + 'ismap', + 'loop', + 'open', + 'required', + 'scoped' ]; // which "type" values create an <input> element? @@ -65,6 +77,12 @@ }); + // can the value be reasonably used as a string? + function stringable(val){ + return /string|number|boolean/.test(typeof val); + } + + function parseAttrs(el, attrs){ // allow ';' or ',' for attribute delimeter (attrs.split(/;|,/) || []).forEach(function(att, i){ @@ -93,7 +111,7 @@ el.appendChild(fn.apply(el, child)); } // ...or an HTML string (or number)... - else if (/(string|number)/.test(typeof child)){ + else if (stringable(child)){ el.innerHTML += child; } // ...or 'appendable' nodes @@ -128,9 +146,11 @@ function spawn(tag, opts, children){ var el, $el, parts, id, classes, tagParts, attrs, isVoid, - // property names to skip later - skip = ['innerHTML', 'html', 'append', 'appendTo', - 'classes', 'className', 'attr', 'style', 'data', 'fn'], + // property names to skip later + skip = [ + 'innerHTML', 'html', 'attr', 'append', 'appendTo', + 'classes', 'className', 'style', 'data', 'fn' + ], errors = []; // collect errors // deal with passing an array as the only argument @@ -207,7 +227,7 @@ // if 'opts' is a string, // set el's innerHTML and // return the element - if (/(string|number)/.test(typeof opts)){ + if (stringable(opts)){ el.innerHTML += opts; return el; } @@ -220,7 +240,7 @@ } // or if 'children' is a string // set THAT to the innerHTML - else if (/(string|number)/.test(typeof children)){ + else if (stringable(children)){ el.innerHTML += children; children = null; } @@ -438,7 +458,7 @@ // allow use of only 2 arguments // with the HTML text being the second - if (/(string|number)/.test(typeof opts)){ + if (stringable(opts)){ el.innerHTML += (opts+''); return el; } diff --git a/src/main/webapp/scripts/utils.js b/src/main/webapp/scripts/utils.js index f3791d4bbc6db00fba19eb56ba661b7201d57b57..877df576314eda81829322f9e705f5963dc4d765 100755 --- a/src/main/webapp/scripts/utils.js +++ b/src/main/webapp/scripts/utils.js @@ -401,7 +401,7 @@ function chosenInit(select, opts, width){ placeholder_text_multiple: 'Select...', search_contains: true }; - if (width) { defaults.width = (width + 'px').replace(/pxpx$/,'px') } + if (width) { defaults.width = (width + 'px').replace(/(px)*$/,'px') } $select.each(function(){ var $this = $(this), dataChosenOpts = {}; diff --git a/src/main/webapp/scripts/xnat/xhr.js b/src/main/webapp/scripts/xnat/xhr.js index fa9e30f6b69e074fdd815119b5d9e58a807e6f11..9be48d60e75ab2fe758aa6e63d00df526686a6d5 100755 --- a/src/main/webapp/scripts/xnat/xhr.js +++ b/src/main/webapp/scripts/xnat/xhr.js @@ -167,7 +167,7 @@ var XNAT = getObject(XNAT||{}), // (url, data, opts, success) // url string, data object, config object, success callback xhr.request = xhr.req = xhr.ajax = function( /* url/opts, data/opts/callback, opts/callback, callback */ ){ - var opts = {}; + var opts = {}, $ajax; if (arguments[0] instanceof RequestOfType){ opts = arguments[0]; @@ -234,10 +234,23 @@ var XNAT = getObject(XNAT||{}), // just do jQuery $.ajax() call if (!opts.yui || opts.jquery){ + $ajax = $.ajax(opts); + + // save jQuery's fail method + $ajax.$fail = $ajax.fail; + + // remap the arguments for consistency with .done() + $ajax.fail = function(callback){ + return $ajax.$fail(function(jqXHR, textStatus, errorThrown) { + callback(errorThrown, textStatus, jqXHR); + return $ajax; + }); + }; + // reset XNAT.xhr.cache to false xhr.cache = false; - return $.ajax(opts); + return $ajax; }