本文所述代码实现基于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>'
}
}