Index: /trunk/grails-app/controllers/AssetDetailedController.groovy
===================================================================
--- /trunk/grails-app/controllers/AssetDetailedController.groovy	(revision 311)
+++ /trunk/grails-app/controllers/AssetDetailedController.groovy	(revision 312)
@@ -9,4 +9,5 @@
     def exportService
     def assetService
+    def assetTreeService
 
     // the delete, save and update actions only accept POST requests
@@ -17,4 +18,9 @@
 
     def importAssetTree = {
+    }
+
+    def assetTree = {
+        def s = assetTreeService.buildAssetTree(params, session)
+        render s
     }
 
Index: /trunk/grails-app/i18n/messages.properties
===================================================================
--- /trunk/grails-app/i18n/messages.properties	(revision 311)
+++ /trunk/grails-app/i18n/messages.properties	(revision 312)
@@ -113,4 +113,6 @@
 assignedGroup.task.not.found=Please select a task and then ''Add Assigned Group''.
 assignedPerson.task.not.found=Please select a task and then ''Add Assigned Person''.
+
+default.close.text=Close
 
 default.list.failure=Could not generate list for class {0}.
Index: /trunk/grails-app/services/AssetTreeService.groovy
===================================================================
--- /trunk/grails-app/services/AssetTreeService.groovy	(revision 312)
+++ /trunk/grails-app/services/AssetTreeService.groovy	(revision 312)
@@ -0,0 +1,409 @@
+class AssetTreeService {
+
+    boolean transactional = false
+
+    def js = new JavascriptService()
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    /** Html class and id settings */
+
+    def buttonHtmlClass() {
+        "tree_button"
+    }
+    def paneHtmlClass() {
+        'overlayPane'
+    }
+    def paneHtmlId() {
+        'assetTreePane'
+    }
+    def paneCloseHtmlClass() {
+        'tree_pane_close'
+    }
+    def tableDivHtmlClass() {
+        'tree'
+    }
+    def tableHtmlId() {
+        'assetTreeTable'
+    }
+    def tableLoadingImgId() {
+        'assetTreeLoadingImg'
+    }
+
+    /**
+    * Build and return the asset tree table.
+    * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div.
+    * This table replaces the contents of the wrapper div.
+    * @returns The asset tree table as a String
+    */
+    def buildAssetTree(params, session) {
+
+        def sites = Site.list()
+
+        def visibleBranches = session.assetTreeVisibleBranches ? session.assetTreeVisibleBranches.tokenize(',') : []
+
+        def branchStyle = { branchId ->
+            if(visibleBranches.contains(branchId))
+                ''
+            else
+                'display:none;'
+        }
+
+        def branchImg = { branchId ->
+            if(visibleBranches.contains(branchId))
+                bulletTreeMinusImg()
+            else
+                bulletTreePlusImg()
+        }
+
+        def divIdCount = 0
+        def divId = ''
+        def nextDivId = {
+            divIdCount++
+            divId = 'assetTreeBranch'+divIdCount
+        }
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw) //this line will be unnecessary in versions of Grails after version 1.2
+
+        // Offer a site create link if no sites are found.
+        if(!sites) {
+            mkp.div(class: tableDivHtmlClass()) {
+
+                div(class: paneCloseHtmlClass()) {
+                    a( href: js.hrefToggle(paneHtmlId()) ) {
+                        img(src: closeImg())
+                    }
+                }
+
+                table(id: tableHtmlId()) {
+                    tr() {
+                        td( valign: 'top', class: 'value') {
+                            ul() {
+                                img(src: treeRootImg(), alt: 'TreeRoot')
+                                li() {
+                                    a(href: siteCreateLink()) {
+                                        img(src: addImg(), alt: 'Add', title: 'Add Site')
+                                    }
+                                } // li
+                            } // ul
+                        } // td
+                    } // tr
+                } // table
+
+                div( class: 'buttons') {
+                    span(class: 'button') {
+                        input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.onclickToggle(paneHtmlId()) )
+                    }
+                } // button div
+            } // mkp
+            return sw.toString()
+        } // if(!sites)
+
+
+        // The main populated table.
+        /// @todo: use a loop for the subItem levels.
+        mkp.div(class: tableDivHtmlClass()) {
+
+            div(class: paneCloseHtmlClass()) {
+                a( href: hrefHideAndSavePane() ) {
+                    img(src: closeImg())
+                }
+            }
+
+            table(id: tableHtmlId()) {
+                tr() {
+                    td(valign: 'top', class: 'value') {
+                        ul() {
+                            img(src: treeRootImg(), alt: 'TreeRoot')
+                            for(site in sites.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                li() {
+                                    if(site.sections) {
+                                        a(href: hrefToggleBranch(nextDivId()) ) {
+                                            img( src: branchImg(divId), id: divId+'img' )
+                                        }
+                                    }
+                                    else
+                                        img(src: dashImg())
+                                    a( href: siteShowLink(site.id), onclick: onclickHideAndSavePane() ) {
+                                        yieldUnescaped( site.encodeAsHTML() )
+                                    }
+                                    a(href: sectionCreateLink(site.id), onclick: onclickHideAndSavePane()) {
+                                        img(src: addImg(), alt: 'Add', title: 'Add Section')
+                                    }
+                                }
+                                if(site.sections) {
+                                    div( id: divId, style: branchStyle(divId) ) {
+                                        ul() {
+                                            for(section in site.sections.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                li() {
+                                                    if(section.assets) {
+                                                        a( href: hrefToggleBranch(nextDivId()) ) {
+                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                        }
+                                                    }
+                                                    else
+                                                        img(src: dashImg())
+                                                    a( href: sectionShowLink(section.id), onclick: onclickHideAndSavePane() ) {
+                                                        yieldUnescaped( section.encodeAsHTML() )
+                                                    }
+                                                    a(href: assetCreateLink(section.id), onclick: onclickHideAndSavePane()) {
+                                                        img(src: addImg(), alt: 'Add', title: 'Add Asset')
+                                                    }
+                                                }
+
+                                                if(section.assets) {
+                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                        ul() {
+                                                            for(asset in section.assets.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                li() {
+                                                                    if(asset.assetSubItems) {
+                                                                        a( href: hrefToggleBranch(nextDivId()) ) {
+                                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                                        }
+                                                                    }
+                                                                    else
+                                                                        img(src: dashImg())
+                                                                    a( href: assetShowLink(asset.id), onclick: onclickHideAndSavePane() ) {
+                                                                        yieldUnescaped( asset.encodeAsHTML() )
+                                                                    }
+                                                                    a(href: assetSubItemCreateLink(asset.id), onclick: onclickHideAndSavePane()) {
+                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                    }
+                                                                    a(href: assetCopyLink(asset.id), onclick: onclickHideAndSavePane()) {
+                                                                        img(src: copyImg(), alt: 'Add', title: 'Copy Asset')
+                                                                    }
+                                                                } // li
+
+                                                                if(asset.assetSubItems) {
+                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                        ul() {
+                                                                            for(assetSubItemL1 in asset.assetSubItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                li() {
+                                                                                    if(assetSubItemL1.subItems) {
+                                                                                        a( href: hrefToggleBranch(nextDivId()) ) {
+                                                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                                                        }
+                                                                                    }
+                                                                                    else
+                                                                                        img(src: dashImg())
+                                                                                    a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: onclickHideAndSavePane() ) {
+                                                                                        yieldUnescaped( assetSubItemL1.encodeAsHTML() )
+                                                                                    }
+                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL1.id), onclick: onclickHideAndSavePane()) {
+                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                    }
+                                                                                } // li
+
+                                                                                if(assetSubItemL1.subItems) {
+                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                        ul() {
+                                                                                            for(assetSubItemL2 in assetSubItemL1.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                li() {
+                                                                                                    if(assetSubItemL2.subItems) {
+                                                                                                        a( href: hrefToggleBranch(nextDivId()) ) {
+                                                                                                            img( src: branchImg(divId), id: divId+'img' )
+                                                                                                        }
+                                                                                                    }
+                                                                                                    else
+                                                                                                        img(src: dashImg())
+                                                                                                    a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                        yieldUnescaped( assetSubItemL2.encodeAsHTML() )
+                                                                                                    }
+                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL2.id), onclick: onclickHideAndSavePane()) {
+                                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                                    }
+                                                                                                } // li
+
+                                                                                                if(assetSubItemL2.subItems) {
+                                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                                        ul() {
+                                                                                                            for(assetSubItemL3 in assetSubItemL2.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                                li() {
+                                                                                                                    if(assetSubItemL3.subItems) {
+                                                                                                                        a( href: hrefToggleBranch(nextDivId()) ) {
+                                                                                                                            img( src: branchImg(divId), id: divId+'img' )
+                                                                                                                        }
+                                                                                                                    }
+                                                                                                                    else
+                                                                                                                        img(src: dashImg())
+                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                                        yieldUnescaped( assetSubItemL3.encodeAsHTML() )
+                                                                                                                    }
+                                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL3.id), onclick: onclickHideAndSavePane()) {
+                                                                                                                        img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+                                                                                                                    }
+                                                                                                                } // li
+
+                                                                                                                if(assetSubItemL3.subItems) {
+                                                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                                                        ul() {
+                                                                                                                            for(assetSubItemL4 in assetSubItemL3.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                                                li() {
+            //                                                                                                                         if(assetSubItemL4.subItems) {
+            //                                                                                                                             a( href: hrefToggleBranch(nextDivId()) ) {
+            //                                                                                                                                 img( src: branchImg(divId), id: divId+'img' )
+            //                                                                                                                             }
+            //                                                                                                                         }
+            //                                                                                                                         else
+                                                                                                                                    img(src: dashImg())
+                                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                                                        yieldUnescaped( assetSubItemL4.encodeAsHTML() )
+                                                                                                                                    }
+            //                                                                                                                         a(href: assetSubItemCreateWithParentLink(assetSubItemL4.id), onclick: onclickHideAndSavePane()) {
+            //                                                                                                                             img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
+            //                                                                                                                         }
+                                                                                                                                } // li
+
+                                                                                                                            } // assetSubItemL4
+                                                                                                                        } // ul
+                                                                                                                    } // div
+                                                                                                                } // if(assetSubItemL3.subItems)
+
+
+                                                                                                            } // assetSubItemL3
+                                                                                                        } // ul
+                                                                                                    } // div
+                                                                                                } // if(assetSubItemL2.subItems)
+
+                                                                                            } // assetSubItemL2
+                                                                                        } // ul
+                                                                                    } // div
+                                                                                } // if(assetSubItemL1.subItems)
+
+                                                                            } // assetSubItemL1
+                                                                        } // ul
+                                                                    } // div
+                                                                } // if(asset.assetSubItems)
+
+                                                            } // assets
+                                                        } // ul
+                                                    } // div
+                                                } // if(section.assets)
+
+                                            } //sections
+                                        } // ul
+                                    } // div
+                                } // if(site.sections)
+                            } // sites
+                        } // ul
+                    } // td
+                } // tr
+            } // table
+
+            div( class: 'buttons') {
+                span(class: 'button') {
+                    input( type: 'button', value: g.message(code: 'default.close.text'), onclick: onclickHideAndSavePane() )
+                }
+            }
+
+        } // mkp
+
+        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 + '\");'
+    }
+
+    def onclickHideAndSavePane() {
+        def saveUrl = g.createLink(controller: 'appCore', action: 'saveAssetTreeStatus')
+        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
+    }
+
+    def hrefHideAndSavePane() {
+        def saveUrl = g.createLink(controller: 'appCore', action: 'saveAssetTreeStatus')
+        'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
+    }
+
+    def hrefToggleBranch(divId) {
+       'javascript: toggleBranch(\"' + 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()
+    }
+
+    def siteEditLink(id) {
+        g.createLink(controller: 'siteDetailed', action: 'edit', params: ['id': id] ).toString()
+    }
+
+    def sectionCreateLink(siteId) {
+        g.createLink(controller: 'sectionDetailed', action: 'create', params: ['site.id': siteId] ).toString()
+    }
+
+    def sectionShowLink(id) {
+        g.createLink(controller: 'sectionDetailed', action: 'show', params: ['id': id] ).toString()
+    }
+
+    def sectionEditLink(id) {
+        g.createLink(controller: 'sectionDetailed', action: 'edit', params: ['id': id] ).toString()
+    }
+
+    def assetCreateLink(sectionId) {
+        g.createLink(controller: 'assetDetailed', action: 'create', params: ['section.id': sectionId] ).toString()
+    }
+
+    def assetShowLink(id) {
+        g.createLink(controller: 'assetDetailed', action: 'show', id: id ).toString()
+    }
+
+    def assetEditLink(id) {
+        g.createLink(controller: 'assetDetailed', action: 'edit', id: id ).toString()
+    }
+
+    def assetCopyLink(id) {
+        g.createLink(controller: 'assetDetailed', action: 'copy', params: ['assetToCopy.id': id] ).toString()
+    }
+
+    def assetSubItemCreateLink(assetId) {
+        g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['asset.id': assetId] ).toString()
+    }
+
+    def assetSubItemCreateWithParentLink(parentItemId) {
+        g.createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['parentItem.id': parentItemId] ).toString()
+    }
+
+    def assetSubItemShowLink(id) {
+        g.createLink(controller: 'assetSubItemDetailed', action: 'show', params: ['id': id] ).toString()
+    }
+
+    def assetSubItemEditLink(id) {
+        g.createLink(controller: 'assetSubItemDetailed', action: 'edit', params: ['id': id] ).toString()
+    }
+
+} // end class
Index: /trunk/grails-app/services/JavascriptService.groovy
===================================================================
--- /trunk/grails-app/services/JavascriptService.groovy	(revision 312)
+++ /trunk/grails-app/services/JavascriptService.groovy	(revision 312)
@@ -0,0 +1,69 @@
+/**
+* Provides some javascript utility methods.
+* To use include the following in the gsp head:
+* <!--
+* <g:javascript src="util.js" />
+* -->
+* @todo: util.js could be placed a taglib resources closure.
+*/
+class JavascriptService {
+
+    boolean transactional = false
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    /**
+    * Toggle the visibility of an html element.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an onclick action.
+    */
+    def onclickToggle(id) {
+        'return toggleUtil(\"' + id + '\");'
+    }
+
+    /**
+    * Toggle the visibility of an html element.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an anchor href.
+    */
+    def hrefToggle(id) {
+        'javascript: toggleUtil(\"' + id + '\");'
+    }
+
+    /**
+    * Show an html element by slowly increasing the visibility.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an onclick action.
+    */
+    def onclickShow(id) {
+        'return showUtil(\"' + id + '\");'
+    }
+
+    /**
+    * Show an html element by slowly increasing the visibility.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an anchor href.
+    */
+    def hrefShow(id) {
+        'javascript: showUtil(\"' + id + '\");'
+    }
+
+    /**
+    * Hide an html element by slowly decreasing the visibility.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an onclick action.
+    */
+    def onclickHide(id) {
+        'return hideUtil(\"' + id + '\");'
+    }
+
+    /**
+    * Hide an html element by slowly decreasing the visibility.
+    * @param id The html id of the element.
+    * @returns A javascript string that can be assigned to an anchor href.
+    */
+    def hrefHide(id) {
+        'javascript: hideUtil(\"' + id + '\");'
+    }
+
+} // end class
Index: /trunk/grails-app/taglib/AssetTreeTagLib.groovy
===================================================================
--- /trunk/grails-app/taglib/AssetTreeTagLib.groovy	(revision 311)
+++ /trunk/grails-app/taglib/AssetTreeTagLib.groovy	(revision 312)
@@ -6,255 +6,48 @@
     static namespace = 'gnuMims'
 
