diff --git a/lib/WebGUI/Admin.pm b/lib/WebGUI/Admin.pm index a100ecc40..d21283b55 100644 --- a/lib/WebGUI/Admin.pm +++ b/lib/WebGUI/Admin.pm @@ -3,6 +3,7 @@ package WebGUI::Admin; # The new WebGUI Admin console use Moose; +use JSON qw( from_json to_json ); use namespace::autoclean; has 'session' => ( @@ -112,6 +113,40 @@ sub getNewContentTemplateVars { my $vars = []; } +#---------------------------------------------------------------------------- + +=head2 getTreePaginator ( $asset ) + +Get a page for the Asset Tree view. Returns a WebGUI::Paginator object +filled with asset IDs. + +=cut + +sub getTreePaginator { + my ( $self, $asset ) = @_; + my $session = $self->session; + + my $orderByColumn = $session->form->get( 'orderByColumn' ) + || "lineage" + ; + my $orderByDirection = lc $session->form->get( 'orderByDirection' ) eq "desc" + ? "DESC" + : "ASC" + ; + + my $recordOffset = $session->form->get( 'recordOffset' ) || 1; + my $rowsPerPage = $session->form->get( 'rowsPerPage' ) || 100; + my $currentPage = int ( $recordOffset / $rowsPerPage ) + 1; + + my $p = WebGUI::Paginator->new( $session, '', $rowsPerPage, 'pn', $currentPage ); + + my $orderBy = $session->db->dbh->quote_identifier( $orderByColumn ) . ' ' . $orderByDirection; + $p->setDataByArrayRef( $asset->getLineage( ['children'], { orderByClause => $orderBy } ) ); + + return $p; +} + + #---------------------------------------------------------------------- =head2 getVersionTagTemplateVars @@ -143,6 +178,61 @@ sub getVersionTagTemplateVars { #---------------------------------------------------------------------- +=head2 www_getTreeData ( ) + +Get the Tree data for a given asset URL + +=cut + +sub www_getTreeData { + my ( $self ) = @_; + my $session = $self->session; + my ( $user, $form ) = $session->quick(qw{ user form }); + + my $assetUrl = $form->get('assetUrl'); + my $asset = WebGUI::Asset->newByUrl( $session, $assetUrl ); + + my $i18n = WebGUI::International->new( $session, "Asset" ); + my $assetInfo = { assets => [] }; + my $p = $self->getTreePaginator( $asset ); + + for my $assetId ( @{ $p->getPageData } ) { + my $asset = WebGUI::Asset->newById( $session, $assetId ); + + # Populate the required fields to fill in + my %fields = ( + assetId => $asset->getId, + url => $asset->getUrl, + lineage => $asset->lineage, + title => $asset->menuTitle, + revisionDate => $asset->revisionDate, + childCount => $asset->getChildCount, + assetSize => $asset->assetSize, + lockedBy => ($asset->isLockedBy ? $asset->lockedBy->username : ''), + actions => $asset->canEdit && $asset->canEditIfLocked, + ); + + $fields{ className } = {}; + # The asset icon + $fields{ icon } = $asset->getIcon("small"); + + # The asset type (i18n name) + $fields{ className } = $asset->getName; + + push @{ $assetInfo->{ assets } }, \%fields; + } + + $assetInfo->{ totalAssets } = $p->getRowCount; + $assetInfo->{ sort } = $session->form->get( 'orderByColumn' ); + $assetInfo->{ dir } = lc $session->form->get( 'orderByDirection' ); + + $session->http->setMimeType( 'application/json' ); + + return to_json( $assetInfo ); +} + +#---------------------------------------------------------------------- + =head2 www_view ( session ) Show the main Admin console wrapper @@ -150,7 +240,7 @@ Show the main Admin console wrapper =cut sub www_view { - my ($self) = @_; + my ( $self ) = @_; my $session = $self->session; my ( $user, $url, $style ) = $session->quick(qw{ user url style }); diff --git a/www/extras/admin/admin.js b/www/extras/admin/admin.js index 696db56dd..af80cf597 100644 --- a/www/extras/admin/admin.js +++ b/www/extras/admin/admin.js @@ -7,38 +7,28 @@ if ( typeof WebGUI == "undefined" ) { WebGUI = {}; } -WebGUI.Admin = (function(){ - // Public methods +WebGUI.Admin = function(){ + // Public properties + this.cfg = cfg; + this.currentAssetDef = null; + this.viewOrTree = 0; // 0 - Last on View tab. 1 - Last on Tree tab - return function (cfg) { - // Public properties - this.cfg = cfg; - this.currentAssetDef = null; - this.viewOrTree = 0; // 0 - Last on View tab. 1 - Last on Tree tab + // Default configuration + if ( !this.cfg.locationBarId ) { + this.cfg.locationBarId = "locationBar"; + } + if ( !this.cfg.tabBarId ) { + this.cfg.tabBarId = "tabBar"; + } - // Default configuration - if ( !this.cfg.locationBarId ) { - this.cfg.locationBarId = "locationBar"; - } - if ( !this.cfg.tabBarId ) { - this.cfg.tabBarId = "tabBar"; - } + this.locationBar = new WebGUI.Admin.LocationBar( this.cfg.locationBarId ); + this.tabBar = new YAHOO.widget.TabView( this.cfg.tabBarId ); + // Keep track of View and Tree tabs + this.tabBar.getTab(0).addListener('click',this.afterShowViewTab,this,true); + this.tabBar.getTab(1).addListener('click',this.afterShowTreeTab,this,true); - // Private properties - var self = this; - - // Private methods - function _init() { - self.locationBar = new WebGUI.Admin.LocationBar( self.cfg.locationBarId ); - self.tabBar = new YAHOO.widget.TabView( self.cfg.tabBarId ); - // Keep track of View and Tree tabs - self.tabBar.getTab(0).addListener('click',self.afterShowViewTab,self,true); - self.tabBar.getTab(1).addListener('click',self.afterShowTreeTab,self,true); - } - - _init(); - }; -})(); + // Private methods +}; /** * afterShowTreeTab() @@ -111,44 +101,41 @@ WebGUI.Admin.LocationBar var self = this; var _element = document.getElementById( self.id ); - function _init () { - // Create buttons - self.btnBack = new YAHOO.widget.Button( "backButton", { - type : "split", - label : '', - disabled : true, - lazyloadmenu : false, - onclick : { fn: self.goBack, scope: self }, - menu : [] - } ); - self.btnForward = new YAHOO.widget.Button( "forwardButton", { - type : "split", - label : '', - disabled : true, - lazyloadmenu : false, - onclick : { fn: self.goForward, scope: self }, - menu : [] - } ); - self.btnSearch = new YAHOO.widget.Button( "searchButton", { - label : '', - onclick : { fn: self.clickSearchButton, scope: self } - } ); - self.btnHome = new YAHOO.widget.Button( "homeButton", { - type : "button", - label : '', - onclick : { fn: self.goHome, scope: self } - } ); - // Take control of the location input - self.klInput = new YAHOO.util.KeyListener( "locationUrl", { keys: 13 }, { - fn: self.doInputSearch, - scope: self, - correctScope: true - } ); - YAHOO.util.Event.addListener( "locationUrl", "focus", self.inputFocus, self, true ); - YAHOO.util.Event.addListener( "locationUrl", "blur", self.inputBlur, self, true ); - } + // Create buttons + this.btnBack = new YAHOO.widget.Button( "backButton", { + type : "split", + label : '', + disabled : true, + lazyloadmenu : false, + onclick : { fn: this.goBack, scope: this }, + menu : [] + } ); + this.btnForward = new YAHOO.widget.Button( "forwardButton", { + type : "split", + label : '', + disabled : true, + lazyloadmenu : false, + onclick : { fn: this.goForward, scope: this }, + menu : [] + } ); + this.btnSearch = new YAHOO.widget.Button( "searchButton", { + label : '', + onclick : { fn: this.clickSearchButton, scope: this } + } ); + this.btnHome = new YAHOO.widget.Button( "homeButton", { + type : "button", + label : '', + onclick : { fn: this.goHome, scope: this } + } ); + // Take control of the location input + this.klInput = new YAHOO.util.KeyListener( "locationUrl", { keys: 13 }, { + fn: this.doInputSearch, + scope: this, + correctScope: true + } ); + YAHOO.util.Event.addListener( "locationUrl", "focus", this.inputFocus, this, true ); + YAHOO.util.Event.addListener( "locationUrl", "blur", this.inputBlur, this, true ); - _init(); }; /** @@ -381,5 +368,400 @@ WebGUI.Admin.LocationBar.prototype.swapForwardToBack }; +/**************************************************************************** + * + * WebGUI.Admin.Tree + */ + +WebGUI.Admin.Tree = function(){ + this.moreMenusDisplayed = {}; + this.crumbMoreMenu = null; +}; + +/** + * appendToUrl( url, params ) + * Add URL components to a URL; + */ +WebGUI.Admin.Tree.prototype.appendToUrl = function ( url, params ) { + var components = [ url ]; + if (url.match(/\?/)) { + components.push(";"); + } + else { + components.push("?"); + } + components.push(params); + return components.join(''); +}; + +/** + * addHighlightToRow ( child ) + * Highlight the row containing this element by adding to it the "highlight" + * class + */ +WebGUI.Admin.Tree.prototype.addHighlightToRow = function ( child ) { + var row = this.findRow( child ); + if ( !YAHOO.util.Dom.hasClass( row, "highlight" ) ) { + YAHOO.util.Dom.addClass( row, "highlight" ); + } +}; + +/** + * buildMoreMenu ( url, linkElement ) + * Build a WebGUI style "More" menu for the asset referred to by url + */ +WebGUI.AssetManager.buildMoreMenu = function ( url, linkElement, isNotLocked ) { + var rawItems = this.moreMenuItems; + var menuItems = []; + var isLocked = !isNotLocked; + for ( var i = 0; i < rawItems.length; i++ ) { + var itemUrl = rawItems[i].url + ? this.appendToUrl(url, rawItems[i].url) + : url + ; + if (! (itemUrl.match( /func=edit;/) && isLocked )) { + menuItems.push( { "url" : itemUrl, "text" : rawItems[i].label } ); + } + } + var options = { + "zindex" : 1000, + "clicktohide" : true, + "position" : "dynamic", + "context" : [ linkElement, "tl", "bl", ["beforeShow", "windowResize"] ], + "itemdata" : menuItems + }; + + return options; +}; + +/** + * findRow ( child ) + * Find the row that contains this child element. + */ +WebGUI.Admin.Tree.prototype.findRow = function ( child ) { + var node = child; + while ( node ) { + if ( node.tagName == "TR" ) { + return node; + } + node = node.parentNode; + } +}; + +/** + * formatActions ( ) + * Format the Edit and More links for the row + */ +WebGUI.AssetManager.formatActions = function ( elCell, oRecord, oColumn, orderNumber ) { + if ( oRecord.getData( 'actions' ) ) { + elCell.innerHTML + = '' + + WebGUI.AssetManager.i18n.get('Asset', 'edit') + '' + + ' | ' + ; + } + else { + elCell.innerHTML = ""; + } + var more = document.createElement( 'a' ); + elCell.appendChild( more ); + more.appendChild( document.createTextNode( WebGUI.AssetManager.i18n.get('Asset','More' ) ) ); + more.href = '#'; + + // Delete the old menu + if ( document.getElementById( 'moreMenu' + oRecord.getData( 'assetId' ) ) ) { + var oldMenu = document.getElementById( 'moreMenu' + oRecord.getData( 'assetId' ) ); + oldMenu.parentNode.removeChild( oldMenu ); + } + + var options = WebGUI.AssetManager.buildMoreMenu(oRecord.getData( 'url' ), more, oRecord.getData( 'actions' )); + + var menu = new YAHOO.widget.Menu( "moreMenu" + oRecord.getData( 'assetId' ), options ); + YAHOO.util.Event.onDOMReady( function () { menu.render( document.getElementById( 'assetManager' ) ); } ); + YAHOO.util.Event.addListener( more, "click", function (e) { YAHOO.util.Event.stopEvent(e); menu.show(); menu.focus(); }, null, menu ); +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatAssetIdCheckbox ( ) + Format the checkbox for the asset ID. +*/ +WebGUI.AssetManager.formatAssetIdCheckbox = function ( elCell, oRecord, oColumn, orderNumber ) { + elCell.innerHTML = ''; +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatAssetSize ( ) + Format the asset class name +*/ +WebGUI.AssetManager.formatAssetSize = function ( elCell, oRecord, oColumn, orderNumber ) { + elCell.innerHTML = oRecord.getData( "assetSize" ); +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatClassName ( ) + Format the asset class name +*/ +WebGUI.AssetManager.formatClassName = function ( elCell, oRecord, oColumn, orderNumber ) { + elCell.innerHTML = ' ' + + oRecord.getData( "className" ); +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatLockedBy ( ) + Format the asset class name +*/ +WebGUI.AssetManager.formatLockedBy = function ( elCell, oRecord, oColumn, orderNumber ) { + var extras = getWebguiProperty('extrasURL'); + elCell.innerHTML + = oRecord.getData( 'lockedBy' ) + ? '' + + '' + WebGUI.AssetManager.i18n.get('WebGUI', 'locked by') + ' ' + oRecord.getData( 'lockedBy' ) + '' + + '' + : '' + + '' + WebGUI.AssetManager.i18n.get('Asset', 'unlocked') + '' + + '' + ; +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatRank ( ) + Format the input for the rank box +*/ +WebGUI.AssetManager.formatRank = function ( elCell, oRecord, oColumn, orderNumber ) { + var rank = oRecord.getData("lineage").match(/[1-9][0-9]{0,5}$/); + elCell.innerHTML = ''; +}; + + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.DefaultSortedBy ( ) +*/ +WebGUI.AssetManager.DefaultSortedBy = { + "key" : "lineage", + "dir" : YAHOO.widget.DataTable.CLASS_ASC +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.BuildQueryString ( ) +*/ +WebGUI.AssetManager.BuildQueryString = function ( state, dt ) { + var query = "recordOffset=" + state.pagination.recordOffset + + ';orderByDirection=' + ((state.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "DESC" : "ASC") + + ';rowsPerPage=' + state.pagination.rowsPerPage + + ';orderByColumn=' + state.sortedBy.key + ; + return query; + }; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatRevisionDate ( ) + Format the asset class name +*/ +WebGUI.AssetManager.formatRevisionDate = function ( elCell, oRecord, oColumn, orderNumber ) { + var revisionDate = new Date( oRecord.getData( "revisionDate" ) * 1000 ); + var minutes = revisionDate.getMinutes(); + if (minutes < 10) { + minutes = "0" + minutes; + } + elCell.innerHTML = revisionDate.getFullYear() + '-' + ( revisionDate.getMonth() + 1 ) + + '-' + revisionDate.getDate() + ' ' + ( revisionDate.getHours() ) + + ':' + minutes + ; +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.formatTitle ( ) + Format the link for the title +*/ +WebGUI.AssetManager.formatTitle = function ( elCell, oRecord, oColumn, orderNumber ) { + elCell.innerHTML = '' + + ( oRecord.getData( 'childCount' ) > 0 ? "+" : " " ) + + ' ' + + oRecord.getData( 'title' ) + + '' + ; +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.initManager ( ) + Initialize the i18n interface +*/ +WebGUI.AssetManager.initManager = function (o) { + WebGUI.AssetManager.i18n + = new WebGUI.i18n( { + namespaces : { + 'Asset' : [ + "edit", + "More", + "unlocked", + "locked by" + ], + 'WebGUI' : [ + "< prev", + "next >" + ] + }, + onpreload : { + fn : WebGUI.AssetManager.initDataTable + } + } ); +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.initDataTable ( ) + Initialize the www_manage page +*/ +WebGUI.AssetManager.initDataTable = function (o) { + var assetPaginator = new YAHOO.widget.Paginator({ + containers : ['pagination'], + pageLinks : 7, + rowsPerPage : 100, + previousPageLinkLabel : WebGUI.AssetManager.i18n.get('WebGUI', '< prev'), + nextPageLinkLabel : WebGUI.AssetManager.i18n.get('WebGUI', 'next >'), + template : "{CurrentPageReport} {PreviousPageLink} {PageLinks} {NextPageLink}" + }); + + + // initialize the data source + WebGUI.AssetManager.DataSource + = new YAHOO.util.DataSource( '?op=assetManager;method=ajaxGetManagerPage;',{connTimeout:30000} ); + WebGUI.AssetManager.DataSource.responseType + = YAHOO.util.DataSource.TYPE_JSON; + WebGUI.AssetManager.DataSource.responseSchema + = { + resultsList: 'assets', + fields: [ + { key: 'assetId' }, + { key: 'lineage' }, + { key: 'actions' }, + { key: 'title' }, + { key: 'className' }, + { key: 'revisionDate' }, + { key: 'assetSize' }, + { key: 'lockedBy' }, + { key: 'icon' }, + { key: 'url' }, + { key: 'childCount' } + ], + metaFields: { + totalRecords: "totalAssets" // Access to value in the server response + } + }; + + + + // Initialize the data table + WebGUI.AssetManager.DataTable + = new YAHOO.widget.DataTable( 'dataTableContainer', + WebGUI.AssetManager.ColumnDefs, + WebGUI.AssetManager.DataSource, + { + initialRequest : 'recordOffset=0', + dynamicData : true, + paginator : assetPaginator, + sortedBy : WebGUI.AssetManager.DefaultSortedBy, + generateRequest : WebGUI.AssetManager.BuildQueryString + } + ); + + WebGUI.AssetManager.DataTable.handleDataReturnPayload = function(oRequest, oResponse, oPayload) { + oPayload.totalRecords = oResponse.meta.totalRecords; + return oPayload; + }; + +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.removeHighlightFromRow ( child ) + Remove the highlight from a row by removing the "highlight" class. +*/ +WebGUI.AssetManager.removeHighlightFromRow = function ( child ) { + var row = WebGUI.AssetManager.findRow( child ); + if ( YAHOO.util.Dom.hasClass( row, "highlight" ) ) { + YAHOO.util.Dom.removeClass( row, "highlight" ); + } +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.selectRow ( child ) + Check the assetId checkbox in the row that contains the given child. + Used when something in the row changes. +*/ +WebGUI.AssetManager.selectRow = function ( child ) { + // First find the row + var node = WebGUI.AssetManager.findRow( child ); + WebGUI.AssetManager.addHighlightToRow( child ); + + // Now find the assetId checkbox in the first element + var inputs = node.getElementsByTagName( "input" ); + for ( var i = 0; i < inputs.length; i++ ) { + if ( inputs[i].name == "assetId" ) { + inputs[i].checked = true; + break; + } + } +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.showMoreMenu ( url, linkTextId ) + Build a More menu for the last element of the Crumb trail +*/ +WebGUI.AssetManager.showMoreMenu += function ( url, linkTextId, isNotLocked ) { + + var menu; + if ( typeof WebGUI.AssetManager.CrumbMoreMenu == "undefined" ) { + var more = document.getElementById(linkTextId); + var options = WebGUI.AssetManager.buildMoreMenu(url, more, isNotLocked); + menu = new YAHOO.widget.Menu( "crumbMoreMenu", options ); + menu.render( document.getElementById( 'assetManager' ) ); + WebGUI.AssetManager.CrumbMoreMenu = menu; + } + else { + menu = WebGUI.AssetManager.CrumbMoreMenu; + } + menu.show(); + menu.focus(); +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.toggleHighlightForRow ( checkbox ) + Toggle the highlight for the row based on the state of the checkbox +*/ +WebGUI.AssetManager.toggleHighlightForRow = function ( checkbox ) { + if ( checkbox.checked ) { + WebGUI.AssetManager.addHighlightToRow( checkbox ); + } + else { + WebGUI.AssetManager.removeHighlightFromRow( checkbox ); + } +}; + +/*--------------------------------------------------------------------------- + WebGUI.AssetManager.toggleRow ( child ) + Toggles the entire row by finding the checkbox and doing what needs to be + done. +*/ +WebGUI.AssetManager.toggleRow = function ( child ) { + var row = WebGUI.AssetManager.findRow( child ); + + // Find the checkbox + var inputs = row.getElementsByTagName( "input" ); + for ( var i = 0; i < inputs.length; i++ ) { + if ( inputs[i].name == "assetId" ) { + inputs[i].checked = inputs[i].checked + ? false + : true + ; + WebGUI.AssetManager.toggleHighlightForRow( inputs[i] ); + break; + } + } +};