From 4409232065d68929eac09a9c3584dae03c56eb03 Mon Sep 17 00:00:00 2001 From: "Mark M. Florida" <markflorida@wustl.edu> Date: Wed, 31 Aug 2016 19:59:48 -0500 Subject: [PATCH] XNAT-4400: Changed checkboxes in Site Admin to new "switchbox" widget (panel.input.switchbox); stripped colon prefix from spawner elements' [data-name] attribute; other minor fixes and improvements to ui elements. --- .../xnat/spawner/site-admin-elements.yaml | 46 +++++++-------- src/main/webapp/scripts/xnat/ui/panel.js | 31 ++++++++-- src/main/webapp/scripts/xnat/ui/select.js | 10 +++- src/main/webapp/scripts/xnat/ui/templates.js | 25 +++++++-- src/main/webapp/style/app.css | 56 +++++++++++++++++-- 5 files changed, 130 insertions(+), 38 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 463a79e0..ba054378 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 @@ -260,17 +260,17 @@ generalSecuritySettings: element: title: Security Channel requireLogin: - kind: panel.input.checkbox + kind: panel.input.switchbox name: requireLogin label: Require User Login description: "If checked, then only registered users will be able to access your site. If false, anyone visiting your site will automatically be logged in as 'guest' with access to public data." restrictUserListAccessToAdmins: - kind: panel.input.checkbox + kind: panel.input.switchbox name: restrictUserListAccessToAdmins label: "Restrict user list access <br>to site administrators?" description: "Should this site restrict access to the list of system users to site administrators only? If turned on, the site is more secure, but this restricts project owners from being able to administer users in their projects directly." uiAllowNonAdminProjectCreation: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":UI.allow-non-admin-project-creation" label: "Allow non-administrators <br>to create projects?" description: "Should this site allow non-administrator users to create new projects? If turned on, the site is more secure, but this can make it more difficult for regular users to create new projects for their research efforts." @@ -449,7 +449,7 @@ passwords: Interval for which users cannot reuse an old password of theirs. Uses <a target="_blank" href="http://www.postgresql.org/docs/9.0/static/functions-datetime.html">PostgreSQL interval notation</a>. requireSaltedPasswords: - kind: panel.input.checkbox + kind: panel.input.switchbox id: requireSaltedPasswords name: requireSaltedPasswords label: Require Passwords To Be Salted @@ -463,12 +463,12 @@ csrf: contentType: json contents: enableCsrfToken: - kind: panel.input.checkbox + kind: panel.input.switchbox name: enableCsrfToken label: Require CSRF Token? description: Should this site require the use of a token to prevent CSRF attacks on POST, PUT, and DELETEs? csrfEmailAlert: - kind: panel.input.checkbox + kind: panel.input.switchbox name: csrfEmailAlert label: CSRF Email Alert description: "Should this site send an email to the site admin whenever a CSRF attack is attempted?" @@ -511,7 +511,7 @@ emailServerSettings: label: Mail Server Settings contents: smtpEnabled: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":smtp.enabled" label: "Enable SMTP?" hostname: @@ -544,11 +544,11 @@ emailServerSettings: name: mailServerProperties label: Properties smtpAuth: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":mail.smtp.auth" label: SMTP Auth? smtpStartTls: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":mail.smtp.starttls.enable" label: Start TLS? smtpSSLTrust: @@ -649,7 +649,7 @@ notifications: description: "What email address(es) should receive update emails. Separate multiple email addresses with commas. If empty, emails will be sent to the site administrator email address." value: "!? XNAT.data.notifications['notifications.emailRecipientUpdate'] || XNAT.data.siteConfig.adminEmail" copyAdminOnNotifications: - kind: panel.input.checkbox + kind: panel.input.switchbox name: copyAdminOnNotifications label: "Copy Administrator on Notifications?" description: "Indicates whether the primary administrator should receive a copy of error, issue, new user, and update notifications if the administrator is not one of the configured recipients." @@ -659,7 +659,7 @@ notifications: label: "Other" emailAllowNonuserSubscribers: - kind: panel.input.checkbox + kind: panel.input.switchbox name: emailAllowNonuserSubscribers label: "Allow Nonuser Subscribers" description: "Indicates whether this site should restrict email addresses for site notifications to addresses that are associated with valid active users of the XNAT installation. If turned on, the site is more secure from exploitation as a spam relay, but restricts the addresses that can be used when alerting administrators to system events." @@ -715,15 +715,15 @@ authenticationMethods: contentType: json contents: xnatInternal: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":provider.providers.xnatInternal" label: XNAT (Internal) ldapProvider: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":provider.providers.ldap" label: LDAP # oauthProvider: -# kind: panel.input.checkbox +# kind: panel.input.switchbox # id: oauthProvider # name: ":provider.providers.oauth" # label: OAuth @@ -811,7 +811,7 @@ registrationOptions: contentType: json contents: requireEmailVerificationToRegister: - kind: panel.input.checkbox + kind: panel.input.switchbox name: emailVerification label: "Require Email Verification <br>to Register?" description: > @@ -830,7 +830,7 @@ registrationOptions: name: emailVerificationExpiration label: "Email Verification Expiration" autoEnableUserRegistration: - kind: panel.input.checkbox + kind: panel.input.switchbox name: userRegistration label: "Auto-enable <br>User Registration?" description: > @@ -838,7 +838,7 @@ registrationOptions: projects immediately. If false, the site administrator will be required to manually enable user accounts. Either way the administrator receives an email notification when a user registers. autoEnablePar: - kind: panel.input.checkbox + kind: panel.input.switchbox name: par label: "Auto-enable with <br>Project Access Request?" description: > @@ -847,7 +847,7 @@ registrationOptions: access requests should override how user registration is normally handled. Either way the administrator receives an email notification when a user registers. uiAllowNewUserComments: - kind: panel.input.checkbox + kind: panel.input.switchbox name: ":UI.allow-new-user-comments" label: "Allow User Comments <br>on Registration?" @@ -906,7 +906,7 @@ anonymization: url: /xapi/siteConfig contents: enableSitewideAnonymizationScript: - kind: panel.input.checkbox + kind: panel.input.switchbox name: enableSitewideAnonymizationScript label: "Enable Site-wide <br>Anonymization Script?" sitewideAnonymizationScript: @@ -926,7 +926,7 @@ seriesImportFilter: url: /xapi/siteConfig contents: enableSitewideSeriesImportFilter: - kind: panel.input.checkbox + kind: panel.input.switchbox name: enableSitewideSeriesImportFilter label: "Enable Site-wide <br>Series Import Filter?" sitewideSeriesImportFilterMode: @@ -1013,7 +1013,7 @@ sessionUploadMethod: # label: Display Applet Link # description: "Enable to display link to Upload Applet on various XNAT pages." enableProjectAppletScript: - kind: panel.input.checkbox + kind: panel.input.switchbox name: enableProjectAppletScript label: Enable Project Applet Script description: "The site-wide applet settings script can be supplemented by applet settings specified at the project level if this setting is enabled." @@ -1109,7 +1109,7 @@ automationSettings: url: /xapi/automation contents: internalScriptingEnabled: - kind: panel.input.checkbox + kind: panel.input.switchbox name: internalScriptingEnabled label: Internal Scripting Enabled description: "When enabled, administrators can create and edit scripts that run internally to the XNAT process. This can be a powerful feature, but also can pose security hazards that may be unacceptable for certain deployments. For these situations, configurable internal scripting can be disabled (XNAT itself may still use some scripting for feature implementation, but these scripts can not be modified or updated by users)." @@ -1124,7 +1124,7 @@ misc: url: /xapi/siteConfig contents: scanTypeMapping: - kind: panel.input.checkbox + kind: panel.input.switchbox name: scanTypeMapping label: Scan Type Mapping? development: diff --git a/src/main/webapp/scripts/xnat/ui/panel.js b/src/main/webapp/scripts/xnat/ui/panel.js index c602a2f0..c7842215 100644 --- a/src/main/webapp/scripts/xnat/ui/panel.js +++ b/src/main/webapp/scripts/xnat/ui/panel.js @@ -332,7 +332,6 @@ var XNAT = getObject(XNAT || {}); _formPanel = spawn('form.xnat-form-panel.panel.panel-default', extend(true, { id: toDashed(opts.id || opts.element.id || opts.name) + '-panel', name: opts.name, - method: opts.method || 'POST', action: opts.action ? XNAT.url.rootUrl(opts.action) : '#!', addClass: opts.classes || '', data: opts.data @@ -349,6 +348,11 @@ var XNAT = getObject(XNAT || {}); ]); + // add [method] attribute ONLY for POST or GET + if (/POST|GET/i.test(opts.method+'')) { + _formPanel.method = opts.method; + } + // if there's a 'validation' (or 'validate') property, add 'validate' class if (opts.validation || opts.validate) { addClassName(_formPanel, 'validate'); @@ -523,7 +527,7 @@ var XNAT = getObject(XNAT || {}); method: $form.data('method') || opts.method || 'POST', url: this.action, success: function(){ - var obj = {}, + var obj = {}, callback, _load = opts.refresh || opts.reload || opts.url || opts.load; // actually, NEVER use returned data... // ALWAYS reload from the server @@ -533,6 +537,19 @@ var XNAT = getObject(XNAT || {}); XNAT.ui.banner.top(2000, 'Data saved successfully.', 'success'); loadData($form, obj); } + // fire callback function if specified + if (opts.success || opts.callback) { + callback = opts.success||opts.callback; + if (typeof callback === 'string') { + callback = eval(callback); + } + try { + callback.apply(this, arguments); + } + catch(e) { + console.log('something is broken: ' + e); + } + } } }; @@ -710,7 +727,7 @@ var XNAT = getObject(XNAT || {}); opts.element.id = (opts.id || opts.element.id) + '-element'; } addClassName(opts.element, 'panel-element'); - addDataObjects(opts.element, { name: opts.name||'' }); + addDataObjects(opts.element, { name: (opts.name||'').replace(/^:*/, '') }); opts.label = opts.label||opts.title||opts.name||''; // add a help info icon if one is specified @@ -871,6 +888,13 @@ var XNAT = getObject(XNAT || {}); return XNAT.ui.template.panelInput(opts).spawned; }; + panel.input.switchbox = function panelInputSwitchbox(opts){ + opts = cloneObject(opts); + opts.type = 'checkbox'; + addClassName(opts, 'switchbox'); + return XNAT.ui.template.panelInput(opts).spawned; + }; + panel.input.radio = function panelInputRadio(opts){ opts = cloneObject(opts); opts.type = 'radio'; @@ -1249,7 +1273,6 @@ var XNAT = getObject(XNAT || {}); $(description).removeClass('hidden'); alert('foo'); }); - //button.onchange = ; label.append = description; diff --git a/src/main/webapp/scripts/xnat/ui/select.js b/src/main/webapp/scripts/xnat/ui/select.js index a2fafb71..2fe34c52 100644 --- a/src/main/webapp/scripts/xnat/ui/select.js +++ b/src/main/webapp/scripts/xnat/ui/select.js @@ -40,6 +40,12 @@ var XNAT = getObject(XNAT); return spawn('option', opt); }); }; + + + // ADD options to a menu + select.addOptions = function(menu, options){ + $$(menu).append(select.options(options)); + }; // ======================================== @@ -55,13 +61,13 @@ var XNAT = getObject(XNAT); config.layout = firstDefined(config.layout, 'left'); config.id = config.id || toDashed(config.name) || randomID('menu-', false); - config.name = config.name || toCamelCase(config.id) || ''; + config.name = config.name || ''; config.element = extend(true, { id: config.id, name: config.name, value: config.value || '', - title: config.title || config.name || config.id || '' + title: config.title || '' }, config.element); menu = spawn('select', config.element); diff --git a/src/main/webapp/scripts/xnat/ui/templates.js b/src/main/webapp/scripts/xnat/ui/templates.js index 2207c18a..9b3f1a5c 100644 --- a/src/main/webapp/scripts/xnat/ui/templates.js +++ b/src/main/webapp/scripts/xnat/ui/templates.js @@ -99,8 +99,9 @@ var XNAT = getObject(XNAT); var _templ, _spawn, _html; opts = cloneObject(opts); addClassName(opts, 'panel-element'); + opts.name = (opts.name||'').replace(/^:*/,''); _templ = [ - 'div|data-name='+(opts.name||''), + 'div|data-name='+opts.name, { className: opts.className }, [].concat(content, spawn('br.clear')) ]; @@ -238,22 +239,36 @@ var XNAT = getObject(XNAT); // add value to [data-value] attribute // (except for textareas - that could get ugly) - if (isArray(element.value) || stringable(element.value)) { - $element.not('textarea').dataAttr('value', element.value); + if (!/textarea/i.test(element.tagName)){ + if (isArray(element.value) || stringable(element.value)) { + $element.dataAttr('value', element.value); + } } var inner = []; // add 'before' content before the core element if (opts.beforeElement) { - opts.beforeElement = stringable(opts.beforeElement) ? [opts.beforeElement] : + opts.beforeElement = stringable(opts.beforeElement) ? [opts.beforeElement] : ''; inner.push(spawn('span.before', opts.beforeElement)); } - inner.push(element); + + // special stuff for switchbox elements + if (/switchbox/i.test(opts.kind)) { + inner.push(spawn('label.switchbox', [ + element, + ['span.switchbox-outer', [['span.switchbox-inner']]] + ])) + } + else { + inner.push(element); + } + // add 'after' content after the core element if (opts.afterElement) { + opts.afterElement = stringable(opts.afterElement) ? [opts.afterElement] : ''; inner.push(spawn('span.after', opts.afterElement)); } diff --git a/src/main/webapp/style/app.css b/src/main/webapp/style/app.css index 989d14e3..33d385a3 100644 --- a/src/main/webapp/style/app.css +++ b/src/main/webapp/style/app.css @@ -286,7 +286,7 @@ div.containerTitle { } div.containerBody { - overflow: auto; + /*overflow: auto;*/ font-size: 12px; line-height: 15px; padding: 0; @@ -324,7 +324,8 @@ div.mainContainerBody { div.containerItem { /* font-size: 11px ; line-height: 13px ; */ - padding: /* 3px 0 0 3px */ 8px 12px 0 12px; + /*padding: !* 3px 0 0 3px *! 8px 12px 0 12px;*/ + margin: 15px; } div.projectIndex { @@ -1120,6 +1121,11 @@ select[multiple] { max-width: 200px; } +/* Chosen menu overrides */ +body.xnat .chosen-container { + font-size: 12px; +} + /* page layout styles */ #page_wrapper { width: 1160px; @@ -1954,7 +1960,7 @@ span.noteOptional { } input.requiredField { - padding: 3px 5px 2px 4px; + /*padding: 3px 5px 2px 4px;*/ border: 1px solid #cc0000; } @@ -1976,6 +1982,11 @@ div.icon-remove { input.invalid { background: #ffc; + border: 1px solid #c00; +} + +input.required.invalid { + background: #fcc; } .summary h3 { @@ -2103,7 +2114,7 @@ input.invalid { /* ADD/EDIT PROJECT FORM */ #new-project-form, #edit-project-form { - /* width: 760px; */ + width: 960px; margin: 0 auto; } @@ -3178,6 +3189,43 @@ label.search-method-label { white-space: nowrap; } +/* "switch" checkbox widgets - pure css */ +label.switchbox > input { display: none; } + +label.switchbox > input + .switchbox-outer { + display: inline-block; + width: 32px; + height: 16px; + background: #c00; + position: relative; + border-radius: 3px; + border: 1px solid #a0a0a0; + box-shadow: inset 0 0 5px rgba(0,0,0,0.3); +} + +label.switchbox > input + .switchbox-outer > .switchbox-inner { + display: inline-block; + width: 16px; + height: 16px; + background: #fff; + border: none; + position: absolute; + right: auto; + top: 0; + border-radius: 1px; + left: 0; + box-shadow: 0 0 3px rgba(0,0,0,0.3); +} + +label.switchbox > input:checked + .switchbox-outer { + background: #0a0; +} + +label.switchbox > input:checked + .switchbox-outer > .switchbox-inner { + right: 0; left: auto; +} + + /* friendlyForm styles. Taken from ConnectomeDB. To be refactored / replaced in XNAT 1.7, most likely */ fieldset, .friendlyForm fieldset { -- GitLab