+    def js = new JavascriptService()
+    def ts = new AssetTreeService()
+
+    /**
+    * Include required javascript and do setup here.
+    */
     def resources = { attrs ->
-        ///@todo: should include our javascript and do setup here.
+        out << g.javascript(src: "assetTree.js")
     }
 
-    def assetTreeButton = {
+    /**
+    * Button that opens the asset tree pane and calls the javascript to populate it.
+    */
+    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: "tree_button") {
-            a(href: showPane()) {
-                img(src: treeRootImg())
+        mkp.div( class: ts.buttonHtmlClass() ) {
+            a( href: ts.hrefShowPane() ) {
+                img(src: ts.treeRootImg())
             }
-        }
-    } // mkp
+        } // mkp
+    } // assetTreeButton
 
-    def assetTree = { attrs ->
-
-        def sites = Site.list()
-
-        def visibleBranches = session.assetTreeVisibleBranches ? session.assetTreeVisibleBranches.tokenize(',') : []
-
-        def branchStyle = { branchId ->
-            if(visibleBranches.contains(branchId))
-                ''
-            else
-                'display:none;'
-        }
-
-        def branchImg = { branchId ->
-            if(visibleBranches.contains(branchId))
-                bulletTreeMinusImg()
-            else
-                bulletTreePlusImg()
-        }
-
-        def divIdCount = 0
-        def divId = ''
-        def nextDivId = {
-            divIdCount++
-            divId = 'assetTreeBranch'+divIdCount
-        }
-
+    /**
+    * The asset tree pane, ready for populating by an ajax call to AssetTreeSevice.
+    */
+    def assetTreePane = { attrs ->
         def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
 
-        // Offer a site create link if no sites are found.
-        if(!sites) {
-            mkp.div(class: 'overlayPane', id: 'assetTreePane', style: 'display:none;') {
-                div(class: 'tree', id: 'assetTreeTable') {
-                    table() {
-                        tr() {
-                            td( valign: 'top', class: 'value') {
-                                ul() {
-                                    img(src: treeRootImg(), alt: 'TreeRoot')
-                                    li() {
-                                        a(href: siteCreateLink()) {
-                                            img(src: addImg(), alt: 'Add', title: 'Add Site')
-                                        }
-                                    } // li
-                                } // ul
-                            } // td
-                        } // tr
-                    } // table
-                } // div
+        mkp.div(class: ts.paneHtmlClass(), id: ts.paneHtmlId(), style: 'display:none;') {
+            div(class: ts.paneCloseHtmlClass()) {
+                a( href: js.hrefToggle(ts.paneHtmlId()) ) {
+                    img(src: ts.closeImg())
+                }
+            }
 
-                div( class: 'buttons') {
-                    span(class: 'button') {
-                        input( type: 'button', value: 'Close', onclick: hideAssetTreePane() )
-                    }
-                } // button div
-            } // mkp
-            return
-        } // if(!sites)
-
-
-        /// @todo: use a loop for the subItem levels.
-        mkp.div(class: 'overlayPane', id: 'assetTreePane', style: 'display:none;') {
-            div(class: 'tree', id: 'assetTreeTable') {
-                table() {
+            div(class: ts.tableDivHtmlClass()) {
+                table(id: ts.tableHtmlId()) {
                     tr() {
-                        td( valign: 'top', class: 'value') {
+                        td(valign: 'top', class: 'value') {
                             ul() {
-                                img(src: treeRootImg(), alt: 'TreeRoot')
-                                for(site in sites.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                    li() {
-                                        if(site.sections) {
-                                            a(href: toggleBranch(nextDivId()) ) {
-                                                img( src: branchImg(divId), id: divId+'img' )
-                                            }
-                                        }
-                                        else
-                                            img(src: dashImg())
-                                        a( href: siteShowLink(site.id), onclick: hideAssetTreePane() ) {
-                                            yieldUnescaped( site.encodeAsHTML() )
-                                        }
-                                        a(href: sectionCreateLink(site.id), onclick: hideAssetTreePane()) {
-                                            img(src: addImg(), alt: 'Add', title: 'Add Section')
-                                        }
-                                    }
-                                    if(site.sections) {
-                                        div( id: divId, style: branchStyle(divId) ) {
-                                            ul() {
-                                                for(section in site.sections.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                    li() {
-                                                        if(section.assets) {
-                                                            a( href: toggleBranch(nextDivId()) ) {
-                                                                img(src: branchImg(divId), id: divId+'img' )
-                                                            }
-                                                        }
-                                                        else
-                                                            img(src: dashImg())
-                                                        a( href: sectionShowLink(section.id), onclick: hideAssetTreePane() ) {
-                                                            yieldUnescaped( section.encodeAsHTML() )
-                                                        }
-                                                        a(href: assetCreateLink(section.id), onclick: hideAssetTreePane()) {
-                                                            img(src: addImg(), alt: 'Add', title: 'Add Asset')
-                                                        }
-                                                    }
-
-                                                    if(section.assets) {
-                                                        div( id: divId, style: branchStyle(divId) ) {
-                                                            ul() {
-                                                                for(asset in section.assets.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                                    li() {
-                                                                        if(asset.assetSubItems) {
-                                                                            a( href: toggleBranch(nextDivId()) ) {
-                                                                                img(src: branchImg(divId), id: divId+'img' )
-                                                                            }
-                                                                        }
-                                                                        else
-                                                                            img(src: dashImg())
-                                                                        a( href: assetShowLink(asset.id), onclick: hideAssetTreePane() ) {
-                                                                            yieldUnescaped( asset.encodeAsHTML() )
-                                                                        }
-                                                                        a(href: assetSubItemCreateLink(asset.id), onclick: hideAssetTreePane()) {
-                                                                            img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
-                                                                        }
-                                                                        a(href: assetCopyLink(asset.id), onclick: hideAssetTreePane()) {
-                                                                            img(src: copyImg(), alt: 'Add', title: 'Copy Asset')
-                                                                        }
-                                                                    } // li
-
-                                                                    if(asset.assetSubItems) {
-                                                                        div( id: divId, style: branchStyle(divId) ) {
-                                                                            ul() {
-                                                                                for(assetSubItemL1 in asset.assetSubItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                                                    li() {
-                                                                                        if(assetSubItemL1.subItems) {
-                                                                                            a( href: toggleBranch(nextDivId()) ) {
-                                                                                                img(src: branchImg(divId), id: divId+'img' )
-                                                                                            }
-                                                                                        }
-                                                                                        else
-                                                                                            img(src: dashImg())
-                                                                                        a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: hideAssetTreePane() ) {
-                                                                                            yieldUnescaped( assetSubItemL1.encodeAsHTML() )
-                                                                                        }
-                                                                                        a(href: assetSubItemCreateWithParentLink(assetSubItemL1.id), onclick: hideAssetTreePane()) {
-                                                                                            img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
-                                                                                        }
-                                                                                    } // li
-
-                                                                                    if(assetSubItemL1.subItems) {
-                                                                                        div( id: divId, style: branchStyle(divId) ) {
-                                                                                            ul() {
-                                                                                                for(assetSubItemL2 in assetSubItemL1.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                                                                    li() {
-                                                                                                        if(assetSubItemL2.subItems) {
-                                                                                                            a( href: toggleBranch(nextDivId()) ) {
-                                                                                                                img( src: branchImg(divId), id: divId+'img' )
-                                                                                                            }
-                                                                                                        }
-                                                                                                        else
-                                                                                                            img(src: dashImg())
-                                                                                                        a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: hideAssetTreePane() ) {
-                                                                                                            yieldUnescaped( assetSubItemL2.encodeAsHTML() )
-                                                                                                        }
-                                                                                                        a(href: assetSubItemCreateWithParentLink(assetSubItemL2.id), onclick: hideAssetTreePane()) {
-                                                                                                            img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
-                                                                                                        }
-                                                                                                    } // li
-
-                                                                                                    if(assetSubItemL2.subItems) {
-                                                                                                        div( id: divId, style: branchStyle(divId) ) {
-                                                                                                            ul() {
-                                                                                                                for(assetSubItemL3 in assetSubItemL2.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                                                                                    li() {
-                                                                                                                        if(assetSubItemL3.subItems) {
-                                                                                                                            a( href: toggleBranch(nextDivId()) ) {
-                                                                                                                                img( src: branchImg(divId), id: divId+'img' )
-                                                                                                                            }
-                                                                                                                        }
-                                                                                                                        else
-                                                                                                                            img(src: dashImg())
-                                                                                                                        a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: hideAssetTreePane() ) {
-                                                                                                                            yieldUnescaped( assetSubItemL3.encodeAsHTML() )
-                                                                                                                        }
-                                                                                                                        a(href: assetSubItemCreateWithParentLink(assetSubItemL3.id), onclick: hideAssetTreePane()) {
-                                                                                                                            img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
-                                                                                                                        }
-                                                                                                                    } // li
-
-                                                                                                                    if(assetSubItemL3.subItems) {
-                                                                                                                        div( id: divId, style: branchStyle(divId) ) {
-                                                                                                                            ul() {
-                                                                                                                                for(assetSubItemL4 in assetSubItemL3.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
-                                                                                                                                    li() {
-                //                                                                                                                         if(assetSubItemL4.subItems) {
-                //                                                                                                                             a( href: toggleBranch(nextDivId()) ) {
-                //                                                                                                                                 img( src: branchImg(divId), id: divId+'img' )
-                //                                                                                                                             }
-                //                                                                                                                         }
-                //                                                                                                                         else
-                                                                                                                                        img(src: dashImg())
-                                                                                                                                        a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: hideAssetTreePane() ) {
-                                                                                                                                            yieldUnescaped( assetSubItemL4.encodeAsHTML() )
-                                                                                                                                        }
-                //                                                                                                                         a(href: assetSubItemCreateWithParentLink(assetSubItemL4.id), onclick: hideAssetTreePane()) {
-                //                                                                                                                             img(src: addImg(), alt: 'Add', title: 'Add Sub Item')
-                //                                                                                                                         }
-                                                                                                                                    } // li
-
-                                                                                                                                } // assetSubItemL4
-                                                                                                                            } // ul
-                                                                                                                        } // div
-                                                                                                                    } // if(assetSubItemL3.subItems)
-
-
-                                                                                                                } // assetSubItemL3
-                                                                                                            } // ul
-                                                                                                        } // div
-                                                                                                    } // if(assetSubItemL2.subItems)
-
-                                                                                                } // assetSubItemL2
-                                                                                            } // ul
-                                                                                        } // div
-                                                                                    } // if(assetSubItemL1.subItems)
-
-                                                                                } // assetSubItemL1
-                                                                            } // ul
-                                                                        } // div
-                                                                    } // if(asset.assetSubItems)
-
-                                                                } // assets
-                                                            } // ul
-                                                        } // div
-                                                    } // if(section.assets)
-
-                                                } //sections
-                                            } // ul
-                                        } // div
-                                    } // if(site.sections) 
-                                } // sites
+                                img(src: ts.treeRootImg(), id: ts.tableLoadingImgId(), alt: 'TreeRoot')
+                                li() {
+                                } // li
                             } // ul
                         } // td
@@ -262,110 +55,6 @@
                 } // table
             } // div
-
-            div( class: 'buttons') {
-                span(class: 'button') {
-                    input( type: 'button', value: 'Close', onclick: hideAssetTreePane() )
-                }
-            }
-
         } // mkp
-
-    } // assetTree
-
-
-    /** Imgs */
-
-    def treeRootImg() {
-        resource(dir:'images/skin',file:'chart_organisation.png').toString()
-    }
-    def addImg() {
-        resource(dir:'images/skin',file:'database_add.png').toString()
-    }
-    def copyImg() {
-        resource(dir:'images/skin',file:'page_copy.png').toString()
-    }
-    def bulletTreePlusImg() {
-        resource(dir:'images/skin',file:'bullet_tree_plus.png').toString()
-    }
-    // actually set in javascript function.
-    def bulletTreeMinusImg() {
-        resource(dir:'images/skin',file:'bullet_tree_minus.png').toString()
-    }
-    def dashImg() {
-        resource(dir:'images/skin',file:'hline_short.png').toString()
-    }
-
-    /** js calls */
-
-    def showPane() {
-       'javascript: showDiv(\"assetTreePane\");'
-    }
-
-    def hideAssetTreePane() {
-        def saveUrl = createLink(controller: 'appCore', action: 'saveAssetTreeStatus').toString()
-        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveUrl + '\");'
-    }
-
-    def toggleBranch(divId) {
-        /// @todo: toggleBranch is in overlayPane.js and should be moved to tree.js
-       'javascript: toggleBranch(\"' + divId + '\", \"' + divId + 'img' +'\", \"' + bulletTreeMinusImg() +'\", \"' + bulletTreePlusImg() + '\");'
-    }
-
-    /** Links */
-
-    def siteCreateLink() {
-        createLink(controller: 'siteDetailed', action: 'create').toString()
-    }
-    def siteShowLink(id) {
-        createLink(controller: 'siteDetailed', action: 'show', params: ['id': id] ).toString()
-    }
-
-    def siteEditLink(id) {
-        createLink(controller: 'siteDetailed', action: 'edit', params: ['id': id] ).toString()
-    }
-
-    def sectionCreateLink(siteId) {
-        createLink(controller: 'sectionDetailed', action: 'create', params: ['site.id': siteId] ).toString()
-    }
-
-    def sectionShowLink(id) {
-        createLink(controller: 'sectionDetailed', action: 'show', params: ['id': id] ).toString()
-    }
-
-    def sectionEditLink(id) {
-        createLink(controller: 'sectionDetailed', action: 'edit', params: ['id': id] ).toString()
-    }
-
-    def assetCreateLink(sectionId) {
-        createLink(controller: 'assetDetailed', action: 'create', params: ['section.id': sectionId] ).toString()
-    }
-
-    def assetShowLink(id) {
-        createLink(controller: 'assetDetailed', action: 'show', id: id ).toString()
-    }
-
-    def assetEditLink(id) {
-        createLink(controller: 'assetDetailed', action: 'edit', id: id ).toString()
-    }
-
-    def assetCopyLink(id) {
-        createLink(controller: 'assetDetailed', action: 'copy', params: ['assetToCopy.id': id] ).toString()
-    }
-
-    def assetSubItemCreateLink(assetId) {
-        createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['asset.id': assetId] ).toString()
-    }
-
-    def assetSubItemCreateWithParentLink(parentItemId) {
-        createLink(controller: 'assetSubItemDetailed', action: 'create', params: ['parentItem.id': parentItemId] ).toString()
-    }
-
-    def assetSubItemShowLink(id) {
-        createLink(controller: 'assetSubItemDetailed', action: 'show', params: ['id': id] ).toString()
-    }
-
-    def assetSubItemEditLink(id) {
-        createLink(controller: 'assetSubItemDetailed', action: 'edit', params: ['id': id] ).toString()
-    }
+    } // assetTreePane
 
 } // end class
