mirror of
https://github.com/apache/archiva.git
synced 2025-02-24 11:35:02 +00:00
[MRM-84]
- add export to CSV - migrated statistics report to struts2 - added date picker git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@706873 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c303ba78c7
commit
ce43e1a9e0
@ -42,9 +42,31 @@ public interface RepositoryStatisticsReportGenerator
|
||||
|
||||
public static final String ARCHETYPE = "archetype";
|
||||
|
||||
/**
|
||||
* Generate report with limits. Used for pagination.
|
||||
*
|
||||
* @param repoContentStats
|
||||
* @param repository
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @param limits
|
||||
* @return
|
||||
* @throws ArchivaReportException
|
||||
*/
|
||||
public List<RepositoryStatistics> generateReport( List<RepositoryContentStatistics> repoContentStats, String repository, Date startDate, Date endDate, DataLimits limits )
|
||||
throws ArchivaReportException;
|
||||
|
||||
public List<RepositoryStatistics> generateReport( List<RepositoryContentStatistics> repoContentStats, String repository, Date startDate, Date endDate )
|
||||
throws ArchivaReportException;
|
||||
/**
|
||||
* Generate report without limits. Used for exporting the report.
|
||||
*
|
||||
* @param repoContentStats
|
||||
* @param repository
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @param firstStatsOnly TODO
|
||||
* @return
|
||||
* @throws ArchivaReportException
|
||||
*/
|
||||
public List<RepositoryStatistics> generateReport( List<RepositoryContentStatistics> repoContentStats, String repository, Date startDate, Date endDate, boolean firstStatsOnly )
|
||||
throws ArchivaReportException;
|
||||
}
|
||||
|
@ -80,14 +80,23 @@ public List<RepositoryStatistics> generateReport( List<RepositoryContentStatisti
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.apache.maven.archiva.reporting.RepositoryStatisticsReportGenerator#generateReport(java.util.List
|
||||
* repoContentStats, java.util.String repository, java.util.Date startDate, java.util.Date endDate)
|
||||
* repoContentStats, java.util.String repository, java.util.Date startDate, java.util.Date endDate, boolean firstStatsOnly)
|
||||
*/
|
||||
public List<RepositoryStatistics> generateReport( List<RepositoryContentStatistics> repoContentStats, String repository, Date startDate, Date endDate )
|
||||
public List<RepositoryStatistics> generateReport( List<RepositoryContentStatistics> repoContentStats,
|
||||
String repository, Date startDate, Date endDate,
|
||||
boolean firstStatsOnly )
|
||||
throws ArchivaReportException
|
||||
{
|
||||
return constructRepositoryStatistics( repoContentStats, repository, endDate, 0, repoContentStats.size() - 1 );
|
||||
if( firstStatsOnly )
|
||||
{
|
||||
return constructRepositoryStatistics( repoContentStats, repository, endDate, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return constructRepositoryStatistics( repoContentStats, repository, endDate, 0, repoContentStats.size() - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<RepositoryStatistics> constructRepositoryStatistics(
|
||||
List<RepositoryContentStatistics> repoContentStats,
|
||||
String repository, Date endDate,
|
||||
|
@ -261,7 +261,7 @@ public void testSimpleReportWithoutPagination()
|
||||
daoControl.replay();
|
||||
artifactDaoControl.replay();
|
||||
|
||||
List<RepositoryStatistics> data = generator.generateReport( repoContentStats, REPO, startDate, endDate );
|
||||
List<RepositoryStatistics> data = generator.generateReport( repoContentStats, REPO, startDate, endDate, false );
|
||||
|
||||
daoControl.verify();
|
||||
artifactDaoControl.verify();
|
||||
|
@ -20,7 +20,9 @@
|
||||
*/
|
||||
|
||||
import com.opensymphony.xwork2.Preparable;
|
||||
import org.apache.commons.lang.time.DateFormatUtils;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
|
||||
import org.apache.maven.archiva.database.ArchivaDAO;
|
||||
@ -48,6 +50,10 @@
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@ -141,6 +147,10 @@ public class GenerateReportAction
|
||||
private String[] datePatterns = new String[] { "MM/dd/yy", "MM/dd/yyyy", "MMMMM/dd/yyyy", "MMMMM/dd/yy",
|
||||
"dd MMMMM yyyy", "dd/MM/yy", "dd/MM/yyyy", "yyyy/MM/dd" };
|
||||
|
||||
public static final String SEND_FILE = "send-file";
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
public void prepare()
|
||||
{
|
||||
repositoryIds = new ArrayList<String>();
|
||||
@ -190,47 +200,14 @@ public String generateStatistics()
|
||||
addFieldError( "rowCount", "Row count must be larger than 10." );
|
||||
return INPUT;
|
||||
}
|
||||
reposSize = selectedRepositories.size();
|
||||
Date startDateInDateFormat = null;
|
||||
Date endDateInDateFormat = null;
|
||||
|
||||
if( startDate == null || "".equals( startDate ) )
|
||||
{
|
||||
startDateInDateFormat = getDefaultStartDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
startDateInDateFormat = DateUtils.parseDate( startDate, datePatterns );
|
||||
}
|
||||
catch ( ParseException e )
|
||||
{
|
||||
addFieldError( "startDate", "Invalid date format.");
|
||||
return INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
if( endDate == null || "".equals( endDate ) )
|
||||
{
|
||||
endDateInDateFormat = getDefaultEndDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
endDateInDateFormat = DateUtils.parseDate( endDate, datePatterns );
|
||||
}
|
||||
catch ( ParseException e )
|
||||
{
|
||||
addFieldError( "endDate", "Invalid date format.");
|
||||
return INPUT;
|
||||
}
|
||||
}
|
||||
reposSize = selectedRepositories.size();
|
||||
|
||||
try
|
||||
{
|
||||
RepositoryContentStatisticsDAO repoContentStatsDao = dao.getRepositoryContentStatisticsDAO();
|
||||
RepositoryContentStatisticsDAO repoContentStatsDao = dao.getRepositoryContentStatisticsDAO();
|
||||
Date startDateInDF = null;
|
||||
Date endDateInDF = null;
|
||||
|
||||
if( selectedRepositories.size() > 1 )
|
||||
{
|
||||
limits.setTotalCount( selectedRepositories.size() );
|
||||
@ -238,34 +215,19 @@ public String generateStatistics()
|
||||
limits.setPerPageCount( 1 );
|
||||
limits.setCountOfPages( 1 );
|
||||
|
||||
// multiple repos
|
||||
for( String repo : selectedRepositories )
|
||||
{
|
||||
try
|
||||
{
|
||||
List contentStats = repoContentStatsDao.queryRepositoryContentStatistics(
|
||||
new RepositoryContentStatisticsByRepositoryConstraint( repo, startDateInDateFormat, endDateInDateFormat ) );
|
||||
|
||||
if( contentStats == null || contentStats.isEmpty() )
|
||||
{
|
||||
log.info( "No statistics available for repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
|
||||
continue;
|
||||
}
|
||||
repositoryStatistics.addAll( generator.generateReport( contentStats, repo, startDateInDateFormat, endDateInDateFormat, limits ) );
|
||||
}
|
||||
catch ( ObjectNotFoundException oe )
|
||||
{
|
||||
log.error( "No statistics available for repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
}
|
||||
catch ( ArchivaDatabaseException ae )
|
||||
{
|
||||
log.error( "Error encountered while querying statistics of repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
}
|
||||
try
|
||||
{
|
||||
startDateInDF = getStartDateInDateFormat();
|
||||
endDateInDF = getEndDateInDateFormat();
|
||||
}
|
||||
catch ( ParseException e )
|
||||
{
|
||||
addActionError( "Error parsing date(s)." );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// multiple repos
|
||||
generateReportForMultipleRepos(repoContentStatsDao, startDateInDF, endDateInDF, true);
|
||||
}
|
||||
else if ( selectedRepositories.size() == 1 )
|
||||
{
|
||||
@ -274,9 +236,12 @@ else if ( selectedRepositories.size() == 1 )
|
||||
|
||||
selectedRepo = selectedRepositories.get( 0 );
|
||||
try
|
||||
{
|
||||
{
|
||||
startDateInDF = getStartDateInDateFormat();
|
||||
endDateInDF = getEndDateInDateFormat();
|
||||
|
||||
List<RepositoryContentStatistics> contentStats = repoContentStatsDao.queryRepositoryContentStatistics(
|
||||
new RepositoryContentStatisticsByRepositoryConstraint( selectedRepo, startDateInDateFormat, endDateInDateFormat ) );
|
||||
new RepositoryContentStatisticsByRepositoryConstraint( selectedRepo, startDateInDF, endDateInDF ) );
|
||||
|
||||
if( contentStats == null || contentStats.isEmpty() )
|
||||
{
|
||||
@ -289,7 +254,7 @@ else if ( selectedRepositories.size() == 1 )
|
||||
int totalPages = ( limits.getTotalCount() / limits.getPerPageCount() ) + extraPage;
|
||||
limits.setCountOfPages( totalPages );
|
||||
|
||||
repositoryStatistics = generator.generateReport( contentStats, selectedRepo, startDateInDateFormat, endDateInDateFormat, limits );
|
||||
repositoryStatistics = generator.generateReport( contentStats, selectedRepo, startDateInDF, endDateInDF, limits );
|
||||
}
|
||||
catch ( ObjectNotFoundException oe )
|
||||
{
|
||||
@ -301,6 +266,11 @@ else if ( selectedRepositories.size() == 1 )
|
||||
addActionError( de.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
catch ( ParseException pe )
|
||||
{
|
||||
addActionError( pe.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -311,18 +281,7 @@ else if ( selectedRepositories.size() == 1 )
|
||||
if( repositoryStatistics.isEmpty() )
|
||||
{
|
||||
return BLANK;
|
||||
}
|
||||
|
||||
if( startDate.equals( getDefaultStartDate() ) )
|
||||
{
|
||||
startDate = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
startDate = DateFormatUtils.format( startDateInDateFormat, "MM/dd/yyyy" );
|
||||
}
|
||||
|
||||
endDate = DateFormatUtils.format( endDateInDateFormat, "MM/dd/yyyy" );
|
||||
}
|
||||
}
|
||||
catch ( ArchivaReportException e )
|
||||
{
|
||||
@ -332,6 +291,252 @@ else if ( selectedRepositories.size() == 1 )
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export report to CSV.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String downloadStatisticsReport()
|
||||
{
|
||||
try
|
||||
{
|
||||
Date startDateInDF = null;
|
||||
Date endDateInDF = null;
|
||||
|
||||
selectedRepositories = parseSelectedRepositories();
|
||||
repositoryStatistics = new ArrayList<RepositoryStatistics>();
|
||||
|
||||
RepositoryContentStatisticsDAO repoContentStatsDao = dao.getRepositoryContentStatisticsDAO();
|
||||
if( selectedRepositories.size() > 1 )
|
||||
{
|
||||
try
|
||||
{
|
||||
startDateInDF = getStartDateInDateFormat();
|
||||
endDateInDF = getEndDateInDateFormat();
|
||||
}
|
||||
catch ( ParseException e )
|
||||
{
|
||||
addActionError( "Error parsing date(s)." );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// multiple repos
|
||||
generateReportForMultipleRepos( repoContentStatsDao, startDateInDF, endDateInDF, false );
|
||||
}
|
||||
else if ( selectedRepositories.size() == 1 )
|
||||
{
|
||||
selectedRepo = selectedRepositories.get( 0 );
|
||||
try
|
||||
{
|
||||
startDateInDF = getStartDateInDateFormat();
|
||||
endDateInDF = getEndDateInDateFormat();
|
||||
|
||||
List<RepositoryContentStatistics> contentStats = repoContentStatsDao.queryRepositoryContentStatistics(
|
||||
new RepositoryContentStatisticsByRepositoryConstraint( selectedRepo, startDateInDF, endDateInDF ) );
|
||||
|
||||
if( contentStats == null || contentStats.isEmpty() )
|
||||
{
|
||||
addActionError( "No statistics available for repository. Repository might not have been scanned." );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
repositoryStatistics = generator.generateReport( contentStats, selectedRepo, startDateInDF, endDateInDF, false );
|
||||
}
|
||||
catch ( ObjectNotFoundException oe )
|
||||
{
|
||||
addActionError( oe.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
catch ( ArchivaDatabaseException de )
|
||||
{
|
||||
addActionError( de.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
catch ( ParseException pe )
|
||||
{
|
||||
addActionError( pe.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addFieldError( "availableRepositories", "Please select a repository (or repositories) from the list." );
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
if( repositoryStatistics.isEmpty() )
|
||||
{
|
||||
return BLANK;
|
||||
}
|
||||
}
|
||||
catch ( ArchivaReportException e )
|
||||
{
|
||||
addActionError( "Error encountered while generating report :: " + e.getMessage() );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
// write output stream depending on single or comparison report
|
||||
StringBuffer input = getInput();
|
||||
StringReader reader = new StringReader( input.toString() );
|
||||
|
||||
try
|
||||
{
|
||||
inputStream = new ByteArrayInputStream( IOUtils.toByteArray( reader ) );
|
||||
}
|
||||
catch ( IOException i )
|
||||
{
|
||||
addActionError( "Error occurred while generating CSV file." );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return SEND_FILE;
|
||||
}
|
||||
|
||||
// hack for parsing the struts list passed as param in <s:url ../>
|
||||
private List<String> parseSelectedRepositories()
|
||||
{
|
||||
List<String> pasedSelectedRepos = new ArrayList<String>();
|
||||
|
||||
for( String repo : selectedRepositories )
|
||||
{
|
||||
String[] tokens = StringUtils.split( repo, ',' );
|
||||
if( tokens.length > 1 )
|
||||
{
|
||||
for( int i = 0; i < tokens.length; i++ )
|
||||
{
|
||||
pasedSelectedRepos.add( StringUtils.remove( StringUtils.remove( tokens[i], '[' ), ']' ).trim() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pasedSelectedRepos.add( StringUtils.remove( StringUtils.remove( repo, '[' ), ']' ).trim() );
|
||||
}
|
||||
}
|
||||
return pasedSelectedRepos;
|
||||
}
|
||||
|
||||
private void generateReportForMultipleRepos( RepositoryContentStatisticsDAO repoContentStatsDao,
|
||||
Date startDateInDF, Date endDateInDF, boolean useLimits )
|
||||
throws ArchivaReportException
|
||||
{
|
||||
for ( String repo : selectedRepositories )
|
||||
{
|
||||
try
|
||||
{
|
||||
List contentStats = repoContentStatsDao.queryRepositoryContentStatistics(
|
||||
new RepositoryContentStatisticsByRepositoryConstraint( repo, startDateInDF, endDateInDF ) );
|
||||
|
||||
if ( contentStats == null || contentStats.isEmpty() )
|
||||
{
|
||||
log.info( "No statistics available for repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
continue;
|
||||
}
|
||||
|
||||
if( useLimits )
|
||||
{
|
||||
repositoryStatistics.addAll( generator.generateReport( contentStats, repo, startDateInDF, endDateInDF,
|
||||
limits ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
repositoryStatistics.addAll( generator.generateReport( contentStats, repo, startDateInDF, endDateInDF, true ) );
|
||||
}
|
||||
}
|
||||
catch ( ObjectNotFoundException oe )
|
||||
{
|
||||
log.error( "No statistics available for repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
}
|
||||
catch ( ArchivaDatabaseException ae )
|
||||
{
|
||||
log.error( "Error encountered while querying statistics of repository '" + repo + "'." );
|
||||
// TODO set repo's stats to 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Date getStartDateInDateFormat()
|
||||
throws ParseException
|
||||
{
|
||||
Date startDateInDF;
|
||||
if ( startDate == null || "".equals( startDate ) )
|
||||
{
|
||||
startDateInDF = getDefaultStartDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
startDateInDF = DateUtils.parseDate( startDate, datePatterns );
|
||||
}
|
||||
return startDateInDF;
|
||||
}
|
||||
|
||||
private Date getEndDateInDateFormat()
|
||||
throws ParseException
|
||||
{
|
||||
Date endDateInDF;
|
||||
if ( endDate == null || "".equals( endDate ) )
|
||||
{
|
||||
endDateInDF = getDefaultEndDate();
|
||||
}
|
||||
else
|
||||
{
|
||||
endDateInDF = DateUtils.parseDate( endDate, datePatterns );
|
||||
}
|
||||
|
||||
return endDateInDF;
|
||||
}
|
||||
|
||||
private StringBuffer getInput()
|
||||
{
|
||||
StringBuffer input = null;
|
||||
|
||||
if( selectedRepositories.size() == 1 )
|
||||
{
|
||||
input = new StringBuffer( "Date of Scan,Total File Count,Total Size,Artifact Count,Group Count,Project Count," +
|
||||
"Plugins,Archetypes,Jars,Wars,Deployments,Downloads\n" );
|
||||
|
||||
for( RepositoryStatistics stats : repositoryStatistics )
|
||||
{
|
||||
input.append( stats.getDateOfScan() ).append( "," );
|
||||
input.append( stats.getFileCount() ).append( "," );
|
||||
input.append( stats.getTotalSize() ).append( "," );
|
||||
input.append( stats.getArtifactCount() ).append( "," );
|
||||
input.append( stats.getGroupCount() ).append( "," );
|
||||
input.append( stats.getProjectCount() ).append( "," );
|
||||
input.append( stats.getPluginCount() ).append( "," );
|
||||
input.append( stats.getArchetypeCount() ).append( "," );
|
||||
input.append( stats.getJarCount() ).append( "," );
|
||||
input.append( stats.getWarCount() ).append( "," );
|
||||
input.append( stats.getDeploymentCount() ).append( "," );
|
||||
input.append( stats.getDownloadCount() ).append( "\n" );
|
||||
}
|
||||
}
|
||||
else if( selectedRepositories.size() > 1 )
|
||||
{
|
||||
input = new StringBuffer( "Repository,Total File Count,Total Size,Artifact Count,Group Count,Project Count," +
|
||||
"Plugins,Archetypes,Jars,Wars,Deployments,Downloads\n" );
|
||||
|
||||
for( RepositoryStatistics stats : repositoryStatistics )
|
||||
{
|
||||
input.append( stats.getRepositoryId() ).append( "," );
|
||||
input.append( stats.getFileCount() ).append( "," );
|
||||
input.append( stats.getTotalSize() ).append( "," );
|
||||
input.append( stats.getArtifactCount() ).append( "," );
|
||||
input.append( stats.getGroupCount() ).append( "," );
|
||||
input.append( stats.getProjectCount() ).append( "," );
|
||||
input.append( stats.getPluginCount() ).append( "," );
|
||||
input.append( stats.getArchetypeCount() ).append( "," );
|
||||
input.append( stats.getJarCount() ).append( "," );
|
||||
input.append( stats.getWarCount() ).append( "," );
|
||||
input.append( stats.getDeploymentCount() ).append( "," );
|
||||
input.append( stats.getDownloadCount() ).append( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private Date getDefaultStartDate()
|
||||
{
|
||||
@ -645,4 +850,9 @@ public void setLimits( DataLimits limits )
|
||||
{
|
||||
this.limits = limits;
|
||||
}
|
||||
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return inputStream;
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,7 @@
|
||||
include a result for 'error' -->
|
||||
<result name="error">/WEB-INF/jsp/generalError.jsp</result>
|
||||
<result name="access_to_no_repos">/WEB-INF/jsp/accessToNoRepos.jsp</result>
|
||||
|
||||
</global-results>
|
||||
</package>
|
||||
|
||||
@ -503,6 +504,23 @@
|
||||
<result name="blank">/WEB-INF/jsp/reports/blankReport.jsp</result>
|
||||
<result>/WEB-INF/jsp/reports/basicReport.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="generateStatisticsReport" class="generateReport" method="generateStatistics">
|
||||
<result name="input">/WEB-INF/jsp/reports/pickReport.jsp</result>
|
||||
<result name="blank">/WEB-INF/jsp/reports/blankReport.jsp</result>
|
||||
<result>/WEB-INF/jsp/reports/statisticsReport.jsp</result>
|
||||
</action>
|
||||
|
||||
<!-- TODO: make report filename dynamic -->
|
||||
<action name="downloadStatsReport" class="generateReport" method="downloadStatisticsReport">
|
||||
<result name="input">/WEB-INF/jsp/reports/pickReport.jsp</result>
|
||||
<result name="blank">/WEB-INF/jsp/reports/blankReport.jsp</result>
|
||||
<result name="send-file" type="stream">
|
||||
<param name="contentType">${contentType}</param>
|
||||
<param name="contentDisposition">attachment; filename="archiva_statistics_report.csv"</param>
|
||||
</result>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
|
||||
<link type="text/css" rel="StyleSheet" href="/archiva/css/datepicker.css" />
|
||||
<script type="text/javascript" src="/archiva/js/datepicker/datepicker.js"></script>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Reports</title>
|
||||
@ -31,16 +34,45 @@
|
||||
<div id="contentArea">
|
||||
|
||||
<h2>Repository Statistics</h2>
|
||||
<s:form action="generateStatisticsReport" namespace="/report" validate="true">
|
||||
<s:form action="generateStatisticsReport" namespace="/report" validate="false">
|
||||
|
||||
<s:optiontransferselect label="Repositories To Be Compared" name="availableRepositories"
|
||||
list="availableRepositories" doubleName="selectedRepositories"
|
||||
doubleList="selectedRepositories" size="8" doubleSize="8"/>
|
||||
|
||||
<s:datetimepicker label="Start Date" name="startDate" id="startDate"/>
|
||||
<s:datetimepicker label="End Date" name="endDate" id="endDate" />
|
||||
<s:textfield label="Row Count" name="rowCount" />
|
||||
|
||||
|
||||
<s:textfield label="Row Count" name="rowCount" />
|
||||
<s:textfield label="Start Date" name="startDate" disabled="true"/>
|
||||
<script type="text/javascript">
|
||||
var d1 = new Date();
|
||||
var dp1 = new DatePicker(d1);
|
||||
|
||||
var tables = document.forms[0].getElementsByTagName("table");
|
||||
var myRow = tables[0].insertRow(3);
|
||||
var actionsCell = myRow.insertCell(0);
|
||||
var startDateCell = myRow.insertCell(1);
|
||||
startDateCell.appendChild(dp1.create());
|
||||
|
||||
dp1.onchange = function () {
|
||||
document.forms[0].startDate.value = dp1.getDate();
|
||||
};
|
||||
</script>
|
||||
|
||||
<s:textfield label="End Date" name="endDate" disabled="true"/>
|
||||
<script type="text/javascript">
|
||||
var d2 = new Date();
|
||||
var dp2 = new DatePicker(d2);
|
||||
|
||||
var tables = document.forms[0].getElementsByTagName("table");
|
||||
var myRow = tables[0].insertRow(5);
|
||||
var actionsCell = myRow.insertCell(0);
|
||||
var startDateCell = myRow.insertCell(1);
|
||||
startDateCell.appendChild(dp2.create());
|
||||
|
||||
dp2.onchange = function () {
|
||||
document.forms[0].endDate.value = dp2.getDate();
|
||||
};
|
||||
</script>
|
||||
|
||||
<s:submit value="View Statistics"/>
|
||||
</s:form>
|
||||
|
||||
|
@ -17,14 +17,14 @@
|
||||
~ under the License.
|
||||
--%>
|
||||
|
||||
<%@ taglib prefix="ww" uri="/webwork" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="archiva" uri="http://archiva.apache.org" %>
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Reports</title>
|
||||
<ww:head/>
|
||||
<s:head/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -44,22 +44,22 @@
|
||||
|
||||
<%-- Set Prev & Next icons --%>
|
||||
<c:set var="prevPageUrl">
|
||||
<ww:url action="generateStatisticsReport" namespace="/report">
|
||||
<ww:param name="selectedRepositories" value="%{'${selectedRepositories}'}"/>
|
||||
<ww:param name="rowCount" value="%{'${rowCount}'}"/>
|
||||
<ww:param name="startDate" value="%{'${startDate}'}"/>
|
||||
<ww:param name="endDate" value="%{'${endDate}'}"/>
|
||||
<ww:param name="page" value="%{'${page - 1}'}"/>
|
||||
</ww:url>
|
||||
<s:url action="generateStatisticsReport" namespace="/report">
|
||||
<s:param name="selectedRepositories" value="%{#attr.selectedRepositories}"/>
|
||||
<s:param name="rowCount" value="%{#attr.rowCount}"/>
|
||||
<s:param name="startDate" value="%{#attr.startDate}"/>
|
||||
<s:param name="endDate" value="%{#attr.endDate}"/>
|
||||
<s:param name="page" value="%{#attr.page - 1}"/>
|
||||
</s:url>
|
||||
</c:set>
|
||||
<c:set var="nextPageUrl">
|
||||
<ww:url action="generateStatisticsReport" namespace="/report">
|
||||
<ww:param name="selectedRepositories" value="%{'${selectedRepositories}'}"/>
|
||||
<ww:param name="rowCount" value="%{'${rowCount}'}"/>
|
||||
<ww:param name="startDate" value="%{'${startDate}'}"/>
|
||||
<ww:param name="endDate" value="%{'${endDate}'}"/>
|
||||
<ww:param name="page" value="%{'${page + 1}'}"/>
|
||||
</ww:url>
|
||||
<s:url action="generateStatisticsReport" namespace="/report">
|
||||
<s:param name="selectedRepositories" value="%{#attr.selectedRepositories}"/>
|
||||
<s:param name="rowCount" value="%{#attr.rowCount}"/>
|
||||
<s:param name="startDate" value="%{#attr.startDate}"/>
|
||||
<s:param name="endDate" value="%{#attr.endDate}"/>
|
||||
<s:param name="page" value="%{#attr.page + 1}"/>
|
||||
</s:url>
|
||||
</c:set>
|
||||
|
||||
<c:choose>
|
||||
@ -101,13 +101,13 @@
|
||||
<c:choose>
|
||||
<c:when test="${i != (page - 1)}">
|
||||
<c:set var="specificPageUrl">
|
||||
<ww:url action="generateStatisticsReport" namespace="/report">
|
||||
<ww:param name="selectedRepositories" value="%{'${selectedRepositories}'}"/>
|
||||
<ww:param name="rowCount" value="%{'${rowCount}'}"/>
|
||||
<ww:param name="startDate" value="%{'${startDate}'}"/>
|
||||
<ww:param name="endDate" value="%{'${endDate}'}"/>
|
||||
<ww:param name="page" value="%{'${page + 1}'}"/>
|
||||
</ww:url>
|
||||
<s:url action="generateStatisticsReport" namespace="/report">
|
||||
<s:param name="selectedRepositories" value="%{#attr.selectedRepositories}"/>
|
||||
<s:param name="rowCount" value="%{#attr.rowCount}"/>
|
||||
<s:param name="startDate" value="%{#attr.startDate}"/>
|
||||
<s:param name="endDate" value="%{#attr.endDate}"/>
|
||||
<s:param name="page" value="%{#attr.page + 1}"/>
|
||||
</s:url>
|
||||
</c:set>
|
||||
<a href="${specificPageUrl}">${i + 1}</a>
|
||||
</c:when>
|
||||
@ -130,6 +130,14 @@
|
||||
</p>
|
||||
<%-- Pagination - end --%>
|
||||
|
||||
<%-- Export to CSV link --%>
|
||||
<s:url id="downloadStatsReportUrl" action="downloadStatsReport" namespace="/report">
|
||||
<s:param name="selectedRepositories" value="%{#attr.selectedRepositories}"/>
|
||||
<s:param name="startDate" value="%{#attr.startDate}"/>
|
||||
<s:param name="endDate" value="%{#attr.endDate}"/>
|
||||
</s:url>
|
||||
<s:a href="%{downloadStatsReportUrl}">Export to CSV</s:a>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${reposSize > 1}">
|
||||
|
||||
|
@ -0,0 +1,143 @@
|
||||
.datePicker {
|
||||
border: 1px solid WindowText;
|
||||
background: Window;
|
||||
width: 170px;
|
||||
padding: 0px;
|
||||
cursor: default;
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
|
||||
.datePicker td {
|
||||
font: smallcaption;
|
||||
font: small-caption;
|
||||
text-align: center;
|
||||
color: WindowText;
|
||||
cursor: default;
|
||||
font-weight: normal !important;
|
||||
-moz-user-select: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.datePicker td.red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.datePicker .header {
|
||||
background: ActiveCaption;
|
||||
padding: 3px;
|
||||
border-bottom: 1px solid WindowText;
|
||||
}
|
||||
|
||||
.datePicker .headerTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datePicker .footer {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.datePicker .footerTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datePicker .grid {
|
||||
padding: 3px;
|
||||
}
|
||||
.datePicker .gridTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datePicker .gridTable td {
|
||||
width: 14.3%;
|
||||
}
|
||||
|
||||
.datePicker .gridTable .daysRow td {
|
||||
font-weight: bold !important;
|
||||
border-bottom: 1px solid ThreeDDarkShadow;
|
||||
}
|
||||
|
||||
.datePicker .grid .gridTable .upperLine {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.datePicker td.today {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.datePicker td.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText !important;
|
||||
}
|
||||
|
||||
.datePicker td.labelContainer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datePicker td .topLabel {
|
||||
color: CaptionText;
|
||||
display: block;
|
||||
font-weight: bold !important;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
|
||||
}
|
||||
|
||||
.datePicker td.filler {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datePicker button {
|
||||
border-width: 1px;
|
||||
font: Caption;
|
||||
font-weight: normal !important;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.datePicker .previousButton {
|
||||
background: buttonface url("../images/arrow.left.png") no-repeat center center;
|
||||
}
|
||||
|
||||
.datePicker .nextButton {
|
||||
background: buttonface url("../images/arrow.right.png") no-repeat center center;
|
||||
}
|
||||
.datePicker .previousButton,
|
||||
.datePicker .nextButton {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.datePicker .todayButton,
|
||||
.datePicker .noneButton {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
|
||||
.datePicker .labelPopup {
|
||||
position: absolute;
|
||||
min-width: 130px;
|
||||
background: Window;
|
||||
border: 1px solid WindowText;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.datePicker .labelPopup a {
|
||||
width: 100%;
|
||||
display: block;
|
||||
color: WindowText;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.datePicker .labelPopup a:hover {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.datePicker .labelPopup a.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 181 B |
Binary file not shown.
After Width: | Height: | Size: 181 B |
@ -0,0 +1,618 @@
|
||||
/*----------------------------------------------------------------------------\
|
||||
| Date Picker 1.06 |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| Created by Erik Arvidsson |
|
||||
| (http://webfx.eae.net/contact.html#erik) |
|
||||
| For WebFX (http://webfx.eae.net/) |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| A DOM based Date Picker |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|
||||
| use this file except in compliance with the License. You may obtain a copy |
|
||||
| of the License at http://www.apache.org/licenses/LICENSE-2.0 |
|
||||
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
||||
| Unless required by applicable law or agreed to in writing, software |
|
||||
| distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
||||
| WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|
||||
| License for the specific language governing permissions and limitations |
|
||||
| under the License. |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| Dependencies: datepicker.css Date picker style declarations |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| 2002-02-10 | Changed _update method to only update the text nodes instead |
|
||||
| | rewriting the entire table. Also added support for mouse wheel |
|
||||
| | in IE6. |
|
||||
| 2002-01-14 | Cleaned up for 1.0 public version |
|
||||
| 2002-01-15 | Replace all innerHTML calls with DOM1 methods |
|
||||
| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse |
|
||||
| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |
|
||||
| | This allows navigation to 6 adjacent months. |
|
||||
| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |
|
||||
| | that caused surroundung months to "overflow" |
|
||||
| | This had the effect that one could get two October months |
|
||||
| | listed. |
|
||||
| 2002-09-06 | I had missed one place were window was used instead of |
|
||||
| | doc.parentWindow |
|
||||
| 2003-08-28 | Added support for ensurin no date overflow when changing |
|
||||
| | months. |
|
||||
| 2004-01-10 | Adding type on the buttons to ensure they are not submit |
|
||||
| | buttons. Minor CSS change for CSS2 |
|
||||
| 2006-05-28 | Changed license to Apache Software License 2.0. |
|
||||
|-----------------------------------------------------------------------------|
|
||||
| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |
|
||||
\----------------------------------------------------------------------------*/
|
||||
|
||||
// The DatePicker constructor
|
||||
// oDate : Date Optional argument representing the date to select
|
||||
function DatePicker( oDate ) {
|
||||
// check arguments
|
||||
if ( arguments.length == 0 ) {
|
||||
this._selectedDate = new Date;
|
||||
this._none = false;
|
||||
}
|
||||
else {
|
||||
this._selectedDate = oDate || new Date();
|
||||
this._none = oDate == null;
|
||||
}
|
||||
|
||||
this._matrix = [[],[],[],[],[],[],[]];
|
||||
this._showNone = true;
|
||||
this._showToday = true;
|
||||
this._firstWeekDay = 0; // start week with monday according to standards
|
||||
this._redWeekDay = 6; // sunday is the default red day.
|
||||
|
||||
this._dontChangeNone = false;
|
||||
}
|
||||
|
||||
// two static fields describing the name of the months abd days
|
||||
DatePicker.months = [
|
||||
"January", "February", "March", "April",
|
||||
"May", "June", "July", "August",
|
||||
"September", "October", "November", "December"];
|
||||
DatePicker.days = ["m", "t", "w", "t", "f", "s", "s"];
|
||||
|
||||
|
||||
DatePicker.prototype.onchange = function () {};
|
||||
|
||||
// create the nodes inside the date picker
|
||||
DatePicker.prototype.create = function ( doc ) {
|
||||
if ( doc == null ) doc = document;
|
||||
|
||||
this._document = doc;
|
||||
|
||||
// create elements
|
||||
this._el = doc.createElement( "div" );
|
||||
this._el.className = "datePicker";
|
||||
|
||||
// header
|
||||
var div = doc.createElement( "div" );
|
||||
div.className = "header";
|
||||
this._el.appendChild( div );
|
||||
|
||||
var headerTable = doc.createElement( "table" );
|
||||
headerTable.className = "headerTable";
|
||||
headerTable.cellSpacing = 0;
|
||||
div.appendChild( headerTable );
|
||||
|
||||
var tBody = doc.createElement( "tbody" );
|
||||
headerTable.appendChild( tBody );
|
||||
|
||||
var tr = doc.createElement( "tr" );
|
||||
tBody.appendChild( tr );
|
||||
|
||||
var td = doc.createElement( "td" );
|
||||
this._previousMonth = doc.createElement( "button" );
|
||||
this._previousMonth.className = "previousButton";
|
||||
this._previousMonth.setAttribute("type", "button");
|
||||
td.appendChild( this._previousMonth );
|
||||
tr.appendChild( td );
|
||||
|
||||
td = doc.createElement( "td" );
|
||||
td.className = "labelContainer";
|
||||
tr.appendChild( td );
|
||||
|
||||
this._topLabel = doc.createElement( "a" );
|
||||
this._topLabel.className = "topLabel";
|
||||
this._topLabel.href = "#";
|
||||
this._topLabel.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );
|
||||
td.appendChild( this._topLabel );
|
||||
|
||||
this._labelPopup = doc.createElement( "div" );
|
||||
this._labelPopup.className = "labelPopup";
|
||||
// no insertion
|
||||
|
||||
td = doc.createElement( "td" );
|
||||
this._nextMonth = doc.createElement( "button" );
|
||||
this._nextMonth.className = "nextButton";
|
||||
this._nextMonth.setAttribute("type", "button");
|
||||
td.appendChild( this._nextMonth );
|
||||
tr.appendChild( td );
|
||||
|
||||
// grid
|
||||
div = doc.createElement( "div" );
|
||||
div.className = "grid";
|
||||
this._el.appendChild( div );
|
||||
this._table = div;
|
||||
|
||||
// footer
|
||||
div = doc.createElement( "div" );
|
||||
div.className = "footer";
|
||||
this._el.appendChild( div );
|
||||
|
||||
var footerTable = doc.createElement( "table" );
|
||||
footerTable.className = "footerTable";
|
||||
footerTable.cellSpacing = 0;
|
||||
div.appendChild( footerTable );
|
||||
|
||||
tBody = doc.createElement( "tbody" );
|
||||
footerTable.appendChild( tBody );
|
||||
|
||||
tr = doc.createElement( "tr" );
|
||||
tBody.appendChild( tr );
|
||||
|
||||
td = doc.createElement( "td" );
|
||||
this._todayButton = doc.createElement( "button" );
|
||||
this._todayButton.className = "todayButton";
|
||||
this._todayButton.setAttribute("type", "button");
|
||||
this._todayButton.appendChild( doc.createTextNode( "Today" ) );
|
||||
td.appendChild( this._todayButton );
|
||||
tr.appendChild( td );
|
||||
|
||||
td = doc.createElement( "td" );
|
||||
td.className = "filler";
|
||||
td.appendChild( doc.createTextNode( String.fromCharCode( 160 ) ) );
|
||||
tr.appendChild( td );
|
||||
|
||||
td = doc.createElement( "td" );
|
||||
this._noneButton = doc.createElement( "button" );
|
||||
this._noneButton.className = "noneButton";
|
||||
this._noneButton.setAttribute("type", "button");
|
||||
this._noneButton.appendChild( doc.createTextNode( "None" ) );
|
||||
td.appendChild( this._noneButton );
|
||||
tr.appendChild( td );
|
||||
|
||||
|
||||
|
||||
this._createTable( doc );
|
||||
|
||||
this._updateTable();
|
||||
this._setTopLabel();
|
||||
|
||||
if ( !this._showNone )
|
||||
this._noneButton.style.visibility = "hidden";
|
||||
if ( !this._showToday )
|
||||
this._todayButton.style.visibility = "hidden";
|
||||
|
||||
// IE55+ extension
|
||||
this._previousMonth.hideFocus = true;
|
||||
this._nextMonth.hideFocus = true;
|
||||
this._todayButton.hideFocus = true;
|
||||
this._noneButton.hideFocus = true;
|
||||
// end IE55+ extension
|
||||
|
||||
// hook up events
|
||||
var dp = this;
|
||||
// buttons
|
||||
this._previousMonth.onclick = function () {
|
||||
dp._dontChangeNone = true;
|
||||
dp.goToPreviousMonth();
|
||||
dp._dontChangeNone = false;
|
||||
};
|
||||
this._nextMonth.onclick = function () {
|
||||
dp._dontChangeNone = true;
|
||||
dp.goToNextMonth();
|
||||
dp._dontChangeNone = false;
|
||||
};
|
||||
this._todayButton.onclick = function () {
|
||||
dp.goToToday();
|
||||
};
|
||||
this._noneButton.onclick = function () {
|
||||
dp.setDate( null );
|
||||
};
|
||||
|
||||
this._el.onselectstart = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
this._table.onclick = function ( e ) {
|
||||
// find event
|
||||
if ( e == null ) e = doc.parentWindow.event;
|
||||
|
||||
// find td
|
||||
var el = e.target != null ? e.target : e.srcElement;
|
||||
while ( el.nodeType != 1 )
|
||||
el = el.parentNode;
|
||||
while ( el != null && el.tagName && el.tagName.toLowerCase() != "td" )
|
||||
el = el.parentNode;
|
||||
|
||||
// if no td found, return
|
||||
if ( el == null || el.tagName == null || el.tagName.toLowerCase() != "td" )
|
||||
return;
|
||||
|
||||
var d = new Date( dp._selectedDate );
|
||||
var n = Number( el.firstChild.data );
|
||||
if ( isNaN( n ) || n <= 0 || n == null )
|
||||
return;
|
||||
|
||||
d.setDate( n );
|
||||
dp.setDate( d );
|
||||
};
|
||||
|
||||
// show popup
|
||||
this._topLabel.onclick = function ( e ) {
|
||||
dp._showLabelPopup();
|
||||
return false;
|
||||
};
|
||||
|
||||
this._el.onkeydown = function ( e ) {
|
||||
if ( e == null ) e = doc.parentWindow.event;
|
||||
var kc = e.keyCode != null ? e.keyCode : e.charCode;
|
||||
|
||||
if ( kc < 37 || kc > 40 ) return true;
|
||||
|
||||
var d = new Date( dp._selectedDate ).valueOf();
|
||||
if ( kc == 37 ) // left
|
||||
d -= 24 * 60 * 60 * 1000;
|
||||
else if ( kc == 39 ) // right
|
||||
d += 24 * 60 * 60 * 1000;
|
||||
else if ( kc == 38 ) // up
|
||||
d -= 7 * 24 * 60 * 60 * 1000;
|
||||
else if ( kc == 40 ) // down
|
||||
d += 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
dp.setDate( new Date( d ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// ie6 extension
|
||||
this._el.onmousewheel = function ( e ) {
|
||||
if ( e == null ) e = doc.parentWindow.event;
|
||||
var n = - e.wheelDelta / 120;
|
||||
var d = new Date( dp._selectedDate );
|
||||
var m = d.getMonth() + n;
|
||||
d.setMonth( m );
|
||||
|
||||
|
||||
dp._dontChangeNone = true;
|
||||
dp.setDate( d );
|
||||
dp._dontChangeNone = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._el;
|
||||
};
|
||||
|
||||
DatePicker.prototype.setDate = function ( oDate ) {
|
||||
|
||||
this._hideLabelPopup();
|
||||
|
||||
// if null then set None
|
||||
if ( oDate == null ) {
|
||||
if ( !this._none ) {
|
||||
this._none = true;
|
||||
this._setTopLabel();
|
||||
this._updateTable();
|
||||
|
||||
if ( typeof this.onchange == "function" )
|
||||
this.onchange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if string or number create a Date object
|
||||
if ( typeof oDate == "string" || typeof oDate == "number" ) {
|
||||
oDate = new Date( oDate );
|
||||
}
|
||||
|
||||
|
||||
// do not update if not really changed
|
||||
if ( this._selectedDate.getDate() != oDate.getDate() ||
|
||||
this._selectedDate.getMonth() != oDate.getMonth() ||
|
||||
this._selectedDate.getFullYear() != oDate.getFullYear() ||
|
||||
this._none ) {
|
||||
|
||||
if ( !this._dontChangeNone )
|
||||
this._none = false;
|
||||
|
||||
this._selectedDate = new Date( oDate );
|
||||
|
||||
this._setTopLabel();
|
||||
this._updateTable();
|
||||
|
||||
if ( typeof this.onchange == "function" )
|
||||
this.onchange();
|
||||
}
|
||||
|
||||
if ( !this._dontChangeNone )
|
||||
this._none = false;
|
||||
}
|
||||
|
||||
|
||||
DatePicker.prototype.getDate = function () {
|
||||
if ( this._none ) return null;
|
||||
return new Date( this._selectedDate ); // create a new instance
|
||||
}
|
||||
|
||||
// creates the table elements and inserts them into the date picker
|
||||
DatePicker.prototype._createTable = function ( doc ) {
|
||||
var str, i;
|
||||
var rows = 6;
|
||||
var cols = 7;
|
||||
var currentWeek = 0;
|
||||
|
||||
var table = doc.createElement( "table" );
|
||||
table.className = "gridTable";
|
||||
table.cellSpacing = 0;
|
||||
|
||||
var tBody = doc.createElement( "tbody" );
|
||||
table.appendChild( tBody );
|
||||
|
||||
// days row
|
||||
var tr = doc.createElement( "tr" );
|
||||
tr.className = "daysRow";
|
||||
|
||||
var td, tn;
|
||||
var nbsp = String.fromCharCode( 160 );
|
||||
for ( i = 0; i < cols; i++ ) {
|
||||
td = doc.createElement( "td" );
|
||||
td.appendChild( doc.createTextNode( nbsp ) );
|
||||
tr.appendChild( td );
|
||||
}
|
||||
tBody.appendChild( tr );
|
||||
|
||||
// upper line
|
||||
tr = doc.createElement( "tr" );
|
||||
td = doc.createElement( "td" );
|
||||
td.className = "upperLine";
|
||||
td.colSpan = 7;
|
||||
tr.appendChild( td );
|
||||
tBody.appendChild( tr );
|
||||
|
||||
// rest
|
||||
for ( i = 0; i < rows; i++ ) {
|
||||
tr = doc.createElement( "tr" );
|
||||
for ( var j = 0; j < cols; j++ ) {
|
||||
td = doc.createElement( "td" );
|
||||
td.appendChild( doc.createTextNode( nbsp ) );
|
||||
tr.appendChild( td );
|
||||
}
|
||||
tBody.appendChild( tr );
|
||||
}
|
||||
str += "</table>";
|
||||
|
||||
if ( this._table != null )
|
||||
this._table.appendChild( table )
|
||||
};
|
||||
// this method updates all the text nodes inside the table as well
|
||||
// as all the classNames on the tds
|
||||
DatePicker.prototype._updateTable = function () {
|
||||
// if no element no need to continue
|
||||
if ( this._table == null ) return;
|
||||
|
||||
var i;
|
||||
var str = "";
|
||||
var rows = 6;
|
||||
var cols = 7;
|
||||
var currentWeek = 0;
|
||||
|
||||
var cells = new Array( rows );
|
||||
this._matrix = new Array( rows )
|
||||
for ( i = 0; i < rows; i++ ) {
|
||||
cells[i] = new Array( cols );
|
||||
this._matrix[i] = new Array( cols );
|
||||
}
|
||||
|
||||
// Set the tmpDate to this month
|
||||
var tmpDate = new Date( this._selectedDate.getFullYear(),
|
||||
this._selectedDate.getMonth(), 1 );
|
||||
var today = new Date();
|
||||
// go thorugh all days this month and store the text
|
||||
// and the class name in the cells matrix
|
||||
for ( i = 1; i < 32; i++ ) {
|
||||
tmpDate.setDate( i );
|
||||
// convert to ISO, Monday is 0 and 6 is Sunday
|
||||
var weekDay = ( tmpDate.getDay() + 6 ) % 7;
|
||||
var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;
|
||||
if ( tmpDate.getMonth() == this._selectedDate.getMonth() ) {
|
||||
|
||||
var isToday = tmpDate.getDate() == today.getDate() &&
|
||||
tmpDate.getMonth() == today.getMonth() &&
|
||||
tmpDate.getFullYear() == today.getFullYear();
|
||||
|
||||
cells[currentWeek][colIndex] = { text: "", className: "" };
|
||||
|
||||
if ( this._selectedDate.getDate() == tmpDate.getDate() && !this._none )
|
||||
cells[currentWeek][colIndex].className += "selected ";
|
||||
if ( isToday )
|
||||
cells[currentWeek][colIndex].className += "today ";
|
||||
if ( ( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay ) // ISO
|
||||
cells[currentWeek][colIndex].className += "red";
|
||||
|
||||
cells[currentWeek][colIndex].text =
|
||||
this._matrix[currentWeek][colIndex] = tmpDate.getDate();
|
||||
|
||||
if ( colIndex == 6 )
|
||||
currentWeek++;
|
||||
}
|
||||
}
|
||||
|
||||
// fix day letter order if not standard
|
||||
var weekDays = DatePicker.days;
|
||||
if (this._firstWeekDay != 0) {
|
||||
weekDays = new Array(7);
|
||||
for ( i = 0; i < 7; i++)
|
||||
weekDays[i] = DatePicker.days[ (i + this._firstWeekDay) % 7];
|
||||
}
|
||||
|
||||
// update text in days row
|
||||
var tds = this._table.firstChild.tBodies[0].rows[0].cells;
|
||||
for ( i = 0; i < cols; i++ )
|
||||
tds[i].firstChild.data = weekDays[i];
|
||||
|
||||
// update the text nodes and class names
|
||||
var trs = this._table.firstChild.tBodies[0].rows;
|
||||
var tmpCell;
|
||||
var nbsp = String.fromCharCode( 160 );
|
||||
for ( var y = 0; y < rows; y++ ) {
|
||||
for (var x = 0; x < cols; x++) {
|
||||
tmpCell = trs[y + 2].cells[x];
|
||||
if ( typeof cells[y][x] != "undefined" ) {
|
||||
tmpCell.className = cells[y][x].className;
|
||||
tmpCell.firstChild.data = cells[y][x].text;
|
||||
}
|
||||
else {
|
||||
tmpCell.className = "";
|
||||
tmpCell.firstChild.data = nbsp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sets the label showing the year and selected month
|
||||
DatePicker.prototype._setTopLabel = function () {
|
||||
var str = this._selectedDate.getFullYear() + " " + DatePicker.months[ this._selectedDate.getMonth() ];
|
||||
if ( this._topLabel != null )
|
||||
this._topLabel.lastChild.data = str;
|
||||
}
|
||||
|
||||
DatePicker.prototype.goToNextMonth = function () {
|
||||
var d = new Date( this._selectedDate );
|
||||
d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,
|
||||
d.getFullYear())) ); // no need to catch dec -> jan for the year
|
||||
d.setMonth( d.getMonth() + 1 );
|
||||
this.setDate( d );
|
||||
}
|
||||
|
||||
DatePicker.prototype.goToPreviousMonth = function () {
|
||||
var d = new Date( this._selectedDate );
|
||||
d.setDate( Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,
|
||||
d.getFullYear())) ); // no need to catch jan -> dec for the year
|
||||
d.setMonth( d.getMonth() - 1 );
|
||||
this.setDate( d );
|
||||
}
|
||||
|
||||
DatePicker.prototype.goToToday = function () {
|
||||
if ( this._none )
|
||||
// change the selectedDate to force update if none was true
|
||||
this._selectedDate = new Date( this._selectedDate + 10000000000 );
|
||||
this._none = false;
|
||||
this.setDate( new Date() );
|
||||
}
|
||||
|
||||
DatePicker.prototype.setShowToday = function ( bShowToday ) {
|
||||
if ( typeof bShowToday == "string" )
|
||||
bShowToday = !/false|0|no/i.test( bShowToday );
|
||||
|
||||
if ( this._todayButton != null )
|
||||
this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";
|
||||
this._showToday = bShowToday;
|
||||
}
|
||||
|
||||
DatePicker.prototype.getShowToday = function () {
|
||||
return this._showToday;
|
||||
}
|
||||
|
||||
DatePicker.prototype.setShowNone = function ( bShowNone ) {
|
||||
if ( typeof bShowNone == "string" )
|
||||
bShowNone = !/false|0|no/i.test( bShowNone );
|
||||
|
||||
if ( this._noneButton != null )
|
||||
this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";
|
||||
this._showNone = bShowNone;
|
||||
}
|
||||
|
||||
DatePicker.prototype.getShowNone = function () {
|
||||
return this._showNone;
|
||||
}
|
||||
|
||||
// 0 is monday and 6 is sunday as in the ISO standard
|
||||
DatePicker.prototype.setFirstWeekDay = function ( nFirstWeekDay ) {
|
||||
if ( this._firstWeekDay != nFirstWeekDay ) {
|
||||
this._firstWeekDay = nFirstWeekDay;
|
||||
this._updateTable();
|
||||
}
|
||||
}
|
||||
|
||||
DatePicker.prototype.getFirstWeekDay = function () {
|
||||
return this._firstWeekDay;
|
||||
}
|
||||
|
||||
// 0 is monday and 6 is sunday as in the ISO standard
|
||||
DatePicker.prototype.setRedWeekDay = function ( nRedWeekDay ) {
|
||||
if ( this._redWeekDay != nRedWeekDay ) {
|
||||
this._redWeekDay = nRedWeekDay;
|
||||
this._updateTable();
|
||||
}
|
||||
}
|
||||
|
||||
DatePicker.prototype.getRedWeekDay = function () {
|
||||
return this._redWeekDay;
|
||||
}
|
||||
|
||||
|
||||
DatePicker.prototype._showLabelPopup = function () {
|
||||
|
||||
/*
|
||||
this._labelPopup document.createElement( "DIV" );
|
||||
div.className = "month-popup";
|
||||
div.noWrap = true;
|
||||
el.unselectable = div.unselectable = "on";
|
||||
el.onselectstart = div.onselectstart = function () { return false; };
|
||||
*/
|
||||
|
||||
var dateContext = function ( dp, d ) {
|
||||
return function ( e ) {
|
||||
dp._dontChangeNone = true;
|
||||
dp._hideLabelPopup();
|
||||
dp.setDate( d );
|
||||
dp._dontChangeNone = false;
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
var dp = this;
|
||||
|
||||
// clear all old elements in the popup
|
||||
while ( this._labelPopup.hasChildNodes() )
|
||||
this._labelPopup.removeChild( this._labelPopup.firstChild );
|
||||
|
||||
var a, tmp, tmp2;
|
||||
for ( var i = -3; i < 4; i++ ) {
|
||||
tmp = new Date( this._selectedDate );
|
||||
tmp2 = new Date( this._selectedDate ); // need another tmp to catch year change when checking leap
|
||||
tmp2.setDate(1);
|
||||
tmp2.setMonth( tmp2.getMonth() + i );
|
||||
tmp.setDate( Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,
|
||||
tmp2.getFullYear())) );
|
||||
tmp.setMonth( tmp.getMonth() + i );
|
||||
|
||||
a = this._document.createElement( "a" );
|
||||
a.href = "javascript:void 0;";
|
||||
a.onclick = dateContext( dp, tmp );
|
||||
a.appendChild( this._document.createTextNode( tmp.getFullYear() + " " +
|
||||
DatePicker.months[ tmp.getMonth() ] ) );
|
||||
if ( i == 0 )
|
||||
a.className = "selected";
|
||||
this._labelPopup.appendChild( a );
|
||||
}
|
||||
|
||||
this._topLabel.parentNode.insertBefore( this._labelPopup, this._topLabel.parentNode.firstChild );
|
||||
};
|
||||
|
||||
DatePicker.prototype._hideLabelPopup = function () {
|
||||
if ( this._labelPopup.parentNode )
|
||||
this._labelPopup.parentNode.removeChild( this._labelPopup );
|
||||
};
|
||||
|
||||
DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
|
||||
DatePicker.getDaysPerMonth = function (nMonth, nYear) {
|
||||
nMonth = (nMonth + 12) % 12;
|
||||
var res = DatePicker._daysPerMonth[nMonth];
|
||||
if (nMonth == 1) {
|
||||
res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
|
||||
}
|
||||
return res;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user