Skip to content

Commit a56645b

Browse files
author
graeme
committed
varous fixes to tag libraries, added tree widget, and adaptive ajax tags that use different ajax implementations (yahoo or prototype at the moment)
git-svn-id: https://svn.codehaus.org/grails/trunk@822 1cfb16fd-6d17-0410-8ff1-b7e8e1e2867d
1 parent c00a986 commit a56645b

File tree

2 files changed

+373
-58
lines changed

2 files changed

+373
-58
lines changed

src/grails/grails-app/taglib/JavascriptTagLib.groovy

Lines changed: 250 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -25,61 +25,178 @@ import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
2525
*/
2626
class 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

Comments
 (0)