2008-10-20 9 views

Odpowiedz

1

znajdę klasę DecimalFormat (i Grails męska formatNumber tag według rozszerzenia) nieco nieprzezroczysta dla pewnych przypadków użycia, a ja nadal nie znalazłem rozsądny sposób to zrobić jakiś ładny podstawowe formatowanie z nim bez brzydkiego wstępnego przetwarzania w celu wygenerowania odpowiedniego ciągu formatu. Kilka miesięcy temu zrzuciłem prosty tag do formatowania liczb, który zasadniczo tworzy ciąg formatujący i wykonuje minimalne przetwarzanie do samego numeru.

To nie jest tak ogólne i eleganckie jak bym chciała (to wszystko, czego potrzebowaliśmy w tym czasie - jest super podstawowe, ale nadal utrzymuje pewne brzydkie przetwarzanie z GSP), ale powinno być łatwe do odczytania, a to oczywiste, gdzie można go w prosty sposób usprawnić (np. uczynienie iteracji skalowania zamiast naiwnego if-elseif slop, pozwalając użytkownikowi na przekazanie niestandardowych znaczników skalowania, pozwalając na użycie niestandardowego walidatora liczb jako parametru itp.).


// 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 
    } 
} 
+0

@ankimal - nie mają wystarczająco dużo rep skomentowania innych - czy próbowałeś:
http://www.grails.org/Contribute+a+Tag#remotePaginate

to ma niedobór jakiegoś typu, czy też niestandardowy tag jest specjalnie dopasowany do jakiegoś zadania? –

1

Mam tag "fmt: relDate", który podaje względne daty na Twitterze "3 dni temu", "mniej niż 30 sekund temu" itp., Z rzeczywistym czasem jako podpowiedź.

Obecna implementacja to po prostu gigantyczny ciąg instrukcji if/then z granicami, które lubię. Algorytm oparty na wyszukiwaniu binarnym byłby lepszy (w sensie "bardziej efektywny"), a obecna implementacja ma moje osobiste preferencje zakodowane w nim, więc niechętnie dzielę się tym znacznikiem.

1

Mam zdalną kartę stronicowania, która pomaga mi paginować wyniki za pośrednictwem ajax. Jest to poprawa w stosunku do domyślnej karty i przyjmuje niestandardowe argumenty.

Oto kod:

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')) 
     } 
    } 

    }