Changeset 1286
- Timestamp:
- Dec 21, 2010, 12:04:37 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 44 added
- 5 deleted
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy
r1224 r1286 1 1 package dbnp.studycapturing 2 2 3 import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLib4 3 import dbnp.studycapturing.* 5 4 import dbnp.authentication.SecUser 6 5 import dbnp.data.* 7 6 import cr.co.arquetipos.crypto.Blowfish 7 import nl.grails.plugins.ajaxflow.AjaxflowTagLib 8 8 9 9 /** … … 19 19 * $Date$ 20 20 */ 21 class WizardTagLib extends JavascriptTagLib {21 class WizardTagLib extends AjaxflowTagLib { 22 22 def AuthenticationService 23 23 … … 25 25 static namespace = "wizard" 26 26 27 // define the AJAX provider to use28 static ajaxProvider = "jquery"29 30 27 // define default text field width 31 28 static defaultTextFieldSize = 25; 32 33 /**34 * ajaxButton tag, this is a modified version of the default35 * grails submitToRemote tag to work with grails webflows.36 * Usage is identical to submitToRemote with the only exception37 * that a 'name' form element attribute is required. E.g.38 * <wizard:ajaxButton name="myAction" value="myButton ... />39 *40 * you can also provide a javascript function to execute after41 * success. This behaviour differs from the default 'after'42 * action which always fires after a button press...43 *44 * @see http://blog.osx.eu/2010/01/18/ajaxifying-a-grails-webflow/45 * @see http://www.grails.org/WebFlow46 * @see http://www.grails.org/Tag+-+submitToRemote47 * @todo perhaps some methods should be moved to a more generic48 * 'webflow' taglib or plugin49 * @param Map attributes50 * @param Closure body51 */52 def ajaxButton = { attrs, body ->53 // get the jQuery version54 def jQueryVersion = grailsApplication.getMetadata()['plugins.jquery']55 56 // fetch the element name from the attributes57 def elementName = attrs['name'].replaceAll(/ /, "_")58 59 // javascript function to call after success60 def afterSuccess = attrs['afterSuccess']61 62 // src parameter?63 def src = attrs['src']64 def alt = attrs['alt']65 66 // generate a normal submitToRemote button67 def button = submitToRemote(attrs, body)68 69 /**70 * as of now (grails 1.2.0 and jQuery 1.3.2.4) the grails webflow does71 * not properly work with AJAX as the submitToRemote button does not72 * handle and submit the form properly. In order to support webflows73 * this method modifies two parts of a 'normal' submitToRemote button:74 *75 * 1) replace 'this' with 'this.form' as the 'this' selector in a button76 * action refers to the button and / or the action upon that button.77 * However, it should point to the form the button is part of as the78 * the button should submit the form data.79 * 2) prepend the button name to the serialized data. The default behaviour80 * of submitToRemote is to remove the element name altogether, while81 * the grails webflow expects a parameter _eventId_BUTTONNAME to execute82 * the appropriate webflow action. Hence, we are going to prepend the83 * serialized formdata with an _eventId_BUTTONNAME parameter.84 */85 if (jQueryVersion =~ /^1.([1|2|3]).(.*)/) {86 // fix for older jQuery plugin versions87 button = button.replaceFirst(/data\:jQuery\(this\)\.serialize\(\)/, "data:\'_eventId_${elementName}=1&\'+jQuery(this.form).serialize()")88 } else {89 // as of jQuery plugin version 1.4.0.1 submitToRemote has been modified and the90 // this.form part has been fixed. Consequently, our wrapper has changed as well...91 button = button.replaceFirst(/data\:jQuery/, "data:\'_eventId_${elementName}=1&\'+jQuery")92 }93 94 // add an after success function call?95 // usefull for performing actions on success data (hence on refreshed96 // wizard pages, such as attaching tooltips)97 if (afterSuccess) {98 button = button.replaceFirst(/\.html\(data\)\;/, '.html(data);' + afterSuccess + ';')99 }100 101 // got an src parameter?102 if (src) {103 def replace = 'type="image" src="' + src + '"'104 105 if (alt) replace = replace + ' alt="' + alt + '"'106 107 button = button.replaceFirst(/type="button"/, replace)108 }109 110 // replace double semi colons111 button = button.replaceAll(/;{2,}/, ';')112 113 // render button114 out << button115 }116 117 /**118 * generate a ajax submit JavaScript119 * @see WizardTagLib::ajaxFlowRedirect120 * @see WizardTagLib::baseElement (ajaxSubmitOnChange)121 */122 def ajaxSubmitJs = { attrs, body ->123 // define AJAX provider124 setProvider([library: ajaxProvider])125 126 // got a function name?127 def functionName = attrs.remove('functionName')128 if (functionName && !attrs.get('name')) {129 attrs.name = functionName130 }131 132 // generate an ajax button133 def button = this.ajaxButton(attrs, body)134 135 // strip the button part to only leave the Ajax call136 button = button.replaceFirst(/<[^\"]*onclick=\"/, '')137 button = button.replaceFirst(/return false.*/, '')138 139 // change form if a form attribute is present140 if (attrs.get('form')) {141 button = button.replace(142 "jQuery(this).parents('form:first')",143 "\$('" + attrs.get('form') + "')"144 )145 }146 147 // change 'this' if a this attribute is preset148 if (attrs.get('this')) {149 button = button.replace('this', attrs.get('this'))150 }151 152 out << button153 }154 155 /**156 * generate ajax webflow redirect javascript157 *158 * As we have an Ajaxified webflow, the initial wizard page159 * cannot contain a wizard form, as upon a failing submit160 * (e.g. the form data does not validate) the form should be161 * shown again. However, the Grails webflow then renders the162 * complete initial wizard page into the success div. As this163 * ruins the page layout (a page within a page) we want the164 * initial page to redirect to the first wizard form to enter165 * the webflow correctly. We do this by emulating an ajax post166 * call which updates the wizard content with the first wizard167 * form.168 *169 * Usage: <wizard:ajaxFlowRedirect form="form#wizardForm" name="next" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" />170 * form = the form identifier171 * name = the action to execute in the webflow172 * update = the divs to update upon success or error173 *174 * OR: to generate a JavaScript function you can call yourself, use 'functionName' instead of 'name'175 *176 * Example initial webflow action to work with this javascript:177 * ...178 * mainPage {179 * render(view: "/wizard/index")180 * onRender {181 * flow.page = 1182 * }183 * on("next").to "pageOne"184 * }185 * ...186 *187 * @param Map attributes188 * @param Closure body189 */190 def ajaxFlowRedirect = { attrs, body ->191 // generate javascript192 out << '<script type="text/javascript">'193 out << '$(document).ready(function() {'194 out << ajaxSubmitJs(attrs, body)195 out << '});'196 out << '</script>'197 }198 199 /**200 * render the content of a particular wizard page201 * @param Map attrs202 * @param Closure body (help text)203 */204 def pageContent = { attrs, body ->205 // define AJAX provider206 setProvider([library: ajaxProvider])207 208 // render new body content209 // - this JavaScript variable is used by baseElement to workaround an IE210 // specific issue (double submit on onchange events). The hell with IE!211 // @see baseElement212 out << '<script type="text/javascript">var lastRequestTime = 0;</script>'213 out << render(template: "/wizard/common/tabs")214 out << '<div class="content">'215 out << body()216 out << '</div>'217 out << render(template: "/wizard/common/navigation")218 out << render(template: "/wizard/common/error")219 }220 29 221 30 /** -
trunk/grails-app/views/common/_topnav.gsp
r1266 r1286 12 12 <li><g:link controller="study" action="list">View studies</g:link></li> 13 13 </sec:ifNotLoggedIn> 14 <li><g:link controller=" wizard" action="index" params="[jump:'create']">Create a new study</g:link></li>15 <li><g:link controller=" wizard" action="index" params="[jump:'edit']">Edit a study</g:link></li>14 <li><g:link controller="studyWizard" action="index" params="[jump:'create']">Create a new study</g:link></li> 15 <li><g:link controller="studyWizard" action="index" params="[jump:'edit']">Edit a study</g:link></li> 16 16 <li><g:link controller="importer" action="index">Import study data</g:link></li> 17 17 <li><g:link controller="simpleQuery" action="index">Search study data</g:link></li> -
trunk/grails-app/views/study/list.gsp
r1181 r1286 34 34 <td><input type="checkbox" name="id" value="${studyInstance.id}" id="${studyInstance.title}"></td> 35 35 <td><g:link action="show" id="${studyInstance?.id}"><img src='${fam.icon(name: 'application_form_magnify')}' border="0" alt="view study" /></g:link></td> 36 <td><g:if test="${studyInstance.canWrite(loggedInUser)}"><g:link class="edit" controller=" wizard" params="[jump:'edit']" id="${studyInstance?.id}"><img src='${fam.icon(name: 'application_form_edit')}' border="0" alt="edit study" /></g:link></g:if><g:else><img src='${fam.icon(name: 'lock')}' border="0" alt="you have no write access to shis study" /></g:else> </td>36 <td><g:if test="${studyInstance.canWrite(loggedInUser)}"><g:link class="edit" controller="studyWizard" params="[jump:'edit']" id="${studyInstance?.id}"><img src='${fam.icon(name: 'application_form_edit')}' border="0" alt="edit study" /></g:link></g:if><g:else><img src='${fam.icon(name: 'lock')}' border="0" alt="you have no write access to shis study" /></g:else> </td> 37 37 <td>${fieldValue(bean: studyInstance, field: "code")}</td> 38 38 <td> … … 77 77 <div class="buttons"> 78 78 <sec:ifLoggedIn> 79 <span class="button"><g:link class="create" controller=" wizard" params="[jump:'create']"><g:message code="default.new.label" args="[entityName]"/></g:link></span>79 <span class="button"><g:link class="create" controller="studyWizard" params="[jump:'create']"><g:message code="default.new.label" args="[entityName]"/></g:link></span> 80 80 </sec:ifLoggedIn> 81 81 </div> -
trunk/grails-app/views/study/show.gsp
r1266 r1286 216 216 <g:hiddenField name="id" value="${studyInstance?.id}"/> 217 217 <g:if test="${studyInstance.canWrite(loggedInUser)}"> 218 <span class="button"><g:link class="edit" controller=" wizard" params="[jump:'edit']" id="${studyInstance?.id}">${message(code: 'default.button.edit.label', default: 'Edit')}</g:link></span>218 <span class="button"><g:link class="edit" controller="studyWizard" params="[jump:'edit']" id="${studyInstance?.id}">${message(code: 'default.button.edit.label', default: 'Edit')}</g:link></span> 219 219 </g:if> 220 220 <g:if test="${studyInstance.isOwner(loggedInUser)}"> -
trunk/web-app/css/default_style.css
r1266 r1286 11 11 text-decoration: none; 12 12 }*/ 13 13 14 h1 { 14 15 color: #006dba; -
trunk/web-app/css/importer.css
r1277 r1286 1 1 /** 2 * ajaxflowcss2 * importer specific css 3 3 * 4 4 * @author Jeroen Wesbeek … … 10 10 * $Date$ 11 11 */ 12 13 /** START :: AJAX FLOW **/14 .ajaxFlow {15 width: 100%;16 }17 .ajaxFlow h1 {18 color: #006DBA;19 font-weight: bold;20 font-size: 18px;21 padding-bottom: 10px;22 }23 .ajaxFlowError {24 width: 97.5%;25 border: 1px dotted red;26 padding: 10px 10px 10px 10px;27 }28 29 /** START :: TABS **/30 .tabs {31 display: block;32 padding-bottom: 2px;33 border-bottom: 2px solid #006DBA;34 width: 100%;35 }36 .tabs ul {37 list-style-type: none; /* suppression of useless elements */38 padding: 0px;39 font-size: 10px;40 margin: 0px;41 font-family: Verdana, Arial, Helvetica, sans-serif;42 font-size: 10px;43 height: 20px;44 width: 100%;45 }46 .tabs li {47 float: left;48 margin: 0px;49 height: 20px;50 float: left;51 display: block;52 text-align: center;53 text-decoration: none;54 color: #006DBA;55 background: #CCC;56 font-weight: bold;57 }58 .tabs li input {59 cursor: pointer;60 color: #006DBA;61 background-color: transparent;62 border: none;63 }64 .tabs li:last-child:after {65 content: url('../images/importer/spacer.gif');66 }67 .tabs li:first-child:before {68 content: url('../images/importer/spacer.gif');69 }70 .tabs li:before {71 content:url(../images/importer/arrowR.gif);72 position:inherit;73 margin-top: 0px;74 margin-bottom: 0px;75 display:inline;76 }77 .tabs li:after {78 content:url(../images/importer/arrowL.gif);79 position:inherit;80 margin-top: 0px;81 margin-bottom: 0px;82 display:inline;83 }84 .tabs .content {85 padding: 0px 10px 0px 10px;86 display: inline;87 border: 0px;88 vertical-align: top;89 line-height: 20px;90 }91 .tabs .active {92 background-color: #006DBA !important;93 color: #fff !important;94 text-shadow: 0px 0px 1px #333;95 }96 97 /** START NAVIGATION **/98 .navigation {99 display: block;100 padding-top: 2px;101 border-top: 2px solid #006DBA;102 width: 100%;103 color: #666666;104 font-size: 10px;105 }106 107 .navigation .prevnext {108 cursor: pointer;109 color: #006DBA;110 background-color: transparent;111 border: none;112 }113 114 /** CONTENT STYLES **/115 .content {116 padding: 20px 0px 20px 0px;117 }118 119 .content h1 {120 color: #006DBA;121 font-weight: bold;122 font-size: 18px;123 }124 .content p {125 text-align: justify;126 padding: 10px 0px 10px 0px;127 }128 129 .content a, .content a:visited {130 color: red;131 text-decoration: none;132 }133 134 12 .header 135 13 {
Note: See TracChangeset
for help on using the changeset viewer.