Index: /trunk/grails-app/services/AssetTreeService.groovy
===================================================================
--- /trunk/grails-app/services/AssetTreeService.groovy	(revision 456)
+++ /trunk/grails-app/services/AssetTreeService.groovy	(revision 457)
@@ -7,26 +7,84 @@
     def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
 
+    /** General */
+    def nameDescriptionSeperator = ' -- '
+
     /** Html class and id settings */
-
-    def buttonHtmlClass() {
-        'tree_button'
-    }
-    def paneHtmlClass() {
-        'overlayPane'
-    }
-    def paneHtmlId() {
-        'assetTreePane'
-    }
-    def paneCloseHtmlClass() {
-        'pane_close'
-    }
-    def tableDivHtmlClass() {
-        'tree'
-    }
-    def tableHtmlId() {
-        'assetTreeTable'
-    }
-    def tableLoadingImgId() {
-        'assetTreeLoadingImg'
+    def buttonHtmlClass = 'tree_button'
+    def paneHtmlClass = 'overlayPane'
+    def paneHtmlId = 'assetTreePane'
+    def paneCloseHtmlClass = 'pane_close'
+    def tableDivHtmlClass = 'tree'
+    def tableHtmlId = 'assetTreeTable'
+    def tableLoadingImgId = 'assetTreeLoadingImg'
+
+    /** Imgs */
+    def treeRootImg = ''
+    def addImg = ''
+    def copyImg = ''
+    def bulletTreePlusImg = ''
+    def bulletTreeMinusImg = ''
+    def dashImg = ''
+    def closeImg = ''
+
+    /** Urls */
+    def assetTreeActionUrl = ''
+    def saveAssetTreeStatusActionUrl = ''
+
+    /** Links */
+    def siteCreateBaseLink = ''
+    def siteShowBaseLink = ''
+    def siteEditBaseLink = ''
+    def sectionCreateBaseLink = ''
+    def sectionShowBaseLink = ''
+    def sectionEditBaseLink = ''
+    def assetCreateBaseLink = ''
+    def assetShowBaseLink = ''
+    def assetEditBaseLink = ''
+    def assetCopyBaseLink = ''
+    def assetSubItemCreateBaseLink = ''
+    def assetSubItemCreateWithParentBaseLink = ''
+    def assetSubItemShowBaseLink = ''
+    def assetSubItemEditBaseLink = ''
+
+    /**
+    * Initialise some class wide variables.
+    * This has been done to optimise since g.link and g.resource calls are expensive.
+    * This can't be done by class construction since some of the metaclass stuff is not available yet, e.g. 'out' etc.
+    * Initialise can't be called from BootStrap.
+    */
+    def initialise() {
+        log.debug "Initialise asset tree variables."
+
+        // Imgs.
+        treeRootImg = g.resource(dir:'images/skin',file:'chart_organisation.png')
+        addImg = g.resource(dir:'images/skin',file:'database_add.png')
+        copyImg = g.resource(dir:'images/skin',file:'page_copy.png')
+        bulletTreePlusImg = g.resource(dir:'images/skin',file:'bullet_tree_plus.png')
+        bulletTreeMinusImg = g.resource(dir:'images/skin',file:'bullet_tree_minus.png')
+        dashImg = g.resource(dir:'images/skin',file:'hline_short.png')
+        closeImg = g.resource(dir:'images/skin',file:'cross.png')
+
+        // Urls.
+        assetTreeActionUrl = g.createLink(controller: 'assetDetailed', action: 'assetTree')
+        saveAssetTreeStatusActionUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
+
+        // Links
+        siteCreateBaseLink = g.createLink(controller: 'siteDetailed', action: 'create').toString()
+        siteShowBaseLink = g.createLink(controller: 'siteDetailed', action: 'show').toString()
+        siteEditBaseLink = g.createLink(controller: 'siteDetailed', action: 'edit').toString()
+        sectionCreateBaseLink = g.createLink(controller: 'sectionDetailed', action: 'create').toString()
+        sectionShowBaseLink = g.createLink(controller: 'sectionDetailed', action: 'show').toString()
+        sectionEditBaseLink = g.createLink(controller: 'sectionDetailed', action: 'edit').toString()
+        assetCreateBaseLink = g.createLink(controller: 'assetDetailed', action: 'create').toString()
+        assetShowBaseLink = g.createLink(controller: 'assetDetailed', action: 'show').toString()
+        assetEditBaseLink = g.createLink(controller: 'assetDetailed', action: 'edit').toString()
+        assetCopyBaseLink = g.createLink(controller: 'assetDetailed', action: 'copy').toString()
+        assetSubItemCreateBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
+        assetSubItemCreateWithParentBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
+        assetSubItemShowBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'show').toString()
+        assetSubItemEditBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'edit').toString()
+        // Success.
+        return true
     }
 
