扩展Grails的datePicker标签

本文所述代码实现基于Grails 1.1 以上版本。

---------------------------------------------------------------------------------------------------------------------------

Grails的datePicker标签是一个常用的标签,它有一个属性years,使用这个属性可以指定列表列出的年份,可以是范围,也可以是多选。这个属性在你需要限制选择范围的时候非常有用,但是如果你还要限制月份,日期,小时,分,秒这些时间单位呢?datePicker标签并没有提供相应的属性,那我们只能自己扩展了。我们希望他有months, days, hours, minuts这些属性,并且和years具有相同的设置方式。

修改步骤:

首先将代码导入IDE中(省略过程),在目录 src\groovy\org\codehaus\groovy\grails\plugins\web\taglib 下找到FormTagLib.groovy(奇怪为什么是在plugins下的),打开并查找"def datePicker ="下面的内容就是datePicker标签的实现代码,阅读代码可以发现这么一段

// create year select
        if (precision >= PRECISION_RANKINGS["year"]) {
            out.println "<select name=\"${name}_year\" id=\"${id}_year\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            for (i in years) {
                out.println "<option value=\"${i}\""
                if (i == year) {
                    out.println " selected=\"selected\""
                }
                out.println ">${i}</option>"
            }
            out.println '</select>'
        }

 这段代码就是标签生成年份选择框的,关键的部分是

for (i in years)

循环生成选择项,它遍历的是years这个变量,往前查找这个变量是这么得到的

def years = attrs['years']

 看到这儿我们就知道了,要实现前面的扩展其实很容易,依葫芦画瓢照样子做就是了。

在years后面添加如下代码:

def months = attrs['months']
        def days = attrs['days']
        def hours = attrs['hours']
        def minutes = attrs['minutes']

 考虑属性不设置为空的情况,需要给变量指定默认值,添加以下代码:

if (months == null) {
			months = 1..12
		}
		if (days == null) {
			days = 1..31
		}
		if (hours == null) {
			hours = 0..23
		}
		if (minutes == null) {
			minutes = 0..59
		}

 然后修改生成每个时间段选择项的代码,如days:将

