source: trunk/grails-app/taglib/CustomTagLib.groovy @ 667

Last change on this file since 667 was 667, checked in by gav, 14 years ago

New custom tag, jasperButtons .

File size: 9.2 KB
Line 
1
2/**
3* General use custom tags.
4* Some are taken from http://www.grails.org/Contribute+a+Tag#checkBoxList
5*/
6class CustomTagLib {
7    static namespace = 'custom'
8
9    def resources = { attrs ->
10        ///@todo: should include our javascript and do setup here.
11    }
12
13    /**
14    * Checkbox list that can be used as a more user-friendly alternative to a multiselect list box.
15     * Usage:
16     * To map the selected ids to corresponding domain objects,
17     * an additional set method is required in the containing domain class:
18     *       //  This additional setter is used to convert the checkBoxList string or string array
19     *       //  of ids selected to the corresponding domain objects.
20     *       public void setAssetSubItemsFromCheckBoxList(ids) {
21     *           def idList = []
22     *           if(ids instanceof String) {
23     *                   if(ids.isInteger())
24     *                       idList << ids.toInteger()
25     *           }
26     *           else {
27     *               ids.each() {
28     *                   if(it.isInteger())
29     *                       idList << it.toInteger()
30     *               }
31     *           }
32     *           this.assetSubItems = idList.collect { AssetSubItem.get( it ) }
33     *       }
34     *
35     * Then a line in the controller:
36     *      assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)
37     *
38     * Fields:
39     *    name - the property name.
40     *    from - the list to select from.
41     *    value - the current value.
42     *    optionKey - the key to use.
43     *    sortBy - (optional) the attribute to sort the from list by.
44     *    displayFields - (optional) defaults to the objects toString()
45     *    displayFieldsSeparator - (optional) defaults to a space.
46     *    linkController - (optional, requires linkAction.) the controller to use for a link to the objects in the checkBoxList.
47     *    linkAction - (optional, requires linkController.) the action to use for a link to the objects in the checkBoxList.
48     *
49     * Example:
50     *    <!--
51     *    <custom:checkBoxList name="assetSubItems"
52     *                                    from="${AssetSubItem.list()}"
53     *                                    value="${assetInstance?.assetSubItems.collect{it.id}}"
54     *                                    optionKey="id"
55     *                                    sortBy="description"
56     *                                    displayFields="['id', 'name']"
57     *                                    displayFieldsSeparator=', '
58     *                                    linkController="assetSubItemDetailed"
59     *                                    linkAction="show"/>
60     *    -->
61     *
62     */
63
64    def checkBoxList = {attrs, body ->
65
66        def from = attrs.from
67        def value = attrs.value
68        def cname = attrs.name
69        def isChecked, ht, wd, style, html
70
71        def sortBy = attrs.sortBy
72        def displayFields = attrs.displayFields
73        def displayFieldsSeparator = attrs.displayFieldsSeparator ?: ' '
74        def linkController = attrs.linkController
75        def linkAction = attrs.linkAction
76
77        def displayValue = " "
78
79        // sets the style to override height and/or width if either of them
80        // is specified, else the default from the CSS is taken
81        style = "style='"
82        if(attrs.height)
83            style += "height:${attrs.height};"
84        if(attrs.width)
85            style += "width:${attrs.width};"
86        if(style.length() == "style='".length())
87            style = ""
88        else
89            style += "'" // closing single quote
90
91        html = "<ul class='CheckBoxList' " + style + ">"
92
93        out << html
94
95        if(sortBy)
96            from.sort { p1, p2 -> p1[sortBy].compareToIgnoreCase(p2[sortBy]) }
97
98        from.each { obj ->
99
100            displayValue = " "
101
102            if(linkController && linkAction)
103                   displayValue += "<a href=\"${createLink(controller: linkController, action: linkAction, id: obj.id).encodeAsHTML()}\">"
104
105            if(displayFields) {
106                displayValue += displayFields.collect { obj[it] }.join(displayFieldsSeparator)
107            }
108            else displayValue += obj // use the obj's default toString()
109
110            if(linkController && linkAction)
111                displayValue += "</a>"
112
113            // if we wanted to select the checkbox using a click anywhere on the label (also hover effect)
114            // but grails does not recognize index suffix in the name as an array:
115            // cname = "${attrs.name}[${idx++}]"
116            // and put this inside the li: <label for='$cname'>...</label>
117
118            isChecked = (value?.contains(obj."${attrs.optionKey}"))? true: false
119
120            out << "<li>" << checkBox(name:cname, value:obj."${attrs.optionKey}", checked: isChecked) << displayValue << "</li>"
121        }
122
123        out << "</ul>"
124
125    } // checkBoxList
126
127    def sortableColumnWithImg = { attrs, body ->
128        def writer = out
129        if(!attrs.property)
130            throwTagError("Tag [sortableColumn] is missing required attribute [property]")
131
132//         if(!attrs.title && !attrs.titleKey)
133//             throwTagError("Tag [sortableColumn] is missing required attribute [title] or [titleKey]")
134
135        def property = attrs.remove("property")
136        def action = attrs.action ? attrs.remove("action") : (actionName ?: "list")
137
138        def defaultOrder = attrs.remove("defaultOrder")
139        if(defaultOrder != "desc") defaultOrder = "asc"
140
141        // current sorting property and order
142        def sort = params.sort
143        def order = params.order
144
145        // add sorting property and params to link params
146        def linkParams = [:]
147        if(params.id) linkParams.put("id",params.id)
148        if(attrs.params) linkParams.putAll(attrs.remove("params"))
149        linkParams.sort = property
150
151        // determine and add sorting order for this column to link params
152        attrs.class = (attrs.class ? "${attrs.class} sortable" : "sortable")
153        if(property == sort) {
154            attrs.class = attrs.class + " sorted " + order
155            if(order == "asc")
156                linkParams.order = "desc"
157            else
158                linkParams.order = "asc"
159        }
160        else
161            linkParams.order = defaultOrder
162
163        // determine column title
164//         def title = attrs.remove("title")
165//         def titleKey = attrs.remove("titleKey")
166//         if(titleKey) {
167//             if(!title) title = titleKey
168//             def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
169//             def locale = RCU.getLocale(request)
170//
171//             title = messageSource.getMessage(titleKey, null, title, locale)
172//         }
173
174        // Image.
175        def img = "<img "
176        def imgAttrs = [:]
177        imgAttrs.src = attrs.remove("imgSrc")
178        imgAttrs.alt = attrs.remove("imgAlt")
179        imgAttrs.title = attrs.remove("imgTitle")
180        imgAttrs.each { k, v ->
181            if(v)
182                img += "${k}=\"${v.encodeAsHTML()}\" "
183        }
184        img += "/>"
185
186        writer << "<th "
187
188        // process remaining attributes
189        attrs.each { k, v ->
190            writer << "${k}=\"${v.encodeAsHTML()}\" "
191        }
192        writer << ">${link(action:action, params:linkParams) { img } }"
193        writer << "</th>"
194
195    } // sortableColumnWithImg
196
197    /**
198    * Customised version of jasperButton as found in jaser plugin.
199     * custom:jasperButtons is intended to be wrapped by g:jasperForm
200     */
201    def jasperButtons = {attrs ->
202        if(!attrs['format']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'format'))}
203        if(!attrs['formName']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'formName'))}
204        String formName = attrs['formName']
205        String buttonClass = attrs['class'] ?:  "jasperButton"
206        String format = attrs['format'].toUpperCase()
207        String text = attrs['text']
208        String heightAttr = attrs['height'] ? ' height="' + attrs['height'] + '"' : '' // leading space on purpose
209        String imgSrc = ''
210        String delimiter = attrs['delimiter'] ?: "|"
211        String delimiterBefore = attrs['delimiterBefore'] ?: delimiter
212        String delimiterAfter = attrs['delimiterAfter'] ?: delimiter
213
214        out << '''
215                    <script type="text/javascript">
216                        function submit_jasperForm(name, fmt) {
217                            var jasperForm = document.getElementsByName(name).item(0)
218                            jasperForm._format.value = fmt;
219                            jasperForm.submit();
220                            return false;
221                        }
222                    </script>
223                    '''
224
225        out << delimiterBefore
226
227        attrs['format'].toUpperCase().split(",").eachWithIndex { it, i ->
228            if (i > 0) out << delimiter
229            imgSrc = g.resource(plugin:"jasper", dir:'images/icons', file:"${it.trim()}.gif")
230            def fmt = it.trim()
231            out << """
232                        <a href="#" class="${buttonClass}" title="${it.trim()}" onClick="return submit_jasperForm('${formName}', '${fmt}')">
233                        <img border="0" src="${imgSrc}"${heightAttr} /></a>
234                        """
235        }
236
237        out << delimiterAfter
238    } // jasperButtons
239
240} // end class
Note: See TracBrowser for help on using the repository browser.