【问题标题】:Have a favorite custom Grails tag?有最喜欢的自定义 Grails 标签吗?
【发布时间】:2008-10-20 03:16:54
【问题描述】:

我一直在我的项目中使用标签。我正在浏览 grails.org 上的自定义标签,为我的库找到一些新标签。

http://www.grails.org/Contribute+a+Tag

我想知道 StackOverflow 社区中的人们是否有他们想要分享的最喜欢的自定义标签。

【问题讨论】:

    标签: grails


    【解决方案1】:

    对于某些用例,我发现 DecimalFormat 类(以及 Grails 的 formatNumber 标记)有点不透明,而且我仍然没有找到一种合理的方法来使用它进行一些非常基本的格式化,而无需进行一些丑陋的预处理来生成适当的格式字符串。几个月前我拼凑了一个简单的数字格式化标签,它本质上构建了一个格式字符串并对数字本身进行了一些最小的处理。

    它不像我想要的那样通用或优雅(这是我们当时所需要的 - 它是超级基本的,但它仍然保留了一些丑陋的处理 GSP),但它应该易于阅读,而且很明显在哪里可以进行微不足道的改进(即,使缩放迭代而不是幼稚的 if-elseif slop,允许用户传入自定义缩放标记,允许自定义数字验证器作为参数等)。

    
    // Formats a number to 3 significant digits, appending appropriate scale marker
    // (k, m, b, t, etc.). Defining var allows you to use a string representation
    // of the formatted number anywhere you need it within the tag body, and 
    // provides the scale as well (in case highlighting or other special formatting
    // based upon scale is desired).
    def formatNumberScaled = {attrs, body -> // number, prefix, suffix, invalid, var
        Double number
        String numberString
        String scale
    
        try {
            number = attrs.'number'.toDouble()
        } catch (Exception e) {
            number = Double.NaN
        }
    
        if (number.isNaN() || number.isInfinite()) {
            numberString = scale = attrs.'invalid' ?: "N/A"
        } else {
            Boolean negative = number < 0d
            number = negative ? -number : number
    
            if (number < 1000d) {
                scale = ''
            } else if (number < 1000000d) {
                scale = 'k'
                number /= 1000d
            } else if (number < 1000000000d) {
                scale = 'm'
                number /= 1000000d
            } else if (number < 1000000000000d) {
                scale = 'b'
                number /= 1000000000d
            } else if (number < 1000000000000000d) {
                scale = 't'
                number /= 1000000000000d
            }
    
            String format
            if (number < 10d) {
                format = '#.00'
            } else if (number < 100d) {
                format = '##.0'
            } else {
                format = '###'
            }
            format = "'${attrs.'prefix' ?: ''}'${format}'${scale} ${attrs.'suffix' ?: ''}'"
    
            numberString = g.formatNumber('number': negative ? -number : number, 'format': format)
        }
    
        // Now, either print the number or output the tag body with
        // the appropriate variables set
        if (attrs.'var') {
            out << body((attrs.'var'): numberString, 'scale': scale)
        } else {
            out << numberString
        }
    }
    

    【讨论】:

    【解决方案2】:

    我有一个“fmt:relDate”标签,它为您提供类似于 Twitter 的相对日期“3 天前”、“不到 30 秒前”等,并以工具提示的形式显示实时时间。

    当前的实现基本上是一个巨大的 if/then 语句链,具有我喜欢的边界。基于二进制搜索的算法会更好(在“更高效”的意义上),并且当前的实现将我的个人偏好编码到其中,所以我不愿意分享标签。

    【讨论】:

      【解决方案3】:

      我有一个远程分页选项卡,它可以帮助我通过 ajax 对结果进行分页。它是对默认选项卡的改进,并接受了自定义参数。

      代码如下:

      class CustomRemotePaginateTagLib {
      
        static namespace = 'myTagLib'
      
        /** * Creates next/previous links to support pagination for the current controller * * <g:paginate total="$ { Account.count() } " />               */
        def remotePaginate = {attrs ->
          def writer = out
          if (attrs.total == null) throwTagError("Tag [remotePaginate] is missing required attribute [total]")
      
          if (attrs.update == null) throwTagError("Tag [remotePaginate] is missing required attribute [update]")
      
          def locale = RequestContextUtils.getLocale(request)
      
          def total = attrs.total.toInteger()
      
          def update = attrs.update
      
          def action = (attrs.action ? attrs.action : (params.action ? params.action : "list"))
          def controller = (attrs.controller ? attrs.controller : params.controller)
          def offset = params.offset?.toInteger()
          def max = params.max?.toInteger()
          def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
      
          if (!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
          if (!max) max = (attrs.max ? attrs.max.toInteger() : 10)
      
          def linkParams = [offset: offset - max, max: max]
          if (params.sort) linkParams.sort = params.sort
          if (params.order) linkParams.order = params.order
          if (attrs.params) linkParams.putAll(attrs.params)
          linkParams['action'] = action
          linkParams['controller'] = controller
      
          def linkTagAttrs = [url: "#"]
          if (attrs.controller) { linkTagAttrs.controller = attrs.controller }
          if (attrs.id != null) { linkTagAttrs.id = attrs.id }
      
          // determine paging variables
          def steps = maxsteps > 0
          int currentstep = (offset / max) + 1
          int firststep = 1
          int laststep = Math.round(Math.ceil(total / max))
      
          // display previous link when not on firststep
          if (currentstep > firststep) {
            linkTagAttrs.class = 'prevLink'
            def prevOffset = linkParams.offset
      
            def params = attrs.params ?: []
            params.'offset' = prevOffset
      
            linkTagAttrs.onclick = g.remoteFunction(update: update, action: linkParams.action, controller: linkParams.controller, params: params)
            writer << link(linkTagAttrs.clone()) {
              (attrs.prev ? attrs.prev : g.message(code: 'default.paginate.prev', default: 'Previous'))
            }
          }
      
          // display steps when steps are enabled and laststep is not firststep
          if (steps && laststep > firststep) {
            linkTagAttrs.class = 'step'
      
            // determine begin and endstep paging variables
            int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
            int endstep = currentstep + Math.round(maxsteps / 2) - 1
      
            if (beginstep < firststep) {
              beginstep = firststep
              endstep = maxsteps
            }
            if (endstep > laststep) {
              beginstep = laststep - maxsteps + 1
              if (beginstep < firststep) {
                beginstep = firststep
              }
              endstep = laststep
            }
      
            // display firststep link when beginstep is not firststep
            if (beginstep > firststep) {
              linkParams.offset = 0
      
              def params = attrs.params ?: []
              params['offset'] = linkParams.offset
      
              linkTagAttrs.onclick = g.remoteFunction(update: update, action: linkParams.action, controller: linkParams.controller, params: params)
              writer << link(linkTagAttrs.clone()) { firststep.toString() }
              writer << '<span class="step">..</span>'
            }
      
            // display paginate steps
            (beginstep..endstep).each {i ->
              if (currentstep == i) {
                writer << "<span class=\"currentStep\">${i}</span>"
              } else {
                linkParams.offset = (i - 1) * max
      
                def params = attrs.params ?: []
                params['offset'] = linkParams.offset
      
                linkTagAttrs.onclick = g.remoteFunction(update: update, action: linkParams.action, controller: linkParams.controller, params: params)
                writer << link(linkTagAttrs.clone()) { i.toString() }
              }
            }
      
            // display laststep link when endstep is not laststep
            if (endstep < laststep) {
              writer << '<span class="step">..</span>'
              linkParams.offset = (laststep - 1) * max
      
              def params = attrs.params ?: []
              params['offset'] = linkParams.offset
      
              linkTagAttrs.onclick = g.remoteFunction(update: update, action: linkParams.action, controller: linkParams.controller, params: params)
              writer << link(linkTagAttrs.clone()) { laststep.toString() }
            }
          }
      
          // display next link when not on laststep
          if (currentstep < laststep) {
            linkTagAttrs.class = 'nextLink'
            linkParams.offset = offset + max
      
            def params = attrs.params ?: []
            params['offset'] = linkParams.offset
      
            linkTagAttrs.onclick = g.remoteFunction(update: update, action: linkParams.action, controller: linkParams.controller, params: params)
            writer << link(linkTagAttrs.clone()) {
              (attrs.next ? attrs.next : g.message(code: 'default.paginate.next', default: 'Next'))
            }
          }
      
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-07
        • 1970-01-01
        • 2011-06-16
        • 1970-01-01
        • 1970-01-01
        • 2015-09-07
        相关资源
        最近更新 更多