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

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

New defaultSort for Tasks, sort by status then priority then target start date.
Small improvement to custom:sortableColumnWithImg to allow imgTitle to be specified.

File size: 7.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} // end class
Note: See TracBrowser for help on using the repository browser.