@@ -39,11 +97,71 @@
     def description(obj) {
         def s =  obj.description.encodeAsHTML()
-        if(s) s = ' -- ' + s
-        else ''
-    }
+        s = s? (nameDescriptionSeperator + s) : ''
+    }
+
+    /**
+    * Build and return the asset tree button.
+    * Built here instead of directly in the taglib since we may need to initialise.
+    */
+    def buildAssetTreeButton(attrs) {
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw)
+
+        mkp.div(class: buttonHtmlClass) {
+            a( href: hrefShowPane() ) {
+                img(src: treeRootImg)
+            }
+        } // mkp
+
+        return sw.toString()
+    }
+
+    /**
+    * Build and return the empty asset tree pane, ready for populating by ajax call to buildAssetTree.
+    * Built here instead of directly in the taglib since we may need to initialise.
+    */
+    def buildAssetTreePane(attrs) {
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw)
+
+        mkp.div(class: paneHtmlClass, id: paneHtmlId, style: 'display:none;') {
+            div(class: paneCloseHtmlClass) {
+                a( href: js.toggle(paneHtmlId) ) {
+                    img(src: closeImg)
+                }
+            }
+
+            div(class: tableDivHtmlClass) {
+                table(id: tableHtmlId) {
+                    tr() {
+                        td(valign: 'top', class: 'value') {
+                            ul() {
+                                img(src: treeRootImg, id: tableLoadingImgId, alt: 'TreeRoot')
+                                li() {
+                                } // li
+                            } // ul
+                        } // td
+                    } // tr
+                } // table
+            } // div
+        } // mkp
+
+        return sw.toString()
+
+    } // buildAssetPane
 
     /**
     * Build and return the asset tree table.
-    * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div.
+    * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div built by buildAssetTreePane().
     * This table replaces the contents of the wrapper div.
     * @returns The asset tree table as a String
@@ -51,5 +169,13 @@
     def buildAssetTree(params, session) {
 
-        def sites = Site.list()
+        def startedAt = System.currentTimeMillis()
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sites = Site.withCriteria {
+            eq("isActive", true)
+        }
 
         def visibleBranches = session.assetTreeVisibleBranches ? session.assetTreeVisibleBranches.tokenize(',') : []
@@ -64,7 +190,7 @@
         def branchImg = { branchId ->
             if(visibleBranches.contains(branchId))
-                bulletTreeMinusImg()
+                bulletTreeMinusImg
             else
-                bulletTreePlusImg()
+                bulletTreePlusImg
         }
 
@@ -77,24 +203,24 @@
 
         def sw = new StringWriter()
-        def mkp = new groovy.xml.MarkupBuilder(sw) //this line will be unnecessary in versions of Grails after version 1.2
+        def mkp = new groovy.xml.MarkupBuilder(sw)
 
         // Offer a site create link if no sites are found.
         if(!sites) {
-            mkp.div(class: tableDivHtmlClass()) {
-
-                div(class: paneCloseHtmlClass()) {
-                    a( href: js.toggle(paneHtmlId()) ) {
-                        img(src: closeImg())
+            mkp.div(class: tableDivHtmlClass) {
+
+                div(class: paneCloseHtmlClass) {
+                    a( href: js.toggle(paneHtmlId) ) {
+                        img(src: closeImg)
                     }
                 }
 
-                table(id: tableHtmlId()) {
+                table(id: tableHtmlId) {
                     tr() {
                         td( valign: 'top', class: 'value') {
                             ul() {
-                                img(src: treeRootImg(), alt: 'TreeRoot')
+                                img(src: treeRootImg, alt: 'TreeRoot')
                                 li() {
-                                    a(href: siteCreateLink()) {
-                                        img(src: addImg(), alt: 'Add', title: 'Add Site')
+                                    a(href: siteCreateBaseLink()) {
+                                        img(src: addImg, alt: 'Add', title: 'Add Site')
                                     }
                                 } // li
@@ -106,5 +232,5 @@
                 div( class: 'buttons') {
                     span(class: 'button') {
-                        input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.toggle(paneHtmlId(), "onclick") )
+                        input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.toggle(paneHtmlId, "onclick") )
                     }
                 } // button div
@@ -116,17 +242,17 @@
         // The main populated table.
         /// @todo: use a loop for the subItem levels.
-        mkp.div(class: tableDivHtmlClass()) {
-
-            div(class: paneCloseHtmlClass()) {
+        mkp.div(class: tableDivHtmlClass) {
+
+            div(class: paneCloseHtmlClass) {
                 a( href: hrefHideAndSavePane() ) {
-                    img(src: closeImg())
+                    img(src: closeImg)
                 }
             }
 
-            table(id: tableHtmlId()) {
+            table(id: tableHtmlId) {
                 tr() {
                     td(valign: 'top', class: 'value') {
                         ul() {
-                            img(src: treeRootImg(), alt: 'TreeRoot')
+                            img(src: treeRootImg, alt: 'TreeRoot')
                             for(site in sites.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
                                 li() {
@@ -137,5 +263,5 @@
                                     }
                                     else
-                                        img(src: dashImg())
+                                        img(src: dashImg)
                                     a( href: siteShowLink(site.id), onclick: onclickHideAndSavePane() ) {
                                         yieldUnescaped( name(site)  )
@@ -143,5 +269,5 @@
                                     yieldUnescaped( description(site)  )
                                     a(href: sectionCreateLink(site.id), onclick: onclickHideAndSavePane()) {
-                                        img(src: addImg(), alt: 'Add', title: 'Add Section')
+                                        img(src: addImg, alt: 'Add', title: 'Add Section')
                                     }
                                 }
@@ -157,5 +283,5 @@
                                                     }
                                                     else
-                                                        img(src: dashImg())
+                                                        img(src: dashImg)
                                                     a( href: sectionShowLink(section.id), onclick: onclickHideAndSavePane() ) {
                                                         yieldUnescaped( name(section) )
@@ -163,5 +289,5 @@
                                                     yieldUnescaped( description(section)  )
                                                     a(href: assetCreateLink(section.id), onclick: onclickHideAndSavePane()) {
-                                                        img(src: addImg(), alt: 'Add', title: 'Add Asset')
+                                                        img(src: addImg, alt: 'Add', title: 'Add Asset')
                                                     }
                                                 }
@@ -178,5 +304,5 @@
                                                                     }
                                                                     else
-                                                                        img(src: dashImg())
+                                                                        img(src: dashImg)
                                                                     a( href: assetShowLink(asset.id), onclick: onclickHideAndSavePane() ) {
                                                                         yieldUnescaped( name(asset) )
@@ -184,8 +310,8 @@
                                                                     yieldUnescaped( description(asset) )
                                                                     a(href: assetSubItemCreateLink(asset.id), onclick: onclickHideAndSavePane()) {
-                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
                                                                     }
                                                                     a(href: assetCopyLink(asset.id), onclick: onclickHideAndSavePane()) {
-                                                                        img(src: copyImg(), alt: 'Add', title: 'Copy Asset')
+                                                                        img(src: copyImg, alt: 'Add', title: 'Copy Asset')
                                                                     }
                                                                 } // li
@@ -202,5 +328,5 @@
                                                                                     }
                                                                                     else
-                                                                                        img(src: dashImg())
+                                                                                        img(src: dashImg)
                                                                                     a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: onclickHideAndSavePane() ) {
                                                                                         yieldUnescaped( name(assetSubItemL1) )
@@ -208,5 +334,5 @@
                                                                                     yieldUnescaped( description(assetSubItemL1) )
                                                                                     a(href: assetSubItemCreateWithParentLink(assetSubItemL1.id), onclick: onclickHideAndSavePane()) {
-                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
                                                                                     }
                                                                                 } // li
@@ -223,5 +349,5 @@
                                                                                                     }
                                                                                                     else
-                                                                                                        img(src: dashImg())
+                                                                                                        img(src: dashImg)
                                                                                                     a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: onclickHideAndSavePane() ) {
                                                                                                         yieldUnescaped( name(assetSubItemL2) )
@@ -229,5 +355,5 @@
                                                                                                     yieldUnescaped( description(assetSubItemL2) )
                                                                                                     a(href: assetSubItemCreateWithParentLink(assetSubItemL2.id), onclick: onclickHideAndSavePane()) {
-                                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
                                                                                                     }
                                                                                                 } // li
@@ -244,5 +370,5 @@
                                                                                                                     }
                                                                                                                     else
-                                                                                                                        img(src: dashImg())
+                                                                                                                        img(src: dashImg)
                                                                                                                     a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: onclickHideAndSavePane() ) {
                                                                                                                         yieldUnescaped( name(assetSubItemL3) )
@@ -250,5 +376,5 @@
                                                                                                                     yieldUnescaped( description(assetSubItemL3) )
                                                                                                                     a(href: assetSubItemCreateWithParentLink(assetSubItemL3.id), onclick: onclickHideAndSavePane()) {
-                                                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
                                                                                                                     }
                                                                                                                 } // li
@@ -265,5 +391,5 @@
             //                                                                                                                         }
             //                                                                                                                         else
-                                                                                                                                    img(src: dashImg())
+                                                                                                                                    img(src: dashImg)
                                                                                                                                     a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: onclickHideAndSavePane() ) {
                                                                                                                                         yieldUnescaped( name(assetSubItemL4) )
@@ -271,5 +397,5 @@
                                                                                                                                     yieldUnescaped( description(assetSubItemL4) )
             //                                                                                                                         a(href: assetSubItemCreateWithParentLink(assetSubItemL4.id), onclick: onclickHideAndSavePane()) {
-            //                                                                                                                             img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+            //                                                                                                                             img(src: addImg, alt: 'Add', title: 'Add Sub Item')
             //                                                                                                                         }
                                                                                                                                 } // li
@@ -319,109 +445,80 @@
         } // mkp
 
+        def totalTime = (System.currentTimeMillis() - startedAt)/1000
+        log.debug "Total time to build asset tree: " + totalTime + "sec."
         return sw.toString()
 
     } // buildAssetTree
 
-
-    /** Imgs */
-
-    def treeRootImg() {
-        g.resource(dir:'images/skin',file:'chart_organisation.png')
-    }
-    def addImg() {
-        g.resource(dir:'images/skin',file:'database_add.png')
-    }
-    def copyImg() {
-        g.resource(dir:'images/skin',file:'page_copy.png')
-    }
-    def bulletTreePlusImg() {
-        g.resource(dir:'images/skin',file:'bullet_tree_plus.png')
-    }
-    def bulletTreeMinusImg() {
-        g.resource(dir:'images/skin',file:'bullet_tree_minus.png')
-    }
-    def dashImg() {
-        g.resource(dir:'images/skin',file:'hline_short.png')
-    }
-    def closeImg() {
-        g.resource(dir:'images/skin',file:'cross.png')
-    }
-
     /** js calls */
 
     def hrefShowPane() {
-        def url = g.createLink(controller: 'assetDetailed', action: 'assetTree')
-        'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + url + '\");'
+        'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + assetTreeActionUrl + '\");'
     }
 
     def onclickHideAndSavePane() {
-        def saveUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
-        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
+        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
     }
 
     def hrefHideAndSavePane() {
-        def saveUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
-        'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
+        'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
     }
 
     def toggleBranch(divId) {
-        js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg(), bulletTreePlusImg())
+        js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg, bulletTreePlusImg)
     }
 
     /** Links */
 
