Changeset 457 for trunk/grails-app


Ignore:
Timestamp:
Mar 26, 2010, 2:22:04 AM (15 years ago)
Author:
gav
Message:

Refactor asset tree generation to improve speed by around 4 fold.

Location:
trunk/grails-app
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/services/AssetTreeService.groovy

    r453 r457  
    77    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
    88
     9    /** General */
     10    def nameDescriptionSeperator = ' -- '
     11
    912    /** Html class and id settings */
    10 
    11     def buttonHtmlClass() {
    12         'tree_button'
    13     }
    14     def paneHtmlClass() {
    15         'overlayPane'
    16     }
    17     def paneHtmlId() {
    18         'assetTreePane'
    19     }
    20     def paneCloseHtmlClass() {
    21         'pane_close'
    22     }
    23     def tableDivHtmlClass() {
    24         'tree'
    25     }
    26     def tableHtmlId() {
    27         'assetTreeTable'
    28     }
    29     def tableLoadingImgId() {
    30         'assetTreeLoadingImg'
     13    def buttonHtmlClass = 'tree_button'
     14    def paneHtmlClass = 'overlayPane'
     15    def paneHtmlId = 'assetTreePane'
     16    def paneCloseHtmlClass = 'pane_close'
     17    def tableDivHtmlClass = 'tree'
     18    def tableHtmlId = 'assetTreeTable'
     19    def tableLoadingImgId = 'assetTreeLoadingImg'
     20
     21    /** Imgs */
     22    def treeRootImg = ''
     23    def addImg = ''
     24    def copyImg = ''
     25    def bulletTreePlusImg = ''
     26    def bulletTreeMinusImg = ''
     27    def dashImg = ''
     28    def closeImg = ''
     29
     30    /** Urls */
     31    def assetTreeActionUrl = ''
     32    def saveAssetTreeStatusActionUrl = ''
     33
     34    /** Links */
     35    def siteCreateBaseLink = ''
     36    def siteShowBaseLink = ''
     37    def siteEditBaseLink = ''
     38    def sectionCreateBaseLink = ''
     39    def sectionShowBaseLink = ''
     40    def sectionEditBaseLink = ''
     41    def assetCreateBaseLink = ''
     42    def assetShowBaseLink = ''
     43    def assetEditBaseLink = ''
     44    def assetCopyBaseLink = ''
     45    def assetSubItemCreateBaseLink = ''
     46    def assetSubItemCreateWithParentBaseLink = ''
     47    def assetSubItemShowBaseLink = ''
     48    def assetSubItemEditBaseLink = ''
     49
     50    /**
     51    * Initialise some class wide variables.
     52    * This has been done to optimise since g.link and g.resource calls are expensive.
     53    * This can't be done by class construction since some of the metaclass stuff is not available yet, e.g. 'out' etc.
     54    * Initialise can't be called from BootStrap.
     55    */
     56    def initialise() {
     57        log.debug "Initialise asset tree variables."
     58
     59        // Imgs.
     60        treeRootImg = g.resource(dir:'images/skin',file:'chart_organisation.png')
     61        addImg = g.resource(dir:'images/skin',file:'database_add.png')
     62        copyImg = g.resource(dir:'images/skin',file:'page_copy.png')
     63        bulletTreePlusImg = g.resource(dir:'images/skin',file:'bullet_tree_plus.png')
     64        bulletTreeMinusImg = g.resource(dir:'images/skin',file:'bullet_tree_minus.png')
     65        dashImg = g.resource(dir:'images/skin',file:'hline_short.png')
     66        closeImg = g.resource(dir:'images/skin',file:'cross.png')
     67
     68        // Urls.
     69        assetTreeActionUrl = g.createLink(controller: 'assetDetailed', action: 'assetTree')
     70        saveAssetTreeStatusActionUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
     71
     72        // Links
     73        siteCreateBaseLink = g.createLink(controller: 'siteDetailed', action: 'create').toString()
     74        siteShowBaseLink = g.createLink(controller: 'siteDetailed', action: 'show').toString()
     75        siteEditBaseLink = g.createLink(controller: 'siteDetailed', action: 'edit').toString()
     76        sectionCreateBaseLink = g.createLink(controller: 'sectionDetailed', action: 'create').toString()
     77        sectionShowBaseLink = g.createLink(controller: 'sectionDetailed', action: 'show').toString()
     78        sectionEditBaseLink = g.createLink(controller: 'sectionDetailed', action: 'edit').toString()
     79        assetCreateBaseLink = g.createLink(controller: 'assetDetailed', action: 'create').toString()
     80        assetShowBaseLink = g.createLink(controller: 'assetDetailed', action: 'show').toString()
     81        assetEditBaseLink = g.createLink(controller: 'assetDetailed', action: 'edit').toString()
     82        assetCopyBaseLink = g.createLink(controller: 'assetDetailed', action: 'copy').toString()
     83        assetSubItemCreateBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
     84        assetSubItemCreateWithParentBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
     85        assetSubItemShowBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'show').toString()
     86        assetSubItemEditBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'edit').toString()
     87        // Success.
     88        return true
    3189    }
    3290
     
    3997    def description(obj) {
    4098        def s =  obj.description.encodeAsHTML()
    41         if(s) s = ' -- ' + s
    42         else ''
    43     }
     99        s = s? (nameDescriptionSeperator + s) : ''
     100    }
     101
     102    /**
     103    * Build and return the asset tree button.
     104    * Built here instead of directly in the taglib since we may need to initialise.
     105    */
     106    def buildAssetTreeButton(attrs) {
     107
     108        // Self initialisation ;-)
     109        if(!treeRootImg)
     110            initialise()
     111
     112        def sw = new StringWriter()
     113        def mkp = new groovy.xml.MarkupBuilder(sw)
     114
     115        mkp.div(class: buttonHtmlClass) {
     116            a( href: hrefShowPane() ) {
     117                img(src: treeRootImg)
     118            }
     119        } // mkp
     120
     121        return sw.toString()
     122    }
     123
     124    /**
     125    * Build and return the empty asset tree pane, ready for populating by ajax call to buildAssetTree.
     126    * Built here instead of directly in the taglib since we may need to initialise.
     127    */
     128    def buildAssetTreePane(attrs) {
     129
     130        // Self initialisation ;-)
     131        if(!treeRootImg)
     132            initialise()
     133
     134        def sw = new StringWriter()
     135        def mkp = new groovy.xml.MarkupBuilder(sw)
     136
     137        mkp.div(class: paneHtmlClass, id: paneHtmlId, style: 'display:none;') {
     138            div(class: paneCloseHtmlClass) {
     139                a( href: js.toggle(paneHtmlId) ) {
     140                    img(src: closeImg)
     141                }
     142            }
     143
     144            div(class: tableDivHtmlClass) {
     145                table(id: tableHtmlId) {
     146                    tr() {
     147                        td(valign: 'top', class: 'value') {
     148                            ul() {
     149                                img(src: treeRootImg, id: tableLoadingImgId, alt: 'TreeRoot')
     150                                li() {
     151                                } // li
     152                            } // ul
     153                        } // td
     154                    } // tr
     155                } // table
     156            } // div
     157        } // mkp
     158
     159        return sw.toString()
     160
     161    } // buildAssetPane
    44162
    45163    /**
    46164    * Build and return the asset tree table.
    47     * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div.
     165    * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div built by buildAssetTreePane().
    48166    * This table replaces the contents of the wrapper div.
    49167    * @returns The asset tree table as a String
     
    51169    def buildAssetTree(params, session) {
    52170
    53         def sites = Site.list()
     171        def startedAt = System.currentTimeMillis()
     172
     173        // Self initialisation ;-)
     174        if(!treeRootImg)
     175            initialise()
     176
     177        def sites = Site.withCriteria {
     178            eq("isActive", true)
     179        }
    54180
    55181        def visibleBranches = session.assetTreeVisibleBranches ? session.assetTreeVisibleBranches.tokenize(',') : []
     
    64190        def branchImg = { branchId ->
    65191            if(visibleBranches.contains(branchId))
    66                 bulletTreeMinusImg()
     192                bulletTreeMinusImg
    67193            else
    68                 bulletTreePlusImg()
     194                bulletTreePlusImg
    69195        }
    70196
     
    77203
    78204        def sw = new StringWriter()
    79         def mkp = new groovy.xml.MarkupBuilder(sw) //this line will be unnecessary in versions of Grails after version 1.2
     205        def mkp = new groovy.xml.MarkupBuilder(sw)
    80206
    81207        // Offer a site create link if no sites are found.
    82208        if(!sites) {
    83             mkp.div(class: tableDivHtmlClass()) {
    84 
    85                 div(class: paneCloseHtmlClass()) {
    86                     a( href: js.toggle(paneHtmlId()) ) {
    87                         img(src: closeImg())
     209            mkp.div(class: tableDivHtmlClass) {
     210
     211                div(class: paneCloseHtmlClass) {
     212                    a( href: js.toggle(paneHtmlId) ) {
     213                        img(src: closeImg)
    88214                    }
    89215                }
    90216
    91                 table(id: tableHtmlId()) {
     217                table(id: tableHtmlId) {
    92218                    tr() {
    93219                        td( valign: 'top', class: 'value') {
    94220                            ul() {
    95                                 img(src: treeRootImg(), alt: 'TreeRoot')
     221                                img(src: treeRootImg, alt: 'TreeRoot')
    96222                                li() {
    97                                     a(href: siteCreateLink()) {
    98                                         img(src: addImg(), alt: 'Add', title: 'Add Site')
     223                                    a(href: siteCreateBaseLink()) {
     224                                        img(src: addImg, alt: 'Add', title: 'Add Site')
    99225                                    }
    100226                                } // li
     
    106232                div( class: 'buttons') {
    107233                    span(class: 'button') {
    108                         input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.toggle(paneHtmlId(), "onclick") )
     234                        input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.toggle(paneHtmlId, "onclick") )
    109235                    }
    110236                } // button div
     
    116242        // The main populated table.
    117243        /// @todo: use a loop for the subItem levels.
    118         mkp.div(class: tableDivHtmlClass()) {
    119 
    120             div(class: paneCloseHtmlClass()) {
     244        mkp.div(class: tableDivHtmlClass) {
     245
     246            div(class: paneCloseHtmlClass) {
    121247                a( href: hrefHideAndSavePane() ) {
    122                     img(src: closeImg())
     248                    img(src: closeImg)
    123249                }
    124250            }
    125251
    126             table(id: tableHtmlId()) {
     252            table(id: tableHtmlId) {
    127253                tr() {
    128254                    td(valign: 'top', class: 'value') {
    129255                        ul() {
    130                             img(src: treeRootImg(), alt: 'TreeRoot')
     256                            img(src: treeRootImg, alt: 'TreeRoot')
    131257                            for(site in sites.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
    132258                                li() {
     
    137263                                    }
    138264                                    else
    139                                         img(src: dashImg())
     265                                        img(src: dashImg)
    140266                                    a( href: siteShowLink(site.id), onclick: onclickHideAndSavePane() ) {
    141267                                        yieldUnescaped( name(site)  )
     
    143269                                    yieldUnescaped( description(site)  )
    144270                                    a(href: sectionCreateLink(site.id), onclick: onclickHideAndSavePane()) {
    145                                         img(src: addImg(), alt: 'Add', title: 'Add Section')
     271                                        img(src: addImg, alt: 'Add', title: 'Add Section')
    146272                                    }
    147273                                }
     
    157283                                                    }
    158284                                                    else
    159                                                         img(src: dashImg())
     285                                                        img(src: dashImg)
    160286                                                    a( href: sectionShowLink(section.id), onclick: onclickHideAndSavePane() ) {
    161287                                                        yieldUnescaped( name(section) )
     
    163289                                                    yieldUnescaped( description(section)  )
    164290                                                    a(href: assetCreateLink(section.id), onclick: onclickHideAndSavePane()) {
    165                                                         img(src: addImg(), alt: 'Add', title: 'Add Asset')
     291                                                        img(src: addImg, alt: 'Add', title: 'Add Asset')
    166292                                                    }
    167293                                                }
     
    178304                                                                    }
    179305                                                                    else
    180                                                                         img(src: dashImg())
     306                                                                        img(src: dashImg)
    181307                                                                    a( href: assetShowLink(asset.id), onclick: onclickHideAndSavePane() ) {
    182308                                                                        yieldUnescaped( name(asset) )
     
    184310                                                                    yieldUnescaped( description(asset) )
    185311                                                                    a(href: assetSubItemCreateLink(asset.id), onclick: onclickHideAndSavePane()) {
    186                                                                         img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
     312                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
    187313                                                                    }
    188314                                                                    a(href: assetCopyLink(asset.id), onclick: onclickHideAndSavePane()) {
    189                                                                         img(src: copyImg(), alt: 'Add', title: 'Copy Asset')
     315                                                                        img(src: copyImg, alt: 'Add', title: 'Copy Asset')
    190316                                                                    }
    191317                                                                } // li
     
    202328                                                                                    }
    203329                                                                                    else
    204                                                                                         img(src: dashImg())
     330                                                                                        img(src: dashImg)
    205331                                                                                    a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: onclickHideAndSavePane() ) {
    206332                                                                                        yieldUnescaped( name(assetSubItemL1) )
     
    208334                                                                                    yieldUnescaped( description(assetSubItemL1) )
    209335                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL1.id), onclick: onclickHideAndSavePane()) {
    210                                                                                         img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
     336                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
    211337                                                                                    }
    212338                                                                                } // li
     
    223349                                                                                                    }
    224350                                                                                                    else
    225                                                                                                         img(src: dashImg())
     351                                                                                                        img(src: dashImg)
    226352                                                                                                    a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: onclickHideAndSavePane() ) {
    227353                                                                                                        yieldUnescaped( name(assetSubItemL2) )
     
    229355                                                                                                    yieldUnescaped( description(assetSubItemL2) )
    230356                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL2.id), onclick: onclickHideAndSavePane()) {
    231                                                                                                         img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
     357                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
    232358                                                                                                    }
    233359                                                                                                } // li
     
    244370                                                                                                                    }
    245371                                                                                                                    else
    246                                                                                                                         img(src: dashImg())
     372                                                                                                                        img(src: dashImg)
    247373                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: onclickHideAndSavePane() ) {
    248374                                                                                                                        yieldUnescaped( name(assetSubItemL3) )
     
    250376                                                                                                                    yieldUnescaped( description(assetSubItemL3) )
    251377                                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL3.id), onclick: onclickHideAndSavePane()) {
    252                                                                                                                         img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
     378                                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
    253379                                                                                                                    }
    254380                                                                                                                } // li
     
    265391            //                                                                                                                         }
    266392            //                                                                                                                         else
    267                                                                                                                                     img(src: dashImg())
     393                                                                                                                                    img(src: dashImg)
    268394                                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: onclickHideAndSavePane() ) {
    269395                                                                                                                                        yieldUnescaped( name(assetSubItemL4) )
     
    271397                                                                                                                                    yieldUnescaped( description(assetSubItemL4) )
    272398            //                                                                                                                         a(href: assetSubItemCreateWithParentLink(assetSubItemL4.id), onclick: onclickHideAndSavePane()) {
    273             //                                                                                                                             img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
     399            //                                                                                                                             img(src: addImg, alt: 'Add', title: 'Add Sub Item')
    274400            //                                                                                                                         }
    275401                                                                                                                                } // li
     
    319445        } // mkp
    320446
     447        def totalTime = (System.currentTimeMillis() - startedAt)/1000
     448        log.debug "Total time to build asset tree: " + totalTime + "sec."
    321449        return sw.toString()
    322450
    323451    } // buildAssetTree
    324452
    325 
    326     /** Imgs */
    327 
    328     def treeRootImg() {
    329         g.resource(dir:'images/skin',file:'chart_organisation.png')
    330     }
    331     def addImg() {
    332         g.resource(dir:'images/skin',file:'database_add.png')
    333     }
    334     def copyImg() {
    335         g.resource(dir:'images/skin',file:'page_copy.png')
    336     }
    337     def bulletTreePlusImg() {
    338         g.resource(dir:'images/skin',file:'bullet_tree_plus.png')
    339     }
    340     def bulletTreeMinusImg() {
    341         g.resource(dir:'images/skin',file:'bullet_tree_minus.png')
    342     }
    343     def dashImg() {
    344         g.resource(dir:'images/skin',file:'hline_short.png')
    345     }
    346     def closeImg() {
    347         g.resource(dir:'images/skin',file:'cross.png')
    348     }
    349 
    350453    /** js calls */
    351454
    352455    def hrefShowPane() {
    353         def url = g.createLink(controller: 'assetDetailed', action: 'assetTree')
    354         'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + url + '\");'
     456        'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + assetTreeActionUrl + '\");'
    355457    }
    356458
    357459    def onclickHideAndSavePane() {
    358         def saveUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
    359         'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
     460        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
    360461    }
    361462
    362463    def hrefHideAndSavePane() {
    363         def saveUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
    364         'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
     464        'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
    365465    }
    366466
    367467    def toggleBranch(divId) {
    368         js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg(), bulletTreePlusImg())
     468        js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg, bulletTreePlusImg)
    369469    }
    370470
    371471    /** Links */
    372472
    373     def siteCreateLink() {
    374         g.createLink(controller: 'siteDetailed', action: 'create').toString()
    375     }
    376473    def siteShowLink(id) {
    377         g.createLink(controller: 'siteDetailed', action: 'show', params: ['id': id] ).toString()
     474        siteShowBaseLink + '/' + id
    378475    }
    379476
    380477    def siteEditLink(id) {
    381         g.createLink(controller: 'siteDetailed', action: 'edit', params: ['id': id] ).toString()
     478        siteEditBaseLink + '/' + id
    382479    }
    383480
    384481    def sectionCreateLink(siteId) {
    385         g.createLink(controller: 'sectionDetailed', action: 'create', params: ['site.id': siteId] ).toString()
     482        sectionCreateBaseLink + '?site.id=' + siteId
    386483    }
    387484
    388485    def sectionShowLink(id) {
    389         g.createLink(controller: 'sectionDetailed', action: 'show', params: ['id': id] ).toString()
     486        sectionShowBaseLink + '/' + id
    390487    }
    391488
    392489    def sectionEditLink(id) {
    393         g.createLink(controller: 'sectionDetailed', action: 'edit', params: ['id': id] ).toString()
     490        sectionEditBaseLink + '/' + id
    394491    }
    395492
    396493    def assetCreateLink(sectionId) {
    397         g.createLink(controller: 'assetDetailed', action: 'create', params: ['section.id': sectionId] ).toString()
     494        assetCreateBaseLink + '?section.id=' + sectionId
    398495    }
    399496
    400497    def assetShowLink(id) {
    401         g.createLink(controller: 'assetDetailed', action: 'show', id: id ).toString()
     498        assetShowBaseLink + '/' + id
    402499    }
    403500
    404501    def assetEditLink(id) {
    405         g.createLink(controller: 'assetDetailed', action: 'edit', id: id ).toString()
     502        assetEditBaseLink + '/' + id
    406503    }
    407504
    408505    def assetCopyLink(id) {
    409         g.createLink(controller: 'assetDetailed', action: 'copy', params: ['assetToCopy.id': id] ).toString()
     506        assetCopyBaseLink + '?assetToCopy.id=' + id
    410507    }
    411508
    412509    def assetSubItemCreateLink(assetId) {
    413         g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['asset.id': assetId] ).toString()
     510        assetSubItemCreateBaseLink + '?asset.id=' + assetId
    414511    }
    415512
    416513    def assetSubItemCreateWithParentLink(parentItemId) {
    417         g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['parentItem.id': parentItemId] ).toString()
     514        assetSubItemCreateWithParentBaseLink + '?parentItem.id=' + parentItemId
    418515    }
    419516
    420517    def assetSubItemShowLink(id) {
    421         g.createLink(controller: 'assetSubItemDetailed', action: 'show', params: ['id': id] ).toString()
     518        assetSubItemShowBaseLink + '/' + id
    422519    }
    423520
    424521    def assetSubItemEditLink(id) {
    425         g.createLink(controller: 'assetSubItemDetailed', action: 'edit', params: ['id': id] ).toString()
     522        assetSubItemEditBaseLink + '/' + id
    426523    }
    427524
  • trunk/grails-app/taglib/AssetTreeTagLib.groovy

    r322 r457  
    77
    88    def js = new JsUtilService()
    9     def ts = new AssetTreeService()
     9    def assetTreeService
    1010
    1111    /**
     
    2020    */
    2121    def assetTreeButton = { attrs ->
    22         def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
    23 
    24         mkp.div( class: ts.buttonHtmlClass() ) {
    25             a( href: ts.hrefShowPane() ) {
    26                 img(src: ts.treeRootImg())
    27             }
    28         } // mkp
     22        out << assetTreeService.buildAssetTreeButton(attrs)
    2923    } // assetTreeButton
    3024
     
    3327    */
    3428    def assetTreePane = { attrs ->
    35         def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
    36 
    37         mkp.div(class: ts.paneHtmlClass(), id: ts.paneHtmlId(), style: 'display:none;') {
    38             div(class: ts.paneCloseHtmlClass()) {
    39                 a( href: js.toggle(ts.paneHtmlId()) ) {
    40                     img(src: ts.closeImg())
    41                 }
    42             }
    43 
    44             div(class: ts.tableDivHtmlClass()) {
    45                 table(id: ts.tableHtmlId()) {
    46                     tr() {
    47                         td(valign: 'top', class: 'value') {
    48                             ul() {
    49                                 img(src: ts.treeRootImg(), id: ts.tableLoadingImgId(), alt: 'TreeRoot')
    50                                 li() {
    51                                 } // li
    52                             } // ul
    53                         } // td
    54                     } // tr
    55                 } // table
    56             } // div
    57         } // mkp
    58     } // assetTreePane
     29        out << assetTreeService.buildAssetTreePane(attrs)
     30    }
    5931
    6032} // end class
Note: See TracChangeset for help on using the changeset viewer.