class AssetTreeService { boolean transactional = false def js = new JsUtilService() 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' /** 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 } /** Name and Description Formatting */ def name(obj) { obj.name.encodeAsHTML() } def description(obj) { def s = obj.description.encodeAsHTML() 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 built by buildAssetTreePane(). * This table replaces the contents of the wrapper div. * @returns The asset tree table as a String */ def buildAssetTree(params, session) { def startedAt = System.currentTimeMillis() // Self initialisation ;-) if(!treeRootImg) initialise() def sites = Site.withCriteria { eq("isActive", true) } 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) // 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) } } table(id: tableHtmlId) { tr() { td( valign: 'top', class: 'value') { ul() { img(src: treeRootImg, alt: 'TreeRoot') li() { a(href: siteCreateBaseLink) { 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.toggle(paneHtmlId, "onclick") ) } } // 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: toggleBranch(nextDivId()) ) { img( src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: siteShowLink(site.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(site) ) } yieldUnescaped( description(site) ) 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: toggleBranch(nextDivId()) ) { img(src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: sectionShowLink(section.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(section) ) } yieldUnescaped( description(section) ) 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: toggleBranch(nextDivId()) ) { img(src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: assetShowLink(asset.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(asset) ) } yieldUnescaped( description(asset) ) 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: toggleBranch(nextDivId()) ) { img(src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(assetSubItemL1) ) } yieldUnescaped( description(assetSubItemL1) ) 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: toggleBranch(nextDivId()) ) { img( src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(assetSubItemL2) ) } yieldUnescaped( description(assetSubItemL2) ) 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: toggleBranch(nextDivId()) ) { img( src: branchImg(divId), id: divId+'img' ) } } else img(src: dashImg) a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(assetSubItemL3) ) } yieldUnescaped( description(assetSubItemL3) ) 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: toggleBranch(nextDivId()) ) { // img( src: branchImg(divId), id: divId+'img' ) // } // } // else img(src: dashImg) a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: onclickHideAndSavePane() ) { yieldUnescaped( name(assetSubItemL4) ) } yieldUnescaped( description(assetSubItemL4) ) // 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 def totalTime = (System.currentTimeMillis() - startedAt)/1000 log.debug "Total time to build asset tree: " + totalTime + "sec." return sw.toString() } // buildAssetTree /** js calls */ def hrefShowPane() { 'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + assetTreeActionUrl + '\");' } def onclickHideAndSavePane() { 'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");' } def hrefHideAndSavePane() { 'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");' } def toggleBranch(divId) { js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg, bulletTreePlusImg) } /** Links */ def siteShowLink(id) { siteShowBaseLink + '/' + id } def siteEditLink(id) { siteEditBaseLink + '/' + id } def sectionCreateLink(siteId) { sectionCreateBaseLink + '?site.id=' + siteId } def sectionShowLink(id) { sectionShowBaseLink + '/' + id } def sectionEditLink(id) { sectionEditBaseLink + '/' + id } def assetCreateLink(sectionId) { assetCreateBaseLink + '?section.id=' + sectionId } def assetShowLink(id) { assetShowBaseLink + '/' + id } def assetEditLink(id) { assetEditBaseLink + '/' + id } def assetCopyLink(id) { assetCopyBaseLink + '?assetToCopy.id=' + id } def assetSubItemCreateLink(assetId) { assetSubItemCreateBaseLink + '?asset.id=' + assetId } def assetSubItemCreateWithParentLink(parentItemId) { assetSubItemCreateWithParentBaseLink + '?parentItem.id=' + parentItemId } def assetSubItemShowLink(id) { assetSubItemShowBaseLink + '/' + id } def assetSubItemEditLink(id) { assetSubItemEditBaseLink + '/' + id } } // end class