Ignore:
Timestamp:
Jan 20, 2010, 5:01:26 PM (11 years ago)
Author:
duh
Message:
  • refactored the wizard initial page to dynamically load pageOne, instead of rendering pageOne within the template itself. This was done because otherwise both the mainPage and pageOne had to contain duplicate logic. The ajaxified webflow works better this way.
  • added an <wizard:ajaxFlowRedirect...> tag which renders javascript code executing a jQuery ajax call (it actually wraps around <wizard:button...> tag but lifts the ajax call out of the button and wraps javascript tags around it)
  • improved the help / tooltip workings
  • extended the <wizard:button...> with an afterSuccess argument which executes some javascript after success. This is different from the default submitToRemote 'after' behaviour which is always executed in parallel with the ajax success call (hence, you javascript cannot access ajax result data while the afterSuccess method can)
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy

    r99 r101  
    3232         * <wizard:ajaxButton name="myAction" value="myButton ... />
    3333         *
     34         * you can also provide a javascript function to execute after
     35         * success. This behaviour differs from the default 'after'
     36         * action which always fires after a button press...
     37         *
    3438         * @see http://blog.osx.eu/2010/01/18/ajaxifying-a-grails-webflow/
    3539         * @see http://www.grails.org/WebFlow
     
    4044         * @param Closure body
    4145         */
    42         def ajaxButton = {attrs, body ->
     46        def ajaxButton = { attrs, body ->
    4347                // get the jQuery version
    4448                def jQueryVersion = grailsApplication.getMetadata()['plugins.jquery']
     
    4650                // fetch the element name from the attributes
    4751                def elementName = attrs['name'].replaceAll(/ /, "_")
     52
     53                // javascript function to call after success
     54                def afterSuccess = attrs['afterSuccess']
    4855
    4956                // generate a normal submitToRemote button
     
    7481                        button = button.replaceFirst(/data\:jQuery/, "data:\'_eventId_${elementName}=1&\'+jQuery")
    7582                }
    76 
     83 
     84                // add an after success function call?
     85                // usefull for performing actions on success data (hence on refreshed
     86                // wizard pages, such as attaching tooltips)
     87                if (afterSuccess) {
     88                        button = button.replaceFirst(/\.html\(data\)\;/, '.html(data);' + afterSuccess + ';')
     89                }
     90
     91                // replace double semi colons
     92                button = button.replaceAll(/;{2,}/, '!!!')
     93               
    7794                // render button
    7895                out << button
     96        }
     97
     98        /**
     99         * generate ajax webflow redirect javascript
     100         *
     101         * As we have an Ajaxified webflow, the initial wizard page
     102         * cannot contain a wizard form, as upon a failing submit
     103         * (e.g. the form data does not validate) the form should be
     104         * shown again. However, the Grails webflow then renders the
     105         * complete initial wizard page into the success div. As this
     106         * ruins the page layout (a page within a page) we want the
     107         * initial page to redirect to the first wizard form to enter
     108         * the webflow correctly. We do this by emulating an ajax post
     109         * call which updates the wizard content with the first wizard
     110         * form.
     111         *
     112         * Usage: <wizard:ajaxFlowRedirect form="form#wizardForm" name="next" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" />
     113         * form = the form identifier
     114         * name = the action to execute in the webflow
     115         * update = the divs to update upon success or error
     116         *
     117         * Example initial webflow action to work with this javascript:
     118         * ...
     119         * mainPage {
     120         *      render(view: "/wizard/index")
     121         *      onRender {
     122         *              flow.page = 1
     123         *      }
     124         *      on("next").to "pageOne"
     125         * }
     126         * ...
     127         *
     128         * @param Map attributes
     129         * @param Closure body
     130         */
     131        def ajaxFlowRedirect = { attrs, body ->
     132                // define AJAX provider
     133                setProvider([library: ajaxProvider])
     134
     135                // generate an ajax button
     136                def button = this.ajaxButton(attrs, body)
     137
     138                // strip the button part to only leave the Ajax call
     139                button = button.replaceFirst(/<[^\"]*\"jQuery.ajax/,'jQuery.ajax')
     140                button = button.replaceFirst(/return false.*/,'')
     141
     142                // change form if a form attribute is present
     143                if (attrs.get('form')) {
     144                        button = button.replaceFirst(/this\.form/,
     145                                "\\\$('" + attrs.get('form') + "')"
     146                        )
     147                }
     148
     149                // generate javascript
     150                out << '<script language="JavaScript">'
     151                out << '$(document).ready(function() {'
     152                out << button
     153                out << '});'
     154                out << '</script>'
    79155        }
    80156
     
    124200                out << '<div class="element">'
    125201                out << ' <div class="description">'
    126                 out << body()
     202                out << attrs.get('description')
    127203                out << ' </div>'
    128204                out << ' <div class="input">'
     
    131207
    132208                // add help icon?
    133                 if (attrs.get('help')) {
     209                if (body()) {
    134210                        out << ' <div class="help">'
    135211                        out << '  <div class="icon"></div>'
    136212                        out << '  <div class="content">'
    137                         out << '    ' + attrs.get('help')
     213                        out << '    ' + body()
    138214                        out << '  </div>'
    139215                        out << ' </div>'
Note: See TracChangeset for help on using the changeset viewer.