@@ -25,61 +25,178 @@ import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
2525 */
2626class JavascriptTagLib extends ApplicationTagLib {
2727
28+ /**
29+ * Mappings to the relevant files to be included for each library
30+ */
31+ static final INCLUDED_LIBRARIES = " org.codehaus.grails.INCLUDED_JS_LIBRARIES"
32+ static final INCLUDED_JS = " org.codehaus.grails.INCLUDED_JS"
33+ static final LIBRARY_MAPPINGS = [
34+ prototype : [' prototype' ],
35+ yahoo : [ ' YAHOO' ,' connect' , ' dom' ,' event' ,' animation' ]
36+ ]
37+
38+ static {
39+ LIBRARY_MAPPINGS . scriptaculous = LIBRARY_MAPPINGS . prototype + [' scriptaculous' ,' builder' ,' controls' ,' effects' ,' slider' ,' draganddrop' ]
40+ LIBRARY_MAPPINGS . rico = LIBRARY_MAPPINGS . prototype + [' rico' ]
41+ }
42+ /**
43+ * Includes a javascript src file, library or inline script
44+ **/
45+ @Property javascript = { attrs , body ->
46+ if (! request[INCLUDED_JS ]) request[INCLUDED_JS ] = []
47+ if (! request[INCLUDED_LIBRARIES ]) request[INCLUDED_LIBRARIES ] = []
48+
49+ if (attrs. src) {
50+ out << ' <script type="text/javascript" src="'
51+ out << grailsAttributes. getApplicationUri(request)
52+ out << " /js/${ attrs.src} "
53+ out. println ' "></script>'
54+ }
55+ else if (attrs. library) {
56+
57+ if (LIBRARY_MAPPINGS . containsKey(attrs. library)) {
58+ if (! request[INCLUDED_LIBRARIES ]. contains(attrs. library)) {
59+ LIBRARY_MAPPINGS [attrs. library]. each {
60+ if (! request[INCLUDED_JS ]. contains(it)) {
61+ request[INCLUDED_JS ] << it
62+ out << ' <script type="text/javascript" src="'
63+ out << grailsAttributes. getApplicationUri(request)
64+ out << " /js/${ it} .js"
65+ out. println ' "></script>'
66+ }
67+ }
68+ request[INCLUDED_LIBRARIES ] << attrs. library
69+ }
70+ }
71+ else {
72+ if (! request[INCLUDED_LIBRARIES ]. contains(attrs. library)) {
73+ out << ' <script type="text/javascript" src="'
74+ out << grailsAttributes. getApplicationUri(request)
75+ out << " /js/${ attrs.library} .js"
76+ out. println ' "></script>'
77+ request[INCLUDED_LIBRARIES ] << attrs. library
78+ request[INCLUDED_JS ] << attrs. library
79+ }
80+ }
81+ }
82+ else {
83+ out. println ' <script type="text/javascript">'
84+ body()
85+ out. println ' </script>'
86+ }
87+ }
2888 /**
2989 * Creates a remote function call using the prototype library
3090 */
31- @Property remoteFunction = { attrs ->
32- // before remote function
33- def after = ' '
34- if (attrs[" before" ])
35- out << " ${ attrs.remove('before')} ;"
36- if (attrs[" after" ])
37- after = " ${ attrs.remove('after')} ;"
38-
39- out << ' new Ajax.'
40- if (attrs[" update" ]) {
41- out << ' Updater('
42- if (attrs[" update" ] instanceof Map ) {
43- out << " {"
44- def update = []
45- if (attrs[" update" ][" success" ]) {
46- update << " success:'${ attrs['update']['success']} '"
47- }
48- if (attrs[" update" ][" failure" ]) {
49- update << " failure:'${ attrs['update']['failure']} '"
50- }
51- out << update. join(' ,' )
52- out << " },"
53- }
54- else {
55- out << " '" << attrs[" update" ] << " ',"
56- }
57- attrs. remove(" update" )
58- }
59- else {
60- out << " Request("
61- }
62-
63- out << " '"
64- if (attrs[' url' ]) {
65- createLink(attrs[' url' ])
66- }
67- else {
68- createLink(attrs)
69- }
70-
71- out << " ',"
91+ @Property remoteFunction = { attrs ->
92+ def isPrototype = request[JavascriptTagLib . INCLUDED_LIBRARIES ]. contains(' prototype' );
93+ def isYahoo = request[JavascriptTagLib . INCLUDED_LIBRARIES ]. contains(' yahoo' );
94+
95+ if (! request[JavascriptTagLib . INCLUDED_LIBRARIES ] || (! isYahoo && ! isPrototype)) {
96+ out << ' function() { alert("Grails Message: The remoteFunction tag requires the \' prototype\' or \' yahoo\' libraries to be included with the <g:javascript library=\' prototype\' /> tag"); }'
97+ }
98+ else {
99+ // before remote function
100+ def after = ' '
101+ if (attrs[" before" ])
102+ out << " ${ attrs.remove('before')} ;"
103+ if (attrs[" after" ])
104+ after = " ${ attrs.remove('after')} ;"
105+
106+ // if the prototype library is included use it
107+ if (isPrototype) {
108+ out << ' new Ajax.'
109+ if (attrs[" update" ]) {
110+ out << ' Updater('
111+ if (attrs[" update" ] instanceof Map ) {
112+ out << " {"
113+ def update = []
114+ if (attrs[" update" ][" success" ]) {
115+ update << " success:'${ attrs['update']['success']} '"
116+ }
117+ if (attrs[" update" ][" failure" ]) {
118+ update << " failure:'${ attrs['update']['failure']} '"
119+ }
120+ out << update. join(' ,' )
121+ out << " },"
122+ }
123+ else {
124+ out << " '" << attrs[" update" ] << " ',"
125+ }
126+ attrs. remove(" update" )
127+ }
128+ else {
129+ out << " Request("
130+ }
131+ out << " '"
132+ }
133+ // otherwise try yahoo
134+ else if (isYahoo) {
135+ out. println ' function() {'
136+ buildYahooCallback(attrs)
137+ def method = (attrs. method ? attrs. method : ' POST' )
138+ out << " YAHOO.util.Connect.asyncRequest('${ method} ','"
139+ }
140+
72141
73- // process options
74- out << getAjaxOptions(attrs)
75- // close
76- out << ' );'
142+ if (attrs[' url' ]) {
143+ createLink(attrs[' url' ])
144+ }
145+ else {
146+ createLink(attrs)
147+ }
148+
149+ if (isPrototype) {
150+ out << " ',"
151+
152+ // process options
153+ out << getAjaxOptions(attrs)
154+ // close
155+ out << ' );'
156+ }
157+ else if (isYahoo) {
158+ out << " ',callback,null); }"
159+ }
160+
161+ // after remote function
162+ if (after)
163+ out << after
164+ }
77165
78- // after remote function
79- if (after)
80- out << after
81166 }
82167
168+ // helper method to create yahoo callback object
169+ def buildYahooCallback (attrs ) {
170+ out. println ''' var callback = {
171+ success: function(o) {'''
172+ if (attrs. update) {
173+ if (attrs. update instanceof Map ) {
174+ if (attrs. update. sucess) {
175+ out. println " document.getElementById('${ attrs.update.success} ').innerHTML = o.responseText;"
176+ }
177+ }
178+ else {
179+ out. println " document.getElementById('${ attrs.update} ').innerHTML = o.responseText;"
180+ }
181+ }
182+ if (attrs. onSuccess) {
183+ out. println " ${ attrs.onSuccess} (o);"
184+ }
185+
186+ out << ''' },
187+ failure: function(o) {'''
188+ if (attrs. update && attrs. update. failure) {
189+ out. println " document.getElementById('${ attrs.update.failure} ').innerHTML = o.responseText;"
190+ }
191+ if (attrs. onFailure) {
192+ out. println " ${ attrs.onFailure} (o);"
193+ }
194+ out. println ' }'
195+ if (attrs. params) {
196+ // todo add arguments
197+ }
198+ out. println ' }'
199+ }
83200 // helper function to build ajax options
84201 def getAjaxOptions (options ) {
85202 def ajaxOptions = []
@@ -106,7 +223,7 @@ class JavascriptTagLib extends ApplicationTagLib {
106223 else
107224 ajaxOptions << " evalScripts:true"
108225
109- if (options[' parameters ' ]) {
226+ if (options[' params ' ]) {
110227 ajaxOptions << " parameters:${ options.remove('parameters')} "
111228 }
112229 // remaining options
@@ -152,17 +269,92 @@ class JavascriptTagLib extends ApplicationTagLib {
152269 * A form which used prototype to serialize its parameters and submit via an asynchronous ajax call
153270 */
154271 @Property formRemote = { attrs , body ->
155- attrs[' parameters' ] = " Form.serialize(this)"
156- out << ' <form onsubmit="' << remoteFunction(attrs) << ' ;return false;" '
157- out << ' method="' << (attrs[' method' ] ? attrs[' method' ] : ' post' ) << ' " '
158- out << ' action="' << (attrs[' action' ] ? attrs[' action' ] : createLink(attrs[' url' ])) << ' ">'
159-
160- // output body
161- body()
162- // close tag
163- out << ' </form>'
272+ def isPrototype = request[JavascriptTagLib . INCLUDED_LIBRARIES ]. contains(' prototype' );
273+ def isYahoo = request[JavascriptTagLib . INCLUDED_LIBRARIES ]. contains(' yahoo' );
274+
275+ if (! request[JavascriptTagLib . INCLUDED_LIBRARIES ] || (! isYahoo && ! isPrototype)) {
276+ out << ' function() { alert("Grails Message: The remoteFunction tag requires the \' prototype\' or \' yahoo\' libraries to be included with the <g:javascript library=\' prototype\' /> tag"); }'
277+ }
278+ else {
279+ if (isPrototype) {
280+ attrs[' parameters' ] = " Form.serialize(this)"
281+ out << ' <form onsubmit="' << remoteFunction(attrs) << ' ;return false;" '
282+ out << ' method="' << (attrs[' method' ] ? attrs[' method' ] : ' post' ) << ' " '
283+ out << ' action="' << (attrs[' action' ] ? attrs[' action' ] : createLink(attrs[' url' ])) << ' ">'
284+
285+ // output body
286+ body()
287+ // close tag
288+ out << ' </form>'
289+ }
290+ else if (isYahoo) {
291+ def url = outToString(createLink,attrs)
292+ def onsubmit = []
293+ if (attrs. before) {
294+ onsubmit << attrs. before
295+ }
296+ onsubmit << " ${ attrs.name} RemoteFunction()"
297+ if (attrs. after) {
298+ onsubmit << attrs. after
299+ }
300+ onsubmit << " return false;"
301+
302+ withTag(name :' form' ,
303+ attrs : [ name : attrs. name,
304+ onsubmit : onsubmit. join(' ;' ),
305+ method : (attrs. method ? attrs. method : ' post' ),
306+ action : (attrs. action ? attrs. action : url)
307+ ] ) {
308+ body()
309+ }
310+ withTag(name :' script' ,attrs :[type :' text/javascript' ]) {
311+ out << """
312+ function ${ attrs.name} RemoteFunction() {
313+ YAHOO.util.Connect.setForm('${ attrs.name} ');"""
314+ buildYahooCallback(attrs)
315+ out << " var cObj = YAHOO.util.Connect.asyncRequest('POST', '$url ', callback);}"
316+ }
317+ }
318+ }
164319 }
165320
321+ /**
322+ * Helper method for outputting to a string instead of the the output write
323+ */
324+ def outToString (tag ,attrs ) {
325+ def saveOut = out
326+ def sw = new StringWriter ()
327+ def result = null
328+ try {
329+ this . out = new PrintWriter (sw)
330+ tag(attrs)
331+ }
332+ finally {
333+ out = saveOut;
334+ }
335+ return sw. toString()
336+ }
337+ /**
338+ * Helper method for creating tags
339+ */
340+ def withTag = { params , body ->
341+ out << " <${ params.name} "
342+ if (params. attrs) {
343+ params. attrs. each{ k ,v ->
344+ if (v instanceof Closure ) {
345+ out << " $k =\" "
346+ v()
347+ out << ' "'
348+ }
349+ else {
350+ out << " $k =\" $v \" "
351+ }
352+ }
353+ }
354+ out << ' >'
355+ body()
356+ out << " </${ params.name} >"
357+ }
166358 /**
167359 * Creates a form submit button that submits the current form to a remote ajax call
168360 */
0 commit comments