for (i in 1..31) {

 修改为

for (i in days) {

 其他都类似,除了月份需要特殊处理,循环时输出时判断,修改如下:

dfs.months.eachWithIndex {m, i ->
                if (m) {
                    def monthIndex = i + 1
                    if(months.contains(monthIndex)){
                        out << "<option value=\"${monthIndex}\""
                        if (month == i) out << " selected=\"selected\""
                        out << '>'
                        out << m
                        out.println '</option>'
                    }
                }
            }
 

最后,用ant执行build.xml中的jar,它会编译并打包至dist目录下,其中grails-web-1.1.jar就是扩展后的标签所在的jar,将这个包复制到Grails安装目录的的lib目录下,覆盖原来的jar文件,就可以使用自己扩展的datePicker标签了。

--------------------------------------------------------

附件:最后修改的代码如下

/**
    * A simple date picker that renders a date as selects
    * eg. <g:datePicker name="myDate" value="${new Date()}" />
    */
    def datePicker = {attrs ->
        def xdefault = attrs['default']
        if (xdefault == null) {
            xdefault = new Date()
        } else if (xdefault.toString() != 'none') {
            if (xdefault instanceof String) {
                xdefault = DateFormat.getInstance().parse(xdefault)
            }else if(!(xdefault instanceof Date)){
                throwTagError("Tag [datePicker] requires the default date to be a parseable String or a Date")
            }
        } else {
            xdefault = null
        }

        def value = attrs['value']
        if (value.toString() == 'none') {
            value = null
        } else if (!value) {
            value = xdefault
        }
        def name = attrs['name']
        def id = attrs['id'] ? attrs['id'] : name

        def noSelection = attrs['noSelection']
        if (noSelection != null)
        {
            noSelection = noSelection.entrySet().iterator().next()
        }

        def years = attrs['years']
        def months = attrs['months']
        def days = attrs['days']
        def hours = attrs['hours']
        def minutes = attrs['minutes']

        final PRECISION_RANKINGS = ["year": 0, "month": 10, "day": 20, "hour": 30, "minute": 40]
        def precision = (attrs['precision'] ? PRECISION_RANKINGS[attrs['precision']] :
            (grailsApplication.config.grails.tags.datePicker.default.precision ?
                PRECISION_RANKINGS["${grailsApplication.config.grails.tags.datePicker.default.precision}"] :
                PRECISION_RANKINGS["minute"]))

        def day
        def month
        def year
        def hour
        def minute
        def dfs = new java.text.DateFormatSymbols(RCU.getLocale(request))

        def c = null
        if (value instanceof Calendar) {
            c = value
        }
        else if (value != null) {
            c = new GregorianCalendar();
            c.setTime(value)
        }

        if (c != null) {
            day = c.get(GregorianCalendar.DAY_OF_MONTH)
            month = c.get(GregorianCalendar.MONTH)
            year = c.get(GregorianCalendar.YEAR)
            hour = c.get(GregorianCalendar.HOUR_OF_DAY)
            minute = c.get(GregorianCalendar.MINUTE)
        }

        if (years == null) {
            def tempyear
            if (year == null) {
                // If no year, we need to get current year to setup a default range... ugly
                def tempc = new GregorianCalendar()
                tempc.setTime(new Date())
                tempyear = tempc.get(GregorianCalendar.YEAR)
            } else {
                tempyear = year
            }
            years = (tempyear - 100)..(tempyear + 100)
        }
        if (months == null) {
            months = 1..12
        }
        if (days == null) {
            days = 1..31
        }
        if (hours == null) {
            hours = 0..23
        }
        if (minutes == null) {
            minutes = 0..59
        }


        out << "<input type=\"hidden\" name=\"${name}\" value=\"struct\" />"

        // create day select
        if (precision >= PRECISION_RANKINGS["day"]) {
            out.println "<select name=\"${name}_day\" id=\"${id}_day\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            for (i in days) {
                out.println "<option value=\"${i}\""
                if (i == day) {
                    out.println " selected=\"selected\""
                }
                out.println ">${i}</option>"
            }
            out.println '</select>'
        }

        // create month select
        if (precision >= PRECISION_RANKINGS["month"]) {
            out.println "<select name=\"${name}_month\" id=\"${id}_month\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            dfs.months.eachWithIndex {m, i ->
                if (m) {
                    def monthIndex = i + 1
                    if(months.contains(monthIndex)){
                        out << "<option value=\"${monthIndex}\""
                        if (month == i) out << " selected=\"selected\""
                        out << '>'
                        out << m
                        out.println '</option>'
                    }
                }
            }
            out.println '</select>'
        }

        // create year select
        if (precision >= PRECISION_RANKINGS["year"]) {
            out.println "<select name=\"${name}_year\" id=\"${id}_year\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            for (i in years) {
                out.println "<option value=\"${i}\""
                if (i == year) {
                    out.println " selected=\"selected\""
                }
                out.println ">${i}</option>"
            }
            out.println '</select>'
        }

        // do hour select
        if (precision >= PRECISION_RANKINGS["hour"]) {
            out.println "<select name=\"${name}_hour\" id=\"${id}_hour\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            for (i in hours) {
                def h = '' + i
                if (i < 10) h = '0' + h
                out << "<option value=\"${h}\" "
                if (hour == h.toInteger()) out << "selected=\"selected\""
                out << '>' << h << '</option>'
                out.println()
            }
            out.println '</select> :'

            // If we're rendering the hour, but not the minutes, then display the minutes as 00 in read-only format
            if (precision < PRECISION_RANKINGS["minute"]) {
                out.println '00'
            }
        }

        // do minute select
        if (precision >= PRECISION_RANKINGS["minute"]) {
            out.println "<select name=\"${name}_minute\" id=\"${id}_minute\">"

            if (noSelection) {
                renderNoSelectionOption(noSelection.key, noSelection.value, '')
                out.println()
            }

            for (i in minutes) {
                def m = '' + i
                if (i < 10) m = '0' + m
                out << "<option value=\"${m}\" "
                if (minute == m.toInteger()) out << "selected=\"selected\""
                out << '>' << m << '</option>'
                out.println()
            }
            out.println '</select>'
        }
    }
 

相关推荐