-    def siteCreateLink() {
-        g.createLink(controller: 'siteDetailed', action: 'create').toString()
-    }
     def siteShowLink(id) {
-        g.createLink(controller: 'siteDetailed', action: 'show', params: ['id': id] ).toString()
+        siteShowBaseLink + '/' + id
     }
 
     def siteEditLink(id) {
-        g.createLink(controller: 'siteDetailed', action: 'edit', params: ['id': id] ).toString()
+        siteEditBaseLink + '/' + id
     }
 
     def sectionCreateLink(siteId) {
-        g.createLink(controller: 'sectionDetailed', action: 'create', params: ['site.id': siteId] ).toString()
+        sectionCreateBaseLink + '?site.id=' + siteId
     }
 
     def sectionShowLink(id) {
-        g.createLink(controller: 'sectionDetailed', action: 'show', params: ['id': id] ).toString()
+        sectionShowBaseLink + '/' + id
     }
 
     def sectionEditLink(id) {
-        g.createLink(controller: 'sectionDetailed', action: 'edit', params: ['id': id] ).toString()
+        sectionEditBaseLink + '/' + id
     }
 
     def assetCreateLink(sectionId) {
-        g.createLink(controller: 'assetDetailed', action: 'create', params: ['section.id': sectionId] ).toString()
+        assetCreateBaseLink + '?section.id=' + sectionId
     }
 
     def assetShowLink(id) {
-        g.createLink(controller: 'assetDetailed', action: 'show', id: id ).toString()
+        assetShowBaseLink + '/' + id
     }
 
     def assetEditLink(id) {
-        g.createLink(controller: 'assetDetailed', action: 'edit', id: id ).toString()
+        assetEditBaseLink + '/' + id
     }
 
     def assetCopyLink(id) {
-        g.createLink(controller: 'assetDetailed', action: 'copy', params: ['assetToCopy.id': id] ).toString()
+        assetCopyBaseLink + '?assetToCopy.id=' + id
     }
 
     def assetSubItemCreateLink(assetId) {
-        g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['asset.id': assetId] ).toString()
+        assetSubItemCreateBaseLink + '?asset.id=' + assetId
     }
 
     def assetSubItemCreateWithParentLink(parentItemId) {
-        g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['parentItem.id': parentItemId] ).toString()
+        assetSubItemCreateWithParentBaseLink + '?parentItem.id=' + parentItemId
     }
 
     def assetSubItemShowLink(id) {
-        g.createLink(controller: 'assetSubItemDetailed', action: 'show', params: ['id': id] ).toString()
+        assetSubItemShowBaseLink + '/' + id
     }
 
     def assetSubItemEditLink(id) {
-        g.createLink(controller: 'assetSubItemDetailed', action: 'edit', params: ['id': id] ).toString()
+        assetSubItemEditBaseLink + '/' + id
     }
 
