source: trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy @ 96

Last change on this file since 96 was 96, checked in by duh, 10 years ago
  • as of jQuery 1.4.0.1 the submitToRemote behaviour has changed which broke the taglibrary functionality. The taglibrary now checks for the jQuery plugin version in order to fix the issue and stay backward compatible
  • Property svn:keywords set to Rev Author Date
File size: 4.5 KB
Line 
1package dbnp.studycapturing
2
3import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLib
4
5/**
6 * Wizard tag library
7 *
8 * @author Jeroen Wesbeek
9 * @since 20100113
10 * @package wizard
11 *
12 * Revision information:
13 * $Rev: 96 $
14 * $Author: duh $
15 * $Date: 2010-01-19 15:18:33 +0000 (di, 19 jan 2010) $
16 */
17class WizardTagLib extends JavascriptTagLib {
18        // define the tag namespace (e.g.: <wizard:action ... />
19        static namespace = "wizard"
20
21        // define the AJAX provider to use
22        static ajaxProvider = "jquery"
23
24        // define default text field width
25        static defaultTextFieldSize = 25;
26
27        /**
28         * ajaxButton tag, this is a modified version of the default
29         * grails submitToRemote tag to work with grails webflows.
30         * Usage is identical to submitToRemote with the only exception
31         * that a 'name' form element attribute is required. E.g.
32         * <wizard:ajaxButton name="myAction" value="myButton ... />
33         *
34         * @see http://blog.osx.eu/2010/01/18/ajaxifying-a-grails-webflow/
35         * @see http://www.grails.org/WebFlow
36         * @see http://www.grails.org/Tag+-+submitToRemote
37         * @todo perhaps some methods should be moved to a more generic
38         *        'webflow' taglib
39         * @param Map attributes
40         * @param Closure body
41         */
42        def ajaxButton = {attrs, body ->
43                // get the jQuery version
44                def jQueryVersion = grailsApplication.getMetadata()['plugins.jquery']
45
46                // fetch the element name from the attributes
47                def elementName = attrs['name'].replaceAll(/ /, "_")
48
49                // generate a normal submitToRemote button
50                def button = submitToRemote(attrs, body)
51
52                /**
53                 * as of now (grails 1.2.0 and jQuery 1.3.2.4) the grails webflow does
54                 * not properly work with AJAX as the submitToRemote button does not
55                 * handle and submit the form properly. In order to support webflows
56                 * this method modifies two parts of a 'normal' submitToRemote button:
57                 *
58                 * 1) replace 'this' with 'this.form' as the 'this' selector in a button
59                 *    action refers to the button and / or the action upon that button.
60                 *    However, it should point to the form the button is part of as the
61                 *    the button should submit the form data.
62                 * 2) prepend the button name to the serialized data. The default behaviour
63                 *    of submitToRemote is to remove the element name altogether, while
64                 *    the grails webflow expects a parameter _eventId_BUTTONNAME to execute
65                 *    the appropriate webflow action. Hence, we are going to prepend the
66                 *    serialized formdata with an _eventId_BUTTONNAME parameter.
67                 */
68                if (jQueryVersion =~ /^1.([1|2|3]).(.*)/) {
69                        // fix for older jQuery plugin versions
70                        button = button.replaceFirst(/data\:jQuery\(this\)\.serialize\(\)/, "data:\'_eventId_${elementName}=1&\'+jQuery(this.form).serialize()")
71                } else {
72                        // as of jQuery plugin version 1.4.0.1 submitToRemote has been modified and the
73                        // this.form part has been fixed. Consequently, our wrapper has changed as well...
74                        button = button.replaceFirst(/data\:jQuery/, "data:\'_eventId_${elementName}=1&\'+jQuery")
75                }
76
77                // render button
78                out << button
79        }
80
81        /**
82         * wizard navigation buttons render wrapper, in order to be able to add
83         * functionality in the future
84         */
85        def previousNext = {attrs ->
86                // define AJAX provider
87                setProvider([library: ajaxProvider])
88
89                // render navigation buttons
90                out << render(template: "/wizard/common/buttons")
91        }
92
93        /**
94         * render the content of a particular wizard page
95         * @param Map attrs
96         * @param Closure body
97         */
98        def pageContent = {attrs, body ->
99                // define AJAX provider
100                setProvider([library: ajaxProvider])
101
102                // render new body content
103                out << render(template: "/wizard/common/tabs")
104                out << '<div class="content">'
105                out << body()
106                out << '</div>'
107                out << render(template: "/wizard/common/navigation")
108        }
109
110        def textFieldElement = {attrs, body ->
111                // set default size, or scale to max length if it is less than the default size
112                if (!attrs.get("size")) {
113                        if (attrs.get("maxlength")) {
114                                attrs.size = ((attrs.get("maxlength") as int) > defaultTextFieldSize) ? defaultTextFieldSize : attrs.get("maxlength")
115                        } else {
116                                attrs.size = defaultTextFieldSize
117                        }
118                }
119
120                // render a text element
121                out << '<div class="element">'
122                out << ' <div class="description">'
123                out << body()
124                out << ' </div>'
125                out << ' <div class="input">'
126                out << textField(attrs)
127                out << ' </div>'
128
129                // add help icon?
130                if (attrs.get('help')) {
131                        out << ' <div class="help">'
132                        out << '  <div class="icon"><img src="../images/icons/famfamfam/help.png"></div>'
133                        out << '  <div class="content">'
134                        out << '   <div class="text">'
135                        out << '    ' + attrs.get('help')
136                        out << '   </div>'
137                        out << '  </div>'
138                        out << ' </div>'
139                }
140
141                out << '</div>'
142        }
143}
Note: See TracBrowser for help on using the repository browser.