Index: /trunk/grails-app/views/layouts/main.gsp
===================================================================
--- /trunk/grails-app/views/layouts/main.gsp	(revision 311)
+++ /trunk/grails-app/views/layouts/main.gsp	(revision 312)
@@ -11,4 +11,6 @@
         <g:javascript library="prototype/effects" />
         <g:javascript src="overlayPane.js" />
+        <g:javascript src="util.js" />
+        <gnuMims:resources />
     </head>
 
@@ -46,5 +48,5 @@
 
         <!-- Asset Tree Pane -->
-        <gnuMims:assetTree />
+        <gnuMims:assetTreePane />
 
     </body>
Index: /trunk/web-app/css/main.css
===================================================================
--- /trunk/web-app/css/main.css	(revision 311)
+++ /trunk/web-app/css/main.css	(revision 312)
@@ -609,4 +609,8 @@
     margin: 2px;
 }
+div.tree_pane_close {
+    float: right;
+    padding: 5px;
+}
 
 /* CheckBoxList Tag Lib */
Index: /trunk/web-app/js/assetTree.js
===================================================================
--- /trunk/web-app/js/assetTree.js	(revision 312)
+++ /trunk/web-app/js/assetTree.js	(revision 312)
@@ -0,0 +1,42 @@
+
+function showAssetTreePane(paneDivId, loadingImg, url) {
+    Effect.Appear(paneDivId,{duration:0.4});
+    new Effect.Pulsate($(loadingImg), { pulses: 200, duration: 133 });
+    new Ajax.Updater({ success: paneDivId }, url, {asynchronous:true,evalScripts:true});
+}
+
+function hideAssetTreePane(paneDivId, tableDivId, saveUrl) {
+
+    // Collect the visible div's first.
+    var visibleDivs = $(tableDivId).select('div').findAll(function(el) { return el.visible(); })
+    var params = "assetTreeVisibleBranches=";
+
+    // Hide the pane.
+    $(paneDivId).toggle();
+
+    // Add the id of each visible div to params.
+    visibleDivs.each(function(it) {
+        params += it.identify();
+        params += ","
+    });
+
+    // Remove the trailing comma.
+    params = params.slice(0,params.length-1);
+
+    // Post the id's of all visible divs.
+    // asynchronous: false is against the prototype recommendations but appears to be needed in this case.
+    new Ajax.Request(saveUrl, {parameters: params, asynchronous: false});
+}
+
+function toggleBranch(divId, imageId, openImgUrl, closedImgUrl) {
+
+    $(divId).toggle();
+
+    if( $(divId).visible() ) {
+        $(imageId).src= openImgUrl;
+    }
+    else {
+        $(imageId).src= closedImgUrl;
+    }
+
+}
Index: /trunk/web-app/js/overlayPane.js
===================================================================
--- /trunk/web-app/js/overlayPane.js	(revision 311)
+++ /trunk/web-app/js/overlayPane.js	(revision 312)
@@ -1,44 +1,2 @@
-function toggleDiv(id) {
-    $(divId).toggle();
-}
-
-function showDiv(id) {
-    Effect.Appear(id,{duration:0.4,queue:'end'});
-}
-
-function hideAssetTreePane(paneDivId, tableDivId, saveUrl) {
-
-    var visibleDivs = $(tableDivId).select('div').findAll(function(el) { return el.visible(); })
-    var params = "assetTreeVisibleBranches=";
-
-    // Add the id of each visible div.
-    visibleDivs.each(function(it) {
-        params += it.identify();
-        params += ","
-    });
-
-    // Remove the trailing comma.
-    params = params.slice(0,params.length-1);
-
-    // Post the id's of all visible divs.
-    // asynchronous: false is against the prototype recommendations but appears to be needed in this case.
-    new Ajax.Request(saveUrl, {parameters: params, asynchronous: false});
-
-    // Hide the pane.
-    $(paneDivId).toggle();
-}
-
-function toggleBranch(divId, imageId, openImgUrl, closedImgUrl) {
-
-    $(divId).toggle();
-
-    if( $(divId).visible() ) {
-        $(imageId).src= openImgUrl;
-    }
-    else {
-        $(imageId).src= closedImgUrl;
-    }
-
-}
 
 function showElement(id) {
Index: /trunk/web-app/js/util.js
===================================================================
--- /trunk/web-app/js/util.js	(revision 312)
+++ /trunk/web-app/js/util.js	(revision 312)
@@ -0,0 +1,12 @@
+
+function toggleUtil(id) {
+    $(id).toggle();
+}
+
+function showUtil(id) {
+    Effect.Appear(id,{duration:0.4,queue:'end'});
+}
+
+function hideUtil(id) {
+    Effect.Fade(id,{duration:0.4,queue:'end'});
+}
