//import org.apache.commons.validator.UrlValidator
import org.codehaus.groovy.grails.validation.routines.UrlValidator
import org.codehaus.groovy.grails.validation.routines.RegexValidator
/**
* General use custom tags.
* Some are taken from http://www.grails.org/Contribute+a+Tag#checkBoxList
*/
class CustomTagLib {
static namespace = 'custom'
private static final Object helpBalloonLockable = new Object();
private static long helpBalloonCount = 0L;
def resources = { attrs ->
///@todo: should include our javascript and do setup here.
}
/**
* Checkbox list that can be used as a more user-friendly alternative to a multiselect list box.
* Usage:
* To map the selected ids to corresponding domain objects,
* an additional set method is required in the containing domain class:
* // This additional setter is used to convert the checkBoxList string or string array
* // of ids selected to the corresponding domain objects.
* public void setAssetSubItemsFromCheckBoxList(ids) {
* def idList = []
* if(ids instanceof String) {
* if(ids.isInteger())
* idList << ids.toInteger()
* }
* else {
* ids.each() {
* if(it.isInteger())
* idList << it.toInteger()
* }
* }
* this.assetSubItems = idList.collect { AssetSubItem.get( it ) }
* }
*
* Then a line in the controller:
* assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)
*
* Fields:
* name - the property name.
* from - the list to select from.
* value - the current value.
* optionKey - the key to use.
* sortBy - (optional) the attribute to sort the from list by.
* displayFields - (optional) defaults to the objects toString()
* displayFieldsSeparator - (optional) defaults to a space.
* linkController - (optional, requires linkAction.) the controller to use for a link to the objects in the checkBoxList.
* linkAction - (optional, requires linkController.) the action to use for a link to the objects in the checkBoxList.
*
* Example:
*
*
*/
def checkBoxList = {attrs, body ->
def from = attrs.from
def value = attrs.value
def cname = attrs.name
def isChecked, ht, wd, style, html
def sortBy = attrs.sortBy
def displayFields = attrs.displayFields
def displayFieldsSeparator = attrs.displayFieldsSeparator ?: ' '
def linkController = attrs.linkController
def linkAction = attrs.linkAction
def displayValue = " "
// sets the style to override height and/or width if either of them
// is specified, else the default from the CSS is taken
style = "style='"
if(attrs.height)
style += "height:${attrs.height};"
if(attrs.width)
style += "width:${attrs.width};"
if(style.length() == "style='".length())
style = ""
else
style += "'" // closing single quote
html = "
"
} // checkBoxList
def sortableColumnWithImg = { attrs, body ->
def writer = out
if(!attrs.property)
throwTagError("Tag [sortableColumn] is missing required attribute [property]")
// if(!attrs.title && !attrs.titleKey)
// throwTagError("Tag [sortableColumn] is missing required attribute [title] or [titleKey]")
def property = attrs.remove("property")
def action = attrs.action ? attrs.remove("action") : (actionName ?: "list")
def defaultOrder = attrs.remove("defaultOrder")
if(defaultOrder != "desc") defaultOrder = "asc"
// current sorting property and order
def sort = params.sort
def order = params.order
// add sorting property and params to link params
def linkParams = [:]
if(params.id) linkParams.put("id",params.id)
if(attrs.params) linkParams.putAll(attrs.remove("params"))
linkParams.sort = property
// determine and add sorting order for this column to link params
attrs.class = (attrs.class ? "${attrs.class} sortable" : "sortable")
if(property == sort) {
attrs.class = attrs.class + " sorted " + order
if(order == "asc")
linkParams.order = "desc"
else
linkParams.order = "asc"
}
else
linkParams.order = defaultOrder
// determine column title
// def title = attrs.remove("title")
// def titleKey = attrs.remove("titleKey")
// if(titleKey) {
// if(!title) title = titleKey
// def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
// def locale = RCU.getLocale(request)
//
// title = messageSource.getMessage(titleKey, null, title, locale)
// }
// Image.
def img = "
if(v)
img += "${k}=\"${v.encodeAsHTML()}\" "
}
img += "/>"
writer << "
writer << "${k}=\"${v.encodeAsHTML()}\" "
}
writer << ">${link(action:action, params:linkParams) { img } }"
writer << " | "
} // sortableColumnWithImg
/**
* Customised version of jasperButton as found in jaser plugin.
* custom:jasperButtons is intended to be wrapped by g:jasperForm
*/
def jasperButtons = {attrs ->
if(!attrs['format']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'format'))}
if(!attrs['jasper']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'jasper'))}
String jasper = attrs['jasper']
String buttonClass = attrs['class'] ?: "jasperButton"
String format = attrs['format'].toUpperCase()
String text = attrs['text']
String heightAttr = attrs['height'] ? ' height="' + attrs['height'] + '"' : '' // leading space on purpose
String imgSrc = ''
String delimiter = attrs['delimiter'] ?: "|"
String delimiterBefore = attrs['delimiterBefore'] ?: delimiter
String delimiterAfter = attrs['delimiterAfter'] ?: delimiter
out << '''
'''
out << delimiterBefore
attrs['format'].toUpperCase().split(",").eachWithIndex { it, i ->
if (i > 0) out << delimiter
imgSrc = g.resource(plugin:"jasper", dir:'images/icons', file:"${it.trim()}.gif")
def fmt = it.trim()
out << """
"""
}
out << delimiterAfter
} // jasperButtons
/**
* Easily create a link from a hopeful url string.
* If the supplied url is not considered a valid url the string is simply displayed.
*
* Fields:
* url - String url to use.
* body - If no body is supplied in the GSP then url.encodeAsHTML() is displayed.
*
* Example:
*
*/
def easyUrl = {attrs, body ->
def url = attrs.url
def html
body = body()
if(!body)
body = url.encodeAsHTML()
html = "${body}"
if(isURLValid(url)) {
html = """
${html}
"""
}
out << html
}
/**
* Get a list of the machines assigned on a taskProcedureRevision.
*
* Fields:
* taskProcedureRevision - TaskProcedureRevision to use.
*
* Example:
*
*/
def taskProcedureMachines = {attrs ->
def taskProcedureRevision = attrs.taskProcedureRevision
def machines = taskProcedureRevision.maintenanceActions.collect {it.assetSubItem.parentItem}.unique()
out << machines.encodeAsHTML()
}
/**
* Customised version of helpBalloon as found in help-balloon plugin.
* This version can be used in ajax rendered templates where the original fails.
*
* Fields added:
* iconId - Optional to specify the anchor elements id, by default an id is generated if iconSrc is supplied.
* iconSrc - Optional to specify anchor image src, if not supplied no anchor image is output by the taglib.
*
* Example:
*
*/
def helpBalloon = {attrs, body ->
def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
def title = attrs["title"]
def content = attrs["content"]
def code = attrs["code"]
def suffix = attrs["suffix"] ?: ".help"
def encodeAs = attrs["encodeAs"]
def iconId = attrs["iconId"]
def iconSrc = attrs["iconSrc"]
if (!title && code) title = g.message(code: code)
if (!content && code) content = g.message(code: code + suffix)
title = title ?: ""
content = content ?: ""
if (encodeAs) {
switch (encodeAs.toUpperCase()) {
case "HTML":
title = title.encodeAsHTML()
content = content.encodeAsHTML()
break
case "XML":
title = title.encodeAsXML()
content = content.encodeAsXML()
break
}
}
def num
synchronized (helpBalloonLockable) {
num = helpBalloonCount++;
}
if(iconSrc) {
iconId = iconId ?: "customHb$num"
mkp.img( id: iconId, src: iconSrc)
}
def javascript = """var customHb$num = new HelpBalloon({
title: '${title.encodeAsJavaScript()}',
content: '${content.encodeAsJavaScript()}'"""
if(iconId) {
javascript +=""",
icon: \$('$iconId')"""
}
javascript += """
});"""
mkp.script(type: "text/javascript") {
yieldUnescaped(javascript)
}
}
/**
* Determine if a supplied string is considered a url or not.
* The scheme/protocol can be adjusted, file:// has been excluded here.
* A domainValidator regex is used to allow localhost domain.
* A Grails branched version of commons.validator is used, this should
* be compatible with the apache 1.4 version release.
* See: http://jira.codehaus.org/browse/GRAILS-1692 for more on Grails url validation.
*/
private Boolean isURLValid(url) {
def schemes = ["http","https", "ftp"] as String[]
//def domainValidator = new RegexValidator("localhost(:(\\d{1,5}))?")
def domainValidator = new RegexValidator(".*(:(\\d{1,5}))?") // Any domain, incl user@host:port
def validator = new UrlValidator(schemes, domainValidator, UrlValidator.ALLOW_2_SLASHES)
return validator.isValid(url)
}
} // end class