Index: /trunk/grails-app/taglib/AssetTreeTagLib.groovy
===================================================================
--- /trunk/grails-app/taglib/AssetTreeTagLib.groovy	(revision 456)
+++ /trunk/grails-app/taglib/AssetTreeTagLib.groovy	(revision 457)
@@ -7,5 +7,5 @@
 
     def js = new JsUtilService()
-    def ts = new AssetTreeService()
+    def assetTreeService
 
     /**
@@ -20,11 +20,5 @@
     */
     def assetTreeButton = { attrs ->
-        def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
-
-        mkp.div( class: ts.buttonHtmlClass() ) {
-            a( href: ts.hrefShowPane() ) {
-                img(src: ts.treeRootImg())
-            }
-        } // mkp
+        out << assetTreeService.buildAssetTreeButton(attrs)
     } // assetTreeButton
 
@@ -33,28 +27,6 @@
     */
     def assetTreePane = { attrs ->
-        def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
-
-        mkp.div(class: ts.paneHtmlClass(), id: ts.paneHtmlId(), style: 'display:none;') {
-            div(class: ts.paneCloseHtmlClass()) {
-                a( href: js.toggle(ts.paneHtmlId()) ) {
-                    img(src: ts.closeImg())
-                }
-            }
-
-            div(class: ts.tableDivHtmlClass()) {
-                table(id: ts.tableHtmlId()) {
-                    tr() {
-                        td(valign: 'top', class: 'value') {
-                            ul() {
-                                img(src: ts.treeRootImg(), id: ts.tableLoadingImgId(), alt: 'TreeRoot')
-                                li() {
-                                } // li
-                            } // ul
-                        } // td
-                    } // tr
-                } // table
-            } // div
-        } // mkp
-    } // assetTreePane
+        out << assetTreeService.buildAssetTreePane(attrs)
+    }
 
 } // end class
