aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules/archiva-web/archiva-webapp/src/main/webapp
diff options
context:
space:
mode:
authorBrett Porter <brett@apache.org>2008-03-29 03:09:22 +0000
committerBrett Porter <brett@apache.org>2008-03-29 03:09:22 +0000
commita05f42cc0ec53b094ddd64661579374792a55231 (patch)
tree32274f5d8286676016f357caf10dce8be975f28e /archiva-modules/archiva-web/archiva-webapp/src/main/webapp
parented0fa81292f6aaca377638a3fbf5b80cef029452 (diff)
downloadarchiva-a05f42cc0ec53b094ddd64661579374792a55231.tar.gz
archiva-a05f42cc0ec53b094ddd64661579374792a55231.zip
restructure according to discussion on the dev list
git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@642497 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'archiva-modules/archiva-web/archiva-webapp/src/main/webapp')
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml14
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/decorators.xml34
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/accessToNoRepos.jsp46
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addLegacyArtifactPath.jsp100
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addProxyConnector.jsp45
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRemoteRepository.jsp48
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRepository.jsp48
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/appearance.jsp96
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/database.jsp177
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteNetworkProxy.jsp53
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteProxyConnector.jsp54
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRemoteRepository.jsp73
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRepository.jsp74
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editAppearance.jsp45
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editNetworkProxy.jsp73
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editPom.jsp53
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editProxyConnector.jsp46
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRemoteRepository.jsp50
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRepository.jsp51
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/errorMessages.jsp29
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/networkProxyForm.jspf26
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf256
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf28
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/repositoryForm.jspf35
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/legacyArtifactPath.jsp113
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/networkProxies.jsp128
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/proxyConnectors.jsp215
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositories.jsp327
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositoryScanning.jsp258
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/alert.jsp45
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/artifact/dependencyTree.jsp28
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browse.jsp99
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseArtifact.jsp59
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseGroup.jsp91
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/components/companyLogo.jsp35
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/artifactDecorator.jsp149
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp198
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/findArtifact.jsp106
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/generalError.jsp36
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactDependencies.jspf40
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactInfo.jspf226
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactReports.jspf38
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/dependencyTree.jspf31
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/mailingLists.jspf84
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/projectDependees.jspf39
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf36
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/uploadForm.jspf35
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp40
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/basicReport.jsp65
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/blankReport.jsp37
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/pickReport.jsp43
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp115
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/showArtifact.jsp166
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/upload.jsp46
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/currentWWUrl.tag52
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/displayUpdatePolicy.tag41
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactLink.tag77
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactTitle.tag46
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/web.xml113
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-base.css201
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-theme.css330
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/print.css27
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css400
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/favicon.icobin0 -> 3638 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archetype.gifbin0 -> 2149 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-splat-32.gifbin0 -> 1294 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-world.pngbin0 -> 1936 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva.pngbin0 -> 9801 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/arrow.gifbin0 -> 88 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/collapsed.gifbin0 -> 53 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/dl.gifbin0 -> 388 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-jar.pngbin0 -> 969 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-java-source.pngbin0 -> 969 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-pom.pngbin0 -> 946 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.bl.gifbin0 -> 179 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.br.gifbin0 -> 120 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.ml.gifbin0 -> 103 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.mr.gifbin0 -> 62 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tl.gifbin0 -> 179 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tr.gifbin0 -> 118 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/expanded.gifbin0 -> 52 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/external.pngbin0 -> 230 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/footerborder.gifbin0 -> 54 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_error_sml.gifbin0 -> 1010 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_info_sml.gifbin0 -> 606 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_success_sml.gifbin0 -> 990 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_warning_sml.gifbin0 -> 576 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-down.pngbin0 -> 237 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-left.pngbin0 -> 231 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-right.pngbin0 -> 228 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-up.pngbin0 -> 230 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/box.pngbin0 -> 255 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/create.pngbin0 -> 236 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/delete.gifbin0 -> 351 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/down.gifbin0 -> 117 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/edit.pngbin0 -> 246 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-key.pngbin0 -> 300 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-lock.pngbin0 -> 281 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/up.gifbin0 -> 117 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/user.pngbin0 -> 344 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/jar.gifbin0 -> 1964 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/mavenplugin.gifbin0 -> 2336 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/newwindow.pngbin0 -> 220 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/other.gifbin0 -> 2160 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/pom.gifbin0 -> 2020 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/skin.gifbin0 -> 2258 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super.gifbin0 -> 1212 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl.gifbin0 -> 1212 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl_sub.gifbin0 -> 985 bytes
-rwxr-xr-xarchiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/supersub.gifbin0 -> 206 bytes
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/index.jsp20
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/builder.js160
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/controls.js969
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/dragdrop.js1178
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/effects.js1156
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/prototype.js2696
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/scriptaculous.js72
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/slider.js365
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/unittest.js744
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/checkboxlist.ftl39
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/radiomap.ftl39
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/theme.properties20
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a-close.ftl1
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a.ftl22
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionerror.ftl7
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionmessage.ftl7
-rw-r--r--archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/hidden.ftl15
127 files changed, 13279 insertions, 0 deletions
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml
new file mode 100644
index 000000000..f6b0fa81d
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+ <bean id="loggerManager" class="org.codehaus.plexus.logging.slf4j.Slf4jLoggerManager"
+ init-method="initialize"/>
+
+ <bean id="urlFailureCache" class="org.apache.maven.archiva.policies.urlcache.DefaultUrlFailureCache">
+ <constructor-arg ref="cache#url-failures-cache" type="org.codehaus.plexus.cache.Cache"/>
+ </bean>
+
+</beans>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/decorators.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/decorators.xml
new file mode 100644
index 000000000..638f2c53a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/decorators.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<decorators defaultdir="/WEB-INF/jsp/decorators">
+ <excludes>
+ <pattern>/repository/*</pattern>
+ <pattern>/components/*</pattern>
+ </excludes>
+
+ <decorator name="default" page="default.jsp">
+ <pattern>/*</pattern>
+ </decorator>
+
+ <decorator name="artifactDetails" page="artifactDecorator.jsp">
+ <pattern>/*/dependencyTree</pattern>
+ </decorator>
+</decorators> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/accessToNoRepos.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/accessToNoRepos.jsp
new file mode 100644
index 000000000..5ed04736f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/accessToNoRepos.jsp
@@ -0,0 +1,46 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+ <title>You have access to no repositories</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<div id="contentArea">
+
+ <div id="results">
+ You have access to no repositories.
+ Ask your system administrator for access.
+ </div>
+
+</div>
+
+<div class="clear">
+ <hr/>
+</div>
+
+</body>
+
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addLegacyArtifactPath.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addLegacyArtifactPath.jsp
new file mode 100644
index 000000000..6c647d426
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addLegacyArtifactPath.jsp
@@ -0,0 +1,100 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Add Legacy Artifact Path</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Add Legacy Artifact Path</h1>
+
+<div id="contentArea">
+
+ <p>
+ Enter the legacy path to map to a particular artifact reference, then adjust the fields as necessary.
+ </p>
+
+ <script type="text/javascript">
+ function parse( path )
+ {
+ var group = path.indexOf( "/" );
+ if ( group > 0 )
+ {
+ document.getElementById( "addLegacyArtifactPath_groupId" ).value
+ = path.substring( 0, group );
+ group += 1;
+ var type = path.indexOf( "/", group );
+ if ( type > 0 )
+ {
+ document.getElementById( "addLegacyArtifactPath_type" ).value
+ = path.substring( group, type - 1 );
+ }
+ type += 1;
+ var version = path.indexOf( "-", type );
+ var ext = path.lastIndexOf( "." );
+ if ( version > 0 )
+ {
+ document.getElementById( "addLegacyArtifactPath_artifactId" ).value
+ = path.substring( type, version );
+ document.getElementById( "addLegacyArtifactPath_version" ).value
+ = path.substring( version + 1, ext );
+ }
+
+ }
+ }
+ </script>
+
+ <ww:actionmessage/>
+ <ww:actionerror/>
+ <ww:form method="post" action="addLegacyArtifactPath!commit" namespace="/admin" validate="true">
+ <ww:textfield name="legacyArtifactPath.path" label="Path" size="50" required="true" onchange="parse( this.value )"/>
+ <ww:textfield name="groupId" label="GroupId" size="20" required="true"/>
+ <ww:textfield name="artifactId" label="ArtifactId" size="20" required="true"/>
+ <ww:textfield name="version" label="Version" size="20" required="true"/>
+ <ww:textfield name="classifier" label="Classifier" size="20" required="false"/>
+ <ww:textfield name="type" label="Type" size="20" required="true"/>
+ <ww:submit value="Add Legacy Artifact Path"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ var ref = document.getElementById("addLegacyArtifactPath_legacyArtifactPath_artifact").value;
+ var i = ref.indexOf( ":" );
+ document.getElementById("addLegacyArtifactPath_groupId").value = ref.substring( 0, i );
+ var j = i + 1;
+ var i = ref.indexOf( ":", j );
+ document.getElementById("addLegacyArtifactPath_artifactId").value = ref.substring( j, i );
+ var j = i + 1;
+ var i = ref.indexOf( ":", j );
+ document.getElementById("addLegacyArtifactPath_version").value = ref.substring( j, i );
+ var j = i + 1;
+ var i = ref.indexOf( ":", j );
+ document.getElementById("addLegacyArtifactPath_classifier").value = ref.substring( j, i );
+
+ document.getElementById("addLegacyArtifactPath_legacyArtifactPath_path").focus();
+ </script>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addProxyConnector.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addProxyConnector.jsp
new file mode 100644
index 000000000..314f9bc1b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addProxyConnector.jsp
@@ -0,0 +1,45 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Add Proxy Connector</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Add Proxy Connector</h1>
+
+<div id="contentArea">
+
+ <ww:actionerror/>
+ <ww:actionmessage/>
+
+ <ww:form name="saveProxyConnector" method="post" action="addProxyConnector!commit" namespace="/admin" validate="true">
+ <%@ include file="/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf" %>
+ <ww:submit value="Add Proxy Connector"/>
+ </ww:form>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRemoteRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRemoteRepository.jsp
new file mode 100644
index 000000000..d1455abf8
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRemoteRepository.jsp
@@ -0,0 +1,48 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Add Remote Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Add Remote Repository</h1>
+
+<div id="contentArea">
+
+ <ww:actionmessage/>
+ <ww:form method="post" action="addRemoteRepository!commit" namespace="/admin" validate="true">
+ <ww:textfield name="repository.id" label="Identifier" size="10" required="true"/>
+ <%@ include file="/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf" %>
+ <ww:submit value="Add Repository"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("addRemoteRepository_id").focus();
+ </script>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRepository.jsp
new file mode 100644
index 000000000..55bbda151
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/addRepository.jsp
@@ -0,0 +1,48 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Add Managed Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Add Managed Repository</h1>
+
+<div id="contentArea">
+
+ <ww:actionmessage/>
+ <ww:form method="post" action="addRepository!commit" namespace="/admin" validate="true">
+ <ww:textfield name="repository.id" label="Identifier" size="10" required="true"/>
+ <%@ include file="/WEB-INF/jsp/admin/include/repositoryForm.jspf" %>
+ <ww:submit value="Add Repository"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("addRepository_repository_id").focus();
+ </script>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/appearance.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/appearance.jsp
new file mode 100644
index 000000000..dfebffbc9
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/appearance.jsp
@@ -0,0 +1,96 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+ <title>Configure Appearance</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Appearance</h1>
+
+<div style="float: right">
+ <a href="<ww:url action='editAppearance' />">Edit</a>
+</div>
+<h2>Company Details</h2>
+
+<p>
+ The logo in the top right of the screen is controlled by your selected 'company POM'.
+</p>
+
+<ww:set name="companyPom" value="companyPom"/>
+
+<c:if test="${empty(companyPom.groupId) || empty(companyPom.artifactId)}">
+ <p>
+ You have not yet specified a company POM. <a href="<ww:url action='editAppearance' />">Select a Company POM</a>
+ </p>
+</c:if>
+
+<c:if test="${!empty(companyPom.groupId) && !empty(companyPom.artifactId)}">
+ <p>
+ Your selected company POM is below. If you would like to change the organization name, url or logo, you can
+ <a href="<ww:url action='editCompanyPom'/>">edit the POM</a>.
+ </p>
+
+ <ww:set name="companyModel" value="companyModel"/>
+ <table>
+ <ww:label name="companyPom.groupId" label="Group ID"/>
+ <ww:label name="companyPom.artifactId" label="Artifact ID"/>
+ <c:if test="${companyModel != null}">
+ <ww:label name="companyModel.version" label="Version"/>
+ </c:if>
+ </table>
+
+ <div style="float: right">
+ <a href="<ww:url action='editCompanyPom' />">Edit Company POM</a>
+ </div>
+ <h3>POM Information</h3>
+
+ <c:choose>
+ <c:when test="${companyModel != null}">
+ <table>
+ <tr>
+ <th>Name</th>
+ <td>${companyModel.organization.name}</td>
+ </tr>
+ <tr>
+ <th>URL</th>
+ <td><a href="${companyModel.organization.url}">
+ <code>${companyModel.organization.url}</code>
+ </a></td>
+ </tr>
+ <tr>
+ <th>Logo URL</th>
+ <td>
+ <code>${companyModel.properties['organization.logo']}</code>
+ </td>
+ </tr>
+ </table>
+ </c:when>
+ <c:otherwise>
+ Company POM '${companyPom.groupId}:${companyPom.artifactId}' doesn't exist.
+ <a href="<ww:url action='editCompanyPom' />">Create company POM</a>
+ </c:otherwise>
+ </c:choose>
+</c:if>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/database.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/database.jsp
new file mode 100644
index 000000000..9ffee7d4e
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/database.jsp
@@ -0,0 +1,177 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+<title>Administration - Database</title>
+<ww:head />
+</head>
+
+<body>
+
+<h1>Administration - Database</h1>
+
+<div id="contentArea">
+
+<ww:actionerror />
+<ww:actionmessage />
+
+<c:url var="iconDeleteUrl" value="/images/icons/delete.gif" />
+<c:url var="iconCreateUrl" value="/images/icons/create.png" />
+
+<div class="admin">
+
+<h2>Database - Unprocessed Artifacts Scanning</h2>
+
+ <ww:form method="post" action="database!updateSchedule"
+ namespace="/admin" validate="false" theme="simple">
+ <table>
+ <ww:textfield name="cron" label="Cron" size="40" theme="xhtml" />
+ <tr>
+ <td colspan="2">
+ <ww:submit value="Update Cron" />
+ </td>
+ </tr>
+ </table>
+ </ww:form>
+
+ <ww:form action="updateDatabase" theme="simple">
+ <ww:submit value="Update Database Now"/>
+ </ww:form>
+
+<h2>Database - Unprocessed Artifacts Scanning</h2>
+
+<c:choose>
+ <c:when test="${empty(unprocessedConsumers)}">
+ <%-- No Consumers. Eeek! --%>
+ <strong>There are no consumers for unprocessed artifacts.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the consumers. --%>
+
+ <ww:form method="post" action="database!updateUnprocessedConsumers"
+ namespace="/admin" validate="false" theme="simple">
+ <table class="consumers">
+ <tr>
+ <th>&nbsp;</th>
+ <th>Enabled?</th>
+ <th>ID</th>
+ <th>Description</th>
+ </tr>
+ <c:forEach items="${unprocessedConsumers}" var="consumer" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="bgcolor" value="even" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" value="odd" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <tr>
+ <td class="${bgcolor}">
+ <input type="checkbox" name="enabledUnprocessedConsumers" theme="simple" value="${consumer.id}" <c:if test="${consumer.enabled}">checked</c:if> />
+ </td>
+ <td class="${bgcolor}">
+ <c:if test="${consumer.enabled}">
+ <strong>enabled</strong>
+ </c:if>
+ </td>
+ <td class="${bgcolor}">
+ <code>${consumer.id}</code>
+ </td>
+ <td class="${bgcolor}">${consumer.description}</td>
+ </tr>
+ </c:forEach>
+ <tr>
+ <td colspan="4">
+ <ww:submit value="Update Consumers" />
+ </td>
+ </tr>
+ </table>
+ </ww:form>
+
+ </c:otherwise>
+</c:choose>
+
+<h2>Database - Artifact Cleanup Scanning</h2>
+
+<c:choose>
+ <c:when test="${empty(cleanupConsumers)}">
+ <%-- No Consumers. Eeek! --%>
+ <strong>There are no consumers for artifact cleanup.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the consumers. --%>
+
+ <ww:form method="post" action="database!updateCleanupConsumers"
+ namespace="/admin" validate="false" theme="simple">
+ <table class="consumers">
+ <tr>
+ <th>&nbsp;</th>
+ <th>Enabled?</th>
+ <th>ID</th>
+ <th>Description</th>
+ </tr>
+ <c:forEach items="${cleanupConsumers}" var="consumer" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="bgcolor" value="even" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" value="odd" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <tr>
+ <td class="${bgcolor}">
+ <input type="checkbox" name="enabledCleanupConsumers" theme="simple" value="${consumer.id}" <c:if test="${consumer.enabled}">checked</c:if> />
+ </td>
+ <td class="${bgcolor}">
+ <c:if test="${consumer.enabled}">
+ <strong>enabled</strong>
+ </c:if>
+ </td>
+ <td class="${bgcolor}">
+ <code>${consumer.id}</code>
+ </td>
+ <td class="${bgcolor}">${consumer.description}</td>
+ </tr>
+ </c:forEach>
+ <tr>
+ <td colspan="4">
+ <ww:submit value="Update Consumers" />
+ </td>
+ </tr>
+ </table>
+ </ww:form>
+
+ </c:otherwise>
+</c:choose>
+
+
+</div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteNetworkProxy.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteNetworkProxy.jsp
new file mode 100644
index 000000000..c4feaa87a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteNetworkProxy.jsp
@@ -0,0 +1,53 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Delete Network Proxy</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Delete Network Proxy</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <h2>Delete Network Proxy</h2>
+
+ <blockquote>
+ <strong><span class="statusFailed">WARNING:</span> This operation can not be undone.</strong>
+ </blockquote>
+
+ <p>
+ Are you sure you want to delete network proxy <code>${proxyid}</code> ?
+ </p>
+
+ <ww:form method="post" action="deleteNetworkProxy!delete" namespace="/admin" validate="true">
+ <ww:hidden name="proxyid"/>
+ <ww:submit value="Delete"/>
+ </ww:form>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteProxyConnector.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteProxyConnector.jsp
new file mode 100644
index 000000000..de6937eca
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteProxyConnector.jsp
@@ -0,0 +1,54 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Delete Proxy Connector</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Delete Proxy Connector</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <h2>Delete Proxy Connector</h2>
+
+ <blockquote>
+ <strong><span class="statusFailed">WARNING:</span> This operation can not be undone.</strong>
+ </blockquote>
+
+ <p>
+ Are you sure you want to delete proxy connector <code>[ ${source} , ${target} ]</code> ?
+ </p>
+
+ <ww:form method="post" action="deleteProxyConnector!delete" namespace="/admin" validate="true">
+ <ww:hidden name="target"/>
+ <ww:hidden name="source"/>
+ <ww:submit value="Delete"/>
+ </ww:form>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRemoteRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRemoteRepository.jsp
new file mode 100644
index 000000000..183da4d23
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRemoteRepository.jsp
@@ -0,0 +1,73 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Delete Remote Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Delete Remote Repository</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <div class="warningbox">
+ <p>
+ <strong>WARNING: This operation can not be undone.</strong>
+ </p>
+ </div>
+
+ <p>
+ Are you sure you want to delete the following remote repository?
+ </p>
+
+ <div class="infobox">
+ <table class="infotable">
+ <tr>
+ <td>ID:</td>
+ <td><code>${repository.id}</code></td>
+ </tr>
+ <tr>
+ <td>Name:</td>
+ <td>${repository.name}</td>
+ </tr>
+ <tr>
+ <td>URL:</td>
+ <td><a href="${repository.url}">${repository.url}</a></td>
+ </tr>
+ </table>
+ </div>
+
+ <ww:form method="post" action="deleteRemoteRepository" namespace="/admin" validate="true" theme="simple">
+ <ww:hidden name="repoid"/>
+ <div class="buttons">
+ <ww:submit value="Confirm" method="delete"/>
+ <ww:submit value="Cancel" method="execute"/>
+ </div>
+ </ww:form>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRepository.jsp
new file mode 100644
index 000000000..7394e1690
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/deleteRepository.jsp
@@ -0,0 +1,74 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Delete Managed Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Delete Managed Repository</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <div class="warningbox">
+ <p>
+ <strong>WARNING: This operation can not be undone.</strong>
+ </p>
+ </div>
+
+ <p>
+ Are you sure you want to delete the following managed repository?
+ </p>
+
+ <div class="infobox">
+ <table class="infotable">
+ <tr>
+ <td>ID:</td>
+ <td><code>${repository.id}</code></td>
+ </tr>
+ <tr>
+ <td>Name:</td>
+ <td>${repository.name}</td>
+ </tr>
+ <tr>
+ <td>Directory:</td>
+ <td>${repository.location}</td>
+ </tr>
+ </table>
+ </div>
+
+ <ww:form method="post" action="deleteRepository" namespace="/admin" validate="true" theme="simple">
+ <ww:hidden name="repoid"/>
+ <div class="buttons">
+ <ww:submit value="Delete Configuration Only" method="deleteEntry" />
+ <ww:submit value="Delete Configuration and Contents" method="deleteContents" />
+ <ww:submit value="Cancel" method="execute"/>
+ </div>
+ </ww:form>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editAppearance.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editAppearance.jsp
new file mode 100644
index 000000000..9061a3137
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editAppearance.jsp
@@ -0,0 +1,45 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<html>
+<head>
+ <title>Configure Appearance</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Appearance</h1>
+
+<h2>Company Details</h2>
+
+<p>
+ Enter the details of the company super POM below. If it exists, the organization name, URL and logo will be read
+ from it.
+</p>
+
+<ww:actionmessage/>
+<ww:form method="post" action="saveAppearance" namespace="/admin" validate="true" theme="xhtml">
+ <ww:textfield name="companyPom.groupId" label="Group ID"/>
+ <ww:textfield name="companyPom.artifactId" label="Artifact ID"/>
+ <ww:submit value="Save"/>
+</ww:form>
+</body>
+
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editNetworkProxy.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editNetworkProxy.jsp
new file mode 100644
index 000000000..bb09274e7
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editNetworkProxy.jsp
@@ -0,0 +1,73 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<c:choose>
+ <c:when test="${mode == 'edit'}">
+ <c:set var="addedit" value="Edit" />
+ <c:set var="networkProxyName" value="${proxy.id}" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="addedit" value="Add" />
+ </c:otherwise>
+</c:choose>
+
+<html>
+<head>
+ <title>Admin: ${addedit} Network Proxy</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: ${addedit} Network Proxy</h1>
+
+<div id="contentArea">
+
+ <h2>${addedit} network proxy: ${networkProxyName}</h2>
+
+ <ww:actionerror/>
+ <ww:actionmessage/>
+
+ <ww:form method="post" action="saveNetworkProxy" namespace="/admin">
+ <ww:hidden name="mode"/>
+
+ <c:choose>
+ <c:when test="${mode == 'edit'}">
+ <ww:hidden name="proxy.id"/>
+ </c:when>
+ <c:otherwise>
+ <ww:textfield name="proxy.id" label="Identifier" size="10" required="true"/>
+ </c:otherwise>
+ </c:choose>
+
+ <%@ include file="/WEB-INF/jsp/admin/include/networkProxyForm.jspf" %>
+ <ww:submit value="Save Network Proxy"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("saveNetworkProxy_host").focus();
+ </script>
+
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editPom.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editPom.jsp
new file mode 100644
index 000000000..7887ea21e
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editPom.jsp
@@ -0,0 +1,53 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<html>
+<head>
+ <title>Edit Company POM</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Company POM</h1>
+
+<ww:actionmessage/>
+<ww:form method="post" action="saveCompanyPom" namespace="/admin" validate="true" theme="xhtml">
+ <ww:label name="companyModel.groupId" label="Group ID"/>
+ <ww:label name="companyModel.artifactId" label="Artifact ID"/>
+ <tr>
+ <td>Version</td>
+ <td>
+ <ww:property value="companyModel.version"/>
+ <i>(The version will automatically be incremented when you save this form)</i>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><h2>Organization</h2></td>
+ </tr>
+ <ww:textfield name="companyModel.organization.name" size="40" label="Name"/>
+ <ww:textfield name="companyModel.organization.url" size="70" label="URL"/>
+ <%-- TODO: how to get it to be a string, not a String[]? --%>
+ <ww:textfield name="companyModel.properties['organization.logo']" size="70" label="Logo URL"/>
+ <ww:submit value="Save"/>
+</ww:form>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editProxyConnector.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editProxyConnector.jsp
new file mode 100644
index 000000000..e13584546
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editProxyConnector.jsp
@@ -0,0 +1,46 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+ <title>Admin : Edit Proxy Connector</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin : Edit Proxy Connector</h1>
+
+<div id="contentArea">
+
+ <ww:actionerror/>
+ <ww:actionmessage/>
+
+ <ww:form name="saveProxyConnector" method="post" action="editProxyConnector!commit" namespace="/admin" validate="true">
+ <%@ include file="/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf" %>
+ <ww:submit value="Save Proxy Connector"/>
+ </ww:form>
+
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRemoteRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRemoteRepository.jsp
new file mode 100644
index 000000000..3f6686c57
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRemoteRepository.jsp
@@ -0,0 +1,50 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Edit Remote Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Edit Remote Repository</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <ww:actionmessage/>
+ <ww:form method="post" action="editRemoteRepository!commit" namespace="/admin" validate="false">
+ <ww:hidden name="repository.id"/>
+ <%@ include file="/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf" %>
+ <ww:submit value="Update Repository"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("editRemoteRepository_repository_name").focus();
+ </script>
+
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRepository.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRepository.jsp
new file mode 100644
index 000000000..a2a899e35
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/editRepository.jsp
@@ -0,0 +1,51 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Admin: Edit Managed Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Admin: Edit Managed Repository</h1>
+
+<ww:actionerror/>
+
+<div id="contentArea">
+
+ <ww:actionmessage/>
+ <ww:form method="post" action="editRepository!commit" namespace="/admin" validate="false">
+ <ww:hidden name="repository.id"/>
+ <ww:label label="ID" name="repository.id" />
+ <%@ include file="/WEB-INF/jsp/admin/include/repositoryForm.jspf" %>
+ <ww:submit value="Update Repository"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("editRepository_repository_name").focus();
+ </script>
+
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/errorMessages.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/errorMessages.jsp
new file mode 100644
index 000000000..f4793128d
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/errorMessages.jsp
@@ -0,0 +1,29 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<p>
+ <ww:if test="hasActionErrors()">
+ <b style="color: red;">Errors:</b>
+ <ww:iterator value="actionErrors">
+ <li style="color: red;">
+ <ww:property/>
+ </li>
+ </ww:iterator>
+ </ww:if>
+</p> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/networkProxyForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/networkProxyForm.jspf
new file mode 100644
index 000000000..935c4b176
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/networkProxyForm.jspf
@@ -0,0 +1,26 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<ww:textfield name="proxy.protocol" label="Protocol" size="5" required="true"/>
+<ww:textfield name="proxy.host" label="Hostname" size="50" required="true"/>
+<ww:textfield name="proxy.port" label="Port" size="5" required="true" />
+<ww:textfield name="proxy.username" label="Username" size="25" required="false" />
+<ww:password name="proxy.password" label="Password" size="25" required="false" />
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf
new file mode 100644
index 000000000..9355963e3
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf
@@ -0,0 +1,256 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<c:url var="iconDeleteUrl" value="/images/icons/delete.gif"/>
+<c:url var="iconCreateUrl" value="/images/icons/create.png"/>
+
+<%-- This hidden 'pattern' field is used by remove (white|black)list scripts --%>
+<ww:hidden name="pattern" />
+
+<ww:hidden name="connector.order" />
+
+<ww:select name="connector.proxyId" list="proxyIdOptions" label="Network Proxy" required="true"/>
+<ww:select name="connector.sourceRepoId" list="managedRepoIdList"
+ label="Managed Repository" required="true"/>
+<ww:select name="connector.targetRepoId" list="remoteRepoIdList"
+ label="Remote Repository" required="true"/>
+
+<tr>
+ <td valign="top"><label>Policies:</label>
+ </td>
+ <td>
+ <table>
+ <c:forEach items="${policyMap}" var="policy" varStatus="i">
+ <tr>
+ <td>
+ <ww:label for="policy_${policy.key}" required="true"
+ theme="simple">${policy.key}:
+ </ww:label>
+ </td>
+ <td>
+ <ww:select name="connector.policies['${policy.key}']"
+ list="policyMap['${policy.key}'].options"
+ value="connector.policies['${policy.key}']"
+ id="policy_${policy.key}"
+ theme="simple"
+ cssStyle="width: 10em"/>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </td>
+</tr>
+
+<tr class="seperator">
+ <td valign="top">
+ <label for="propertiesEntry">Properties:</label>
+ </td>
+ <td>
+ <ww:textfield name="propertyKey" size="15" id="propertiesEntry" theme="simple"
+ onkeypress="submitenter(event, 'addProperty')"/>
+ :
+ <ww:textfield name="propertyValue" size="15" id="propertiesValue" theme="simple"
+ onkeypress="submitenter(event, 'addProperty')"/>
+ <input type="button" onclick="submitForm('addProperty')" value="Add Property" />
+ </td>
+</tr>
+
+<tr>
+ <td>
+ </td>
+ <td>
+ <c:choose>
+ <c:when test="${empty(connector.properties)}">
+ <i>No properties have been set.</i>
+ </c:when>
+ <c:otherwise>
+ <table>
+ <c:forEach items="${connector.properties}" var="property" varStatus="i">
+ <tr>
+ <td>
+ <ww:label for="property_${property.key}"
+ theme="simple">${property.key}</ww:label>
+ </td>
+ <td>
+ <ww:textfield name="connector.properties['${property.key}']"
+ size="15"
+ id="property_${property.key}"
+ theme="simple"/>
+ </td>
+ <td>
+ <ww:a href="#" title="Remove [${property.key}] Property"
+ onclick="setAndSubmit('propertyKey', '${property.key}', 'removeProperty')"
+ theme="simple">
+ <img src="${iconDeleteUrl}"/></ww:a>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </c:otherwise>
+ </c:choose>
+ </td>
+</tr>
+
+<tr class="seperator">
+ <td valign="top">
+ <label for="blackListEntry">Black List:</label>
+ </td>
+ <td>
+ <ww:textfield name="blackListPattern" size="30" id="blackListEntry" theme="simple"
+ onkeypress="submitenter(event, 'addBlackListPattern')"/>
+ <input type="button" onclick="submitForm('addBlackListPattern')" value="Add Pattern" />
+ </td>
+</tr>
+
+<tr>
+ <td>
+ </td>
+ <td>
+ <c:choose>
+ <c:when test="${empty(connector.blackListPatterns)}">
+ <i>No black list patterns have been set.</i>
+ </c:when>
+ <c:otherwise>
+ <table>
+ <c:forEach items="${connector.blackListPatterns}" var="pattern" varStatus="i">
+ <tr>
+ <td>
+ <ww:hidden name="connector.blackListPatterns" value="${pattern}"/>
+ <code>"${pattern}"</code>
+ </td>
+ <td>
+ <a href="#" title="Remove [${pattern}] Pattern"
+ onclick="setAndSubmit('pattern', '${pattern}', 'removeBlackListPattern')">
+ <img src="${iconDeleteUrl}"/></a>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </c:otherwise>
+ </c:choose>
+ </td>
+</tr>
+
+<tr class="seperator">
+ <td valign="top">
+ <label for="whiteListEntry">White List:</label>
+ </td>
+ <td>
+ <ww:textfield name="whiteListPattern" size="30" id="whiteListEntry" theme="simple"
+ onkeypress="submitenter(event, 'addWhiteListPattern')"/>
+ <input type="button" onclick="submitForm('addWhiteListPattern')" value="Add Pattern" />
+ </td>
+</tr>
+<tr>
+ <td>
+ </td>
+ <td>
+ <c:choose>
+ <c:when test="${empty(connector.whiteListPatterns)}">
+ <i>No white list patterns have been set.</i>
+ </c:when>
+ <c:otherwise>
+ <table>
+ <c:forEach items="${connector.whiteListPatterns}" var="pattern" varStatus="i">
+ <tr>
+ <td>
+ <ww:hidden name="connector.whiteListPatterns" value="${pattern}"/>
+ <code>"${pattern}"</code>
+ </td>
+ <td>
+ <ww:a href="#" title="Remove [${pattern}] Pattern"
+ onclick="setAndSubmit('pattern', '${pattern}', 'removeWhiteListPattern')"
+ theme="simple">
+ <img src="${iconDeleteUrl}"/></ww:a>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+ </c:otherwise>
+ </c:choose>
+ </td>
+</tr>
+
+<script type="text/javascript">
+ <!--
+ function adjustActionMethod( action, method )
+ {
+ var idx = action.indexOf( "!" );
+ if( idx == (-1) )
+ {
+ // no "name!method.action" defined, split by ".action" instead.
+ idx = action.indexOf( ".action" );
+ }
+
+ return action.substring( 0, idx ) + "!" + method + ".action";
+ }
+
+ function setAndSubmit( id, value, method )
+ {
+ var f = document.forms['saveProxyConnector'];
+
+ f.action = adjustActionMethod( f.action, method );
+ f.elements[id].value = value;
+ f.submit();
+ }
+
+ function submitForm( method )
+ {
+ var f = document.forms['saveProxyConnector'];
+
+ var before = f.action;
+ f.action = adjustActionMethod( f.action, method );
+ f.submit();
+ }
+
+ function submitenter( e, method )
+ {
+ var keycode;
+
+
+ if ( window.event )
+ {
+ keycode = window.event.keyCode;
+ }
+ else if ( e )
+ {
+ keycode = e.which;
+ }
+ else
+ {
+ return true;
+ }
+
+ if ( keycode == 13 )
+ {
+ submitForm( method );
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ document.forms["saveProxyConnector"]["connector.proxyId"].focus();
+ //-->
+</script>
+
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf
new file mode 100644
index 000000000..b59fa8f50
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/remoteRepositoryForm.jspf
@@ -0,0 +1,28 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<ww:textfield name="repository.name" label="Name" size="50" required="true"/>
+<ww:textfield name="repository.url" label="URL" size="50" required="true"/>
+<ww:textfield name="repository.username" label="Username" size="25" required="false"/>
+<ww:password name="repository.password" label="Password" size="25" required="false"/>
+<ww:textfield name="repository.timeout" label="Timeout in seconds" size="3" required="false"/>
+<ww:select list="#@java.util.LinkedHashMap@{'default' : 'Maven 2.x Repository', 'legacy' : 'Maven 1.x Repository'}"
+ name="repository.layout" label="Type"/>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/repositoryForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/repositoryForm.jspf
new file mode 100644
index 000000000..8840a4e3c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/repositoryForm.jspf
@@ -0,0 +1,35 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<ww:textfield name="repository.name" label="Name" size="50" required="true"/>
+<ww:textfield name="repository.location" label="Directory" size="50" required="true"/>
+<ww:select list="#@java.util.LinkedHashMap@{'default' : 'Maven 2.x Repository', 'legacy' : 'Maven 1.x Repository'}"
+ name="repository.layout" label="Type"/>
+<ww:textfield name="repository.refreshCronExpression" label="Cron" size="40" required="true"/>
+<ww:textfield name="repository.daysOlder" label="Repository Purge By Days Older Than" size="5"/>
+<ww:textfield name="repository.retentionCount" label="Repository Purge By Retention Count" size="5"/>
+<ww:checkbox name="repository.releases" value="repository.releases" label="Releases Included"/>
+<ww:checkbox name="repository.snapshots" value="repository.snapshots" label="Snapshots Included"/>
+<ww:checkbox name="repository.scanned" value="repository.scanned" label="Scannable"/>
+<ww:checkbox name="repository.deleteReleasedSnapshots" value="repository.deleteReleasedSnapshots"
+ label="Delete Released Snapshots"/>
+
+
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/legacyArtifactPath.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/legacyArtifactPath.jsp
new file mode 100644
index 000000000..2380622ee
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/legacyArtifactPath.jsp
@@ -0,0 +1,113 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Administration - Legacy support</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Administration - Legacy Artifact Path Resolution</h1>
+
+<div id="contentArea">
+
+<ww:actionerror/>
+<ww:actionmessage/>
+
+<div class="admin">
+<div class="controls">
+ <redback:ifAuthorized permission="archiva-manage-configuration">
+ <ww:url id="addLegacyArtifactPathUrl" action="addLegacyArtifactPath"/>
+ <ww:a href="%{addLegacyArtifactPathUrl}">
+ <img src="<c:url value="/images/icons/create.png" />" alt="" width="16" height="16"/>
+ Add
+ </ww:a>
+ </redback:ifAuthorized>
+</div>
+<h2>Path Mappings</h2>
+
+<c:choose>
+<c:when test="${empty(legacyArtifactPaths)}">
+ <%-- No paths. --%>
+ <p><strong>There are no legacy artifact paths configured yet.</strong></p>
+</c:when>
+<c:otherwise>
+ <%-- Display the paths. --%>
+
+<c:forEach items="${legacyArtifactPaths}" var="legacyArtifactPath" varStatus="i">
+<c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="rowColor" value="dark" scope="page"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="rowColor" value="lite" scope="page"/>
+ </c:otherwise>
+</c:choose>
+
+<div class="legacyArtifactPath ${rowColor}">
+
+<div class="controls">
+ <%-- TODO: make some icons --%>
+ <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
+ <ww:url id="deleteLegacyArtifactPath" action="deleteLegacyArtifactPath">
+ <ww:param name="path" value="%{'${legacyArtifactPath.path}'}"/>
+ </ww:url>
+ <ww:a href="%{deleteLegacyArtifactPath}">
+ <img src="<c:url value="/images/icons/delete.gif" />" alt="" width="16" height="16"/>
+ Delete
+ </ww:a>
+ </redback:ifAnyAuthorized>
+</div>
+
+<table class="infoTable">
+<tr>
+ <th>Path</th>
+ <td>
+ <code>${legacyArtifactPath.path}</code>
+ </td>
+</tr>
+<tr>
+ <th>Artifact</th>
+ <td>
+ <code>${legacyArtifactPath.artifact}</code>
+ </td>
+</tr>
+</table>
+
+</div>
+</c:forEach>
+
+</c:otherwise>
+</c:choose>
+
+
+
+</div>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/networkProxies.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/networkProxies.jsp
new file mode 100644
index 000000000..a81deecf5
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/networkProxies.jsp
@@ -0,0 +1,128 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva"%>
+
+<html>
+<head>
+<title>Administration - Network Proxies</title>
+<ww:head />
+</head>
+
+<body>
+
+<h1>Administration - Network Proxies</h1>
+
+<div id="contentArea">
+
+<ww:actionerror /> <ww:actionmessage />
+
+<div class="admin">
+<div class="controls">
+<redback:ifAuthorized
+ permission="archiva-manage-configuration">
+ <ww:url id="addNetworkProxyUrl" action="addNetworkProxy" />
+ <ww:a href="%{addNetworkProxyUrl}">
+ <img src="<c:url value="/images/icons/create.png" />" />
+ Add Network Proxy</ww:a>
+</redback:ifAuthorized></div>
+<h2>Network Proxies</h2>
+
+<c:choose>
+ <c:when test="${empty(networkProxies)}">
+ <%-- No Local Repositories. --%>
+ <strong>There are no network proxies configured yet.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the repositories. --%>
+
+ <c:forEach items="${networkProxies}" var="proxy" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="rowColor" value="dark" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="rowColor" value="lite" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <div class="netproxy ${rowColor}">
+
+ <div class="controls">
+ <redback:ifAnyAuthorized
+ permissions="archiva-manage-configuration">
+ <ww:url id="editNetworkProxyUrl" action="editNetworkProxy">
+ <ww:param name="proxyid" value="%{'${proxy.id}'}" />
+ </ww:url>
+ <ww:url id="deleteNetworkProxyUrl" action="deleteNetworkProxy" method="confirm">
+ <ww:param name="proxyid" value="%{'${proxy.id}'}" />
+ </ww:url>
+ <ww:a href="%{editNetworkProxyUrl}">
+ <img src="<c:url value="/images/icons/edit.png" />" />
+ Edit Network Proxy</ww:a>
+ <ww:a href="%{deleteNetworkProxyUrl}">
+ <img src="<c:url value="/images/icons/delete.gif" />" />
+ Delete Network Proxy</ww:a>
+ </redback:ifAnyAuthorized></div>
+
+ <table class="infoTable">
+ <tr>
+ <th>Identifier</th>
+ <td><code>${proxy.id}</code></td>
+ </tr>
+ <tr>
+ <th>Protocol</th>
+ <td>${proxy.protocol}</td>
+ </tr>
+ <tr>
+ <th>Host</th>
+ <td>${proxy.host}</td>
+ </tr>
+ <tr>
+ <th>Port</th>
+ <td>${proxy.port}</td>
+ </tr>
+ <c:if test="${not empty(proxy.username)}">
+ <tr>
+ <th>Username</th>
+ <td>${proxy.username}</td>
+ </tr>
+ <c:if test="${not empty(proxy.password)}">
+ <tr>
+ <th>Password</th>
+ <td>&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;</td>
+ </tr>
+ </c:if>
+ </c:if>
+ </table>
+
+ </div>
+ </c:forEach>
+
+ </c:otherwise>
+</c:choose>
+</div>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/proxyConnectors.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/proxyConnectors.jsp
new file mode 100644
index 000000000..488d77875
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/proxyConnectors.jsp
@@ -0,0 +1,215 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Administration - Proxy Connectors</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Administration - Proxy Connectors</h1>
+
+<c:url var="iconDeleteUrl" value="/images/icons/delete.gif"/>
+<c:url var="iconEditUrl" value="/images/icons/edit.png"/>
+<c:url var="iconCreateUrl" value="/images/icons/create.png"/>
+<c:url var="iconUpUrl" value="/images/icons/up.gif"/>
+<c:url var="iconDownUrl" value="/images/icons/down.gif"/>
+
+<div id="contentArea">
+
+<ww:actionerror/>
+<ww:actionmessage/>
+
+<div style="float:right">
+ <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
+ <ww:url id="addProxyConnectorUrl" action="addProxyConnector"/>
+ <ww:a href="%{addProxyConnectorUrl}" cssClass="create">
+ <img src="<c:url value="/images/icons/create.png" />"/>
+ Add
+ </ww:a>
+ </redback:ifAnyAuthorized>
+</div>
+
+<h2>Repository Proxy Connectors</h2>
+
+<c:choose>
+<c:when test="${empty(proxyConnectorMap)}">
+ <strong>No Repository Proxy Connectors Defined.</strong>
+</c:when>
+<c:otherwise>
+
+<div class="admin">
+
+<c:forEach items="${proxyConnectorMap}" var="repository" varStatus="i">
+
+<div class="proxyConfig">
+ <div class="managedRepo">
+ <img src="<c:url value="/images/archiva-splat-32.gif"/>"/>
+ <p class="id">${repository.key}</p>
+ <p class="name">${repoMap[repository.key].name}</p>
+ </div>
+
+ <c:forEach items="${repository.value}" var="connector" varStatus="pc">
+
+ <c:choose>
+ <c:when test='${(pc.index)%2 eq 0}'>
+ <c:set var="rowColor" value="dark" scope="page"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="rowColor" value="lite" scope="page"/>
+ </c:otherwise>
+ </c:choose>
+
+ <div class="connector ${rowColor}">
+ <div class="controls">
+ <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
+ <ww:url id="sortDownProxyConnectorUrl" action="sortDownProxyConnector">
+ <ww:param name="target" value="%{'${connector.targetRepoId}'}"/>
+ <ww:param name="source" value="%{'${connector.sourceRepoId}'}"/>
+ </ww:url>
+ <ww:url id="sortUpProxyConnectorUrl" action="sortUpProxyConnector">
+ <ww:param name="target" value="%{'${connector.targetRepoId}'}"/>
+ <ww:param name="source" value="%{'${connector.sourceRepoId}'}"/>
+ </ww:url>
+ <ww:url id="editProxyConnectorUrl" action="editProxyConnector">
+ <ww:param name="target" value="%{'${connector.targetRepoId}'}"/>
+ <ww:param name="source" value="%{'${connector.sourceRepoId}'}"/>
+ </ww:url>
+ <ww:url id="deleteProxyConnectorUrl" action="deleteProxyConnector" method="confirmDelete">
+ <ww:param name="source" value="%{'${connector.sourceRepoId}'}"/>
+ <ww:param name="target" value="%{'${connector.targetRepoId}'}"/>
+ </ww:url>
+ <ww:a href="%{sortUpProxyConnectorUrl}" cssClass="up" title="Move Proxy Connector Up">
+ <img src="${iconUpUrl}"/>
+ </ww:a>
+ <ww:a href="%{sortDownProxyConnectorUrl}" cssClass="down" title="Move Proxy Connector Down">
+ <img src="${iconDownUrl}"/>
+ </ww:a>
+ <ww:a href="%{editProxyConnectorUrl}" cssClass="edit" title="Edit Proxy Connector">
+ <img src="${iconEditUrl}"/>
+ </ww:a>
+ <ww:a href="%{deleteProxyConnectorUrl}" cssClass="delete" title="Delete Proxy Connector">
+ <img src="${iconDeleteUrl}"/>
+ </ww:a>
+ </redback:ifAnyAuthorized>
+ </div>
+
+ <h4>Proxy Connector</h4>
+
+ <div class="remoteRepo">
+ <img src="<c:url value="/images/archiva-world.png"/>"/>
+ <p class="id">${connector.targetRepoId}</p>
+ <p class="name">${repoMap[connector.targetRepoId].name}</p>
+ <p class="url"><a href="${repoMap[connector.targetRepoId].url}">${repoMap[connector.targetRepoId].url}</a></p>
+ </div>
+
+ <a class="expand" href="#" onclick="Effect.toggle('proxySettings_${connector.sourceRepoId}_${connector.targetRepoId}','slide'); return false;">Expand</a>
+ <table class="settings" style="display: none;" id="proxySettings_${connector.sourceRepoId}_${connector.targetRepoId}">
+ <tr>
+ <th nowrap="nowrap">Network Proxy:</th>
+ <td>
+ <c:choose>
+ <c:when test="${empty(connector.proxyId)}">
+ <span class="directConnection">(Direct Connection)</span>
+ </c:when>
+ <c:otherwise>
+ <ww:url id="editProxyIdUrl" action="editNetworkProxy">
+ <ww:param name="proxyid" value="%{'${connector.proxyId}'}"/>
+ </ww:url>
+ <ww:a href="%{editProxyIdUrl}" cssClass="edit" title="Edit Network Proxy">
+ ${connector.proxyId}
+ <img src="${iconEditUrl}"/>
+ </ww:a>
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ <tr>
+ <th>Policies:</th>
+ <td nowrap="nowrap">
+ <table class="policies">
+ <c:forEach items="${connector.policies}" var="policies">
+ <tr>
+ <th>${policies.key}</th>
+ <td>${policies.value}</td>
+ </tr>
+ </c:forEach>
+ </table>
+ </td>
+ </tr>
+
+ <c:if test="${not(empty(connector.whiteListPatterns))}">
+ <tr>
+ <th nowrap="nowrap">White List:</th>
+ <td nowrap="nowrap">
+ <c:forEach items="${connector.whiteListPatterns}" var="pattern">
+ <p><code>"${pattern}"</code></p>
+ </c:forEach>
+ </td>
+ </tr>
+ </c:if>
+
+ <c:if test="${not(empty(connector.blackListPatterns))}">
+ <tr>
+ <th nowrap="nowrap">Black List:</th>
+ <td>
+ <c:forEach items="${connector.blackListPatterns}" var="pattern">
+ <p><code>"${pattern}"</code></p>
+ </c:forEach>
+ </td>
+ </tr>
+ </c:if>
+
+ <c:if test="${not(empty(connector.properties))}">
+ <tr>
+ <th>Properties:</th>
+ <td>
+ <table class="props">
+ <c:forEach items="${connector.properties}" var="prop">
+ <tr>
+ <th>${prop.key}</th>
+ <td>${prop.value}</td>
+ </tr>
+ </c:forEach>
+ </table>
+ </td>
+ </tr>
+ </c:if>
+ </table>
+ </div> <%-- connector --%>
+
+</c:forEach>
+</div> <%-- proxyConfig --%>
+</c:forEach>
+</div> <%-- admin --%>
+</c:otherwise>
+</c:choose>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositories.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositories.jsp
new file mode 100644
index 000000000..0ba26bce2
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositories.jsp
@@ -0,0 +1,327 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Administration - Repositories</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Administration - Repositories</h1>
+
+<div id="contentArea">
+
+<ww:actionerror/>
+<ww:actionmessage/>
+
+<div class="admin">
+<div class="controls">
+ <redback:ifAuthorized permission="archiva-manage-configuration">
+ <ww:url id="addRepositoryUrl" action="addRepository"/>
+ <ww:a href="%{addRepositoryUrl}">
+ <img src="<c:url value="/images/icons/create.png" />" alt="" width="16" height="16"/>
+ Add
+ </ww:a>
+ </redback:ifAuthorized>
+</div>
+<h2>Managed Repositories</h2>
+
+<c:choose>
+<c:when test="${empty(managedRepositories)}">
+ <%-- No Managed Repositories. --%>
+ <strong>There are no managed repositories configured yet.</strong>
+</c:when>
+<c:otherwise>
+<%-- Display the repositories. --%>
+
+<c:forEach items="${managedRepositories}" var="repository" varStatus="i">
+<c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="rowColor" value="dark" scope="page"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="rowColor" value="lite" scope="page"/>
+ </c:otherwise>
+</c:choose>
+
+<div class="repository ${rowColor}">
+
+<div class="controls">
+ <%-- TODO: make some icons --%>
+ <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
+ <ww:url id="editRepositoryUrl" action="editRepository">
+ <ww:param name="repoid" value="%{'${repository.id}'}"/>
+ </ww:url>
+ <ww:url id="deleteRepositoryUrl" action="confirmDeleteRepository">
+ <ww:param name="repoid" value="%{'${repository.id}'}"/>
+ </ww:url>
+ <ww:a href="%{editRepositoryUrl}">
+ <img src="<c:url value="/images/icons/edit.png" />" alt="" width="16" height="16"/>
+ Edit
+ </ww:a>
+ <ww:a href="%{deleteRepositoryUrl}">
+ <img src="<c:url value="/images/icons/delete.gif" />" alt="" width="16" height="16"/>
+ Delete
+ </ww:a>
+ </redback:ifAnyAuthorized>
+</div>
+
+<div style="float: left">
+ <img src="<c:url value="/images/archiva-splat-32.gif"/>" alt="" width="32" height="32"/>
+</div>
+
+<h3 class="repository">${repository.name}</h3>
+
+<table class="infoTable">
+<tr>
+ <th>Identifier</th>
+ <td>
+ <code>${repository.id}</code>
+ </td>
+</tr>
+<tr>
+ <th>Name</th>
+ <td>
+ <code>${repository.name}</code>
+ </td>
+</tr>
+<tr>
+ <th>Directory</th>
+ <td>${repository.location}</td>
+</tr>
+<tr>
+ <th>WebDAV URL</th>
+ <td><a href="${baseUrl}/${repository.id}/">${baseUrl}/${repository.id}/</a></td>
+</tr>
+<tr>
+ <th>Type</th>
+ <%-- TODO: can probably just use layout appended to a key prefix in i18n to simplify this --%>
+ <td>
+ <c:choose>
+ <c:when test="${repository.layout == 'default'}">
+ Maven 2.x Repository
+ </c:when>
+ <c:otherwise>
+ Maven 1.x Repository
+ </c:otherwise>
+ </c:choose>
+ </td>
+</tr>
+<tr>
+ <th>Releases Included</th>
+ <td class="${repository.releases ? 'donemark' : 'errormark'} booleanIcon"> </td>
+</tr>
+<tr>
+ <th>Snapshots Included</th>
+ <td class="${repository.snapshots ? 'donemark' : 'errormark'} booleanIcon"> </td>
+</tr>
+<c:if test="${repository.snapshots}">
+ <tr>
+ <th>Delete Released Snapshots</th>
+ <td class="${repository.deleteReleasedSnapshots ? 'donemark' : 'errormark'} booleanIcon"> </td>
+ </tr>
+ <tr>
+ <th>Repository Purge By Days Older Than</th>
+ <td>${repository.daysOlder}</td>
+ </tr>
+ <tr>
+ <th>Repository Purge By Retention Count</th>
+ <td>${repository.retentionCount}</td>
+ </tr>
+</c:if>
+<tr>
+ <th>Scanned</th>
+ <td class="${repository.scanned ? 'donemark' : 'errormark'} booleanIcon"> </td>
+</tr>
+<c:if test="${repository.scanned}">
+ <tr>
+ <th>Scanning Cron</th>
+ <td>${repository.refreshCronExpression}</td>
+ </tr>
+ <tr>
+ <th>
+ Actions
+ </th>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <redback:ifAuthorized permission="archiva-run-indexer">
+ <ww:form action="indexRepository" theme="simple">
+ <ww:hidden name="repoid" value="%{'${repository.id}'}"/>
+ <ww:submit value="Scan Repository Now"/>
+ </ww:form>
+ </redback:ifAuthorized>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>Stats</th>
+ <td>
+ <c:set var="stats" value="${repositoryStatistics[repository.id]}"/>
+ <c:choose>
+ <c:when test="${empty(stats)}">
+ No Statistics Available.
+ </c:when>
+ <c:otherwise>
+ <table>
+ <tr>
+ <th>Last Scanned</th>
+ <td>${stats.whenGathered}</td>
+ </tr>
+ <tr>
+ <th>Duration</th>
+ <td>${stats.duration} ms</td>
+ </tr>
+ <tr>
+ <th>Total File Count</th>
+ <td>${stats.totalFileCount}
+ </tr>
+ <tr>
+ <th>New Files Found</th>
+ <td>${stats.newFileCount}
+ </tr>
+ </table>
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+</c:if>
+<tr>
+ <th>POM Snippet</th>
+ <td>
+ <archiva:copy-paste-snippet object="${repository}" wrapper="toggle" />
+ </td>
+</tr>
+</table>
+
+</div>
+</c:forEach>
+
+</c:otherwise>
+</c:choose>
+
+<div class="controls">
+ <redback:ifAuthorized permission="archiva-manage-configuration">
+ <ww:url id="addRepositoryUrl" action="addRemoteRepository"/>
+ <ww:a href="%{addRepositoryUrl}">
+ <img src="<c:url value="/images/icons/create.png" />" alt="" width="16" height="16"/>
+ Add
+ </ww:a>
+ </redback:ifAuthorized>
+</div>
+<h2>Remote Repositories</h2>
+
+<c:choose>
+ <c:when test="${empty(remoteRepositories)}">
+ <%-- No Remote Repositories. --%>
+ <strong>There are no remote repositories configured yet.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the repositories. --%>
+ <c:forEach items="${remoteRepositories}" var="repository" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="rowColor" value="dark" scope="page"/>
+ </c:when>
+ <c:otherwise>
+ <c:set var="rowColor" value="lite" scope="page"/>
+ </c:otherwise>
+ </c:choose>
+
+ <div class="repository ${rowColor}">
+
+ <div class="controls">
+ <redback:ifAnyAuthorized permissions="archiva-manage-configuration">
+ <ww:url id="editRepositoryUrl" action="editRemoteRepository">
+ <ww:param name="repoid" value="%{'${repository.id}'}"/>
+ </ww:url>
+ <ww:a href="%{editRepositoryUrl}">
+ <img src="<c:url value="/images/icons/edit.png" />" alt="" width="16" height="16"/>
+ Edit
+ </ww:a>
+ <ww:url id="deleteRepositoryUrl" action="confirmDeleteRemoteRepository">
+ <ww:param name="repoid" value="%{'${repository.id}'}"/>
+ </ww:url>
+ <ww:a href="%{deleteRepositoryUrl}">
+ <img src="<c:url value="/images/icons/delete.gif" />" alt="" width="16" height="16"/>
+ Delete
+ </ww:a>
+ </redback:ifAnyAuthorized>
+ </div>
+
+ <div style="float: left">
+ <img src="<c:url value="/images/archiva-world.png"/>" alt="" width="32" height="32"/>
+ </div>
+
+ <h3 class="repository">${repository.name}</h3>
+
+ <table class="infoTable">
+ <tr>
+ <th>Identifier</th>
+ <td>
+ <code>${repository.id}</code>
+ </td>
+ </tr>
+ <tr>
+ <th>Name</th>
+ <td>
+ <code>${repository.name}</code>
+ </td>
+ </tr>
+ <tr>
+ <th>URL</th>
+ <td>${repository.url}</td>
+ </tr>
+ <tr>
+ <th>Type</th>
+ <%-- TODO: can probably just use layout appended to a key prefix in i18n to simplify this --%>
+ <td>
+ <c:choose>
+ <c:when test="${repository.layout == 'default'}">
+ Maven 2.x Repository
+ </c:when>
+ <c:otherwise>
+ Maven 1.x Repository
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ </table>
+
+ </div>
+ </c:forEach>
+ </c:otherwise>
+</c:choose>
+
+</div>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositoryScanning.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositoryScanning.jsp
new file mode 100644
index 000000000..b6bfeffec
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/repositoryScanning.jsp
@@ -0,0 +1,258 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva"%>
+
+<html>
+<head>
+<title>Administration - Repository Scanning</title>
+<ww:head />
+</head>
+
+<body>
+
+<h1>Administration - Repository Scanning</h1>
+
+<div id="contentArea">
+
+<ww:actionerror />
+<ww:actionmessage />
+
+<c:url var="iconDeleteUrl" value="/images/icons/delete.gif" />
+<c:url var="iconCreateUrl" value="/images/icons/create.png" />
+<ww:url id="removeFiletypePatternUrl" action="repositoryScanning" method="removeFiletypePattern" />
+<ww:url id="addFiletypePatternUrl" action="repositoryScanning" method="addFiletypePattern" />
+
+<script type="text/javascript">
+<!--
+ function removeFiletypePattern(filetypeId, pattern)
+ {
+ var f = document.getElementById('filetypeForm');
+
+ f.action = "${removeFiletypePatternUrl}";
+ f['pattern'].value = pattern;
+ f['fileTypeId'].value = filetypeId;
+ f.submit();
+ }
+
+ function addFiletypePattern(filetypeId, newPatternId)
+ {
+ var f = document.forms['filetypeForm'];
+
+ f.action = "${addFiletypePatternUrl}";
+ f.elements['pattern'].value = document.getElementById(newPatternId).value;
+ f.elements['fileTypeId'].value = filetypeId;
+ f.submit();
+ }
+//-->
+</script>
+
+<div class="admin">
+<h2>Repository Scanning - File Types</h2>
+
+<c:choose>
+ <c:when test="${empty(fileTypeMap)}">
+ <%-- No File Types. Eeek! --%>
+ <strong>There are no file types configured.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the filetypes. --%>
+
+ <ww:form method="post" action="repositoryScanning"
+ namespace="/admin" validate="false"
+ id="filetypeForm" theme="simple">
+ <input type="hidden" name="pattern" />
+ <input type="hidden" name="fileTypeId" />
+ </ww:form>
+
+ <ww:url id="addFiletypePatternUrl" action="repositoryScanning" method="addFiletypePattern" />
+
+ <c:forEach items="${fileTypeIds}" var="filetypeId" varStatus="j">
+
+ <div class="filetype">
+
+ <div class="controls"><%-- Does this even make sense for file types? --%></div>
+
+ <h3 class="filetype">${filetypeId}</h3>
+
+ <table>
+ <c:forEach items="${fileTypeMap[filetypeId].patterns}" var="pattern" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="bgcolor" value="even" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" value="odd" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <c:set var="escapedPattern" value="${fn:escapeXml(pattern)}" scope="page" />
+
+ <tr>
+ <td class="pattern ${bgcolor}">
+ <code>${escapedPattern}</code>
+ </td>
+ <td class="controls ${bgcolor}">
+ <ww:a href="#" title="Remove [${escapedPattern}] Pattern from [${filetypeId}]"
+ onclick="removeFiletypePattern( '${filetypeId}', '${escapedPattern}' )"
+ theme="simple">
+ <img src="${iconDeleteUrl}" />
+ </ww:a>
+ </td>
+ </tr>
+ </c:forEach>
+ <tr>
+ <td>
+ <ww:textfield size="40"
+ id="newpattern_${j.index}"
+ theme="simple" />
+ </td>
+ <td>
+ <ww:a href="#"
+ title="Add Pattern to [${filetypeId}]"
+ onclick="addFiletypePattern( '${filetypeId}', 'newpattern_${j.index}' )"
+ theme="simple">
+ <img src="${iconCreateUrl}" />
+ </ww:a>
+ </td>
+ </tr>
+ </table>
+
+ </div>
+ </c:forEach>
+
+ </c:otherwise>
+</c:choose>
+
+<h2>Repository Scanning - Consumers of Known Content</h2>
+
+<c:choose>
+ <c:when test="${empty(knownContentConsumers)}">
+ <%-- No Good Consumers. Eeek! --%>
+ <strong>There are no consumers of known content available.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the consumers. --%>
+
+ <ww:form method="post" action="repositoryScanning!updateKnownConsumers"
+ namespace="/admin" validate="false" theme="simple">
+ <table class="consumers">
+ <tr>
+ <th>&nbsp;</th>
+ <th>Enabled?</th>
+ <th>ID</th>
+ <th>Description</th>
+ </tr>
+ <c:forEach items="${knownContentConsumers}" var="consumer" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="bgcolor" value="even" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" value="odd" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <tr>
+ <td class="${bgcolor}">
+ <input type="checkbox" name="enabledKnownContentConsumers" theme="simple" value="${consumer.id}" <c:if test="${consumer.enabled}">checked</c:if> />
+ </td>
+ <td class="${bgcolor}">
+ <c:if test="${consumer.enabled}">
+ <strong>enabled</strong>
+ </c:if>
+ </td>
+ <td class="${bgcolor}">
+ <code>${consumer.id}</code>
+ </td>
+ <td class="${bgcolor}">${consumer.description}</td>
+ </tr>
+ </c:forEach>
+ <tr>
+ <td colspan="4">
+ <ww:submit value="Update Consumers" />
+ </td>
+ </tr>
+ </table>
+ </ww:form>
+
+ </c:otherwise>
+</c:choose>
+
+
+<h2>Repository Scanning - Consumers of Invalid Content</h2>
+
+<c:choose>
+ <c:when test="${empty(invalidContentConsumers)}">
+ <%-- No Consumers. Eeek! --%>
+ <strong>There are no consumers of invalid content available.</strong>
+ </c:when>
+ <c:otherwise>
+ <%-- Display the consumers. --%>
+
+ <ww:form method="post" action="repositoryScanning!updateInvalidConsumers"
+ namespace="/admin" validate="false" theme="simple">
+ <table class="consumers">
+ <tr>
+ <th>&nbsp;</th>
+ <th>Enabled?</th>
+ <th>ID</th>
+ <th>Description</th>
+ </tr>
+ <c:forEach items="${invalidContentConsumers}" var="consumer" varStatus="i">
+ <c:choose>
+ <c:when test='${(i.index)%2 eq 0}'>
+ <c:set var="bgcolor" value="even" scope="page" />
+ </c:when>
+ <c:otherwise>
+ <c:set var="bgcolor" value="odd" scope="page" />
+ </c:otherwise>
+ </c:choose>
+
+ <tr>
+ <td class="${bgcolor}">
+ <input type="checkbox" name="enabledInvalidContentConsumers" theme="simple" value="${consumer.id}" <c:if test="${consumer.enabled}">checked</c:if> />
+ </td>
+ <td class="${bgcolor}">
+ <c:if test="${consumer.enabled}">
+ <strong>enabled</strong>
+ </c:if>
+ </td>
+ <td class="${bgcolor}">
+ <code>${consumer.id}</code>
+ </td>
+ <td class="${bgcolor}">${consumer.description}</td>
+ </tr>
+ </c:forEach>
+ <tr>
+ <td colspan="4">
+ <ww:submit value="Update Consumers" />
+ </td>
+ </tr>
+ </table>
+ </ww:form>
+
+ </c:otherwise>
+</c:choose></div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/alert.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/alert.jsp
new file mode 100644
index 000000000..897c82a4c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/alert.jsp
@@ -0,0 +1,45 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+ <title>Security Alert Page</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<div id="contentArea">
+ <div id="searchBox">
+ <div id="results">
+ You are not authorized for this activity.
+ </div>
+ </div>
+</div>
+
+<div class="clear">
+ <hr/>
+</div>
+
+</body>
+
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/artifact/dependencyTree.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/artifact/dependencyTree.jsp
new file mode 100644
index 000000000..da2758350
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/artifact/dependencyTree.jsp
@@ -0,0 +1,28 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="page" uri="http://www.opensymphony.com/sitemesh/page" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<archiva:dependency-tree groupId="${groupId}" artifactId="${artifactId}" version="${version}"
+ modelVersion="${model.version}">
+ <my:showArtifactLink groupId="${node.groupId}" artifactId="${node.artifactId}"
+ version="${node.version}"/>
+</archiva:dependency-tree>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browse.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browse.jsp
new file mode 100644
index 000000000..a41557403
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browse.jsp
@@ -0,0 +1,99 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+
+<html>
+<head>
+ <title>Browse Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Browse Repository</h1>
+
+<div id="contentArea">
+ <c:if test="${not empty results.selectedGroupId}">
+ <p>
+ <archiva:groupIdLink var="${results.selectedGroupId}" includeTop="true" />
+ <c:if test="${not empty results.selectedArtifactId}">
+ <strong>${artifactId}</strong>
+ </c:if>
+ </p>
+ </c:if>
+
+ <c:if test="${not empty results.groupIds}">
+ <div id="nameColumn">
+ <h2>Groups</h2>
+ <ul>
+ <c:forEach items="${results.groupIds}" var="groupId">
+ <c:set var="url">
+ <ww:url action="browseGroup" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${groupId}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+ </c:if>
+
+ <c:if test="${not empty results.artifacts}">
+ <div id="nameColumn">
+ <h2>Artifacts</h2>
+ <ul>
+ <c:forEach items="${results.artifacts}" var="artifactId">
+ <c:set var="url">
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${results.selectedGroupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${artifactId}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+ </c:if>
+
+ <c:if test="${not empty results.versions}">
+ <div id="nameColumn">
+ <h2>Versions</h2>
+ <ul>
+ <c:forEach items="${results.versions}" var="version">
+ <c:set var="url">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${results.selectedGroupId}'}"/>
+ <ww:param name="artifactId" value="%{'${results.selectedArtifactId}'}"/>
+ <ww:param name="version" value="%{'${version}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${version}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+ </c:if>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseArtifact.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseArtifact.jsp
new file mode 100644
index 000000000..3dde3fca8
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseArtifact.jsp
@@ -0,0 +1,59 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Browse Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Browse Repository</h1>
+
+<div id="contentArea">
+ <div id="nameColumn">
+ <p>
+ <archiva:groupIdLink var="${groupId}" includeTop="true" />
+ <strong>${artifactId}</strong>
+ </p>
+
+ <h2>Versions</h2>
+ <ul>
+ <ww:set name="versions" value="versions"/>
+ <c:forEach items="${versions}" var="version">
+ <c:set var="url">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ <ww:param name="version" value="%{'${version}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${version}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseGroup.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseGroup.jsp
new file mode 100644
index 000000000..d9de0fefd
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/browseGroup.jsp
@@ -0,0 +1,91 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Browse Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Browse Repository</h1>
+
+<div id="contentArea">
+ <p>
+ <archiva:groupIdLink var="${results.selectedGroupId}" includeTop="true" />
+ </p>
+
+ <div id="nameColumn">
+ <h2>Groups</h2>
+ <ul>
+ <c:forEach items="${results.groupIds}" var="groupId">
+ <c:set var="url">
+ <ww:url action="browseGroup" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${groupId}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+
+ <c:if test="${not empty results.versions}">
+ <div id="nameColumn">
+ <h2>Versions</h2>
+ <ul>
+ <c:forEach items="${results.versions}" var="version">
+ <c:set var="url">
+ <ww:url action="browseVersion" namespace="/">
+ <ww:param name="groupId" value="%{'${results.selectedGroupId}'}"/>
+ <ww:param name="version" value="%{'${version}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${version}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+ </c:if>
+
+ <c:if test="${not empty results.artifacts}">
+ <div id="nameColumn">
+ <h2>Artifacts</h2>
+ <ul>
+ <c:forEach items="${results.artifacts}" var="artifactId">
+ <c:set var="url">
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ </ww:url>
+ </c:set>
+ <li><a href="${url}">${artifactId}/</a></li>
+ </c:forEach>
+ </ul>
+ </div>
+ </c:if>
+
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/components/companyLogo.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/components/companyLogo.jsp
new file mode 100644
index 000000000..1a1815a3f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/components/companyLogo.jsp
@@ -0,0 +1,35 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib uri="/webwork" prefix="ww" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<ww:set name="companyLogo" value="companyLogo"/>
+<c:if test="${!empty(companyLogo)}">
+ <ww:set name="companyUrl" value="companyUrl"/>
+ <c:choose>
+ <c:when test="${!empty(companyUrl)}">
+ <a href="${companyUrl}">
+ <img src="${companyLogo}" title="${companyName}" border="0" alt=""/>
+ </a>
+ </c:when>
+ <c:otherwise>
+ <img src="${companyLogo}" title="${companyName}" border="0" alt=""/>
+ </c:otherwise>
+ </c:choose>
+</c:if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/artifactDecorator.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/artifactDecorator.jsp
new file mode 100644
index 000000000..29515ec14
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/artifactDecorator.jsp
@@ -0,0 +1,149 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
+<%@ taglib prefix="page" uri="http://www.opensymphony.com/sitemesh/page" %>
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<page:applyDecorator name="default">
+
+<html>
+<head>
+ <title>Browse Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<ww:set name="model" value="model"/>
+<c:choose>
+ <c:when test="${model.packaging == 'maven-plugin'}">
+ <c:url var="imageUrl" value="/images/mavenplugin.gif"/>
+ <c:set var="packageName">Maven Plugin</c:set>
+ </c:when>
+ <c:when test="${model.packaging == 'pom'}">
+ <c:url var="imageUrl" value="/images/pom.gif"/>
+ <c:set var="packageName">POM</c:set>
+ </c:when>
+ <%-- These types aren't usually set in the POM yet, so we fudge them for the well known ones --%>
+ <c:when test="${model.packaging == 'maven-archetype' or model.groupId == 'org.apache.maven.archetypes'}">
+ <c:url var="imageUrl" value="/images/archetype.gif"/>
+ <c:set var="packageName">Maven Archetype</c:set>
+ </c:when>
+ <c:when test="${model.packaging == 'maven-skin' or model.groupId == 'org.apache.maven.skins'}">
+ <c:url var="imageUrl" value="/images/skin.gif"/>
+ <c:set var="packageName">Maven Skin</c:set>
+ </c:when>
+ <%-- Must be last so that the above get picked up if possible --%>
+ <c:when test="${model.packaging == 'jar'}">
+ <c:url var="imageUrl" value="/images/jar.gif"/>
+ <c:set var="packageName">JAR</c:set>
+ </c:when>
+ <c:otherwise>
+ <c:url var="imageUrl" value="/images/other.gif"/>
+ <c:set var="packageName"></c:set>
+ </c:otherwise>
+</c:choose>
+<img src="${imageUrl}" width="66" height="66" alt="${packageName}" title="${packageName}" style="float: left"/>
+
+<h1>
+ <c:choose>
+ <c:when test="${empty(model.name)}">
+ ${model.artifactId}
+ </c:when>
+ <c:otherwise>
+ ${model.name}
+ </c:otherwise>
+ </c:choose>
+</h1>
+
+<div id="contentArea">
+ <div id="tabs">
+ <span>
+ <c:set var="url">
+ <ww:url action="showArtifact">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Info</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependencies">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Dependencies</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependencyTree">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Dependency Tree</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependees">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Used By</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactMailingLists">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Mailing Lists</my:currentWWUrl>
+ <%-- POSTPONED to 1.0-alpha-2
+ <redback:ifAnyAuthorized permissions="archiva-access-reports">
+ <c:set var="url">
+ <ww:url action="showArtifactReports">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Reports</my:currentWWUrl>
+ </redback:ifAnyAuthorized>
+ --%>
+
+ </span>
+ </div>
+
+<div class="sidebar3">
+ <archiva:downloadArtifact groupId="${groupId}" artifactId="${artifactId}" version="${model.version}" />
+</div>
+
+ <decorator:body />
+</div>
+
+</body>
+</html>
+
+</page:applyDecorator>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp
new file mode 100644
index 000000000..679645c80
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/decorators/default.jsp
@@ -0,0 +1,198 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
+<%@ taglib uri="/webwork" prefix="ww" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+<%@ page import="org.apache.maven.archiva.web.startup.ArchivaVersion" %>
+<%@ page import="java.util.Calendar" %>
+
+<html>
+<head>
+ <title>Apache Archiva \
+ <decorator:title default="Apache Archiva"/>
+ </title>
+
+ <link rel="stylesheet" href="<c:url value="/css/maven-base.css"/>" type="text/css" media="all"/>
+ <link rel="stylesheet" href="<c:url value="/css/maven-theme.css"/>" type="text/css" media="all"/>
+ <link rel="stylesheet" href="<c:url value="/css/redback/table.css"/>" type="text/css" media="all"/>
+ <link rel="stylesheet" href="<c:url value="/css/site.css"/>" type="text/css" media="all"/>
+ <link rel="stylesheet" href="<c:url value="/css/print.css"/>" type="text/css" media="print"/>
+ <link rel="shortcut icon" href="<c:url value="/favicon.ico" />"/>
+ <script type="text/javascript" src="<c:url value="/js/scriptaculous/prototype.js"/>"></script>
+ <script type="text/javascript" src="<c:url value="/js/scriptaculous/scriptaculous.js"/>"></script>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+</head>
+
+<body onload="<decorator:getProperty property="body.onload" />" class="composite">
+<div id="banner">
+ <span id="bannerLeft">
+ <my:currentWWUrl action="index" namespace="/">
+ <img src="<c:url value='/images/archiva.png' />" alt="" width="188" height="69"/>
+ </my:currentWWUrl>
+ </span>
+ <span id="bannerRight">
+ <ww:action namespace="/components" name="companyInfo" executeResult="true"/>
+ </span>
+
+ <div class="clear">
+ <hr/>
+ </div>
+</div>
+
+<div id="breadcrumbs">
+ <div class="xleft">
+ <%@ include file="/WEB-INF/jsp/redback/include/securityLinks.jsp" %>
+ </div>
+
+ <div class="xright">
+ <a href="http://maven.apache.org/archiva">Archiva</a> |
+ <a href="http://maven.apache.org/">Maven</a> |
+ <a href="http://www.apache.org/">Apache</a>
+ </div>
+
+ <div class="clear">
+ <hr/>
+ </div>
+</div>
+
+<div id="leftColumn">
+
+ <div id="navcolumn">
+
+ <h5>Find</h5>
+ <ul>
+ <li class="none">
+ <my:currentWWUrl action="index" namespace="/">Search</my:currentWWUrl>
+ </li>
+
+ <ww:if test="${applicationScope.uiOptions.showFindArtifacts}">
+ <li class="none">
+ <my:currentWWUrl action="findArtifact" namespace="/">Find Artifact</my:currentWWUrl>
+ </li>
+ </ww:if>
+
+ <li class="none">
+ <my:currentWWUrl action="browse" namespace="/">Browse</my:currentWWUrl>
+ </li>
+
+ <li class="none">
+ <my:currentWWUrl action="upload" namespace="/">Upload Artifact</my:currentWWUrl>
+ </li>
+ </ul>
+
+ <redback:ifAnyAuthorized permissions="archiva-manage-users,archiva-access-reports,archiva-manage-configuration">
+ <h5>Manage</h5>
+ <ul>
+ <redback:ifAuthorized permission="archiva-access-reports">
+ <li class="none">
+ <my:currentWWUrl action="pickReport" namespace="/report">Reports</my:currentWWUrl>
+ </li>
+ </redback:ifAuthorized>
+ <%-- POSTPONED to 1.1 series
+ <li class="none">
+ <a href="#">Synchronisation</a>
+ </li>
+ --%>
+ <redback:ifAuthorized permission="archiva-manage-users">
+ <li class="none">
+ <my:currentWWUrl action="userlist" namespace="/security">User Management</my:currentWWUrl>
+ </li>
+ </redback:ifAuthorized>
+ <redback:ifAuthorized permission="archiva-manage-configuration">
+ <li class="none">
+ <my:currentWWUrl action="configureAppearance" namespace="/admin">Appearance</my:currentWWUrl>
+ </li>
+ </redback:ifAuthorized>
+ <%-- TODO: future options here.
+ * Repository Statistics.
+ * Web Services Statistics.
+ --%>
+ </ul>
+ </redback:ifAnyAuthorized>
+
+ <redback:ifAuthorized permission="archiva-manage-configuration">
+ <h5>Administration</h5>
+ <ul>
+ <li class="none">
+ <my:currentWWUrl action="repositories" namespace="/admin">Repositories</my:currentWWUrl>
+ </li>
+ <li class="none">
+ <my:currentWWUrl action="proxyConnectors" namespace="/admin">Proxy Connectors</my:currentWWUrl>
+ </li>
+ <li class="none">
+ <my:currentWWUrl action="legacyArtifactPath" namespace="/admin">Legacy support</my:currentWWUrl>
+ </li>
+ <li class="none">
+ <my:currentWWUrl action="networkProxies" namespace="/admin">Network Proxies</my:currentWWUrl>
+ </li>
+ <li class="none">
+ <my:currentWWUrl action="repositoryScanning" namespace="/admin">Repository Scanning</my:currentWWUrl>
+ </li>
+ <li class="none">
+ <my:currentWWUrl action="database" namespace="/admin">Database</my:currentWWUrl>
+ </li>
+ <%-- TODO: future options here.
+ * Repository Syncing Connectors. (rsync, ftp, scp, etc...)
+ * Web Services (enable / disable), role based?
+ --%>
+ </ul>
+ </redback:ifAuthorized>
+
+ </div>
+</div>
+
+<div id="bodyColumn">
+ <div id="contentBox">
+ <decorator:body/>
+ </div>
+</div>
+
+<div class="clear">
+ <hr/>
+</div>
+
+<%
+ int inceptionYear = 2005;
+ int currentYear = Calendar.getInstance().get( Calendar.YEAR );
+ String copyrightRange = String.valueOf( inceptionYear );
+ if ( inceptionYear != currentYear )
+ {
+ copyrightRange = copyrightRange + "-" + String.valueOf( currentYear );
+ }
+%>
+<div id="footer">
+ <div class="xleft">
+ Apache Archiva <%= ArchivaVersion.getVersion() %>
+ </div>
+ <div class="xright">
+ Copyright &#169; <%= copyrightRange %> The Apache Software Foundation
+ </div>
+
+ <div class="clear">
+ <hr/>
+
+ </div>
+</div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/findArtifact.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/findArtifact.jsp
new file mode 100644
index 000000000..c325c2286
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/findArtifact.jsp
@@ -0,0 +1,106 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Find Artifact</title>
+ <ww:head/>
+</head>
+
+<body onload="document.checksumSearch.file.disabled = false">
+
+<h1>Find Artifact</h1>
+
+<div id="contentArea">
+ <div id="searchBox">
+ <ww:if test="${applicationScope.uiOptions.appletFindEnabled}">
+ <script type="text/javascript">
+ function generateMd5( file, defVal )
+ {
+ if ( file )
+ {
+ var s = document.ChecksumApplet.generateMd5(file);
+ // If there is a space, it's an error message, not a checksum
+ if ( s.indexOf(" ") >= 0 )
+ {
+ alert(s);
+ return "";
+ }
+ else
+ return s;
+ }
+ return defVal;
+ }
+ </script>
+
+ <noscript>
+ <span class="errorMessage">JavaScript is disabled: using the file browser will not work.</span>
+ </noscript>
+
+ <ww:form method="POST" action="checksumSearch" namespace="/"
+ onsubmit="this.q.value = generateMd5(this.file.value,this.md5.value); this.file.disabled = true;">
+ <ww:hidden name="q"/>
+ <tr>
+ <td class="tdLabel"><label for="checksumSearch_file" class="label">Search for:</label></td>
+ <td>
+ <input type="file" name="file" size="50" value="" id="checksumSearch_file"/>
+ </td>
+ </tr>
+ <ww:textfield label="Checksum" size="50" name="md5"/>
+ <ww:submit value="Search"/>
+ </ww:form>
+
+ <p>
+ This allows you to search the repository using the checksum of an artifact that you are trying to identify.
+ You can either specify the checksum to look for directly, or scan a local artifact file.
+ </p>
+
+ <p>
+ To scan a local file, select the file you would like to locate in the remote repository.
+ The entire file will
+ <b>not</b>
+ be uploaded to the server. See the progress bar below for progress of
+ locally creating a checksum that is uploaded to the server after you hit "Search".
+ <ww:actionerror/>
+ </p>
+
+ <p>
+ <applet code="org/apache/maven/archiva/applet/ChecksumApplet.class"
+ archive="archiva-applet.jar"
+ width="400" height="20" name="ChecksumApplet">
+ </applet>
+ </p>
+ </ww:if>
+ <ww:else>
+ <ww:form method="POST" action="checksumSearch" namespace="/">
+ <ww:textfield label="Checksum" size="50" name="q"/>
+ <ww:submit value="Search"/>
+ </ww:form>
+
+ <p>
+ <ww:actionerror/>
+ </p>
+ </ww:else>
+ </div>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/generalError.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/generalError.jsp
new file mode 100644
index 000000000..49a6c1abf
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/generalError.jsp
@@ -0,0 +1,36 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+ <title>Error Occurred</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Error Occurred</h1>
+
+<ww:actionerror/>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactDependencies.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactDependencies.jspf
new file mode 100644
index 000000000..a92f9cc4f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactDependencies.jspf
@@ -0,0 +1,40 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+
+<%-- TODO: paginate [MRM-491] --%>
+<c:forEach items="${dependencies}" var="dependency">
+ <h3 class="artifact-title">
+ <my:showArtifactTitle groupId="${dependency.groupId}" artifactId="${dependency.artifactId}"
+ version="${dependency.version}"/>
+
+ </h3>
+
+ <p>
+ <my:showArtifactLink groupId="${dependency.groupId}" artifactId="${dependency.artifactId}"
+ version="${dependency.version}" scope="${dependency.scope}"
+ classifier="${dependency.classifier}"/>
+ </p>
+</c:forEach>
+<c:if test="${empty(dependencies)}">
+ <strong>No results</strong>
+</c:if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactInfo.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactInfo.jspf
new file mode 100644
index 000000000..43243548b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactInfo.jspf
@@ -0,0 +1,226 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<p>
+ <archiva:groupIdLink var="${model.groupId}" includeTop="true" />
+
+ <c:set var="url">
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${model.groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${model.artifactId}'}"/>
+ </ww:url>
+ </c:set>
+ <a href="${url}">${model.artifactId}</a> /
+ <strong>${version}</strong>
+
+ <%-- TODO: new versions?
+ (<strong class="statusFailed">Newer version available:</strong>
+ <a href="artifact.html">2.0.3</a>)
+ --%>
+</p>
+
+<c:if test="${!empty(model.description)}">
+ <blockquote>${model.description}</blockquote>
+</c:if>
+
+<table class="infoTable">
+ <tr>
+ <th>Group ID</th>
+ <td>${model.groupId}</td>
+ </tr>
+ <tr>
+ <th>Artifact ID</th>
+ <td>${model.artifactId}</td>
+ </tr>
+ <tr>
+ <th>Version</th>
+ <td>${model.version}</td>
+ </tr>
+ <tr>
+ <th>Packaging</th>
+ <td><code>${model.packaging}</code></td>
+ </tr>
+ <%-- TODO: derivatives
+ <tr>
+ <th>Derivatives</th>
+ <td>
+ <a href="#">Source</a>
+ |
+ <a href="#">Javadoc</a>
+ </td>
+ </tr>
+ --%>
+ <c:if test="${model.parentProject != null}">
+ <tr>
+ <th>Parent</th>
+ <td>
+ ${model.parentProject.groupId} ${model.parentProject.artifactId} ${model.parentProject.version}
+ <c:set var="url">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${model.parentProject.groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${model.parentProject.artifactId}'}"/>
+ <ww:param name="version" value="%{'${model.parentProject.version}'}"/>
+ </ww:url>
+ </c:set>
+ (<a href="${url}">View</a>)
+ </td>
+ </tr>
+ </c:if>
+ <%-- TODO: deployment timestamp
+ <tr>
+ <th>Deployment Date</th>
+ <td>
+ 15 Jan 2006, 20:38:00 +1000
+ </td>
+ </tr>
+ --%>
+ <%-- TODO: origin
+ <tr>
+ <th>Origin</th>
+ <td>
+ <a href="TODO">Apache Repository</a>
+ </td>
+ </tr>
+ --%>
+</table>
+
+<c:if test="${model.packaging != 'pom'}">
+ <h2>POM Dependency Snippet</h2>
+<pre class="pom">
+ &lt;dependency>
+ &lt;groupId>${model.groupId}&lt;/groupId>
+ &lt;artifactId>${model.artifactId}&lt;/artifactId>
+ &lt;version>${version}&lt;/version><c:if test="${model.packaging != 'jar'}">
+ &lt;type>${model.packaging}&lt;/type></c:if>
+ &lt;/dependency>
+</pre>
+</c:if>
+
+<c:if test="${!empty(model.url) || model.organization != null || !empty(model.licenses)
+ || model.issueManagement != null || model.ciManagement != null}">
+
+ <h2>Other Details</h2>
+ <table class="infoTable">
+ <c:if test="${!empty(model.url)}">
+ <tr>
+ <th>URL</th>
+ <td>
+ <a href="${model.url}">${model.url}</a>
+ </td>
+ </tr>
+ </c:if>
+ <c:if test="${model.organization != null}">
+ <tr>
+ <th>Organisation</th>
+ <td>
+ <c:choose>
+ <c:when test="${model.organization != null}">
+ <a href="${model.organization.url}">${model.organization.name}</a>
+ </c:when>
+ <c:otherwise>
+ ${model.organization.name}
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ </c:if>
+ <c:if test="${!empty(model.licenses)}">
+ <c:forEach items="${model.licenses}" var="license">
+ <tr>
+ <th>License</th>
+ <td>
+ <c:choose>
+ <c:when test="${!empty(license.url)}">
+ <a href="${license.url}">${license.name}</a>
+ </c:when>
+ <c:otherwise>
+ ${license.name}
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ </c:forEach>
+ </c:if>
+ <c:if test="${model.issueManagement != null}">
+ <tr>
+ <th>Issue Tracker</th>
+ <td>
+ <c:choose>
+ <c:when test="${!empty(model.issueManagement.url)}">
+ <a href="${model.issueManagement.url}">${model.issueManagement.system}</a>
+ </c:when>
+ <c:otherwise>
+ ${model.issueManagement.system}
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ </c:if>
+ <c:if test="${model.ciManagement != null}">
+ <tr>
+ <th>Continuous Integration</th>
+ <td>
+ <c:choose>
+ <c:when test="${!empty(model.ciManagement.url)}">
+ <a href="${model.ciManagement.url}">${model.ciManagement.system}</a>
+ </c:when>
+ <c:otherwise>
+ ${model.ciManagement.system}
+ </c:otherwise>
+ </c:choose>
+ </td>
+ </tr>
+ </c:if>
+ </table>
+</c:if>
+
+<c:if test="${model.scm != null}">
+ <h2>SCM</h2>
+ <table class="infoTable">
+ <c:if test="${!empty(model.scm.connection)}">
+ <tr>
+ <th>Connection</th>
+ <td>
+ <code>${model.scm.connection}</code>
+ </td>
+ </tr>
+ </c:if>
+ <c:if test="${!empty(model.scm.developerConnection)}">
+ <tr>
+ <th>Dev. Connection</th>
+ <td>
+ <code>${model.scm.developerConnection}</code>
+ </td>
+ </tr>
+ </c:if>
+ <c:if test="${!empty(model.scm.url)}">
+ <tr>
+ <th>Viewer</th>
+ <td>
+ <a href="${model.scm.url}">${model.scm.url}</a>
+ </td>
+ </tr>
+ </c:if>
+ </table>
+</c:if>
+
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactReports.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactReports.jspf
new file mode 100644
index 000000000..1a9d41638
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/artifactReports.jspf
@@ -0,0 +1,38 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+
+<c:forEach items="${reports}" var="report">
+ <h3>
+ ${report.groupId} : ${report.artifactId} : ${report.version} : ${report.classifier} : ${report.type}
+ </h3>
+ <ul>
+ <c:forEach items="${repor.results}" var="result">
+ <li>
+ <b>${result.reason}</b>
+ </li>
+ </c:forEach>
+ </ul>
+</c:forEach>
+<c:if test="${empty(reports)}">
+ <strong>No reports for this artifact.</strong>
+</c:if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/dependencyTree.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/dependencyTree.jspf
new file mode 100644
index 000000000..ed09eb7ae
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/dependencyTree.jspf
@@ -0,0 +1,31 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<archiva:dependency-tree groupId="${groupId}" artifactId="${artifactId}" version="${version}" />
+
+ <%--
+ <my:showArtifactLink groupId="${node.artifact.groupId}" artifactId="${node.artifact.artifactId}"
+ version="${node.artifact.version}"/>
+ --%>
+ \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/mailingLists.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/mailingLists.jspf
new file mode 100644
index 000000000..69d30630c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/mailingLists.jspf
@@ -0,0 +1,84 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+
+<c:forEach items="${mailingLists}" var="mailingList">
+ <h3>
+ ${mailingList.name}
+ </h3>
+ <%-- TODO: description
+ <p>
+ Description blah blah blah
+ </p>
+ --%>
+ <ul>
+ <c:if test="${!empty(mailingList.subscribeAddress)}">
+ <li>
+ <b>Subscribe:</b>
+ <a href="mailto:${mailingList.subscribeAddress}">${mailingList.subscribeAddress}</a>
+ </li>
+ </c:if>
+ <c:if test="${!empty(mailingList.postAddress)}">
+ <li>
+ <b>Post:</b>
+ <a href="mailto:${mailingList.postAddress}">${mailingList.postAddress}</a>
+ </li>
+ </c:if>
+ <c:if test="${!empty(mailingList.unsubscribeAddress)}">
+ <li>
+ <b>Unsubscribe:</b>
+ <a href="mailto:${mailingList.unsubscribeAddress}">${mailingList.unsubscribeAddress}</a>
+ </li>
+ </c:if>
+ <%-- TODO: not in the POM yet
+ <li>
+ <b>List owner:</b>
+ <a href="mailto:${mailingList.owner}">${mailingList.owner}</a>
+ </li>
+ --%>
+ <c:if test="${!empty(mailingList.mainArchiveUrl)}">
+ <li>
+ <b>Archive:</b>
+ <ul>
+ <li>
+ <a href="${mailingList.mainArchiveUrl}">${mailingList.mainArchiveUrl}</a>
+ </li>
+ </ul>
+ </li>
+ </c:if>
+ <%-- <c:if test="${!empty(mailingList.otherArchives)}">
+ <li>
+ <b>Other Archives:</b>
+ <ul>
+ <c:forEach items="${mailingList.otherArchives}" var="archive">
+ <li>
+ <a href="${archive}">${archive}</a>
+ </li>
+ </c:forEach>
+ </ul>
+ </li>
+ </c:if> --%>
+ </ul>
+</c:forEach>
+<c:if test="${empty(mailingLists)}">
+ <strong>No mailing lists</strong>
+</c:if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/projectDependees.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/projectDependees.jspf
new file mode 100644
index 000000000..fcaa38bb6
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/projectDependees.jspf
@@ -0,0 +1,39 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+
+<%-- TODO: paginate [MRM-491] --%>
+<c:forEach items="${dependees}" var="project">
+ <h3 class="artifact-title">
+ <my:showArtifactTitle groupId="${project.groupId}" artifactId="${project.artifactId}"
+ version="${project.version}"/>
+
+ </h3>
+
+ <p>
+ <my:showArtifactLink groupId="${project.groupId}" artifactId="${project.artifactId}"
+ version="${project.version}"/>
+ </p>
+</c:forEach>
+<c:if test="${empty(dependees)}">
+ <strong>No results</strong>
+</c:if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf
new file mode 100644
index 000000000..7db37265b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/quickSearchForm.jspf
@@ -0,0 +1,36 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<div id="searchBox">
+ <ww:form method="get" action="quickSearch" validate="true">
+ <ww:textfield label="Search for" size="50" name="q"/>
+ <ww:submit label="Go!"/>
+ </ww:form>
+
+ <script type="text/javascript">
+ document.getElementById("quickSearch_q").focus();
+ </script>
+
+ <p>
+ Enter your search terms. A variety of data will be searched for your keywords.
+ <ww:actionerror/>
+ </p>
+</div> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/uploadForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/uploadForm.jspf
new file mode 100644
index 000000000..91635a367
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/include/uploadForm.jspf
@@ -0,0 +1,35 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%-- http://www.opensymphony.com/webwork/wikidocs/File%20Upload%20Interceptor.html --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<ww:textfield name="groupId" label="Group Id" size="50" required="true"/>
+<ww:textfield name="artifactId" label="Artifact Id" size="50" required="true"/>
+<ww:textfield name="version" label="Version" size="50" required="true"/>
+<ww:textfield name="packaging" label="Packaging" size="50" required="true"/>
+<ww:textfield name="classifier" label="Classifier" size="50" required="false"/>
+<ww:select name="repositoryId" list="managedRepoIdList" label="Repository Id"/>
+<ww:file name="upload" label="File"/>
+<ww:checkbox name="generatePom" value="generatePom"
+ label="Generate Pom (Currently, only Maven 2 poms can be generated)"/>
+
+
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
new file mode 100644
index 000000000..690ea4f25
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
@@ -0,0 +1,40 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<html>
+<head>
+ <title>Quick Search</title>
+ <ww:head/>
+</head>
+
+<ww:if test="%{infoMessage != null}">
+ <p>${infoMessage}</p>
+</ww:if>
+
+<body>
+
+<h1>Search</h1>
+
+<div id="contentArea">
+ <%@ include file="/WEB-INF/jsp/include/quickSearchForm.jspf" %>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/basicReport.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/basicReport.jsp
new file mode 100644
index 000000000..a84e10ae8
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/basicReport.jsp
@@ -0,0 +1,65 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<html>
+<head>
+ <title>Reports</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Reports</h1>
+
+<div id="contentArea">
+
+ <ww:set name="reports" value="reports"/>
+
+ <c:forEach var="repository" items="${repositoriesMap}">
+ <strong>Repository: ${repository.key}</strong>
+ <c:forEach var="report" items='${repository.value}'>
+
+ <p>
+ <archiva:groupIdLink var="${report.groupId}" includeTop="true"/>
+ <c:set var="url">
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${report.groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${report.artifactId}'}"/>
+ </ww:url>
+ </c:set>
+ <a href="${url}">${report.artifactId}</a> /
+ <strong>${report.version}</strong>
+ </p>
+
+ <blockquote>${report.message}</blockquote>
+ </c:forEach>
+ </c:forEach>
+
+ <ww:set name="page" value="page"/>
+ <c:if test="${page > 1}"><a href="<ww:property value='prev' />">&lt;&lt;</a></c:if>
+ Page: ${page}
+ <ww:set name="isLastPage" value="isLastPage"/>
+ <c:if test="${!isLastPage}"><a href="<ww:property value='next' />">&gt;&gt;</a></c:if>
+
+</div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/blankReport.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/blankReport.jsp
new file mode 100644
index 000000000..14cf9a385
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/blankReport.jsp
@@ -0,0 +1,37 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Reports</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Reports</h1>
+
+<div id="contentArea">
+
+ <ww:text name="The operation generated an empty report."/>
+
+</div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/pickReport.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/pickReport.jsp
new file mode 100644
index 000000000..117db55eb
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/reports/pickReport.jsp
@@ -0,0 +1,43 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+
+<html>
+<head>
+ <title>Reports</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Reports</h1>
+
+<div id="contentArea">
+
+ <ww:form action="generateReport" namespace="/report" validate="true">
+ <ww:textfield label="Row Count" name="rowCount" />
+ <ww:textfield label="Group ID" name="groupId"/>
+ <ww:select label="Repository ID" name="repositoryId" list="repositoryIds"/>
+ <ww:submit value="Show Report"/>
+ </ww:form>
+
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp
new file mode 100644
index 000000000..3367c299f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp
@@ -0,0 +1,115 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib uri="/webwork" prefix="ww" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+
+<html>
+<head>
+ <title>Search Results</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<h1>Search</h1>
+
+<div id="contentArea">
+ <div id="searchBox">
+ <%@ include file="/WEB-INF/jsp/include/quickSearchForm.jspf" %>
+ </div>
+
+ <h1>Results</h1>
+
+ <div id="resultsBox">
+ <c:choose>
+
+ <%-- search was made from the indices --%>
+ <c:when test="${databaseResults == null}">
+ <p>Hits: ${fn:length(results.hits)} of ${results.totalHits}</p>
+
+ <c:choose>
+ <c:when test="${empty results.hits}">
+ <p>No results</p>
+ </c:when>
+ <c:otherwise>
+ <c:forEach items="${results.hits}" var="record" varStatus="i">
+ <c:choose>
+ <c:when test="${not empty (record.groupId)}">
+ <h3 class="artifact-title">
+ <my:showArtifactTitle groupId="${record.groupId}" artifactId="${record.artifactId}"
+ version="${record.version}"/>
+ </h3>
+ <p>
+ <my:showArtifactLink groupId="${record.groupId}" artifactId="${record.artifactId}"
+ version="${record.version}" versions="${record.versions}"/>
+ </p>
+ </c:when>
+ <c:otherwise>
+ <p>
+ <c:url var="hiturl" value="/repository/${record.url}" />
+ <a href="${hiturl}">${record.urlFilename}</a>
+ </p>
+ </c:otherwise>
+ </c:choose>
+ </c:forEach>
+ </c:otherwise>
+ </c:choose>
+ </c:when>
+
+ <%-- search was made from the database (find artifact)--%>
+ <c:otherwise>
+ <p>Hits: ${fn:length(databaseResults)}</p>
+
+ <c:choose>
+ <c:when test="${empty databaseResults}">
+ <p>No results</p>
+ </c:when>
+ <c:otherwise>
+ <c:forEach items="${databaseResults}" var="artifactModel" varStatus="i">
+ <c:choose>
+ <c:when test="${not empty (artifactModel.groupId)}">
+ <h3 class="artifact-title">
+ <my:showArtifactTitle groupId="${artifactModel.groupId}" artifactId="${artifactModel.artifactId}"
+ version="${artifactModel.version}"/>
+ </h3>
+ <p>
+ <my:showArtifactLink groupId="${artifactModel.groupId}" artifactId="${artifactModel.artifactId}"
+ version="${artifactModel.version}" versions="${artifactModel.versions}"/>
+ </p>
+ </c:when>
+ <c:otherwise>
+ <p>
+ <c:url var="hiturl" value="/repository/${artifactModel.repositoryId}" />
+ <a href="${hiturl}">${artifactModel.repositoryId}</a>
+ </p>
+ </c:otherwise>
+ </c:choose>
+ </c:forEach>
+ </c:otherwise>
+ </c:choose>
+
+ </c:otherwise>
+ </c:choose>
+ </div>
+</div>
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/showArtifact.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/showArtifact.jsp
new file mode 100644
index 000000000..71ac3988a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/showArtifact.jsp
@@ -0,0 +1,166 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+<%@ taglib prefix="redback" uri="http://plexus.codehaus.org/redback/taglib-1.0" %>
+
+<html>
+<head>
+ <title>Browse Repository</title>
+ <ww:head/>
+</head>
+
+<body>
+
+<ww:set name="model" value="model"/>
+<c:choose>
+ <c:when test="${model.packaging == 'maven-plugin'}">
+ <c:url var="imageUrl" value="/images/mavenplugin.gif"/>
+ <c:set var="packageName">Maven Plugin</c:set>
+ </c:when>
+ <c:when test="${model.packaging == 'pom'}">
+ <c:url var="imageUrl" value="/images/pom.gif"/>
+ <c:set var="packageName">POM</c:set>
+ </c:when>
+ <%-- These types aren't usually set in the POM yet, so we fudge them for the well known ones --%>
+ <c:when test="${model.packaging == 'maven-archetype' or model.groupId == 'org.apache.maven.archetypes'}">
+ <c:url var="imageUrl" value="/images/archetype.gif"/>
+ <c:set var="packageName">Maven Archetype</c:set>
+ </c:when>
+ <c:when test="${model.packaging == 'maven-skin' or model.groupId == 'org.apache.maven.skins'}">
+ <c:url var="imageUrl" value="/images/skin.gif"/>
+ <c:set var="packageName">Maven Skin</c:set>
+ </c:when>
+ <%-- Must be last so that the above get picked up if possible --%>
+ <c:when test="${model.packaging == 'jar'}">
+ <c:url var="imageUrl" value="/images/jar.gif"/>
+ <c:set var="packageName">JAR</c:set>
+ </c:when>
+ <c:otherwise>
+ <c:url var="imageUrl" value="/images/other.gif"/>
+ <c:set var="packageName"></c:set>
+ </c:otherwise>
+</c:choose>
+<img src="${imageUrl}" width="66" height="66" alt="${packageName}" title="${packageName}" style="float: left"/>
+
+<h1>
+ <c:choose>
+ <c:when test="${empty(model.name)}">
+ ${model.artifactId}
+ </c:when>
+ <c:otherwise>
+ ${model.name}
+ </c:otherwise>
+ </c:choose>
+</h1>
+
+<div id="contentArea">
+ <div id="tabs">
+ <span>
+ <c:set var="url">
+ <ww:url action="showArtifact">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Info</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependencies">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Dependencies</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependencyTree">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Dependency Tree</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactDependees">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Used By</my:currentWWUrl>
+ <c:set var="url">
+ <ww:url action="showArtifactMailingLists">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Mailing Lists</my:currentWWUrl>
+ <%-- POSTPONED to 1.0-alpha-2
+ <redback:ifAnyAuthorized permissions="archiva-access-reports">
+ <c:set var="url">
+ <ww:url action="showArtifactReports">
+ <ww:param name="groupId" value="%{groupId}"/>
+ <ww:param name="artifactId" value="%{artifactId}"/>
+ <ww:param name="version" value="%{version}"/>
+ </ww:url>
+ </c:set>
+ <my:currentWWUrl url="${url}">Reports</my:currentWWUrl>
+ </redback:ifAnyAuthorized>
+ --%>
+
+ </span>
+ </div>
+
+ <div class="sidebar3">
+ <archiva:downloadArtifact groupId="${model.groupId}" artifactId="${model.artifactId}" version="${model.version}"/>
+ </div>
+
+ <%-- TODO: perhaps using ajax? --%>
+ <%-- TODO: panels? this is ugly as is --%>
+ <div id="tabArea">
+ <c:choose>
+ <c:when test="${dependencies != null}">
+ <%@ include file="/WEB-INF/jsp/include/artifactDependencies.jspf" %>
+ </c:when>
+ <c:when test="${dependencyTree != null}">
+ <%@ include file="/WEB-INF/jsp/include/dependencyTree.jspf" %>
+ </c:when>
+ <c:when test="${dependees != null}">
+ <%@ include file="/WEB-INF/jsp/include/projectDependees.jspf" %>
+ </c:when>
+ <c:when test="${mailingLists != null}">
+ <%@ include file="/WEB-INF/jsp/include/mailingLists.jspf" %>
+ </c:when>
+ <c:when test="${reports != null}">
+ <%@ include file="/WEB-INF/jsp/include/artifactReports.jspf" %>
+ </c:when>
+ <c:otherwise>
+ <%@ include file="/WEB-INF/jsp/include/artifactInfo.jspf" %>
+ </c:otherwise>
+ </c:choose>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/upload.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/upload.jsp
new file mode 100644
index 000000000..c22bccc97
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/upload.jsp
@@ -0,0 +1,46 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%-- http://www.opensymphony.com/webwork/wikidocs/File%20Upload%20Interceptor.html --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+ <title>Upload Artifact</title>
+ <ww:head/>
+</head>
+
+<body>
+<h1>Upload Artifact</h1>
+
+<div id="contentArea">
+
+ <ww:actionerror/>
+ <ww:actionmessage/>
+
+ <ww:form action="upload!doUpload" method="post" enctype="multipart/form-data" validate="true">
+ <%@ include file="/WEB-INF/jsp/include/uploadForm.jspf" %>
+ <ww:submit/>
+ </ww:form>
+</div>
+
+</body>
+</html>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/currentWWUrl.tag b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/currentWWUrl.tag
new file mode 100644
index 000000000..761ff6640
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/currentWWUrl.tag
@@ -0,0 +1,52 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib uri="/webwork" prefix="ww" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ attribute name="action" %>
+<%@ attribute name="namespace" %>
+<%@ attribute name="url" %>
+
+<c:set var="currentUrl">
+ <ww:url/>
+</c:set>
+<c:if test="${!empty(action) && !empty(namespace)}">
+ <c:set var="url">
+ <ww:url action="${action}" namespace="${namespace}"/>
+ </c:set>
+</c:if>
+<c:set var="text">
+ <jsp:doBody/>
+</c:set>
+<c:choose>
+ <c:when test="${currentUrl == url}">
+ <b>
+
+ ${text}
+
+ </b>
+ </c:when>
+ <c:otherwise>
+ <a href="${url}">
+
+ ${text}
+
+ </a>
+ </c:otherwise>
+</c:choose>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/displayUpdatePolicy.tag b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/displayUpdatePolicy.tag
new file mode 100644
index 000000000..702d74d76
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/displayUpdatePolicy.tag
@@ -0,0 +1,41 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%-- TODO: this could perhaps just be a i18n call --%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ attribute name="policy" required="true" %>
+<%@ attribute name="interval" %>
+
+<c:choose>
+ <c:when test="${policy == 'disabled'}">
+ Disabled
+ </c:when>
+ <c:when test="${policy == 'always'}">
+ Updated every request
+ </c:when>
+ <c:when test="${policy == 'hourly'}">
+ Updated hourly
+ </c:when>
+ <c:when test="${policy == 'daily'}">
+ Updated daily
+ </c:when>
+ <c:when test="${policy == 'interval'}">
+ Updated every ${interval} minutes
+ </c:when>
+</c:choose> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactLink.tag b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactLink.tag
new file mode 100644
index 000000000..6ebbb6d3b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactLink.tag
@@ -0,0 +1,77 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib prefix="archiva" uri="http://maven.apache.org/archiva" %>
+
+<%@ attribute name="groupId" required="true" %>
+<%@ attribute name="artifactId" %>
+<%@ attribute name="version" %>
+<%@ attribute name="classifier" %>
+<%@ attribute name="scope" %>
+<%@ attribute name="versions" type="java.util.List" %>
+
+<span class="artifact-link">
+ <archiva:groupIdLink var="${groupId}" includeTop="false" />
+
+ <c:if test="${!empty(artifactId)}">
+ <c:set var="url">
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ </ww:url>
+ </c:set>
+ <a href="${url}">${artifactId}</a>
+ </c:if>
+ | <strong>Version(s):</strong>
+ <c:choose>
+ <c:when test="${!empty(version)}">
+ <c:set var="url">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ <c:if test="${!empty(version)}">
+ <ww:param name="version" value="%{'${version}'}"/>
+ </c:if>
+ </ww:url>
+ </c:set>
+ <a href="${url}">${version}</a>
+ </c:when>
+ <c:otherwise>
+ <c:forEach items="${versions}" var="v" varStatus="i">
+ <c:set var="url">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ <ww:param name="version" value="%{'${v}'}"/>
+ </ww:url>
+ </c:set>
+ <a href="${url}">${v}</a>
+ <c:if test="${!i.last}">,</c:if>
+ </c:forEach>
+ </c:otherwise>
+ </c:choose>
+ <c:if test="${!empty(scope)}">
+ | <strong>Scope:</strong> ${scope}
+ </c:if>
+ <c:if test="${!empty(classifier)}">
+ | <strong>Classifier:</strong> ${classifier}
+ </c:if>
+</span>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactTitle.tag b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactTitle.tag
new file mode 100644
index 000000000..5ecea37d7
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/tags/showArtifactTitle.tag
@@ -0,0 +1,46 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ attribute name="groupId" required="true" %>
+<%@ attribute name="artifactId" %>
+<%@ attribute name="version" %>
+
+ <span class="artifact-title">
+ <c:set var="url">
+ <c:choose>
+ <c:when test="${!empty(version)}">
+ <ww:url action="showArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ <ww:param name="version" value="%{'${version}'}"/>
+ </ww:url>
+ </c:when>
+ <c:otherwise>
+ <ww:url action="browseArtifact" namespace="/">
+ <ww:param name="groupId" value="%{'${groupId}'}"/>
+ <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+ </ww:url>
+ </c:otherwise>
+ </c:choose>
+ </c:set>
+ <%-- TODO: showing the name and description would be nice, but that would require loading the POMs --%>
+ <a href="${url}">${artifactId}</a>
+ </span>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/web.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..3a5c4083f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+ <display-name>Apache Archiva</display-name>
+
+ <filter>
+ <filter-name>webwork-cleanup</filter-name>
+ <filter-class>com.opensymphony.webwork.dispatcher.ActionContextCleanUp</filter-class>
+ </filter>
+
+ <filter>
+ <filter-name>sitemesh</filter-name>
+ <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
+ </filter>
+
+ <filter>
+ <filter-name>webwork</filter-name>
+ <filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
+ </filter>
+
+ <!-- this must be before the sitemesh filter -->
+ <filter-mapping>
+ <filter-name>webwork-cleanup</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>sitemesh</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>webwork</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+ <listener>
+ <!-- TODO: some Spring technique for this? -->
+ <listener-class>org.apache.maven.archiva.web.startup.ArchivaStartup</listener-class>
+ </listener>
+
+ <context-param>
+ <param-name>contextClass</param-name>
+ <param-value>org.codehaus.plexus.spring.PlexusWebApplicationContext</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>
+ classpath*:META-INF/plexus/components.xml
+ classpath*:META-INF/spring-context.xml
+ /WEB-INF/classes/META-INF/plexus/application.xml
+ /WEB-INF/classes/META-INF/plexus/components.xml
+ /WEB-INF/applicationContext.xml
+ </param-value>
+ </context-param>
+
+ <servlet>
+ <servlet-name>RepositoryServlet</servlet-name>
+ <servlet-class>org.apache.maven.archiva.web.repository.RepositoryServlet</servlet-class>
+ <!-- Loading this on startup so as to take advantage of configuration listeners -->
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>RepositoryServlet</servlet-name>
+ <url-pattern>/repository/*</url-pattern>
+ </servlet-mapping>
+
+ <resource-ref>
+ <res-ref-name>jdbc/users</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ <resource-ref>
+ <res-ref-name>jdbc/archiva</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+ <resource-ref>
+ <res-ref-name>mail/Session</res-ref-name>
+ <res-type>javax.mail.Session</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+
+</web-app>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-base.css b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-base.css
new file mode 100644
index 000000000..ca951f8d0
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-base.css
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+body {
+ margin: 0px;
+ padding: 0px;
+}
+
+img {
+ border: none;
+}
+
+table {
+ padding: 0px;
+ width: 100%;
+ margin-left: -2px;
+ margin-right: -2px;
+}
+
+acronym {
+ cursor: help;
+ border-bottom: 1px dotted #feb;
+}
+
+table.bodyTable th, table.bodyTable td {
+ padding: 2px 4px 2px 4px;
+ vertical-align: top;
+}
+
+div.clear {
+ clear: both;
+ visibility: hidden;
+}
+
+div.clear hr {
+ display: none;
+}
+
+#bannerLeft, #bannerRight {
+ font-size: xx-large;
+ font-weight: bold;
+}
+
+#bannerLeft img, #bannerRight img {
+ margin: 0px;
+}
+
+.xleft, #bannerLeft img {
+ float: left;
+}
+
+.xright, #bannerRight img {
+ float: right;
+}
+
+#banner {
+ padding: 0px;
+}
+
+#banner img {
+ border: none;
+}
+
+#breadcrumbs {
+ padding: 3px 10px 3px 10px;
+}
+
+#leftColumn {
+ width: 170px;
+ float: left;
+ overflow: auto;
+}
+
+#bodyColumn {
+ margin-right: 1.5em;
+ margin-left: 197px;
+}
+
+#legend {
+ padding: 8px 0 8px 0;
+}
+
+#navcolumn {
+ padding: 8px 4px 0 8px;
+}
+
+#navcolumn h5 {
+ margin: 0;
+ padding: 0;
+ font-size: small;
+}
+
+#navcolumn ul {
+ margin: 0;
+ padding: 0;
+ font-size: small;
+}
+
+#navcolumn li {
+ list-style-type: none;
+ background-image: none;
+ background-repeat: no-repeat;
+ background-position: 0 0.4em;
+ padding-left: 16px;
+ list-style-position: outside;
+ line-height: 1.2em;
+ font-size: smaller;
+}
+
+#navcolumn li.expanded {
+ background-image: url( ../images/expanded.gif );
+}
+
+#navcolumn li.collapsed {
+ background-image: url( ../images/collapsed.gif );
+}
+
+#poweredBy {
+ text-align: center;
+}
+
+#navcolumn img {
+ margin-top: 10px;
+ margin-bottom: 3px;
+}
+
+#poweredBy img {
+ display: block;
+ margin: 20px 0 20px 17px;
+ border: 1px solid black;
+ width: 90px;
+ height: 30px;
+}
+
+#search img {
+ margin: 0px;
+ display: block;
+}
+
+#search #q, #search #btnG {
+ border: 1px solid #999;
+ margin-bottom: 10px;
+}
+
+#search form {
+ margin: 0px;
+}
+
+#lastPublished {
+ font-size: x-small;
+}
+
+.navSection {
+ margin-bottom: 2px;
+ padding: 8px;
+}
+
+.navSectionHead {
+ font-weight: bold;
+ font-size: x-small;
+}
+
+.section {
+ padding: 4px;
+}
+
+#footer {
+ padding: 3px 10px 3px 10px;
+ font-size: x-small;
+}
+
+#breadcrumbs {
+ font-size: x-small;
+ margin: 0pt;
+}
+
+.source {
+ padding: 12px;
+ margin: 1em 7px 1em 7px;
+}
+
+.source pre {
+ margin: 0px;
+ padding: 0px;
+}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-theme.css b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-theme.css
new file mode 100644
index 000000000..983e387b2
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/maven-theme.css
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+body {
+ padding: 0 0 10px 0;
+}
+
+body, td, th, select, input, li {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+ font-size: 11pt;
+}
+
+select, input {
+ font-size: 0.9em;
+ border: 1px solid #AAAAAA;
+}
+
+select {
+ padding-left: 3px;
+ height: 1.4em;
+}
+
+input {
+ padding: 2px;
+}
+
+label .required {
+ color: red;
+ font-weight: bold;
+}
+
+th {
+ text-align: right;
+ padding-right: 1em;
+ font-size: x-small;
+ vertical-align: top;
+}
+
+.infoTable th {
+ width: 15em;
+}
+
+#contentBox h1 {
+ background-image: url( ../images/arrow.gif );
+ background-repeat: no-repeat;
+ background-position: left bottom;
+ border-bottom: 1px solid #DFDEDE;
+ padding: 0 0 1px 23px;
+ margin-bottom: 0.5em;
+ color: #333;
+ voice-family: inherit;
+ font-size: medium !important;
+}
+
+#contentBox h2 {
+ border-bottom: 1px solid #DFDEDE;
+ padding: 0 0 1px 0;
+ margin-bottom: 0.5em;
+ color: #333;
+ voice-family: inherit;
+ font-size: small !important;
+}
+
+#contentBox h3 {
+ border-bottom: 1px solid #DFDEDE;
+ padding: 0 0 1px 0;
+ margin-bottom: 0.5em;
+ color: #333;
+ voice-family: inherit;
+ font-size: small !important;
+ margin-left: 2em;
+}
+
+table {
+ width: auto;
+}
+
+code {
+ font-family: Courier, monospace;
+ font-size: 13px;
+}
+
+#legend li.externalLink {
+ background: url( ../images/external.png ) left top no-repeat;
+ padding-left: 18px;
+}
+
+a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
+ background: url( ../images/external.png ) right center no-repeat;
+ padding-right: 18px;
+}
+
+#legend li.newWindow {
+ background: url( ../images/newwindow.png ) left top no-repeat;
+ padding-left: 18px;
+}
+
+a.newWindow, a.newWindow:link, a.newWindow:visited, a.newWindow:active, a.newWindow:hover {
+ background: url( ../images/newwindow.png ) right center no-repeat;
+ padding-right: 18px;
+}
+
+p {
+ line-height: 1.3em;
+ font-size: small;
+}
+
+#breadcrumbs {
+ border-top: 1px solid #fff;
+ border-bottom: 1px solid #999;
+ background-color: #F3B455;
+ padding: 2px 8px;
+}
+
+#navcolumn h5 {
+ color: gray;
+ font-weight: bold;
+ font-size: 11px;
+ padding: 10px 0 1px 19px;
+}
+
+.source {
+ border: 1px solid #999;
+}
+
+dl {
+ padding: 4px 4px 4px 6px;
+ border: 1px solid #aaa;
+ background-color: #ffc;
+}
+
+dt {
+ color: #900;
+}
+
+#organizationLogo img, #projectLogo img, #projectLogo span {
+ margin: 8px;
+}
+
+#banner {
+ border-bottom: 1px solid #fff;
+ padding: 8px;
+}
+
+#breadcrumbs a:link {
+ text-decoration: none;
+}
+
+#breadcrumbs a:visited {
+ text-decoration: none;
+ color: #333
+}
+
+#breadcrumbs a:hover {
+ text-decoration: none;
+ color: white
+}
+
+.errormark, .warningmark, .donemark, .infomark {
+ background: url( ../images/icon_error_sml.gif ) no-repeat;
+}
+
+.warningmark {
+ background-image: url( ../images/icon_warning_sml.gif );
+}
+
+.donemark {
+ background-image: url( ../images/icon_success_sml.gif );
+}
+
+.infomark {
+ background-image: url( ../images/icon_info_sml.gif );
+}
+
+.booleanIcon {
+ padding-left: 20px;
+ height: 20px;
+}
+
+pre.pom {
+ font-size: 0.9em;
+ border: 1px solid #ddddff;
+ background-color: #f8f8ff;
+ padding: 5px;
+}
+
+pre.pom code {
+ font-size: 0.9em;
+}
+
+#leftColumn {
+ padding: 4px 4px 4px 4px;
+ overflow: hidden;
+}
+
+#navcolumn {
+ padding: 6px 0 0 2px;
+}
+
+#navcolumn li {
+ font-size: 9px;
+ text-indent: 19px;
+ line-height: 24px;
+ height: 25px;
+ width: 161px;
+ background-image: url( ../images/super.gif );
+ background-position: 0 0;
+ background-repeat: no-repeat;
+ display: block;
+ padding-left: 0;
+}
+
+#navcolumn li li {
+ padding-left: 16px;
+ background: none;
+ display: block;
+}
+
+#navcolumn li li a:hover {
+ color: black !important;
+ background: none;
+ display: block;
+}
+
+#navcolumn li li a:active {
+ color: red !important;
+ background: none;
+ display: block;
+}
+
+#navcolumn li.collapsed {
+ background-image: url( ../images/super.gif );
+}
+
+#navcolumn li.expanded {
+ background-image: url( ../images/super.gif );
+ height: inherit;
+}
+
+#navcolumn li a:link {
+ color: #666;
+ display: block;
+}
+
+#navcolumn li a:hover {
+ color: #fff !important;
+ background: url( ../images/super_hl.gif ) 0 -25px no-repeat;
+ display: block;
+}
+
+#navcolumn li a:active {
+ color: #fff !important;
+ background: url( ../images/super_hl.gif ) 0 -50px no-repeat;
+ display: block;
+}
+
+#navcolumn li a:visited {
+ color: #666;
+ display: block;
+}
+
+#navcolumn li ul li {
+ color: #333 !important;
+ text-indent: 30px !important;
+ line-height: 20px !important;
+ height: 20px !important;
+ background-image: url( ../images/supersub.gif ) !important;
+ font-size: 9px;
+ width: 161px;
+ background-repeat: no-repeat;
+ display: block;
+ padding-left: 0;
+}
+
+#navcolumn li ul li a:hover {
+ color: #fff !important;
+ background: url( ../images/super_hl_sub.gif ) 0 -20px no-repeat;
+ background-position: right;
+ width: 161px;
+ display: block;
+}
+
+#footer {
+ background: url( ../images/footerborder.gif ) 0 5px repeat-x;
+ padding: 14px 4px 12px 4px;
+ margin-top: 2em;
+}
+
+a:link, a:visited {
+ color: #333;
+}
+
+#navcolumn a {
+ text-decoration: none;
+}
+
+a:active, a:hover {
+ color: #f30;
+}
+
+blockquote {
+ border-left: 1px solid #DFDEDE;
+ padding-left: 1em;
+}
+
+.missing {
+ background-color: red;
+ color: white;
+ font-weight: bold;
+ padding: 4px;
+ margin-left: 20px;
+ margin-right: 20px;
+
+}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/print.css b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/print.css
new file mode 100644
index 000000000..7f9db33dc
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/print.css
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+#banner, #footer, #leftcol, #breadcrumbs, .docs #toc, .docs .courtesylinks, #leftColumn, #navColumn {
+ display: none !important;
+}
+
+#bodyColumn, body.docs div.docs {
+ margin: 0 !important;
+ border: none !important
+}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css
new file mode 100644
index 000000000..195420b67
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/css/site.css
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+.sidebar3 {
+ width: 10em;
+ float: right;
+ text-align: center;
+}
+
+#sidebarb {
+ font-size: small;
+ text-align: center;
+ padding: 10px 10px 10px 10px;
+ border: 1px #DFDEDE solid;
+ width: 10em;
+}
+
+#sidebar {
+ float: right;
+ font-size: small;
+ margin: 10px;
+ padding: 10px;
+ border: 1px #DFDEDE solid;
+ width: 10em;
+}
+
+.download {
+ float: right;
+ font-size: small;
+ font-weight: bold;
+ margin: 15px auto 0px auto;
+ height: auto;
+ width: 150px;
+ min-width: 120px;
+ display: block;
+}
+
+.download .hd .c,
+.download .ft .c {
+ font-size: 1px; /* ensure minimum height */
+ height: 10px;
+}
+
+.download .ft .c {
+ height: 10px;
+}
+
+.download .hd {
+ background: transparent url(../images/download.tl.gif) no-repeat 0px 0px;
+}
+
+.download .hd .c {
+ background: transparent url(../images/download.tr.gif) no-repeat right 0px;
+}
+
+.download .bd {
+ background: transparent url(../images/download.ml.gif) repeat-y 0px 0px;
+}
+
+.download .bd .c {
+ background: transparent url(../images/download.mr.gif) repeat-y right 0px;
+}
+
+.download .bd .c .s {
+ margin: 0px 8px 0px 4px;
+ background: #000 url(../images/download.ms.jpg) repeat-x 0px 0px;
+ padding: 1em;
+}
+
+.download .ft {
+ background: transparent url(../images/download.bl.gif) no-repeat 0px 0px;
+}
+
+.download .ft .c {
+ background: transparent url(../images/download.br.gif) no-repeat right 0px;
+}
+
+.download .bd h2 {
+ margin: 0px;
+ text-align: center;
+ border-bottom-width: 0px !important;
+}
+
+.download .bd p {
+ margin: 0px;
+ border: 0px;
+ text-align: left;
+ padding-left: 0px;
+}
+
+.download a {
+ text-decoration: none;
+}
+
+.download p.body {
+ font-weight: bold;
+}
+
+.download table {
+ margin-left: 2px;
+ width: 140px;
+}
+
+.download .icon {
+ width: 16px;
+}
+
+.download .type {
+ font-size: 0.9em;
+ text-align: center;
+}
+
+.download .size {
+ font-weight: normal;
+ font-size: 0.8em;
+ text-align: right;
+}
+
+#contentArea {
+ /* margin-right: 15em; */
+ padding: 1em;
+}
+
+#tabs b {
+ border: 1px #DFDEDE solid;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+#tabs a {
+ border: 1px #DFDEDE solid;
+ padding-left: 1em;
+ padding-right: 1em;
+ text-decoration: none;
+}
+
+#tabArea {
+ border-top: 1px solid #DFDEDE;
+ padding: 1em;
+}
+
+#searchTypes {
+ text-align: right;
+ font-size: xx-small;
+}
+
+.statusFailed {
+ color: red;
+ font-weight: bold;
+}
+
+/* WebWork validation failures */
+.errorMessage {
+ color: red;
+ font-weight: bold;
+}
+
+.actionMessage {
+ font-size: 1.0em;
+ font-weight: bold;
+ color: blue;
+}
+
+.errorBullet {
+ list-style-image: url( "../images/icon_error_sml.gif" );
+}
+
+.warningBullet {
+ list-style-image: url( "../images/icon_warning_sml.gif" );
+}
+
+.infoBullet {
+ list-style-image: url( "../images/icon_info_sml.gif" );
+}
+
+.artifact-link {
+ font-size: x-small;
+ padding-left: 5em;
+}
+
+.artifact-title {
+
+}
+
+ul.dependencyTree {
+ margin-left: 50px;
+}
+
+ul.dependencyTree span.artifact-link {
+ padding-left: 0px;
+}
+
+.eXtremeTable tr.filter {
+ padding: 1px;
+}
+
+.eXtremeTable .tableRegion,.eXtremeTable .statusBar {
+ width: 100%;
+}
+
+.eXtremeTable .tableRegion .tableHeader {
+ background-color: #F3B455;
+}
+
+.eXtremeTable .tableRegion .tableHeaderSort {
+ background-color: #FFBF5F;
+}
+
+.eXtremeTable .compactToolbar td {
+ white-space: nowrap;
+}
+
+.tools {
+ border-color: gray !important;
+}
+
+.tools .toolHeading {
+ padding: 0px 3px 0px 3px;
+ margin: 0px !important;
+ font-size: 11px !important;
+ background-color: #F3B455 !important;
+}
+
+div.repository h3 {
+ border-bottom: 0px !important;
+ padding-left: 15px !important;
+}
+
+div.repository {
+ border-bottom: 1px solid #DFDEDE;
+}
+
+div.proxyConfig {
+ border: 1px dashed #DFDEDE;
+ margin-bottom: 15px;
+ padding: 5px;
+}
+
+div.proxyConfig div.managedRepo,
+div.proxyConfig div.remoteRepo {
+ border: 1px dotted gray;
+ padding: 5px;
+ background-color: white;
+}
+
+div.proxyConfig div.remoteRepo {
+ margin: 5px;
+}
+
+div.proxyConfig div.managedRepo img,
+div.proxyConfig div.remoteRepo img {
+ float: left;
+ border: 0px;
+}
+
+div.proxyConfig div.managedRepo p,
+div.proxyConfig div.remoteRepo p {
+ margin: 0px;
+ margin-left: 40px;
+ padding: 0px;
+}
+
+div.proxyConfig div.managedRepo p.id,
+div.proxyConfig div.remoteRepo p.id {
+ font-family: monospace;
+}
+
+div.proxyConfig div.connector {
+ border: 1px solid #aaaaff;
+ margin-top: 10px;
+ margin-left: 40px !important;
+}
+
+div.proxyConfig a.expand {
+ font-size: 7pt;
+ color: gray;
+}
+
+div.proxyConfig div.controls {
+ float: right;
+}
+
+div.proxyConfig div.connector h4 {
+ padding: 3px;
+ font-size: 8pt;
+ margin: 0px;
+}
+
+div.proxyConfig div.connector table.settings {
+ border: 0px;
+ background-color: transparent;
+ font-size: 8pt;
+ margin-left: 10px;
+}
+
+div.proxyConfig div.connector table.settings th,
+div.proxyConfig div.connector table.settings td {
+ font-size: 8pt;
+}
+
+div.proxyConfig div.connector table.settings table.policies {
+ border: 1px dotted gray;
+}
+
+div.proxyConfig div.connector table p {
+ margin: 0px;
+ padding: 0px;
+}
+div.admin div.dark,
+div.admin div.lite {
+ border: 1px solid #aaaaaa;
+ font-size: 11pt;
+ margin-left: 15px;
+ margin-right: 15px;
+ margin-bottom: 5px;
+ padding: 5px;
+}
+
+div.admin div.lite {
+ background-color: white;
+}
+
+div.admin div.dark {
+ background-color: #eeeeee;
+}
+
+div.admin div.controls {
+ float: right;
+ font-size: 8pt !important;
+}
+
+div.admin div.filetype table {
+ margin-left: 25px;
+ border: 1px solid gray;
+}
+
+div.filetype table td.controls {
+ width: 5%;
+}
+
+div.filetype table td.odd,
+div.admin table.consumers td.odd {
+ background-color: #dddddd;
+}
+
+div.filetype table td.even,
+div.admin table.consumers td.even {
+ background-color: white;
+}
+
+div.admin table.consumers {
+ margin-left: 15px;
+ border: 1px solid gray;
+}
+
+div.admin table.consumers th {
+ font-size: 1.0em;
+ background-color: #cccccc;
+ text-align: left;
+}
+
+div.admin table.consumers td strong {
+ font-size: 0.8em;
+}
+
+div.warningbox {
+ margin: 20px 40px 20px 40px;
+ border: 1px solid #CC0000;
+ background-color: #FFCCCC;
+ color: #000000;
+ font-size: 15pt;
+ padding: 20px;
+}
+
+div.infobox {
+ margin: 20px 40px 20px 40px;
+ border: 1px solid #0000CC;
+ background-color: #EEEEFF;
+ font-size: 9pt;
+ padding: 20px;
+}
+
+div.buttons {
+ text-align: center;
+} \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/favicon.ico b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/favicon.ico
new file mode 100644
index 000000000..06714d34a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/favicon.ico
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archetype.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archetype.gif
new file mode 100755
index 000000000..fc84feff5
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archetype.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-splat-32.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-splat-32.gif
new file mode 100644
index 000000000..8625d2311
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-splat-32.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-world.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-world.png
new file mode 100644
index 000000000..8afb6cc93
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva-world.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva.png
new file mode 100644
index 000000000..a1e638175
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/archiva.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/arrow.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/arrow.gif
new file mode 100755
index 000000000..ce00e3d0c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/arrow.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/collapsed.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/collapsed.gif
new file mode 100644
index 000000000..6e7108406
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/collapsed.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/dl.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/dl.gif
new file mode 100755
index 000000000..710e7b848
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/dl.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-jar.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-jar.png
new file mode 100644
index 000000000..146e1fd8f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-jar.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-java-source.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-java-source.png
new file mode 100644
index 000000000..9660957eb
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-java-source.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-pom.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-pom.png
new file mode 100644
index 000000000..d0e4c12bf
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download-type-pom.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.bl.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.bl.gif
new file mode 100644
index 000000000..c59ba0062
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.bl.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.br.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.br.gif
new file mode 100644
index 000000000..d80f62ee8
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.br.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.ml.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.ml.gif
new file mode 100644
index 000000000..8fcfa4220
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.ml.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.mr.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.mr.gif
new file mode 100644
index 000000000..ded125be9
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.mr.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tl.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tl.gif
new file mode 100644
index 000000000..b4a8e97d3
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tl.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tr.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tr.gif
new file mode 100644
index 000000000..07aeccee5
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/download.tr.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/expanded.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/expanded.gif
new file mode 100644
index 000000000..0fef3d89e
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/expanded.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/external.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/external.png
new file mode 100644
index 000000000..3f999fc88
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/external.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/footerborder.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/footerborder.gif
new file mode 100644
index 000000000..958ce7ae3
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/footerborder.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_error_sml.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_error_sml.gif
new file mode 100644
index 000000000..61132ef2b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_error_sml.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_info_sml.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_info_sml.gif
new file mode 100644
index 000000000..c6cb9ad7c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_info_sml.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_success_sml.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_success_sml.gif
new file mode 100644
index 000000000..52e85a430
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_success_sml.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_warning_sml.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_warning_sml.gif
new file mode 100644
index 000000000..873bbb52c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icon_warning_sml.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-down.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-down.png
new file mode 100644
index 000000000..7ced90cd2
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-down.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-left.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-left.png
new file mode 100644
index 000000000..9e37b4128
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-left.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-right.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-right.png
new file mode 100644
index 000000000..00a443dbe
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-right.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-up.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-up.png
new file mode 100644
index 000000000..310c61728
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/arrow-up.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/box.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/box.png
new file mode 100644
index 000000000..4d62e48ec
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/box.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/create.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/create.png
new file mode 100644
index 000000000..24a84bb49
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/create.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/delete.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/delete.gif
new file mode 100644
index 000000000..b6922ac11
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/delete.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/down.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/down.gif
new file mode 100644
index 000000000..9561bbe2a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/down.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/edit.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/edit.png
new file mode 100644
index 000000000..5ea781e6d
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/edit.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-key.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-key.png
new file mode 100644
index 000000000..e66758a83
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-key.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-lock.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-lock.png
new file mode 100644
index 000000000..be4d4da03
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/security-lock.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/up.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/up.gif
new file mode 100644
index 000000000..61942d6d1
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/up.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/user.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/user.png
new file mode 100644
index 000000000..7f4c6d739
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/icons/user.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/jar.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/jar.gif
new file mode 100755
index 000000000..63dcb611a
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/jar.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/mavenplugin.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/mavenplugin.gif
new file mode 100755
index 000000000..4e335e3f2
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/mavenplugin.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/newwindow.png b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/newwindow.png
new file mode 100644
index 000000000..6287f72bd
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/newwindow.png
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/other.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/other.gif
new file mode 100755
index 000000000..9b01e3e2c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/other.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/pom.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/pom.gif
new file mode 100755
index 000000000..b6efdc34c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/pom.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/skin.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/skin.gif
new file mode 100755
index 000000000..64ff878eb
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/skin.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super.gif
new file mode 100644
index 000000000..c8ee24344
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl.gif
new file mode 100644
index 000000000..d90b8f0f8
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl_sub.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl_sub.gif
new file mode 100755
index 000000000..0b35f7a26
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/super_hl_sub.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/supersub.gif b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/supersub.gif
new file mode 100755
index 000000000..3f28dbce5
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/images/supersub.gif
Binary files differ
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/index.jsp b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/index.jsp
new file mode 100644
index 000000000..77a2bd6a9
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/index.jsp
@@ -0,0 +1,20 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+
+<%response.sendRedirect( request.getContextPath() + "/index.action" );%> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/builder.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/builder.js
new file mode 100644
index 000000000..b7466ad83
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/builder.js
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us builder.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// See scriptaculous.js for full license.
+
+var Builder = {
+ NODEMAP: {
+ AREA: 'map',
+ CAPTION: 'table',
+ COL: 'table',
+ COLGROUP: 'table',
+ LEGEND: 'fieldset',
+ OPTGROUP: 'select',
+ OPTION: 'select',
+ PARAM: 'object',
+ TBODY: 'table',
+ TD: 'table',
+ TFOOT: 'table',
+ TH: 'table',
+ THEAD: 'table',
+ TR: 'table'
+ },
+// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+// due to a Firefox bug
+ node: function( elementName )
+ {
+ elementName = elementName.toUpperCase();
+
+ // try innerHTML approach
+ var parentTag = this.NODEMAP[elementName] || 'div';
+ var parentElement = document.createElement(parentTag);
+ try
+ { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+ }
+ catch( e )
+ {
+ }
+ var element = parentElement.firstChild || null;
+
+ // see if browser added wrapping tags
+ if ( element && (element.tagName != elementName) )
+ element = element.getElementsByTagName(elementName)[0];
+
+ // fallback to createElement approach
+ if ( !element ) element = document.createElement(elementName);
+
+ // abort if nothing could be created
+ if ( !element ) return;
+
+ // attributes (or text)
+ if ( arguments[1] )
+ if ( this._isStringOrNumber(arguments[1]) || (arguments[1] instanceof Array) )
+ {
+ this._children(element, arguments[1]);
+ }
+ else
+ {
+ var attrs = this._attributes(arguments[1]);
+ if ( attrs.length )
+ {
+ try
+ { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + " " + attrs + "></" + elementName + ">";
+ }
+ catch( e )
+ {
+ }
+ element = parentElement.firstChild || null;
+ // workaround firefox 1.0.X bug
+ if ( !element )
+ {
+ element = document.createElement(elementName);
+ for ( attr in arguments[1] )
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+ }
+ if ( element.tagName != elementName )
+ element = parentElement.getElementsByTagName(elementName)[0];
+ }
+ }
+
+ // text, or array of children
+ if ( arguments[2] )
+ this._children(element, arguments[2]);
+
+ return element;
+ },
+ _text: function( text )
+ {
+ return document.createTextNode(text);
+ },
+ _attributes: function( attributes )
+ {
+ var attrs = [];
+ for ( attribute in attributes )
+ attrs.push((attribute == 'className' ? 'class' : attribute) + '="' +
+ attributes[attribute].toString().escapeHTML() + '"');
+ return attrs.join(" ");
+ },
+ _children: function( element, children )
+ {
+ if ( typeof children == 'object' )
+ { // array can hold nodes and text
+ children.flatten().each(function( e )
+ {
+ if ( typeof e == 'object' )
+ element.appendChild(e)
+ else
+ if ( Builder._isStringOrNumber(e) )
+ element.appendChild(Builder._text(e));
+ });
+ }
+ else
+ if ( Builder._isStringOrNumber(children) )
+ element.appendChild(Builder._text(children));
+ },
+ _isStringOrNumber: function( param )
+ {
+ return(typeof param == 'string' || typeof param == 'number');
+ },
+ dump: function( scope )
+ {
+ if ( typeof scope != 'object' && typeof scope != 'function' ) scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX " +
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P " +
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD " +
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each(function( tag )
+ {
+ scope[tag] = function()
+ {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/controls.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/controls.js
new file mode 100644
index 000000000..8920d9375
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/controls.js
@@ -0,0 +1,969 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us controls.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// See scriptaculous.js for full license.
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+if ( typeof Effect == 'undefined' )
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = {}
+Autocompleter.Base = function()
+{
+};
+Autocompleter.Base.prototype = {
+ baseInitialize: function( element, update, options )
+ {
+ this.element = $(element);
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+
+ if ( this.setOptions )
+ this.setOptions(options);
+ else
+ this.options = options || {};
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow || function( element, update )
+ {
+ if ( !update.style.position || update.style.position == 'absolute' )
+ {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update, {duration:0.15});
+ };
+ this.options.onHide = this.options.onHide || function( element, update )
+ {
+ new Effect.Fade(update, {duration:0.15})
+ };
+
+ if ( typeof(this.options.tokens) == 'string' )
+ this.options.tokens = new Array(this.options.tokens);
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete', 'off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function()
+ {
+ if ( Element.getStyle(this.update, 'display') == 'none' ) this.options.onShow(this.element, this.update);
+ if ( !this.iefix && (navigator.appVersion.indexOf('MSIE') > 0) && (navigator.userAgent.indexOf('Opera') < 0) &&
+ (Element.getStyle(this.update, 'position') == 'absolute') )
+ {
+ new Insertion.After(this.update, '<iframe id="' + this.update.id + '_iefix" ' +
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id + '_iefix');
+ }
+ if ( this.iefix ) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function()
+ {
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function()
+ {
+ this.stopIndicator();
+ if ( Element.getStyle(this.update, 'display') != 'none' ) this.options.onHide(this.element, this.update);
+ if ( this.iefix ) Element.hide(this.iefix);
+ },
+
+ startIndicator: function()
+ {
+ if ( this.options.indicator ) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function()
+ {
+ if ( this.options.indicator ) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function( event )
+ {
+ if ( this.active )
+ switch ( event.keyCode )
+ {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ if ( navigator.appVersion.indexOf('AppleWebKit') > 0 ) Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ if ( navigator.appVersion.indexOf('AppleWebKit') > 0 ) Event.stop(event);
+ return;
+ }
+ else
+ if ( event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN ||
+ (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0) ) return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if ( this.observer ) clearTimeout(this.observer);
+ this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000);
+ },
+
+ activate: function()
+ {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
+ onHover: function( event )
+ {
+ var element = Event.findElement(event, 'LI');
+ if ( this.index != element.autocompleteIndex )
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function( event )
+ {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function( event )
+ {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function()
+ {
+ if ( this.entryCount > 0 )
+ {
+ for ( var i = 0; i < this.entryCount; i++ )
+ this.index == i ? Element.addClassName(this.getEntry(i), "selected")
+ : Element.removeClassName(this.getEntry(i), "selected");
+
+ if ( this.hasFocus )
+ {
+ this.show();
+ this.active = true;
+ }
+ }
+ else
+ {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function()
+ {
+ if ( this.index > 0 ) this.index--
+ else this.index = this.entryCount - 1;
+ this.getEntry(this.index).scrollIntoView(true);
+ },
+
+ markNext: function()
+ {
+ if ( this.index < this.entryCount - 1 ) this.index++
+ else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
+ },
+
+ getEntry: function( index )
+ {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function()
+ {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function()
+ {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function( selectedElement )
+ {
+ if ( this.options.updateElement )
+ {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+ var value = '';
+ if ( this.options.select )
+ {
+ var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
+ if ( nodes.length > 0 ) value = Element.collectTextNodes(nodes[0], this.options.select);
+ }
+ else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+ var lastTokenPos = this.findLastToken();
+ if ( lastTokenPos != -1 )
+ {
+ var newValue = this.element.value.substr(0, lastTokenPos + 1);
+ var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+ if ( whitespace )
+ newValue += whitespace[0];
+ this.element.value = newValue + value;
+ }
+ else
+ {
+ this.element.value = value;
+ }
+ this.element.focus();
+
+ if ( this.options.afterUpdateElement )
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function( choices )
+ {
+ if ( !this.changed && this.hasFocus )
+ {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.firstChild);
+
+ if ( this.update.firstChild && this.update.firstChild.childNodes )
+ {
+ this.entryCount = this.update.firstChild.childNodes.length;
+ for ( var i = 0; i < this.entryCount; i++ )
+ {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ }
+ else
+ {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if ( this.entryCount == 1 && this.options.autoSelect )
+ {
+ this.selectEntry();
+ this.hide();
+ }
+ else
+ {
+ this.render();
+ }
+ }
+ },
+
+ addObservers: function( element )
+ {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function()
+ {
+ this.changed = false;
+ if ( this.getToken().length >= this.options.minChars )
+ {
+ this.startIndicator();
+ this.getUpdatedChoices();
+ }
+ else
+ {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ getToken: function()
+ {
+ var tokenPos = this.findLastToken();
+ if ( tokenPos != -1 )
+ var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/, '').replace(/\s+$/, '');
+ else
+ var ret = this.element.value;
+
+ return /\n/.test(ret) ? '' : ret;
+ },
+
+ findLastToken: function()
+ {
+ var lastTokenPos = -1;
+
+ for ( var i = 0; i < this.options.tokens.length; i++ )
+ {
+ var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
+ if ( thisTokenPos > lastTokenPos )
+ lastTokenPos = thisTokenPos;
+ }
+ return lastTokenPos;
+ }
+}
+
+Ajax.Autocompleter = Class.create();
+Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
+ initialize: function( element, update, url, options )
+ {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function()
+ {
+ entry = encodeURIComponent(this.options.paramName) + '=' + encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ? this.options.callback(this.element, entry) : entry;
+
+ if ( this.options.defaultParams )
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function( request )
+ {
+ this.updateChoices(request.responseText);
+ }
+
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create();
+Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
+ initialize: function( element, update, array, options )
+ {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function()
+ {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function( options )
+ {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function( instance )
+ {
+ var ret = [];
+ // Beginning matches
+ var partial = [];
+ // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for ( var i = 0; i < instance.options.array.length && ret.length < instance.options.choices; i++ )
+ {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase())
+ : elem.indexOf(entry);
+
+ while ( foundPos != -1 )
+ {
+ if ( foundPos == 0 && elem.length != entry.length )
+ {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ }
+ else if ( entry.length >= instance.options.partialChars && instance.options.partialSearch &&
+ foundPos != -1 )
+ {
+ if ( instance.options.fullSearch || /\s/.test(elem.substr(foundPos - 1, 1)) )
+ {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" +
+ elem.substr(foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos =
+ instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1)
+ : elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if ( partial.length )
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || {});
+ }
+});
+
+// AJAX in-place editor
+//
+// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function( field )
+{
+ setTimeout(function()
+ {
+ Field.activate(field);
+ }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create();
+Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
+Ajax.InPlaceEditor.prototype = {
+ initialize: function( element, url, options )
+ {
+ this.url = url;
+ this.element = $(element);
+
+ this.options = Object.extend({
+ okButton: true,
+ okText: "ok",
+ cancelLink: true,
+ cancelText: "cancel",
+ savingText: "Saving...",
+ clickToEditText: "Click to edit",
+ okText: "ok",
+ rows: 1,
+ onComplete: function( transport, element )
+ {
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
+ },
+ onFailure: function( transport )
+ {
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
+ },
+ callback: function( form )
+ {
+ return Form.serialize(form);
+ },
+ handleLineBreaks: true,
+ loadingText: 'Loading...',
+ savingClassName: 'inplaceeditor-saving',
+ loadingClassName: 'inplaceeditor-loading',
+ formClassName: 'inplaceeditor-form',
+ highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
+ highlightendcolor: "#FFFFFF",
+ externalControl: null,
+ submitOnBlur: false,
+ ajaxOptions: {},
+ evalScripts: false
+ }, options || {});
+
+ if ( !this.options.formId && this.element.id )
+ {
+ this.options.formId = this.element.id + "-inplaceeditor";
+ if ( $(this.options.formId) )
+ {
+ // there's already a form with that name, don't specify an id
+ this.options.formId = null;
+ }
+ }
+
+ if ( this.options.externalControl )
+ {
+ this.options.externalControl = $(this.options.externalControl);
+ }
+
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
+ if ( !this.originalBackground )
+ {
+ this.originalBackground = "transparent";
+ }
+
+ this.element.title = this.options.clickToEditText;
+
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+ this.mouseoverListener = this.enterHover.bindAsEventListener(this);
+ this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
+ Event.observe(this.element, 'click', this.onclickListener);
+ Event.observe(this.element, 'mouseover', this.mouseoverListener);
+ Event.observe(this.element, 'mouseout', this.mouseoutListener);
+ if ( this.options.externalControl )
+ {
+ Event.observe(this.options.externalControl, 'click', this.onclickListener);
+ Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ },
+ enterEditMode: function( evt )
+ {
+ if ( this.saving ) return;
+ if ( this.editing ) return;
+ this.editing = true;
+ this.onEnterEditMode();
+ if ( this.options.externalControl )
+ {
+ Element.hide(this.options.externalControl);
+ }
+ Element.hide(this.element);
+ this.createForm();
+ this.element.parentNode.insertBefore(this.form, this.element);
+ if ( !this.options.loadTextURL ) Field.scrollFreeActivate(this.editField);
+ // stop the event to avoid a page refresh in Safari
+ if ( evt )
+ {
+ Event.stop(evt);
+ }
+ return false;
+ },
+ createForm: function()
+ {
+ this.form = document.createElement("form");
+ this.form.id = this.options.formId;
+ Element.addClassName(this.form, this.options.formClassName)
+ this.form.onsubmit = this.onSubmit.bind(this);
+
+ this.createEditField();
+
+ if ( this.options.textarea )
+ {
+ var br = document.createElement("br");
+ this.form.appendChild(br);
+ }
+
+ if ( this.options.okButton )
+ {
+ okButton = document.createElement("input");
+ okButton.type = "submit";
+ okButton.value = this.options.okText;
+ okButton.className = 'editor_ok_button';
+ this.form.appendChild(okButton);
+ }
+
+ if ( this.options.cancelLink )
+ {
+ cancelLink = document.createElement("a");
+ cancelLink.href = "#";
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+ cancelLink.onclick = this.onclickCancel.bind(this);
+ cancelLink.className = 'editor_cancel';
+ this.form.appendChild(cancelLink);
+ }
+ },
+ hasHTMLLineBreaks: function( string )
+ {
+ if ( !this.options.handleLineBreaks ) return false;
+ return string.match(/<br/i) || string.match(/<p>/i);
+ },
+ convertHTMLLineBreaks: function( string )
+ {
+ return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
+ },
+ createEditField: function()
+ {
+ var text;
+ if ( this.options.loadTextURL )
+ {
+ text = this.options.loadingText;
+ }
+ else
+ {
+ text = this.getText();
+ }
+
+ var obj = this;
+
+ if ( this.options.rows == 1 && !this.hasHTMLLineBreaks(text) )
+ {
+ this.options.textarea = false;
+ var textField = document.createElement("input");
+ textField.obj = this;
+ textField.type = "text";
+ textField.name = "value";
+ textField.value = text;
+ textField.style.backgroundColor = this.options.highlightcolor;
+ textField.className = 'editor_field';
+ var size = this.options.size || this.options.cols || 0;
+ if ( size != 0 ) textField.size = size;
+ if ( this.options.submitOnBlur )
+ textField.onblur = this.onSubmit.bind(this);
+ this.editField = textField;
+ }
+ else
+ {
+ this.options.textarea = true;
+ var textArea = document.createElement("textarea");
+ textArea.obj = this;
+ textArea.name = "value";
+ textArea.value = this.convertHTMLLineBreaks(text);
+ textArea.rows = this.options.rows;
+ textArea.cols = this.options.cols || 40;
+ textArea.className = 'editor_field';
+ if ( this.options.submitOnBlur )
+ textArea.onblur = this.onSubmit.bind(this);
+ this.editField = textArea;
+ }
+
+ if ( this.options.loadTextURL )
+ {
+ this.loadExternalText();
+ }
+ this.form.appendChild(this.editField);
+ },
+ getText: function()
+ {
+ return this.element.innerHTML;
+ },
+ loadExternalText: function()
+ {
+ Element.addClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = true;
+ new Ajax.Request(this.options.loadTextURL, Object.extend({
+ asynchronous: true,
+ onComplete: this.onLoadedExternalText.bind(this)
+ }, this.options.ajaxOptions));
+ },
+ onLoadedExternalText: function( transport )
+ {
+ Element.removeClassName(this.form, this.options.loadingClassName);
+ this.editField.disabled = false;
+ this.editField.value = transport.responseText.stripTags();
+ Field.scrollFreeActivate(this.editField);
+ },
+ onclickCancel: function()
+ {
+ this.onComplete();
+ this.leaveEditMode();
+ return false;
+ },
+ onFailure: function( transport )
+ {
+ this.options.onFailure(transport);
+ if ( this.oldInnerHTML )
+ {
+ this.element.innerHTML = this.oldInnerHTML;
+ this.oldInnerHTML = null;
+ }
+ return false;
+ },
+ onSubmit: function()
+ {
+ // onLoading resets these so we need to save them away for the Ajax call
+ var form = this.form;
+ var value = this.editField.value;
+
+ // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
+ // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
+ // to be displayed indefinitely
+ this.onLoading();
+
+ if ( this.options.evalScripts )
+ {
+ new Ajax.Request(this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this),
+ asynchronous:true,
+ evalScripts:true
+ }, this.options.ajaxOptions));
+ }
+ else
+ {
+ new Ajax.Updater({ success: this.element,
+ // don't update on failure (this could be an option)
+ failure: null }, this.url, Object.extend({
+ parameters: this.options.callback(form, value),
+ onComplete: this.onComplete.bind(this),
+ onFailure: this.onFailure.bind(this)
+ }, this.options.ajaxOptions));
+ }
+ // stop the event to avoid a page refresh in Safari
+ if ( arguments.length > 1 )
+ {
+ Event.stop(arguments[0]);
+ }
+ return false;
+ },
+ onLoading: function()
+ {
+ this.saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ showSaving: function()
+ {
+ this.oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ Element.addClassName(this.element, this.options.savingClassName);
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ },
+ removeForm: function()
+ {
+ if ( this.form )
+ {
+ if ( this.form.parentNode ) Element.remove(this.form);
+ this.form = null;
+ }
+ },
+ enterHover: function()
+ {
+ if ( this.saving ) return;
+ this.element.style.backgroundColor = this.options.highlightcolor;
+ if ( this.effect )
+ {
+ this.effect.cancel();
+ }
+ Element.addClassName(this.element, this.options.hoverClassName)
+ },
+ leaveHover: function()
+ {
+ if ( this.options.backgroundColor )
+ {
+ this.element.style.backgroundColor = this.oldBackground;
+ }
+ Element.removeClassName(this.element, this.options.hoverClassName)
+ if ( this.saving ) return;
+ this.effect = new Effect.Highlight(this.element, {
+ startcolor: this.options.highlightcolor,
+ endcolor: this.options.highlightendcolor,
+ restorecolor: this.originalBackground
+ });
+ },
+ leaveEditMode: function()
+ {
+ Element.removeClassName(this.element, this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this.originalBackground;
+ Element.show(this.element);
+ if ( this.options.externalControl )
+ {
+ Element.show(this.options.externalControl);
+ }
+ this.editing = false;
+ this.saving = false;
+ this.oldInnerHTML = null;
+ this.onLeaveEditMode();
+ },
+ onComplete: function( transport )
+ {
+ this.leaveEditMode();
+ this.options.onComplete.bind(this)(transport, this.element);
+ },
+ onEnterEditMode: function()
+ {
+ },
+ onLeaveEditMode: function()
+ {
+ },
+ dispose: function()
+ {
+ if ( this.oldInnerHTML )
+ {
+ this.element.innerHTML = this.oldInnerHTML;
+ }
+ this.leaveEditMode();
+ Event.stopObserving(this.element, 'click', this.onclickListener);
+ Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+ if ( this.options.externalControl )
+ {
+ Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+ Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+ Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+ }
+ }
+};
+
+Ajax.InPlaceCollectionEditor = Class.create();
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
+ createEditField: function()
+ {
+ if ( !this.cached_selectTag )
+ {
+ var selectTag = document.createElement("select");
+ var collection = this.options.collection || [];
+ var optionTag;
+ collection.each(function( e, i )
+ {
+ optionTag = document.createElement("option");
+ optionTag.value = (e instanceof Array) ? e[0] : e;
+ if ( (typeof this.options.value == 'undefined') &&
+ ((e instanceof Array) ? this.element.innerHTML == e[1] : e ==
+ optionTag.value) ) optionTag.selected =
+ true;
+ if ( this.options.value == optionTag.value ) optionTag.selected = true;
+ optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
+ selectTag.appendChild(optionTag);
+ }.bind(this));
+ this.cached_selectTag = selectTag;
+ }
+
+ this.editField = this.cached_selectTag;
+ if ( this.options.loadTextURL ) this.loadExternalText();
+ this.form.appendChild(this.editField);
+ this.options.callback = function( form, value )
+ {
+ return "value=" + encodeURIComponent(value);
+ }
+ }
+});
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+ initialize: function( element, delay, callback )
+ {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element, 'keyup', this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function( event )
+ {
+ if ( this.lastValue == $F(this.element) ) return;
+ if ( this.timer ) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function()
+ {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+};
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/dragdrop.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/dragdrop.js
new file mode 100644
index 000000000..2f8c0522b
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/dragdrop.js
@@ -0,0 +1,1178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us dragdrop.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
+//
+// See scriptaculous.js for full license.
+
+/*--------------------------------------------------------------------------*/
+
+if ( typeof Effect == 'undefined' )
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+ drops: [],
+
+ remove: function( element )
+ {
+ this.drops = this.drops.reject(function( d )
+ {
+ return d.element == $(element)
+ });
+ },
+
+ add: function( element )
+ {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || {});
+
+ // cache containers
+ if ( options.containment )
+ {
+ options._containers = [];
+ var containment = options.containment;
+ if ( (typeof containment == 'object') && (containment.constructor == Array) )
+ {
+ containment.each(function( c )
+ {
+ options._containers.push($(c))
+ });
+ }
+ else
+ {
+ options._containers.push($(containment));
+ }
+ }
+
+ if ( options.accept ) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element);
+ // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ findDeepestChild: function( drops )
+ {
+ deepest = drops[0];
+
+ for ( i = 1; i < drops.length; ++i )
+ if ( Element.isParent(drops[i].element, deepest.element) )
+ deepest = drops[i];
+
+ return deepest;
+ },
+
+ isContained: function( element, drop )
+ {
+ var containmentNode;
+ if ( drop.tree )
+ {
+ containmentNode = element.treeNode;
+ }
+ else
+ {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function( c )
+ {
+ return containmentNode == c
+ });
+ },
+
+ isAffected: function( point, element, drop )
+ {
+ return (
+ (drop.element != element) && ((!drop._containers) || this.isContained(element, drop)) &&
+ ((!drop.accept) || (Element.classNames(element).detect(function( v )
+ {
+ return drop.accept.include(v)
+ }) )) && Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function( drop )
+ {
+ if ( drop.hoverclass )
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function( drop )
+ {
+ if ( drop.hoverclass )
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function( point, element )
+ {
+ if ( !this.drops.length ) return;
+ var affected = [];
+
+ if ( this.last_active ) this.deactivate(this.last_active);
+ this.drops.each(function( drop )
+ {
+ if ( Droppables.isAffected(point, element, drop) )
+ affected.push(drop);
+ });
+
+ if ( affected.length > 0 )
+ {
+ drop = Droppables.findDeepestChild(affected);
+ Position.within(drop.element, point[0], point[1]);
+ if ( drop.onHover )
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ Droppables.activate(drop);
+ }
+ },
+
+ fire: function( event, element )
+ {
+ if ( !this.last_active ) return;
+ Position.prepare();
+
+ if ( this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active) )
+ if ( this.last_active.onDrop )
+ this.last_active.onDrop(element, this.last_active.element, event);
+ },
+
+ reset: function()
+ {
+ if ( this.last_active )
+ this.deactivate(this.last_active);
+ }
+}
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function( draggable )
+ {
+ if ( this.drags.length == 0 )
+ {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function( draggable )
+ {
+ this.drags = this.drags.reject(function( d )
+ {
+ return d == draggable
+ });
+ if ( this.drags.length == 0 )
+ {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function( draggable )
+ {
+ if ( draggable.options.delay )
+ {
+ this._timeout = setTimeout(function()
+ {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ }
+ else
+ {
+ window.focus();
+ // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
+ },
+
+ deactivate: function()
+ {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function( event )
+ {
+ if ( !this.activeDraggable ) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if ( this._lastPointer && (this._lastPointer.inspect() == pointer.inspect()) ) return;
+ this._lastPointer = pointer;
+
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function( event )
+ {
+ if ( this._timeout )
+ {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if ( !this.activeDraggable ) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function( event )
+ {
+ if ( this.activeDraggable )
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function( observer )
+ {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function( element )
+ { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject(function( o )
+ {
+ return o.element == element
+ });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function( eventName, draggable, event )
+ { // 'onStart', 'onEnd', 'onDrag'
+ if ( this[eventName + 'Count'] > 0 )
+ this.observers.each(function( o )
+ {
+ if ( o[eventName] ) o[eventName](eventName, draggable, event);
+ });
+ if ( draggable.options[eventName] ) draggable.options[eventName](draggable, event);
+ },
+
+ _cacheObserverCallbacks: function()
+ {
+ ['onStart','onEnd','onDrag'].each(function( eventName )
+ {
+ Draggables[eventName + 'Count'] = Draggables.observers.select(function( o )
+ {
+ return o[eventName];
+ }).length;
+ });
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create();
+Draggable._dragging = {};
+
+Draggable.prototype = {
+ initialize: function( element )
+ {
+ var defaults = {
+ handle: false,
+ reverteffect: function( element, top_offset, left_offset )
+ {
+ var dur = Math.sqrt(Math.abs(top_offset ^ 2) + Math.abs(left_offset ^ 2)) * 0.02;
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ },
+ endeffect: function( element )
+ {
+ var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function()
+ {
+ Draggable._dragging[element] = false
+ }
+ });
+ },
+ zindex: 1000,
+ revert: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if ( arguments[1] && typeof arguments[1].endeffect == 'undefined' )
+ Object.extend(defaults, {
+ starteffect: function( element )
+ {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || {});
+
+ this.element = $(element);
+
+ if ( options.handle && (typeof options.handle == 'string') )
+ {
+ var h = Element.childrenWithClassName(this.element, options.handle, true);
+ if ( h.length > 0 ) this.handle = h[0];
+ }
+ if ( !this.handle ) this.handle = $(options.handle);
+ if ( !this.handle ) this.handle = this.element;
+
+ if ( options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML )
+ {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
+
+ Element.makePositioned(this.element);
+ // fix IE
+
+ this.delta = this.currentDelta();
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function()
+ {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function()
+ {
+ return([
+ parseInt(Element.getStyle(this.element, 'left') || '0'),
+ parseInt(Element.getStyle(this.element, 'top') || '0')]);
+ },
+
+ initDrag: function( event )
+ {
+ if ( typeof Draggable._dragging[this.element] != 'undefined' && Draggable._dragging[this.element] ) return;
+ if ( Event.isLeftClick(event) )
+ {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if ( src.tagName && (
+ src.tagName == 'INPUT' || src.tagName == 'SELECT' || src.tagName == 'OPTION' ||
+ src.tagName == 'BUTTON' || src.tagName == 'TEXTAREA') ) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map(function( i )
+ {
+ return (pointer[i] - pos[i])
+ });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function( event )
+ {
+ this.dragging = true;
+
+ if ( this.options.zindex )
+ {
+ this.originalZ = parseInt(Element.getStyle(this.element, 'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if ( this.options.ghosting )
+ {
+ this._clone = this.element.cloneNode(true);
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if ( this.options.scroll )
+ {
+ if ( this.options.scroll == window )
+ {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ }
+ else
+ {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if ( this.options.starteffect ) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function( event, pointer )
+ {
+ if ( !this.dragging ) this.startDrag(event);
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ Draggables.notify('onDrag', this, event);
+
+ this.draw(pointer);
+ if ( this.options.change ) this.options.change(this);
+
+ if ( this.options.scroll )
+ {
+ this.stopScrolling();
+
+ var p;
+ if ( this.options.scroll == window )
+ {
+ with ( this._getWindowScroll(this.options.scroll) )
+ {
+ p = [ left, top, left + width, top + height ];
+ }
+ }
+ else
+ {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft;
+ p[1] += this.options.scroll.scrollTop;
+
+ p[0] += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0);
+ p[1] += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
+
+ p.push(p[0] + this.options.scroll.offsetWidth);
+ p.push(p[1] + this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if ( pointer[0] < (p[0] + this.options.scrollSensitivity) ) speed[0] = pointer[0] - (p[0] +
+ this.options.scrollSensitivity);
+ if ( pointer[1] < (p[1] + this.options.scrollSensitivity) ) speed[1] = pointer[1] - (p[1] +
+ this.options.scrollSensitivity);
+ if ( pointer[0] > (p[2] - this.options.scrollSensitivity) ) speed[0] = pointer[0] - (p[2] -
+ this.options.scrollSensitivity);
+ if ( pointer[1] > (p[3] - this.options.scrollSensitivity) ) speed[1] = pointer[1] - (p[3] -
+ this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if ( navigator.appVersion.indexOf('AppleWebKit') > 0 ) window.scrollBy(0, 0);
+
+ Event.stop(event);
+ },
+
+ finishDrag: function( event, success )
+ {
+ this.dragging = false;
+
+ if ( this.options.ghosting )
+ {
+ Position.relativize(this.element);
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ if ( success ) Droppables.fire(event, this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if ( revert && typeof revert == 'function' ) revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if ( revert && this.options.reverteffect )
+ {
+ this.options.reverteffect(this.element, d[1] - this.delta[1], d[0] - this.delta[0]);
+ }
+ else
+ {
+ this.delta = d;
+ }
+
+ if ( this.options.zindex )
+ this.element.style.zIndex = this.originalZ;
+
+ if ( this.options.endeffect )
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function( event )
+ {
+ if ( event.keyCode != Event.KEY_ESC ) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function( event )
+ {
+ if ( !this.dragging ) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function( point )
+ {
+ var pos = Position.cumulativeOffset(this.element);
+ if ( this.options.ghosting )
+ {
+ var r = Position.realOffset(this.element);
+ window.status = r.inspect();
+ pos[0] += r[0] - Position.deltaX;
+ pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0];
+ pos[1] -= d[1];
+
+ if ( this.options.scroll && (this.options.scroll != window && this._isScrollChild) )
+ {
+ pos[0] -= this.options.scroll.scrollLeft - this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop - this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function( i )
+ {
+ return (point[i] - pos[i] - this.offset[i])
+ }.bind(this));
+
+ if ( this.options.snap )
+ {
+ if ( typeof this.options.snap == 'function' )
+ {
+ p = this.options.snap(p[0], p[1], this);
+ }
+ else
+ {
+ if ( this.options.snap instanceof Array )
+ {
+ p = p.map(function( v, i )
+ {
+ return Math.round(v / this.options.snap[i]) * this.options.snap[i]
+ }.bind(this))
+ }
+ else
+ {
+ p = p.map(function( v )
+ {
+ return Math.round(v / this.options.snap) * this.options.snap
+ }.bind(this))
+ }
+ }
+ }
+
+ var style = this.element.style;
+ if ( (!this.options.constraint) || (this.options.constraint == 'horizontal') )
+ style.left = p[0] + "px";
+ if ( (!this.options.constraint) || (this.options.constraint == 'vertical') )
+ style.top = p[1] + "px";
+
+ if ( style.visibility == "hidden" ) style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function()
+ {
+ if ( this.scrollInterval )
+ {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function( speed )
+ {
+ if ( !(speed[0] || speed[1]) ) return;
+ this.scrollSpeed = [speed[0] * this.options.scrollSpeed,speed[1] * this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function()
+ {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if ( this.options.scroll == window )
+ {
+ with ( this._getWindowScroll(this.options.scroll) )
+ {
+ if ( this.scrollSpeed[0] || this.scrollSpeed[1] )
+ {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo(left + d * this.scrollSpeed[0], top + d * this.scrollSpeed[1]);
+ }
+ }
+ }
+ else
+ {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if ( this._isScrollChild )
+ {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if ( Draggables._lastScrollPointer[0] < 0 )
+ Draggables._lastScrollPointer[0] = 0;
+ if ( Draggables._lastScrollPointer[1] < 0 )
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if ( this.options.change ) this.options.change(this);
+ },
+
+ _getWindowScroll: function( w )
+ {
+ var T, L, W, H;
+ with ( w.document )
+ {
+ if ( w.document.documentElement && documentElement.scrollTop )
+ {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ }
+ else if ( w.document.body )
+ {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if ( w.innerWidth )
+ {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ }
+ else if ( w.document.documentElement && documentElement.clientWidth )
+ {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ }
+ else
+ {
+ W = body.offsetWidth;
+ H = body.offsetHeight
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+ initialize: function( element, observer )
+ {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function()
+ {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function()
+ {
+ Sortable.unmark();
+ if ( this.lastValue != Sortable.serialize(this.element) )
+ this.observer(this.element)
+ }
+}
+
+var Sortable = {
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+
+ sortables: {},
+
+ _findRootElement: function( element )
+ {
+ while ( element.tagName != "BODY" )
+ {
+ if ( element.id && Sortable.sortables[element.id] ) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function( element )
+ {
+ element = Sortable._findRootElement($(element));
+ if ( !element ) return;
+ return Sortable.sortables[element.id];
+ },
+
+ destroy: function( element )
+ {
+ var s = Sortable.options(element);
+
+ if ( s )
+ {
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function( d )
+ {
+ Droppables.remove(d)
+ });
+ s.draggables.invoke('destroy');
+
+ delete Sortable.sortables[s.element.id];
+ }
+ },
+
+ create: function( element )
+ {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false,
+ treeTag: 'ul',
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ delay: 0,
+ hoverclass: null,
+ ghosting: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || {});
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if ( options.starteffect )
+ options_for_draggable.starteffect = options.starteffect;
+
+ if ( options.reverteffect )
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if ( options.ghosting ) options_for_draggable.reverteffect = function( element )
+ {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if ( options.endeffect )
+ options_for_draggable.endeffect = options.endeffect;
+
+ if ( options.zindex )
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ tree: options.tree,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover
+ //greedy: !options.dropOnEmpty
+ }
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
+ }
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if ( options.dropOnEmpty || options.tree )
+ {
+ Droppables.add(element, options_for_tree);
+ options.droppables.push(element);
+ }
+
+ (this.findElements(element, options) || []).each(function( e )
+ {
+ // handles are per-draggable
+ var handle = options.handle ? Element.childrenWithClassName(e, options.handle)[0] : e;
+ options.draggables.push(new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ if ( options.tree ) e.treeNode = element;
+ options.droppables.push(e);
+ });
+
+ if ( options.tree )
+ {
+ (Sortable.findTreeElements(element, options) || []).each(function( e )
+ {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
+
+ // keep reference
+ this.sortables[element.id] = options;
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+// return all suitable-for-sortable elements in a guaranteed order
+ findElements: function( element, options )
+ {
+ return Element.findChildren(element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function( element, options )
+ {
+ return Element.findChildren(element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ onHover: function( element, dropon, overlap )
+ {
+ if ( Element.isParent(dropon, element) ) return;
+
+ if ( overlap > .33 && overlap < .66 && Sortable.options(dropon).tree )
+ {
+ return;
+ }
+ else if ( overlap > 0.5 )
+ {
+ Sortable.mark(dropon, 'before');
+ if ( dropon.previousSibling != element )
+ {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden";
+ // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if ( dropon.parentNode != oldParentNode )
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ else
+ {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if ( nextElement != element )
+ {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden";
+ // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if ( dropon.parentNode != oldParentNode )
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function( element, dropon, overlap )
+ {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if ( !Element.isParent(dropon, element) )
+ {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if ( children )
+ {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for ( index = 0; index < children.length; index += 1 )
+ {
+ if ( offset - Element.offsetSize(children[index], droponOptions.overlap) >= 0 )
+ {
+ offset -= Element.offsetSize(children[index], droponOptions.overlap);
+ }
+ else if ( offset - (Element.offsetSize(children[index], droponOptions.overlap) / 2) >= 0 )
+ {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ }
+ else
+ {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ Sortable.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ unmark: function()
+ {
+ if ( Sortable._marker ) Element.hide(Sortable._marker);
+ },
+
+ mark: function( dropon, position )
+ {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if ( sortable && !sortable.ghosting ) return;
+
+ if ( !Sortable._marker )
+ {
+ Sortable._marker = $('dropmarker') || document.createElement('DIV');
+ Element.hide(Sortable._marker);
+ Element.addClassName(Sortable._marker, 'dropmarker');
+ Sortable._marker.style.position = 'absolute';
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = Position.cumulativeOffset(dropon);
+ Sortable._marker.style.left = offsets[0] + 'px';
+ Sortable._marker.style.top = offsets[1] + 'px';
+
+ if ( position == 'after' )
+ if ( sortable.overlap == 'horizontal' )
+ Sortable._marker.style.left = (offsets[0] + dropon.clientWidth) + 'px';
+ else
+ Sortable._marker.style.top = (offsets[1] + dropon.clientHeight) + 'px';
+
+ Element.show(Sortable._marker);
+ },
+
+ _tree: function( element, options, parent )
+ {
+ var children = Sortable.findElements(element, options) || [];
+
+ for ( var i = 0; i < children.length; ++i )
+ {
+ var match = children[i].id.match(options.format);
+
+ if ( !match ) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: new Array,
+ position: parent.children.length,
+ container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
+ }
+
+ /* Get the element containing the children and recurse over it */
+ if ( child.container )
+ this._tree(child.container, options, child)
+
+ parent.children.push(child);
+ }
+
+ return parent;
+ },
+
+/* Finds the first element of the given tag type within a parent element.
+Used for finding the first LI[ST] within a L[IST]I[TEM].*/
+ _findChildrenElement: function ( element, containerTag )
+ {
+ if ( element && element.hasChildNodes )
+ for ( var i = 0; i < element.childNodes.length; ++i )
+ if ( element.childNodes[i].tagName == containerTag )
+ return element.childNodes[i];
+
+ return null;
+ },
+
+ tree: function( element )
+ {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, arguments[1] || {});
+
+ var root = {
+ id: null,
+ parent: null,
+ children: new Array,
+ container: element,
+ position: 0
+ }
+
+ return Sortable._tree(element, options, root);
+ },
+
+/* Construct a [i] index for a particular node */
+ _constructIndex: function( node )
+ {
+ var index = '';
+ do {
+ if ( node.id ) index = '[' + node.position + ']' + index;
+ }
+ while ( (node = node.parent) != null );
+ return index;
+ },
+
+ sequence: function( element )
+ {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || {});
+
+ return $(this.findElements(element, options) || []).map(function( item )
+ {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function( element, new_sequence )
+ {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || {});
+
+ var nodeMap = {};
+ this.findElements(element, options).each(function( n )
+ {
+ if ( n.id.match(options.format) )
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function( ident )
+ {
+ var n = nodeMap[ident];
+ if ( n )
+ {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function( element )
+ {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || {});
+ var name = encodeURIComponent((arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if ( options.tree )
+ {
+ return Sortable.tree(element, arguments[1]).children.map(function ( item )
+ {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ }
+ else
+ {
+ return Sortable.sequence(element, arguments[1]).map(function( item )
+ {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
+ }
+}
+
+/* Returns true if child is contained within element */
+Element.isParent = function( child, element )
+{
+ if ( !child.parentNode || child == element ) return false;
+
+ if ( child.parentNode == element ) return true;
+
+ return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function( element, only, recursive, tagName )
+{
+ if ( !element.hasChildNodes() ) return null;
+ tagName = tagName.toUpperCase();
+ if ( only ) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each(function( e )
+ {
+ if ( e.tagName && e.tagName.toUpperCase() == tagName && (!only || (Element.classNames(e).detect(function( v )
+ {
+ return only.include(v)
+ }))) )
+ elements.push(e);
+ if ( recursive )
+ {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if ( grandchildren ) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length > 0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function ( element, type )
+{
+ if ( type == 'vertical' || type == 'height' )
+ return element.offsetHeight;
+ else
+ return element.offsetWidth;
+} \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/effects.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/effects.js
new file mode 100644
index 000000000..4b7ffa132
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/effects.js
@@ -0,0 +1,1156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us effects.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// See scriptaculous.js for full license.
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function()
+{
+ var color = '#';
+ if ( this.slice(0, 4) == 'rgb(' )
+ {
+ var cols = this.slice(4, this.length - 1).split(',');
+ var i = 0;
+ do {
+ color += parseInt(cols[i]).toColorPart()
+ }
+ while ( ++i < 3 );
+ }
+ else
+ {
+ if ( this.slice(0, 1) == '#' )
+ {
+ if ( this.length == 4 ) for ( var i = 1; i < 4; i++ ) color +=
+ (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if ( this.length == 7 ) color = this.toLowerCase();
+ }
+ }
+ return(color.length == 7 ? color : (arguments[0] || this));
+}
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function( element )
+{
+ return $A($(element).childNodes).collect(function( node )
+ {
+ return (node.nodeType == 3 ? node.nodeValue : (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+}
+
+Element.collectTextNodesIgnoreClass = function( element, className )
+{
+ return $A($(element).childNodes).collect(function( node )
+ {
+ return (node.nodeType == 3 ? node.nodeValue : ((node.hasChildNodes() && !Element.hasClassName(node, className))
+ ? Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+}
+
+Element.setContentZoom = function( element, percent )
+{
+ element = $(element);
+ Element.setStyle(element, {fontSize: (percent / 100) + 'em'});
+ if ( navigator.appVersion.indexOf('AppleWebKit') > 0 ) window.scrollBy(0, 0);
+}
+
+Element.getOpacity = function( element )
+{
+ var opacity;
+ if ( opacity = Element.getStyle(element, 'opacity') )
+ return parseFloat(opacity);
+ if ( opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/) )
+ if ( opacity[1] ) return parseFloat(opacity[1]) / 100;
+ return 1.0;
+}
+
+Element.setOpacity = function( element, value )
+{
+ element = $(element);
+ if ( value == 1 )
+ {
+ Element.setStyle(element, { opacity:
+ (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999
+ : 1.0 });
+ if ( /MSIE/.test(navigator.userAgent) && !window.opera )
+ Element.setStyle(element, {filter: Element.getStyle(element, 'filter').replace(/alpha\([^\)]*\)/gi, '')});
+ }
+ else
+ {
+ if ( value < 0.00001 ) value = 0;
+ Element.setStyle(element, {opacity: value});
+ if ( /MSIE/.test(navigator.userAgent) && !window.opera )
+ Element.setStyle(element, { filter: Element.getStyle(element, 'filter').replace(/alpha\([^\)]*\)/gi, '') +
+ 'alpha(opacity=' + value * 100 + ')' });
+ }
+}
+
+Element.getInlineOpacity = function( element )
+{
+ return $(element).style.opacity || '';
+}
+
+Element.childrenWithClassName = function( element, className, findFirst )
+{
+ var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
+ var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select'](function( c )
+ {
+ return (c.className && c.className.match(classNameRegExp));
+ });
+ if ( !results ) results = [];
+ return results;
+}
+
+Element.forceRerendering = function( element )
+{
+ try
+ {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ }
+ catch( e )
+ {
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Array.prototype.call = function()
+{
+ var args = arguments;
+ this.each(function( f )
+ {
+ f.apply(this, args)
+ });
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ tagifyText: function( element )
+ {
+ if ( typeof Builder == 'undefined' )
+ throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
+
+ var tagifyStyle = 'position:relative';
+ if ( /MSIE/.test(navigator.userAgent) && !window.opera ) tagifyStyle += ';zoom:1';
+ element = $(element);
+ $A(element.childNodes).each(function( child )
+ {
+ if ( child.nodeType == 3 )
+ {
+ child.nodeValue.toArray().each(function( character )
+ {
+ element.insertBefore(Builder.node('span', {style: tagifyStyle}, character == ' '
+ ? String.fromCharCode(160) : character), child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function( element, effect )
+ {
+ var elements;
+ if ( ((typeof element == 'object') || (typeof element == 'function')) && (element.length) )
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || {});
+ var masterDelay = options.delay;
+
+ $A(elements).each(function( element, index )
+ {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function( element, effect )
+ {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+ var options = Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || {});
+ Effect[element.visible() ? Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+ }
+};
+
+var Effect2 = Effect;
+// deprecated
+
+/* ------------- transitions ------------- */
+
+Effect.Transitions = {}
+
+Effect.Transitions.linear = Prototype.K;
+
+Effect.Transitions.sinoidal = function( pos )
+{
+ return (-Math.cos(pos * Math.PI) / 2) + 0.5;
+}
+Effect.Transitions.reverse = function( pos )
+{
+ return 1 - pos;
+}
+Effect.Transitions.flicker = function( pos )
+{
+ return ((-Math.cos(pos * Math.PI) / 4) + 0.75) + Math.random() / 4;
+}
+Effect.Transitions.wobble = function( pos )
+{
+ return (-Math.cos(pos * Math.PI * (9 * pos)) / 2) + 0.5;
+}
+Effect.Transitions.pulse = function( pos )
+{
+ return (Math.floor(pos * 10) % 2 == 0 ? (pos * 10 - Math.floor(pos * 10)) : 1 - (pos * 10 - Math.floor(pos * 10)));
+}
+Effect.Transitions.none = function( pos )
+{
+ return 0;
+}
+Effect.Transitions.full = function( pos )
+{
+ return 1;
+}
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create();
+Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
+ initialize: function()
+ {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function( iterator )
+ {
+ this.effects._each(iterator);
+ },
+ add: function( effect )
+ {
+ var timestamp = new Date().getTime();
+
+ var position = (typeof effect.options.queue == 'string') ? effect.options.queue : effect.options.queue.position;
+
+ switch ( position )
+ {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function( e )
+ {
+ return e.state == 'idle'
+ }).each(function( e )
+ {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if ( !effect.options.queue.limit || (this.effects.length < effect.options.queue.limit) )
+ this.effects.push(effect);
+
+ if ( !this.interval )
+ this.interval = setInterval(this.loop.bind(this), 40);
+ },
+ remove: function( effect )
+ {
+ this.effects = this.effects.reject(function( e )
+ {
+ return e == effect
+ });
+ if ( this.effects.length == 0 )
+ {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function()
+ {
+ var timePos = new Date().getTime();
+ this.effects.invoke('loop', timePos);
+ }
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function( queueName )
+ {
+ if ( typeof queueName != 'string' ) return queueName;
+
+ if ( !this.instances[queueName] )
+ this.instances[queueName] = new Effect.ScopedQueue();
+
+ return this.instances[queueName];
+ }
+}
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.DefaultOptions = {
+ transition: Effect.Transitions.sinoidal,
+ duration: 1.0, // seconds
+ fps: 25.0, // max. 25fps due to Effect.Queue implementation
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+}
+
+Effect.Base = function()
+{
+};
+Effect.Base.prototype = {
+ position: null,
+ start: function( options )
+ {
+ this.options = Object.extend(Object.extend({}, Effect.DefaultOptions), options || {});
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay * 1000;
+ this.finishOn = this.startOn + (this.options.duration * 1000);
+ this.event('beforeStart');
+ if ( !this.options.sync )
+ Effect.Queues.get(typeof this.options.queue == 'string' ? 'global' : this.options.queue.scope).add(this);
+ },
+ loop: function( timePos )
+ {
+ if ( timePos >= this.startOn )
+ {
+ if ( timePos >= this.finishOn )
+ {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if ( this.finish ) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
+ var frame = Math.round(pos * this.options.fps * this.options.duration);
+ if ( frame > this.currentFrame )
+ {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ render: function( pos )
+ {
+ if ( this.state == 'idle' )
+ {
+ this.state = 'running';
+ this.event('beforeSetup');
+ if ( this.setup ) this.setup();
+ this.event('afterSetup');
+ }
+ if ( this.state == 'running' )
+ {
+ if ( this.options.transition ) pos = this.options.transition(pos);
+ pos *= (this.options.to - this.options.from);
+ pos += this.options.from;
+ this.position = pos;
+ this.event('beforeUpdate');
+ if ( this.update ) this.update(pos);
+ this.event('afterUpdate');
+ }
+ },
+ cancel: function()
+ {
+ if ( !this.options.sync )
+ Effect.Queues.get(typeof this.options.queue == 'string' ? 'global' : this.options.queue.scope).remove(this);
+ this.state = 'finished';
+ },
+ event: function( eventName )
+ {
+ if ( this.options[eventName + 'Internal'] ) this.options[eventName + 'Internal'](this);
+ if ( this.options[eventName] ) this.options[eventName](this);
+ },
+ inspect: function()
+ {
+ return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+}
+
+Effect.Parallel = Class.create();
+Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
+ initialize: function( effects )
+ {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function( position )
+ {
+ this.effects.invoke('render', position);
+ },
+ finish: function( position )
+ {
+ this.effects.each(function( effect )
+ {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if ( effect.finish ) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Opacity = Class.create();
+Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
+ initialize: function( element )
+ {
+ this.element = $(element);
+ if ( !this.element ) throw(Effect._elementDoesNotExistError);
+ // make this work on IE on elements without 'layout'
+ if ( /MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout) )
+ this.element.setStyle({zoom: 1});
+ var options = Object.extend({
+ from: this.element.getOpacity() || 0.0,
+ to: 1.0
+ }, arguments[1] || {});
+ this.start(options);
+ },
+ update: function( position )
+ {
+ this.element.setOpacity(position);
+ }
+});
+
+Effect.Move = Class.create();
+Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
+ initialize: function( element )
+ {
+ this.element = $(element);
+ if ( !this.element ) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || {});
+ this.start(options);
+ },
+ setup: function()
+ {
+ // Bug in Opera: Opera returns the "real" position of a static element or
+ // relative element that does not have top/left explicitly set.
+ // ==> Always set top and left for position relative elements in your stylesheets
+ // (to 0 if you do not need them)
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if ( this.options.mode == 'absolute' )
+ {
+ // absolute movement, so we need to calc deltaX and deltaY
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
+ },
+ update: function( position )
+ {
+ this.element.setStyle({
+ left: Math.round(this.options.x * position + this.originalLeft) + 'px',
+ top: Math.round(this.options.y * position + this.originalTop) + 'px'
+ });
+ }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function( element, toTop, toLeft )
+{
+ return new Effect.Move(element, Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
+};
+
+Effect.Scale = Class.create();
+Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
+ initialize: function( element, percent )
+ {
+ this.element = $(element);
+ if ( !this.element ) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or {} with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || {});
+ this.start(options);
+ },
+ setup: function()
+ {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = this.element.getStyle('position');
+
+ this.originalStyle = {};
+ ['top','left','width','height','fontSize'].each(function( k )
+ {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each(function( fontSizeType )
+ {
+ if ( fontSize.indexOf(fontSizeType) > 0 )
+ {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom) / 100;
+
+ this.dims = null;
+ if ( this.options.scaleMode == 'box' )
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if ( /^content/.test(this.options.scaleMode) )
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if ( !this.dims )
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function( position )
+ {
+ var currentScale = (this.options.scaleFrom / 100.0) + (this.factor * position);
+ if ( this.options.scaleContent && this.fontSize )
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function( position )
+ {
+ if ( this.restoreAfterFinish ) this.element.setStyle(this.originalStyle);
+ },
+ setDimensions: function( height, width )
+ {
+ var d = {};
+ if ( this.options.scaleX ) d.width = Math.round(width) + 'px';
+ if ( this.options.scaleY ) d.height = Math.round(height) + 'px';
+ if ( this.options.scaleFromCenter )
+ {
+ var topd = (height - this.dims[0]) / 2;
+ var leftd = (width - this.dims[1]) / 2;
+ if ( this.elementPositioning == 'absolute' )
+ {
+ if ( this.options.scaleY ) d.top = this.originalTop - topd + 'px';
+ if ( this.options.scaleX ) d.left = this.originalLeft - leftd + 'px';
+ }
+ else
+ {
+ if ( this.options.scaleY ) d.top = -topd + 'px';
+ if ( this.options.scaleX ) d.left = -leftd + 'px';
+ }
+ }
+ this.element.setStyle(d);
+ }
+});
+
+Effect.Highlight = Class.create();
+Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
+ initialize: function( element )
+ {
+ this.element = $(element);
+ if ( !this.element ) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
+ this.start(options);
+ },
+ setup: function()
+ {
+ // Prevent executing on elements not in the layout flow
+ if ( this.element.getStyle('display') == 'none' )
+ {
+ this.cancel();
+ return;
+ }
+ // Disable background image during the effect
+ this.oldStyle = {
+ backgroundImage: this.element.getStyle('background-image') };
+ this.element.setStyle({backgroundImage: 'none'});
+ if ( !this.options.endcolor )
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if ( !this.options.restorecolor )
+ this.options.restorecolor = this.element.getStyle('background-color');
+ // init color calculations
+ this._base = $R(0, 2).map(function( i )
+ {
+ return parseInt(this.options.startcolor.slice(i * 2 + 1, i * 2 + 3), 16)
+ }.bind(this));
+ this._delta = $R(0, 2).map(function( i )
+ {
+ return parseInt(this.options.endcolor.slice(i * 2 + 1, i * 2 + 3), 16) - this._base[i]
+ }.bind(this));
+ },
+ update: function( position )
+ {
+ this.element.setStyle({backgroundColor: $R(0, 2).inject('#', function( m, v, i )
+ {
+ return m + (Math.round(this._base[i] + (this._delta[i] * position)).toColorPart());
+ }.bind(this)) });
+ },
+ finish: function()
+ {
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = Class.create();
+Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
+ initialize: function( element )
+ {
+ this.element = $(element);
+ this.start(arguments[1] || {});
+ },
+ setup: function()
+ {
+ Position.prepare();
+ var offsets = Position.cumulativeOffset(this.element);
+ if ( this.options.offset ) offsets[1] += this.options.offset;
+ var max = window.innerHeight ? window.height - window.innerHeight : document.body.scrollHeight -
+ (document.documentElement.clientHeight
+ ? document.documentElement.clientHeight
+ : document.body.clientHeight);
+ this.scrollStart = Position.deltaY;
+ this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
+ },
+ update: function( position )
+ {
+ Position.prepare();
+ window.scrollTo(Position.deltaX, this.scrollStart + (position * this.delta));
+ }
+});
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function( element )
+{
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ var options = Object.extend({
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function( effect )
+ {
+ if ( effect.options.to != 0 ) return;
+ effect.element.hide();
+ effect.element.setStyle({opacity: oldOpacity});
+ }}, arguments[1] || {});
+ return new Effect.Opacity(element, options);
+}
+
+Effect.Appear = function( element )
+{
+ element = $(element);
+ var options = Object.extend({
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function( effect )
+ {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function( effect )
+ {
+ effect.element.setOpacity(effect.options.from);
+ effect.element.show();
+ }}, arguments[1] || {});
+ return new Effect.Opacity(element, options);
+}
+
+Effect.Puff = function( element )
+{
+ element = $(element);
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ return new Effect.Parallel([ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ], Object.extend({ duration: 1.0,
+ beforeSetupInternal: function( effect )
+ {
+ Position.absolutize(effect.effects[0].element)
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.effects[0].element.hide();
+ effect.effects[0].element.setStyle(oldStyle);
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.BlindUp = function( element )
+{
+ element = $(element);
+ element.makeClipping();
+ return new Effect.Scale(element, 0, Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function( effect )
+ {
+ effect.element.hide();
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.BlindDown = function( element )
+{
+ element = $(element);
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function( effect )
+ {
+ effect.element.makeClipping();
+ effect.element.setStyle({height: '0px'});
+ effect.element.show();
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.SwitchOff = function( element )
+{
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function( effect )
+ {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function( effect )
+ {
+ effect.element.makePositioned();
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.undoPositioned();
+ effect.element.setStyle({opacity: oldOpacity});
+ }
+ })
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.DropOut = function( element )
+{
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
+ return new Effect.Parallel([ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ], Object.extend({ duration: 0.5,
+ beforeSetup: function( effect )
+ {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.effects[0].element.hide();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle);
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.Shake = function( element )
+{
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element, { x: 20, y: 0, duration: 0.05, afterFinishInternal: function( effect )
+ {
+ new Effect.Move(effect.element, { x: -40, y: 0, duration: 0.1, afterFinishInternal: function( effect )
+ {
+ new Effect.Move(effect.element, { x: 40, y: 0, duration: 0.1, afterFinishInternal: function( effect )
+ {
+ new Effect.Move(effect.element, { x: -40, y: 0, duration: 0.1, afterFinishInternal: function( effect )
+ {
+ new Effect.Move(effect.element, { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(
+ effect )
+ {
+ new Effect.Move(effect.element, { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(
+ effect )
+ {
+ effect.element.undoPositioned();
+ effect.element.setStyle(oldStyle);
+ }})
+ }})
+ }})
+ }})
+ }})
+ }});
+}
+
+Effect.SlideDown = function( element )
+{
+ element = $(element);
+ element.cleanWhitespace();
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = $(element.firstChild).getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: window.opera ? 0 : 1,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function( effect )
+ {
+ effect.element.makePositioned();
+ effect.element.firstChild.makePositioned();
+ if ( window.opera ) effect.element.setStyle({top: ''});
+ effect.element.makeClipping();
+ effect.element.setStyle({height: '0px'});
+ effect.element.show();
+ },
+ afterUpdateInternal: function( effect )
+ {
+ effect.element.firstChild.setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.element.undoClipping();
+ // IE will crash if child is undoPositioned first
+ if ( /MSIE/.test(navigator.userAgent) && !window.opera )
+ {
+ effect.element.undoPositioned();
+ effect.element.firstChild.undoPositioned();
+ }
+ else
+ {
+ effect.element.firstChild.undoPositioned();
+ effect.element.undoPositioned();
+ }
+ effect.element.firstChild.setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || {}));
+}
+
+Effect.SlideUp = function( element )
+{
+ element = $(element);
+ element.cleanWhitespace();
+ var oldInnerBottom = $(element.firstChild).getStyle('bottom');
+ return new Effect.Scale(element, window.opera ? 0 : 1, Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ restoreAfterFinish: true,
+ beforeStartInternal: function( effect )
+ {
+ effect.element.makePositioned();
+ effect.element.firstChild.makePositioned();
+ if ( window.opera ) effect.element.setStyle({top: ''});
+ effect.element.makeClipping();
+ effect.element.show();
+ },
+ afterUpdateInternal: function( effect )
+ {
+ effect.element.firstChild.setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.firstChild.undoPositioned();
+ effect.element.undoPositioned();
+ effect.element.setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || {}));
+}
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function( element )
+{
+ return new Effect.Scale(element, window.opera ? 1 : 0, { restoreAfterFinish: true,
+ beforeSetup: function( effect )
+ {
+ effect.element.makeClipping(effect.element);
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.element.hide(effect.element);
+ effect.element.undoClipping(effect.element);
+ }
+ });
+}
+
+Effect.Grow = function( element )
+{
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch ( options.direction )
+ {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetup: function( effect )
+ {
+ effect.element.hide();
+ effect.element.makeClipping();
+ effect.element.makePositioned();
+ },
+ afterFinishInternal: function( effect )
+ {
+ new Effect.Parallel([ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1
+ : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function( effect )
+ {
+ effect.effects[0].element.setStyle({height: '0px'});
+ effect.effects[0].element.show();
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.effects[0].element.undoClipping();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle);
+ }
+ }, options))
+ }
+ });
+}
+
+Effect.Shrink = function( element )
+{
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || {});
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var moveX, moveY;
+
+ switch ( options.direction )
+ {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel([ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1
+ : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function( effect )
+ {
+ effect.effects[0].element.makePositioned();
+ effect.effects[0].element.makeClipping();
+ },
+ afterFinishInternal: function( effect )
+ {
+ effect.effects[0].element.hide();
+ effect.effects[0].element.undoClipping();
+ effect.effects[0].element.undoPositioned();
+ effect.effects[0].element.setStyle(oldStyle);
+ }
+ }, options));
+}
+
+Effect.Pulsate = function( element )
+{
+ element = $(element);
+ var options = arguments[1] || {};
+ var oldOpacity = element.getInlineOpacity();
+ var transition = options.transition || Effect.Transitions.sinoidal;
+ var reverser = function( pos )
+ {
+ return transition(1 - Effect.Transitions.pulse(pos))
+ };
+ reverser.bind(transition);
+ return new Effect.Opacity(element, Object.extend(Object.extend({ duration: 3.0, from: 0,
+ afterFinishInternal: function( effect )
+ {
+ effect.element.setStyle({opacity: oldOpacity});
+ }
+ }, options), {transition: reverser}));
+}
+
+Effect.Fold = function( element )
+{
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ Element.makeClipping(element);
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function( effect )
+ {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function( effect )
+ {
+ effect.element.hide();
+ effect.element.undoClipping();
+ effect.element.setStyle(oldStyle);
+ } });
+ }}, arguments[1] || {}));
+};
+
+['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
+ 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(function( f )
+{
+ Element.Methods[f] = Element[f];
+});
+
+Element.Methods.visualEffect = function( element, effect, options )
+{
+ s = effect.gsub(/_/, '-').camelize();
+ effect_class = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[effect_class](element, options);
+ return $(element);
+};
+
+Element.addMethods(); \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/prototype.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/prototype.js
new file mode 100644
index 000000000..3131da7ff
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/prototype.js
@@ -0,0 +1,2696 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/* Prototype JavaScript framework, version 1.5.0_rc1
+ * (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.5.0_rc1',
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+
+ emptyFunction: function()
+ {
+ },
+ K: function( x )
+ {
+ return x
+ }
+}
+
+var Class = {
+ create: function()
+ {
+ return function()
+ {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function( destination, source )
+{
+ for ( var property in source )
+ {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.extend(Object, {
+ inspect: function( object )
+ {
+ try
+ {
+ if ( object == undefined ) return 'undefined';
+ if ( object == null ) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ }
+ catch ( e )
+ {
+ if ( e instanceof RangeError ) return '...';
+ throw e;
+ }
+ },
+
+ keys: function( object )
+ {
+ var keys = [];
+ for ( var property in object )
+ keys.push(property);
+ return keys;
+ },
+
+ values: function( object )
+ {
+ var values = [];
+ for ( var property in object )
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function( object )
+ {
+ return Object.extend({}, object);
+ }
+});
+
+Function.prototype.bind = function()
+{
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function()
+ {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function( object )
+{
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function( event )
+ {
+ return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function()
+ {
+ var digits = this.toString(16);
+ if ( this < 16 ) return '0' + digits;
+ return digits;
+ },
+
+ succ: function()
+ {
+ return this + 1;
+ },
+
+ times: function( iterator )
+ {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function()
+ {
+ var returnValue;
+
+ for ( var i = 0; i < arguments.length; i++ )
+ {
+ var lambda = arguments[i];
+ try
+ {
+ returnValue = lambda();
+ break;
+ }
+ catch ( e )
+ {
+ }
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ initialize: function( callback, frequency )
+ {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function()
+ {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ stop: function()
+ {
+ if ( !this.timer ) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function()
+ {
+ if ( !this.currentlyExecuting )
+ {
+ try
+ {
+ this.currentlyExecuting = true;
+ this.callback(this);
+ }
+ finally
+ {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+Object.extend(String.prototype, {
+ gsub: function( pattern, replacement )
+ {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while ( source.length > 0 )
+ {
+ if ( match = source.match(pattern) )
+ {
+ result += source.slice(0, match.index);
+ result += (replacement(match) || '').toString();
+ source = source.slice(match.index + match[0].length);
+ }
+ else
+ {
+ result += source,source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function( pattern, replacement, count )
+ {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = count === undefined ? 1 : count;
+
+ return this.gsub(pattern, function( match )
+ {
+ if ( --count < 0 ) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function( pattern, iterator )
+ {
+ this.gsub(pattern, iterator);
+ return this;
+ },
+
+ truncate: function( length, truncation )
+ {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ? this.slice(0, length - truncation.length) + truncation : this;
+ },
+
+ strip: function()
+ {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function()
+ {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function()
+ {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function()
+ {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function( scriptTag )
+ {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function()
+ {
+ return this.extractScripts().map(function( script )
+ {
+ return eval(script)
+ });
+ },
+
+ escapeHTML: function()
+ {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function()
+ {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function()
+ {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function( params, pairString )
+ {
+ var pair = pairString.split('=');
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+ params[decodeURIComponent(pair[0])] = value;
+ return params;
+ });
+ },
+
+ toArray: function()
+ {
+ return this.split('');
+ },
+
+ camelize: function()
+ {
+ var oStringList = this.split('-');
+ if ( oStringList.length == 1 ) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0 ? oStringList[0].charAt(0).toUpperCase() +
+ oStringList[0].substring(1) : oStringList[0];
+
+ for ( var i = 1, len = oStringList.length; i < len; i++ )
+ {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function( useDoubleQuotes )
+ {
+ var escapedString = this.replace(/\\/g, '\\\\');
+ if ( useDoubleQuotes )
+ return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ else
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function( replacement )
+{
+ if ( typeof replacement == 'function' ) return replacement;
+ var template = new Template(replacement);
+ return function( match )
+ {
+ return template.evaluate(match)
+ };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function( template, pattern )
+ {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function( object )
+ {
+ return this.template.gsub(this.pattern, function( match )
+ {
+ var before = match[1];
+ if ( before == '\\' ) return match[2];
+ return before + (object[match[3]] || '').toString();
+ });
+ }
+}
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function( iterator )
+ {
+ var index = 0;
+ try
+ {
+ this._each(function( value )
+ {
+ try
+ {
+ iterator(value, index++);
+ }
+ catch ( e )
+ {
+ if ( e != $continue ) throw e;
+ }
+ });
+ }
+ catch ( e )
+ {
+ if ( e != $break ) throw e;
+ }
+ },
+
+ all: function( iterator )
+ {
+ var result = true;
+ this.each(function( value, index )
+ {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if ( !result ) throw $break;
+ });
+ return result;
+ },
+
+ any: function( iterator )
+ {
+ var result = false;
+ this.each(function( value, index )
+ {
+ if ( result = !!(iterator || Prototype.K)(value, index) )
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function( iterator )
+ {
+ var results = [];
+ this.each(function( value, index )
+ {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function ( iterator )
+ {
+ var result;
+ this.each(function( value, index )
+ {
+ if ( iterator(value, index) )
+ {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function( iterator )
+ {
+ var results = [];
+ this.each(function( value, index )
+ {
+ if ( iterator(value, index) )
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function( pattern, iterator )
+ {
+ var results = [];
+ this.each(function( value, index )
+ {
+ var stringValue = value.toString();
+ if ( stringValue.match(pattern) )
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function( object )
+ {
+ var found = false;
+ this.each(function( value )
+ {
+ if ( value == object )
+ {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function( memo, iterator )
+ {
+ this.each(function( value, index )
+ {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function( method )
+ {
+ var args = $A(arguments).slice(1);
+ return this.collect(function( value )
+ {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function( iterator )
+ {
+ var result;
+ this.each(function( value, index )
+ {
+ value = (iterator || Prototype.K)(value, index);
+ if ( result == undefined || value >= result )
+ result = value;
+ });
+ return result;
+ },
+
+ min: function( iterator )
+ {
+ var result;
+ this.each(function( value, index )
+ {
+ value = (iterator || Prototype.K)(value, index);
+ if ( result == undefined || value < result )
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function( iterator )
+ {
+ var trues = [], falses = [];
+ this.each(function( value, index )
+ {
+ ((iterator || Prototype.K)(value, index) ? trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function( property )
+ {
+ var results = [];
+ this.each(function( value, index )
+ {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function( iterator )
+ {
+ var results = [];
+ this.each(function( value, index )
+ {
+ if ( !iterator(value, index) )
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function( iterator )
+ {
+ return this.collect(function( value, index )
+ {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function( left, right )
+ {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function()
+ {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function()
+ {
+ var iterator = Prototype.K, args = $A(arguments);
+ if ( typeof args.last() == 'function' )
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function( value, index )
+ {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ inspect: function()
+ {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function( iterable )
+{
+ if ( !iterable ) return [];
+ if ( iterable.toArray )
+ {
+ return iterable.toArray();
+ }
+ else
+ {
+ var results = [];
+ for ( var i = 0; i < iterable.length; i++ )
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if ( !Array.prototype._reverse )
+ Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function( iterator )
+ {
+ for ( var i = 0; i < this.length; i++ )
+ iterator(this[i]);
+ },
+
+ clear: function()
+ {
+ this.length = 0;
+ return this;
+ },
+
+ first: function()
+ {
+ return this[0];
+ },
+
+ last: function()
+ {
+ return this[this.length - 1];
+ },
+
+ compact: function()
+ {
+ return this.select(function( value )
+ {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function()
+ {
+ return this.inject([], function( array, value )
+ {
+ return array.concat(value && value.constructor == Array ? value.flatten() : [value]);
+ });
+ },
+
+ without: function()
+ {
+ var values = $A(arguments);
+ return this.select(function( value )
+ {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function( object )
+ {
+ for ( var i = 0; i < this.length; i++ )
+ if ( this[i] == object ) return i;
+ return -1;
+ },
+
+ reverse: function( inline )
+ {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function()
+ {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function()
+ {
+ return this.inject([], function( array, value )
+ {
+ return array.include(value) ? array : array.concat([value]);
+ });
+ },
+
+ inspect: function()
+ {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function( iterator )
+ {
+ for ( var key in this )
+ {
+ var value = this[key];
+ if ( typeof value == 'function' ) continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function()
+ {
+ return this.pluck('key');
+ },
+
+ values: function()
+ {
+ return this.pluck('value');
+ },
+
+ merge: function( hash )
+ {
+ return $H(hash).inject($H(this), function( mergedHash, pair )
+ {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function()
+ {
+ return this.map(function( pair )
+ {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function()
+ {
+ return '#<Hash:{' + this.map(function( pair )
+ {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+}
+
+function $H( object )
+{
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function( start, end, exclusive )
+ {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function( iterator )
+ {
+ var value = this.start;
+ while ( this.include(value) )
+ {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function( value )
+ {
+ if ( value < this.start )
+ return false;
+ if ( this.exclusive )
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function( start, end, exclusive )
+{
+ return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+ getTransport: function()
+ {
+ return Try.these(function()
+ {
+ return new XMLHttpRequest()
+ }, function()
+ {
+ return new ActiveXObject('Msxml2.XMLHTTP')
+ }, function()
+ {
+ return new ActiveXObject('Microsoft.XMLHTTP')
+ }) || false;
+ },
+
+ activeRequestCount: 0
+}
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function( iterator )
+ {
+ this.responders._each(iterator);
+ },
+
+ register: function( responderToAdd )
+ {
+ if ( !this.include(responderToAdd) )
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function( responderToRemove )
+ {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function( callback, request, transport, json )
+ {
+ this.each(function( responder )
+ {
+ if ( responder[callback] && typeof responder[callback] == 'function' )
+ {
+ try
+ {
+ responder[callback].apply(responder, [request, transport, json]);
+ }
+ catch ( e )
+ {
+ }
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function()
+ {
+ Ajax.activeRequestCount++;
+ },
+
+ onComplete: function()
+ {
+ Ajax.activeRequestCount--;
+ }
+});
+
+Ajax.Base = function()
+{
+};
+Ajax.Base.prototype = {
+ setOptions: function( options )
+ {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ responseIsSuccess: function()
+ {
+ return this.transport.status == undefined || this.transport.status == 0 ||
+ (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ responseIsFailure: function()
+ {
+ return !this.responseIsSuccess();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function( url, options )
+ {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function( url )
+ {
+ var parameters = this.options.parameters || '';
+ if ( parameters.length > 0 ) parameters += '&_=';
+
+ /* Simulate other verbs over post */
+ if ( this.options.method != 'get' && this.options.method != 'post' )
+ {
+ parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
+ this.options.method = 'post';
+ }
+
+ try
+ {
+ this.url = url;
+ if ( this.options.method == 'get' && parameters.length > 0 )
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url, this.options.asynchronous);
+
+ if ( this.options.asynchronous )
+ setTimeout(function()
+ {
+ this.respondToReadyState(1)
+ }.bind(this), 10);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ var body = this.options.postBody ? this.options.postBody : parameters;
+ this.transport.send(this.options.method == 'post' ? body : null);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if ( !this.options.asynchronous && this.transport.overrideMimeType )
+ this.onStateChange();
+
+ }
+ catch ( e )
+ {
+ this.dispatchException(e);
+ }
+ },
+
+ setRequestHeaders: function()
+ {
+ var requestHeaders = ['X-Requested-With', 'XMLHttpRequest',
+ 'X-Prototype-Version', Prototype.Version,
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
+
+ if ( this.options.method == 'post' )
+ {
+ requestHeaders.push('Content-type', this.options.contentType);
+
+ /* Force "Connection: close" for Mozilla browsers to work around
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
+ * header. See Mozilla Bugzilla #246651.
+ */
+ if ( this.transport.overrideMimeType )
+ requestHeaders.push('Connection', 'close');
+ }
+
+ if ( this.options.requestHeaders )
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+ for ( var i = 0; i < requestHeaders.length; i += 2 )
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i + 1]);
+ },
+
+ onStateChange: function()
+ {
+ var readyState = this.transport.readyState;
+ if ( readyState != 1 )
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ header: function( name )
+ {
+ try
+ {
+ return this.transport.getResponseHeader(name);
+ }
+ catch ( e )
+ {
+ }
+ },
+
+ evalJSON: function()
+ {
+ try
+ {
+ return eval('(' + this.header('X-JSON') + ')');
+ }
+ catch ( e )
+ {
+ }
+ },
+
+ evalResponse: function()
+ {
+ try
+ {
+ return eval(this.transport.responseText);
+ }
+ catch ( e )
+ {
+ this.dispatchException(e);
+ }
+ },
+
+ respondToReadyState: function( readyState )
+ {
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if ( event == 'Complete' )
+ {
+ try
+ {
+ (this.options['on' + this.transport.status] ||
+ this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] ||
+ Prototype.emptyFunction)(transport, json);
+ }
+ catch ( e )
+ {
+ this.dispatchException(e);
+ }
+
+ if ( (this.header('Content-type') || '').match(/^text\/javascript/i) )
+ this.evalResponse();
+ }
+
+ try
+ {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ }
+ catch ( e )
+ {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if ( event == 'Complete' )
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function( exception )
+ {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function( container, url, options )
+ {
+ this.containers = {
+ success: container.success ? $(container.success) : $(container),
+ failure: container.failure ? $(container.failure) : (container.success ? null : $(container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function( transport, object )
+ {
+ this.updateContent();
+ onComplete(transport, object);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function()
+ {
+ var receiver = this.responseIsSuccess() ? this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
+
+ if ( !this.options.evalScripts )
+ response = response.stripScripts();
+
+ if ( receiver )
+ {
+ if ( this.options.insertion )
+ {
+ new this.options.insertion(receiver, response);
+ }
+ else
+ {
+ Element.update(receiver, response);
+ }
+ }
+
+ if ( this.responseIsSuccess() )
+ {
+ if ( this.onComplete )
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function( container, url, options )
+ {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function()
+ {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function()
+ {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function( request )
+ {
+ if ( this.options.decay )
+ {
+ this.decay = (request.responseText == this.lastText ? this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function()
+ {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $()
+{
+ var results = [], element;
+ for ( var i = 0; i < arguments.length; i++ )
+ {
+ element = arguments[i];
+ if ( typeof element == 'string' )
+ element = document.getElementById(element);
+ results.push(Element.extend(element));
+ }
+ return results.reduce();
+}
+
+document.getElementsByClassName = function( className, parentElement )
+{
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ return $A(children).inject([], function( elements, child )
+ {
+ if ( child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")) )
+ elements.push(Element.extend(child));
+ return elements;
+ });
+}
+
+/*--------------------------------------------------------------------------*/
+
+if ( !window.Element )
+ var Element = new Object();
+
+Element.extend = function( element )
+{
+ if ( !element ) return;
+ if ( _nativeExtensions || element.nodeType == 3 ) return element;
+
+ if ( !element._extended && element.tagName && element != window )
+ {
+ var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+ if ( element.tagName == 'FORM' )
+ Object.extend(methods, Form.Methods);
+ if ( ['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName) )
+ Object.extend(methods, Form.Element.Methods);
+
+ for ( var property in methods )
+ {
+ var value = methods[property];
+ if ( typeof value == 'function' )
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
+}
+
+Element.extend.cache = {
+ findOrStore: function( value )
+ {
+ return this[value] = this[value] || function()
+ {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+}
+
+Element.Methods = {
+ visible: function( element )
+ {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function( element )
+ {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+ hide: function( element )
+ {
+ $(element).style.display = 'none';
+ return element;
+ },
+
+ show: function( element )
+ {
+ $(element).style.display = '';
+ return element;
+ },
+
+ remove: function( element )
+ {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function( element, html )
+ {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function()
+ {
+ html.evalScripts()
+ }, 10);
+ return element;
+ },
+
+ replace: function( element, html )
+ {
+ element = $(element);
+ if ( element.outerHTML )
+ {
+ element.outerHTML = html.stripScripts();
+ }
+ else
+ {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function()
+ {
+ html.evalScripts()
+ }, 10);
+ return element;
+ },
+
+ inspect: function( element )
+ {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function( pair )
+ {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if ( value ) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function( element, property )
+ {
+ element = $(element);
+ var elements = [];
+ while ( element = element[property] )
+ if ( element.nodeType == 1 )
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function( element )
+ {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function( element )
+ {
+ element = $(element);
+ return $A(element.getElementsByTagName('*'));
+ },
+
+ previousSiblings: function( element )
+ {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function( element )
+ {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function( element )
+ {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function( element, selector )
+ {
+ element = $(element);
+ if ( typeof selector == 'string' )
+ selector = new Selector(selector);
+ return selector.match(element);
+ },
+
+ up: function( element, expression, index )
+ {
+ return Selector.findElement($(element).ancestors(), expression, index);
+ },
+
+ down: function( element, expression, index )
+ {
+ return Selector.findElement($(element).descendants(), expression, index);
+ },
+
+ previous: function( element, expression, index )
+ {
+ return Selector.findElement($(element).previousSiblings(), expression, index);
+ },
+
+ next: function( element, expression, index )
+ {
+ return Selector.findElement($(element).nextSiblings(), expression, index);
+ },
+
+ getElementsBySelector: function()
+ {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ getElementsByClassName: function( element, className )
+ {
+ element = $(element);
+ return document.getElementsByClassName(className, element);
+ },
+
+ getHeight: function( element )
+ {
+ element = $(element);
+ return element.offsetHeight;
+ },
+
+ classNames: function( element )
+ {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function( element, className )
+ {
+ if ( !(element = $(element)) ) return;
+ return Element.classNames(element).include(className);
+ },
+
+ addClassName: function( element, className )
+ {
+ if ( !(element = $(element)) ) return;
+ Element.classNames(element).add(className);
+ return element;
+ },
+
+ removeClassName: function( element, className )
+ {
+ if ( !(element = $(element)) ) return;
+ Element.classNames(element).remove(className);
+ return element;
+ },
+
+ observe: function()
+ {
+ Event.observe.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ stopObserving: function()
+ {
+ Event.stopObserving.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+// removes whitespace-only text node children
+ cleanWhitespace: function( element )
+ {
+ element = $(element);
+ var node = element.firstChild;
+ while ( node )
+ {
+ var nextNode = node.nextSibling;
+ if ( node.nodeType == 3 && !/\S/.test(node.nodeValue) )
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function( element )
+ {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ childOf: function( element, ancestor )
+ {
+ element = $(element),ancestor = $(ancestor);
+ while ( element = element.parentNode )
+ if ( element == ancestor ) return true;
+ return false;
+ },
+
+ scrollTo: function( element )
+ {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ return element;
+ },
+
+ getStyle: function( element, style )
+ {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if ( !value )
+ {
+ if ( document.defaultView && document.defaultView.getComputedStyle )
+ {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ }
+ else if ( element.currentStyle )
+ {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if ( window.opera && ['left', 'top', 'right', 'bottom'].include(style) )
+ if ( Element.getStyle(element, 'position') == 'static' ) value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function( element, style )
+ {
+ element = $(element);
+ for ( var name in style )
+ element.style[name.camelize()] = style[name];
+ return element;
+ },
+
+ getDimensions: function( element )
+ {
+ element = $(element);
+ if ( Element.getStyle(element, 'display') != 'none' )
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function( element )
+ {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if ( pos == 'static' || !pos )
+ {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if ( window.opera )
+ {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function( element )
+ {
+ element = $(element);
+ if ( element._madePositioned )
+ {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top = element.style.left = element.style.bottom = element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function( element )
+ {
+ element = $(element);
+ if ( element._overflow ) return;
+ element._overflow = element.style.overflow || 'auto';
+ if ( (Element.getStyle(element, 'overflow') || 'visible') != 'hidden' )
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function( element )
+ {
+ element = $(element);
+ if ( !element._overflow ) return;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ }
+}
+
+// IE is missing .innerHTML support for TABLE-related elements
+if ( document.all )
+{
+ Element.Methods.update = function( element, html )
+ {
+ element = $(element);
+ var tagName = element.tagName.toUpperCase();
+ if ( ['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1 )
+ {
+ var div = document.createElement('div');
+ switch ( tagName )
+ {
+ case 'THEAD':
+ case 'TBODY':
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
+ depth = 2;
+ break;
+ case 'TR':
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
+ depth = 3;
+ break;
+ case 'TD':
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
+ depth = 4;
+ }
+ $A(element.childNodes).each(function( node )
+ {
+ element.removeChild(node)
+ });
+ depth.times(function()
+ {
+ div = div.firstChild
+ });
+
+ $A(div.childNodes).each(function( node )
+ {
+ element.appendChild(node)
+ });
+ }
+ else
+ {
+ element.innerHTML = html.stripScripts();
+ }
+ setTimeout(function()
+ {
+ html.evalScripts()
+ }, 10);
+ return element;
+ }
+}
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if ( !window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent) )
+{
+ /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,
+and HTMLSelectElement in Safari */
+ ['', 'Form', 'Input', 'TextArea', 'Select'].each(function( tag )
+ {
+ var klass = window['HTML' + tag + 'Element'] = {};
+ klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+ });
+}
+
+Element.addMethods = function( methods )
+{
+ Object.extend(Element.Methods, methods || {});
+
+ function copy( methods, destination )
+ {
+ var cache = Element.extend.cache;
+ for ( var property in methods )
+ {
+ var value = methods[property];
+ destination[property] = cache.findOrStore(value);
+ }
+ }
+
+ if ( typeof HTMLElement != 'undefined' )
+ {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Form.Methods, HTMLFormElement.prototype);
+ [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function( klass )
+ {
+ copy(Form.Element.Methods, klass.prototype);
+ });
+ _nativeExtensions = true;
+ }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function( adjacency )
+{
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function( element, content )
+ {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if ( this.adjacency && this.element.insertAdjacentHTML )
+ {
+ try
+ {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ }
+ catch ( e )
+ {
+ var tagName = this.element.tagName.toLowerCase();
+ if ( tagName == 'tbody' || tagName == 'tr' )
+ {
+ this.insertContent(this.contentFromAnonymousTable());
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ this.range = this.element.ownerDocument.createRange();
+ if ( this.initializeRange ) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function()
+ {
+ content.evalScripts()
+ }, 10);
+ },
+
+ contentFromAnonymousTable: function()
+ {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function()
+ {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function( fragments )
+ {
+ fragments.each((function( fragment )
+ {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function()
+ {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function( fragments )
+ {
+ fragments.reverse(false).each((function( fragment )
+ {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function()
+ {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function( fragments )
+ {
+ fragments.each((function( fragment )
+ {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function()
+ {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function( fragments )
+ {
+ fragments.each((function( fragment )
+ {
+ this.element.parentNode.insertBefore(fragment, this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function( element )
+ {
+ this.element = $(element);
+ },
+
+ _each: function( iterator )
+ {
+ this.element.className.split(/\s+/).select(function( name )
+ {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function( className )
+ {
+ this.element.className = className;
+ },
+
+ add: function( classNameToAdd )
+ {
+ if ( this.include(classNameToAdd) ) return;
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function( classNameToRemove )
+ {
+ if ( !this.include(classNameToRemove) ) return;
+ this.set(this.select(function( className )
+ {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function()
+ {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function( expression )
+ {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function()
+ {
+ function abort( message )
+ {
+ throw 'Parse error in selector: ' + message;
+ }
+
+ if ( this.expression == '' ) abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while ( match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i) )
+ {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if ( expr == '*' ) return this.params.wildcard = true;
+
+ while ( match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i) )
+ {
+ modifier = match[1],clause = match[2],rest = match[3];
+ switch ( modifier )
+ {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if ( expr.length > 0 ) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function()
+ {
+ var params = this.params, conditions = [], clause;
+
+ if ( params.wildcard )
+ conditions.push('true');
+ if ( clause = params.id )
+ conditions.push('element.id == ' + clause.inspect());
+ if ( clause = params.tagName )
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ( (clause = params.classNames).length > 0 )
+ for ( var i = 0; i < clause.length; i++ )
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
+ if ( clause = params.attributes )
+ {
+ clause.each(function( attribute )
+ {
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function( delimiter )
+ {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch ( attribute.operator )
+ {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() +
+ ')'); break;
+ case '|=': conditions.push(splitValueBy('-') + '.first().toUpperCase() == ' +
+ attribute.value.toUpperCase().inspect()); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push(value + ' != null'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function()
+ {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function( scope )
+ {
+ var element;
+
+ if ( element = $(this.params.id) )
+ if ( this.match(element) )
+ if ( !scope || Element.childOf(element, scope) )
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for ( var i = 0; i < scope.length; i++ )
+ if ( this.match(element = scope[i]) )
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function()
+ {
+ return this.expression;
+ }
+}
+
+Object.extend(Selector, {
+ matchElements: function( elements, expression )
+ {
+ var selector = new Selector(expression);
+ return elements.select(selector.match.bind(selector));
+ },
+
+ findElement: function( elements, expression, index )
+ {
+ if ( typeof expression == 'number' ) index = expression,expression = false;
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function( element, expressions )
+ {
+ return expressions.map(function( expression )
+ {
+ return expression.strip().split(/\s+/).inject([null], function( results, expr )
+ {
+ var selector = new Selector(expr);
+ return results.inject([], function( elements, result )
+ {
+ return elements.concat(selector.findElements(result || element));
+ });
+ });
+ }).flatten();
+ }
+});
+
+function $$()
+{
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function( form )
+ {
+ $(form).reset();
+ return form;
+ }
+};
+
+Form.Methods = {
+ serialize: function( form )
+ {
+ var elements = Form.getElements($(form));
+ var queryComponents = new Array();
+
+ for ( var i = 0; i < elements.length; i++ )
+ {
+ var queryComponent = Form.Element.serialize(elements[i]);
+ if ( queryComponent )
+ queryComponents.push(queryComponent);
+ }
+
+ return queryComponents.join('&');
+ },
+
+ getElements: function( form )
+ {
+ form = $(form);
+ var elements = new Array();
+
+ for ( var tagName in Form.Element.Serializers )
+ {
+ var tagElements = form.getElementsByTagName(tagName);
+ for ( var j = 0; j < tagElements.length; j++ )
+ elements.push(tagElements[j]);
+ }
+ return elements;
+ },
+
+ getInputs: function( form, typeName, name )
+ {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if ( !typeName && !name )
+ return inputs;
+
+ var matchingInputs = new Array();
+ for ( var i = 0; i < inputs.length; i++ )
+ {
+ var input = inputs[i];
+ if ( (typeName && input.type != typeName) || (name && input.name != name) )
+ continue;
+ matchingInputs.push(input);
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function( form )
+ {
+ form = $(form);
+ var elements = Form.getElements(form);
+ for ( var i = 0; i < elements.length; i++ )
+ {
+ var element = elements[i];
+ element.blur();
+ element.disabled = 'true';
+ }
+ return form;
+ },
+
+ enable: function( form )
+ {
+ form = $(form);
+ var elements = Form.getElements(form);
+ for ( var i = 0; i < elements.length; i++ )
+ {
+ var element = elements[i];
+ element.disabled = '';
+ }
+ return form;
+ },
+
+ findFirstElement: function( form )
+ {
+ return Form.getElements(form).find(function( element )
+ {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function( form )
+ {
+ form = $(form);
+ Field.activate(Form.findFirstElement(form));
+ return form;
+ }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+ focus: function( element )
+ {
+ $(element).focus();
+ return element;
+ },
+
+ select: function( element )
+ {
+ $(element).select();
+ return element;
+ }
+}
+
+Form.Element.Methods = {
+ serialize: function( element )
+ {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if ( parameter )
+ {
+ var key = encodeURIComponent(parameter[0]);
+ if ( key.length == 0 ) return;
+
+ if ( parameter[1].constructor != Array )
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function( value )
+ {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ },
+
+ getValue: function( element )
+ {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if ( parameter )
+ return parameter[1];
+ },
+
+ clear: function( element )
+ {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function( element )
+ {
+ return $(element).value != '';
+ },
+
+ activate: function( element )
+ {
+ element = $(element);
+ element.focus();
+ if ( element.select )
+ element.select();
+ return element;
+ },
+
+ disable: function( element )
+ {
+ element = $(element);
+ element.disabled = '';
+ return element;
+ },
+
+ enable: function( element )
+ {
+ element = $(element);
+ element.blur();
+ element.disabled = 'true';
+ return element;
+ }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function( element )
+ {
+ switch ( element.type.toLowerCase() )
+ {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ default:
+ return Form.Element.Serializers.textarea(element);
+ }
+ return false;
+ },
+
+ inputSelector: function( element )
+ {
+ if ( element.checked )
+ return [element.name, element.value];
+ },
+
+ textarea: function( element )
+ {
+ return [element.name, element.value];
+ },
+
+ select: function( element )
+ {
+ return Form.Element.Serializers[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function( element )
+ {
+ var value = '', opt, index = element.selectedIndex;
+ if ( index >= 0 )
+ {
+ opt = element.options[index];
+ value = opt.value || opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function( element )
+ {
+ var value = [];
+ for ( var i = 0; i < element.length; i++ )
+ {
+ var opt = element.options[i];
+ if ( opt.selected )
+ value.push(opt.value || opt.text);
+ }
+ return [element.name, value];
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function()
+{
+}
+Abstract.TimedObserver.prototype = {
+ initialize: function( element, frequency, callback )
+ {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function()
+ {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function()
+ {
+ var value = this.getValue();
+ if ( this.lastValue != value )
+ {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function()
+ {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function()
+ {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function()
+{
+}
+Abstract.EventObserver.prototype = {
+ initialize: function( element, callback )
+ {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if ( this.element.tagName.toLowerCase() == 'form' )
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function()
+ {
+ var value = this.getValue();
+ if ( this.lastValue != value )
+ {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function()
+ {
+ var elements = Form.getElements(this.element);
+ for ( var i = 0; i < elements.length; i++ )
+ this.registerCallback(elements[i]);
+ },
+
+ registerCallback: function( element )
+ {
+ if ( element.type )
+ {
+ switch ( element.type.toLowerCase() )
+ {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function()
+ {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function()
+ {
+ return Form.serialize(this.element);
+ }
+});
+if ( !window.Event )
+{
+ var Event = new Object();
+}
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+
+ element: function( event )
+ {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function( event )
+ {
+ return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function( event )
+ {
+ return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function( event )
+ {
+ return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function( event )
+ {
+ if ( event.preventDefault )
+ {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ else
+ {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+// find the first node with the given tagName, starting from the
+// node the event was triggered on; traverses the DOM upwards
+ findElement: function( event, tagName )
+ {
+ var element = Event.element(event);
+ while ( element.parentNode && (!element.tagName || (element.tagName.toUpperCase() != tagName.toUpperCase())) )
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function( element, name, observer, useCapture )
+ {
+ if ( !this.observers ) this.observers = [];
+ if ( element.addEventListener )
+ {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ }
+ else if ( element.attachEvent )
+ {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function()
+ {
+ if ( !Event.observers ) return;
+ for ( var i = 0; i < Event.observers.length; i++ )
+ {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function( element, name, observer, useCapture )
+ {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if ( name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent) )
+ name = 'keydown';
+
+ Event._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function( element, name, observer, useCapture )
+ {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if ( name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.detachEvent) )
+ name = 'keydown';
+
+ if ( element.removeEventListener )
+ {
+ element.removeEventListener(name, observer, useCapture);
+ }
+ else if ( element.detachEvent )
+ {
+ try
+ {
+ element.detachEvent('on' + name, observer);
+ }
+ catch ( e )
+ {
+ }
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+if ( navigator.appVersion.match(/\bMSIE\b/) )
+ Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+// set to true if needed, warning: firefox performance problems
+// NOT neeeded for page scrolling, only if draggable contained in
+// scrollable elements
+ includeScrollOffsets: false,
+
+// must be called before calling withinIncludingScrolloffset, every time the
+// page is scrolled
+ prepare: function()
+ {
+ this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
+ this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
+ },
+
+ realOffset: function( element )
+ {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ }
+ while ( element );
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function( element )
+ {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ }
+ while ( element );
+ return [valueL, valueT];
+ },
+
+ positionedOffset: function( element )
+ {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if ( element )
+ {
+ p = Element.getStyle(element, 'position');
+ if ( p == 'relative' || p == 'absolute' ) break;
+ }
+ }
+ while ( element );
+ return [valueL, valueT];
+ },
+
+ offsetParent: function( element )
+ {
+ if ( element.offsetParent ) return element.offsetParent;
+ if ( element == document.body ) return element;
+
+ while ( (element = element.parentNode) && element != document.body )
+ if ( Element.getStyle(element, 'position') != 'static' )
+ return element;
+
+ return document.body;
+ },
+
+// caches x/y coordinate pair to use with overlap
+ within: function( element, x, y )
+ {
+ if ( this.includeScrollOffsets )
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function( element, x, y )
+ {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+// within must be called directly before
+ overlap: function( mode, element )
+ {
+ if ( !mode ) return 0;
+ if ( mode == 'vertical' )
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight;
+ if ( mode == 'horizontal' )
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth;
+ },
+
+ page: function( forElement )
+ {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if ( element.offsetParent == document.body )
+ if ( Element.getStyle(element, 'position') == 'absolute' ) break;
+
+ }
+ while ( element = element.offsetParent );
+
+ element = forElement;
+ do {
+ if ( !window.opera || element.tagName == 'BODY' )
+ {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ }
+ while ( element = element.parentNode );
+
+ return [valueL, valueT];
+ },
+
+ clone: function( source, target )
+ {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if ( Element.getStyle(target, 'position') == 'absolute' )
+ {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if ( parent == document.body )
+ {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if ( options.setLeft ) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if ( options.setTop ) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if ( options.setWidth ) target.style.width = source.offsetWidth + 'px';
+ if ( options.setHeight ) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function( element )
+ {
+ element = $(element);
+ if ( element.style.position == 'absolute' ) return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ ;
+ element.style.left = left + 'px';
+ ;
+ element.style.width = width + 'px';
+ ;
+ element.style.height = height + 'px';
+ ;
+ },
+
+ relativize: function( element )
+ {
+ element = $(element);
+ if ( element.style.position == 'relative' ) return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if ( /Konqueror|Safari|KHTML/.test(navigator.userAgent) )
+{
+ Position.cumulativeOffset = function( element )
+ {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if ( element.offsetParent == document.body )
+ if ( Element.getStyle(element, 'position') == 'absolute' ) break;
+
+ element = element.offsetParent;
+ }
+ while ( element );
+
+ return [valueL, valueT];
+ }
+}
+
+Element.addMethods(); \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/scriptaculous.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/scriptaculous.js
new file mode 100644
index 000000000..60489ef74
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/scriptaculous.js
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us scriptaculous.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var Scriptaculous = {
+ Version: '1.6.4',
+ require: function( libraryName )
+ {
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="' + libraryName + '"></script>');
+ },
+ load: function()
+ {
+ if ( (typeof Prototype == 'undefined') || (typeof Element == 'undefined') ||
+ (typeof Element.Methods == 'undefined') ||
+ parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1]) < 1.5 )
+ throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0");
+
+ $A(document.getElementsByTagName("script")).findAll(function( s )
+ {
+ return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
+ }).each(function( s )
+ {
+ var path = s.src.replace(/scriptaculous\.js(\?.*)?$/, '');
+ var includes = s.src.match(/\?.*load=([a-z,]*)/);
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(function( include )
+ {
+ Scriptaculous.require(path + include + '.js')
+ });
+ });
+ }
+}
+
+Scriptaculous.load(); \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/slider.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/slider.js
new file mode 100644
index 000000000..82a1cd1f0
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/slider.js
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us slider.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Marty Haught, Thomas Fuchs
+//
+// See http://script.aculo.us for more info
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+if ( !Control ) var Control = {};
+Control.Slider = Class.create();
+
+// options:
+// axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+// onChange(value)
+// onSlide(value)
+Control.Slider.prototype = {
+ initialize: function( handle, track, options )
+ {
+ var slider = this;
+
+ if ( handle instanceof Array )
+ {
+ this.handles = handle.collect(function( e )
+ {
+ return $(e)
+ });
+ }
+ else
+ {
+ this.handles = [$(handle)];
+ }
+
+ this.track = $(track);
+ this.options = options || {};
+
+ this.axis = this.options.axis || 'horizontal';
+ this.increment = this.options.increment || 1;
+ this.step = parseInt(this.options.step || '1');
+ this.range = this.options.range || $R(0, 1);
+
+ this.value = 0;
+ // assure backwards compat
+ this.values = this.handles.map(function()
+ {
+ return 0
+ });
+ this.spans = this.options.spans ? this.options.spans.map(function( s )
+ {
+ return $(s)
+ }) : false;
+ this.options.startSpan = $(this.options.startSpan || null);
+ this.options.endSpan = $(this.options.endSpan || null);
+
+ this.restricted = this.options.restricted || false;
+
+ this.maximum = this.options.maximum || this.range.end;
+ this.minimum = this.options.minimum || this.range.start;
+
+ // Will be used to align the handle onto the track, if necessary
+ this.alignX = parseInt(this.options.alignX || '0');
+ this.alignY = parseInt(this.options.alignY || '0');
+
+ this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+ this.handleLength = this.isVertical() ? (this.handles[0].offsetHeight != 0 ? this.handles[0].offsetHeight
+ : this.handles[0].style.height.replace(/px$/, "")) : (this.handles[0].offsetWidth != 0
+ ? this.handles[0].offsetWidth : this.handles[0].style.width.replace(/px$/, ""));
+
+ this.active = false;
+ this.dragging = false;
+ this.disabled = false;
+
+ if ( this.options.disabled ) this.setDisabled();
+
+ // Allowed values array
+ this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+ if ( this.allowedValues )
+ {
+ this.minimum = this.allowedValues.min();
+ this.maximum = this.allowedValues.max();
+ }
+
+ this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.update.bindAsEventListener(this);
+
+ // Initialize handles in reverse (make sure first handle is active)
+ this.handles.each(function( h, i )
+ {
+ i = slider.handles.length - 1 - i;
+ slider.setValue(parseFloat((slider.options.sliderValue instanceof Array ? slider.options.sliderValue[i]
+ : slider.options.sliderValue) || slider.range.start), i);
+ Element.makePositioned(h);
+ // fix IE
+ Event.observe(h, "mousedown", slider.eventMouseDown);
+ });
+
+ Event.observe(this.track, "mousedown", this.eventMouseDown);
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+
+ this.initialized = true;
+ },
+ dispose: function()
+ {
+ var slider = this;
+ Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ this.handles.each(function( h )
+ {
+ Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+ });
+ },
+ setDisabled: function()
+ {
+ this.disabled = true;
+ },
+ setEnabled: function()
+ {
+ this.disabled = false;
+ },
+ getNearestValue: function( value )
+ {
+ if ( this.allowedValues )
+ {
+ if ( value >= this.allowedValues.max() ) return(this.allowedValues.max());
+ if ( value <= this.allowedValues.min() ) return(this.allowedValues.min());
+
+ var offset = Math.abs(this.allowedValues[0] - value);
+ var newValue = this.allowedValues[0];
+ this.allowedValues.each(function( v )
+ {
+ var currentOffset = Math.abs(v - value);
+ if ( currentOffset <= offset )
+ {
+ newValue = v;
+ offset = currentOffset;
+ }
+ });
+ return newValue;
+ }
+ if ( value > this.range.end ) return this.range.end;
+ if ( value < this.range.start ) return this.range.start;
+ return value;
+ },
+ setValue: function( sliderValue, handleIdx )
+ {
+ if ( !this.active )
+ {
+ this.activeHandleIdx = handleIdx || 0;
+ this.activeHandle = this.handles[this.activeHandleIdx];
+ this.updateStyles();
+ }
+ handleIdx = handleIdx || this.activeHandleIdx || 0;
+ if ( this.initialized && this.restricted )
+ {
+ if ( (handleIdx > 0) && (sliderValue < this.values[handleIdx - 1]) )
+ sliderValue = this.values[handleIdx - 1];
+ if ( (handleIdx < (this.handles.length - 1)) && (sliderValue > this.values[handleIdx + 1]) )
+ sliderValue = this.values[handleIdx + 1];
+ }
+ sliderValue = this.getNearestValue(sliderValue);
+ this.values[handleIdx] = sliderValue;
+ this.value = this.values[0];
+ // assure backwards compat
+
+ this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = this.translateToPx(sliderValue);
+
+ this.drawSpans();
+ if ( !this.dragging || !this.event ) this.updateFinished();
+ },
+ setValueBy: function( delta, handleIdx )
+ {
+ this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, handleIdx || this.activeHandleIdx ||
+ 0);
+ },
+ translateToPx: function( value )
+ {
+ return Math.round(((this.trackLength - this.handleLength) / (this.range.end - this.range.start)) *
+ (value - this.range.start)) + "px";
+ },
+ translateToValue: function( offset )
+ {
+ return ((offset / (this.trackLength - this.handleLength) * (this.range.end - this.range.start)) +
+ this.range.start);
+ },
+ getRange: function( range )
+ {
+ var v = this.values.sortBy(Prototype.K);
+ range = range || 0;
+ return $R(v[range], v[range + 1]);
+ },
+ minimumOffset: function()
+ {
+ return(this.isVertical() ? this.alignY : this.alignX);
+ },
+ maximumOffset: function()
+ {
+ return(this.isVertical() ? (this.track.offsetHeight != 0 ? this.track.offsetHeight
+ : this.track.style.height.replace(/px$/, "")) - this.alignY : (this.track.offsetWidth != 0
+ ? this.track.offsetWidth : this.track.style.width.replace(/px$/, "")) - this.alignY);
+ },
+ isVertical: function()
+ {
+ return (this.axis == 'vertical');
+ },
+ drawSpans: function()
+ {
+ var slider = this;
+ if ( this.spans )
+ $R(0, this.spans.length - 1).each(function( r )
+ {
+ slider.setSpan(slider.spans[r], slider.getRange(r))
+ });
+ if ( this.options.startSpan )
+ this.setSpan(this.options.startSpan, $R(0, this.values.length > 1 ? this.getRange(0).min() : this.value));
+ if ( this.options.endSpan )
+ this.setSpan(this.options.endSpan, $R(this.values.length > 1 ? this.getRange(this.spans.length - 1).max()
+ : this.value, this.maximum));
+ },
+ setSpan: function( span, range )
+ {
+ if ( this.isVertical() )
+ {
+ span.style.top = this.translateToPx(range.start);
+ span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+ }
+ else
+ {
+ span.style.left = this.translateToPx(range.start);
+ span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+ }
+ },
+ updateStyles: function()
+ {
+ this.handles.each(function( h )
+ {
+ Element.removeClassName(h, 'selected')
+ });
+ Element.addClassName(this.activeHandle, 'selected');
+ },
+ startDrag: function( event )
+ {
+ if ( Event.isLeftClick(event) )
+ {
+ if ( !this.disabled )
+ {
+ this.active = true;
+
+ var handle = Event.element(event);
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var track = handle;
+ if ( track == this.track )
+ {
+ var offsets = Position.cumulativeOffset(this.track);
+ this.event = event;
+ this.setValue(this.translateToValue((this.isVertical() ? pointer[1] - offsets[1] : pointer[0] -
+ offsets[0]) -
+ (this.handleLength / 2)));
+ var offsets = Position.cumulativeOffset(this.activeHandle);
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ }
+ else
+ {
+ // find the handle (prevents issues with Safari)
+ while ( (this.handles.indexOf(handle) == -1) && handle.parentNode )
+ handle = handle.parentNode;
+
+ this.activeHandle = handle;
+ this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+ this.updateStyles();
+
+ var offsets = Position.cumulativeOffset(this.activeHandle);
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ }
+ }
+ Event.stop(event);
+ }
+ },
+ update: function( event )
+ {
+ if ( this.active )
+ {
+ if ( !this.dragging ) this.dragging = true;
+ this.draw(event);
+ // fix AppleWebKit rendering
+ if ( navigator.appVersion.indexOf('AppleWebKit') > 0 ) window.scrollBy(0, 0);
+ Event.stop(event);
+ }
+ },
+ draw: function( event )
+ {
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var offsets = Position.cumulativeOffset(this.track);
+ pointer[0] -= this.offsetX + offsets[0];
+ pointer[1] -= this.offsetY + offsets[1];
+ this.event = event;
+ this.setValue(this.translateToValue(this.isVertical() ? pointer[1] : pointer[0]));
+ if ( this.initialized && this.options.onSlide )
+ this.options.onSlide(this.values.length > 1 ? this.values : this.value, this);
+ },
+ endDrag: function( event )
+ {
+ if ( this.active && this.dragging )
+ {
+ this.finishDrag(event, true);
+ Event.stop(event);
+ }
+ this.active = false;
+ this.dragging = false;
+ },
+ finishDrag: function( event, success )
+ {
+ this.active = false;
+ this.dragging = false;
+ this.updateFinished();
+ },
+ updateFinished: function()
+ {
+ if ( this.initialized && this.options.onChange )
+ this.options.onChange(this.values.length > 1 ? this.values : this.value, this);
+ this.event = null;
+ }
+} \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/unittest.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/unittest.js
new file mode 100644
index 000000000..cd3143305
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/scriptaculous/unittest.js
@@ -0,0 +1,744 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// script.aculo.us unittest.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006
+
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+// experimental, Firefox-only
+Event.simulateMouse = function( element, eventName )
+{
+ var options = Object.extend({
+ pointerX: 0,
+ pointerY: 0,
+ buttons: 0
+ }, arguments[2] || {});
+ var oEvent = document.createEvent("MouseEvents");
+ oEvent.initMouseEvent(eventName, true, true, document.defaultView, options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, false, false, false, false, 0, $(element));
+
+ if ( this.mark ) Element.remove(this.mark);
+ this.mark = document.createElement('div');
+ this.mark.appendChild(document.createTextNode(" "));
+ document.body.appendChild(this.mark);
+ this.mark.style.position = 'absolute';
+ this.mark.style.top = options.pointerY + "px";
+ this.mark.style.left = options.pointerX + "px";
+ this.mark.style.width = "5px";
+ this.mark.style.height = "5px;";
+ this.mark.style.borderTop = "1px solid red;"
+ this.mark.style.borderLeft = "1px solid red;"
+
+ if ( this.step )
+ alert('[' + new Date().getTime().toString() + '] ' + eventName + '/' + Test.Unit.inspect(options));
+
+ $(element).dispatchEvent(oEvent);
+};
+
+// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
+// You need to downgrade to 1.0.4 for now to get this working
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
+Event.simulateKey = function( element, eventName )
+{
+ var options = Object.extend({
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false,
+ keyCode: 0,
+ charCode: 0
+ }, arguments[2] || {});
+
+ var oEvent = document.createEvent("KeyEvents");
+ oEvent.initKeyEvent(eventName, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode);
+ $(element).dispatchEvent(oEvent);
+};
+
+Event.simulateKeys = function( element, command )
+{
+ for ( var i = 0; i < command.length; i++ )
+ {
+ Event.simulateKey(element, 'keypress', {charCode:command.charCodeAt(i)});
+ }
+};
+
+var Test = {}
+Test.Unit = {};
+
+// security exception workaround
+Test.Unit.inspect = Object.inspect;
+
+Test.Unit.Logger = Class.create();
+Test.Unit.Logger.prototype = {
+ initialize: function( log )
+ {
+ this.log = $(log);
+ if ( this.log )
+ {
+ this._createLogTable();
+ }
+ },
+ start: function( testName )
+ {
+ if ( !this.log ) return;
+ this.testName = testName;
+ this.lastLogLine = document.createElement('tr');
+ this.statusCell = document.createElement('td');
+ this.nameCell = document.createElement('td');
+ this.nameCell.appendChild(document.createTextNode(testName));
+ this.messageCell = document.createElement('td');
+ this.lastLogLine.appendChild(this.statusCell);
+ this.lastLogLine.appendChild(this.nameCell);
+ this.lastLogLine.appendChild(this.messageCell);
+ this.loglines.appendChild(this.lastLogLine);
+ },
+ finish: function( status, summary )
+ {
+ if ( !this.log ) return;
+ this.lastLogLine.className = status;
+ this.statusCell.innerHTML = status;
+ this.messageCell.innerHTML = this._toHTML(summary);
+ },
+ message: function( message )
+ {
+ if ( !this.log ) return;
+ this.messageCell.innerHTML = this._toHTML(message);
+ },
+ summary: function( summary )
+ {
+ if ( !this.log ) return;
+ this.logsummary.innerHTML = this._toHTML(summary);
+ },
+ _createLogTable: function()
+ {
+ this.log.innerHTML = '<div id="logsummary"></div>' + '<table id="logtable">' +
+ '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+ '<tbody id="loglines"></tbody>' + '</table>';
+ this.logsummary = $('logsummary')
+ this.loglines = $('loglines');
+ },
+ _toHTML: function( txt )
+ {
+ return txt.escapeHTML().replace(/\n/g, "<br/>");
+ }
+}
+
+Test.Unit.Runner = Class.create();
+Test.Unit.Runner.prototype = {
+ initialize: function( testcases )
+ {
+ this.options = Object.extend({
+ testLog: 'testlog'
+ }, arguments[1] || {});
+ this.options.resultsURL = this.parseResultsURLQueryParameter();
+ if ( this.options.testLog )
+ {
+ this.options.testLog = $(this.options.testLog) || null;
+ }
+ if ( this.options.tests )
+ {
+ this.tests = [];
+ for ( var i = 0; i < this.options.tests.length; i++ )
+ {
+ if ( /^test/.test(this.options.tests[i]) )
+ {
+ this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
+ }
+ }
+ }
+ else
+ {
+ if ( this.options.test )
+ {
+ this.tests =
+ [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
+ }
+ else
+ {
+ this.tests = [];
+ for ( var testcase in testcases )
+ {
+ if ( /^test/.test(testcase) )
+ {
+ this.tests.push(new Test.Unit.Testcase(this.options.context ? ' -> ' +
+ this.options.titles[testcase]
+ : testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
+ }
+ }
+ }
+ }
+ this.currentTest = 0;
+ this.logger = new Test.Unit.Logger(this.options.testLog);
+ setTimeout(this.runTests.bind(this), 1000);
+ },
+ parseResultsURLQueryParameter: function()
+ {
+ return window.location.search.parseQuery()["resultsURL"];
+ },
+// Returns:
+// "ERROR" if there was an error,
+// "FAILURE" if there was a failure, or
+// "SUCCESS" if there was neither
+ getResult: function()
+ {
+ var hasFailure = false;
+ for ( var i = 0; i < this.tests.length; i++ )
+ {
+ if ( this.tests[i].errors > 0 )
+ {
+ return "ERROR";
+ }
+ if ( this.tests[i].failures > 0 )
+ {
+ hasFailure = true;
+ }
+ }
+ if ( hasFailure )
+ {
+ return "FAILURE";
+ }
+ else
+ {
+ return "SUCCESS";
+ }
+ },
+ postResults: function()
+ {
+ if ( this.options.resultsURL )
+ {
+ new Ajax.Request(this.options.resultsURL, { method: 'get', parameters: 'result=' +
+ this.getResult(), asynchronous: false });
+ }
+ },
+ runTests: function()
+ {
+ var test = this.tests[this.currentTest];
+ if ( !test )
+ {
+ // finished!
+ this.postResults();
+ this.logger.summary(this.summary());
+ return;
+ }
+ if ( !test.isWaiting )
+ {
+ this.logger.start(test.name);
+ }
+ test.run();
+ if ( test.isWaiting )
+ {
+ this.logger.message("Waiting for " + test.timeToWait + "ms");
+ setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
+ }
+ else
+ {
+ this.logger.finish(test.status(), test.summary());
+ this.currentTest++;
+ // tail recursive, hopefully the browser will skip the stackframe
+ this.runTests();
+ }
+ },
+ summary: function()
+ {
+ var assertions = 0;
+ var failures = 0;
+ var errors = 0;
+ var messages = [];
+ for ( var i = 0; i < this.tests.length; i++ )
+ {
+ assertions += this.tests[i].assertions;
+ failures += this.tests[i].failures;
+ errors += this.tests[i].errors;
+ }
+ return (
+ (this.options.context ? this.options.context + ': ' : '') + this.tests.length + " tests, " + assertions +
+ " assertions, " + failures + " failures, " + errors + " errors");
+ }
+}
+
+Test.Unit.Assertions = Class.create();
+Test.Unit.Assertions.prototype = {
+ initialize: function()
+ {
+ this.assertions = 0;
+ this.failures = 0;
+ this.errors = 0;
+ this.messages = [];
+ },
+ summary: function()
+ {
+ return (
+ this.assertions + " assertions, " + this.failures + " failures, " + this.errors + " errors" + "\n" +
+ this.messages.join("\n"));
+ },
+ pass: function()
+ {
+ this.assertions++;
+ },
+ fail: function( message )
+ {
+ this.failures++;
+ this.messages.push("Failure: " + message);
+ },
+ info: function( message )
+ {
+ this.messages.push("Info: " + message);
+ },
+ error: function( error )
+ {
+ this.errors++;
+ this.messages.push(error.name + ": " + error.message + "(" + Test.Unit.inspect(error) + ")");
+ },
+ status: function()
+ {
+ if ( this.failures > 0 ) return 'failed';
+ if ( this.errors > 0 ) return 'error';
+ return 'passed';
+ },
+ assert: function( expression )
+ {
+ var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
+ try
+ {
+ expression ? this.pass() : this.fail(message);
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertEqual: function( expected, actual )
+ {
+ var message = arguments[2] || "assertEqual";
+ try
+ {
+ (expected == actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertEnumEqual: function( expected, actual )
+ {
+ var message = arguments[2] || "assertEnumEqual";
+ try
+ {
+ $A(expected).length == $A(actual).length && expected.zip(actual).all(function( pair )
+ {
+ return pair[0] == pair[1]
+ }) ? this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + ', actual ' +
+ Test.Unit.inspect(actual));
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertNotEqual: function( expected, actual )
+ {
+ var message = arguments[2] || "assertNotEqual";
+ try
+ {
+ (expected != actual) ? this.pass() : this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertIdentical: function( expected, actual )
+ {
+ var message = arguments[2] || "assertIdentical";
+ try
+ {
+ (expected === actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertNotIdentical: function( expected, actual )
+ {
+ var message = arguments[2] || "assertNotIdentical";
+ try
+ {
+ !(expected === actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertNull: function( obj )
+ {
+ var message = arguments[1] || 'assertNull'
+ try
+ {
+ (obj == null) ? this.pass() : this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertMatch: function( expected, actual )
+ {
+ var message = arguments[2] || 'assertMatch';
+ var regex = new RegExp(expected);
+ try
+ {
+ (regex.exec(actual)) ? this.pass() : this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) +
+ ' did not match: ' + Test.Unit.inspect(actual) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertHidden: function( element )
+ {
+ var message = arguments[1] || 'assertHidden';
+ this.assertEqual("none", element.style.display, message);
+ },
+ assertNotNull: function( object )
+ {
+ var message = arguments[1] || 'assertNotNull';
+ this.assert(object != null, message);
+ },
+ assertType: function( expected, actual )
+ {
+ var message = arguments[2] || 'assertType';
+ try
+ {
+ (actual.constructor == expected) ? this.pass() : this.fail(message + ': expected "' +
+ Test.Unit.inspect(expected) + '", actual "' +
+ (actual.constructor) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertNotOfType: function( expected, actual )
+ {
+ var message = arguments[2] || 'assertNotOfType';
+ try
+ {
+ (actual.constructor != expected) ? this.pass() : this.fail(message + ': expected "' +
+ Test.Unit.inspect(expected) + '", actual "' +
+ (actual.constructor) + '"');
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertInstanceOf: function( expected, actual )
+ {
+ var message = arguments[2] || 'assertInstanceOf';
+ try
+ {
+ (actual instanceof expected) ? this.pass() : this.fail(message +
+ ": object was not an instance of the expected type");
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertNotInstanceOf: function( expected, actual )
+ {
+ var message = arguments[2] || 'assertNotInstanceOf';
+ try
+ {
+ !(actual instanceof expected) ? this.pass() : this.fail(message +
+ ": object was an instance of the not expected type");
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertRespondsTo: function( method, obj )
+ {
+ var message = arguments[2] || 'assertRespondsTo';
+ try
+ {
+ (obj[method] && typeof obj[method] == 'function') ? this.pass() : this.fail(message +
+ ": object doesn't respond to [" +
+ method + "]");
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertReturnsTrue: function( method, obj )
+ {
+ var message = arguments[2] || 'assertReturnsTrue';
+ try
+ {
+ var m = obj[method];
+ if ( !m ) m = obj['is' + method.charAt(0).toUpperCase() + method.slice(1)];
+ m() ? this.pass() : this.fail(message + ": method returned false");
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertReturnsFalse: function( method, obj )
+ {
+ var message = arguments[2] || 'assertReturnsFalse';
+ try
+ {
+ var m = obj[method];
+ if ( !m ) m = obj['is' + method.charAt(0).toUpperCase() + method.slice(1)];
+ !m() ? this.pass() : this.fail(message + ": method returned true");
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ },
+ assertRaise: function( exceptionName, method )
+ {
+ var message = arguments[2] || 'assertRaise';
+ try
+ {
+ method();
+ this.fail(message + ": exception expected but none was raised");
+ }
+ catch( e )
+ {
+ (e.name == exceptionName) ? this.pass() : this.error(e);
+ }
+ },
+ assertElementsMatch: function()
+ {
+ var expressions = $A(arguments), elements = $A(expressions.shift());
+ if ( elements.length != expressions.length )
+ {
+ this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length +
+ ' expressions');
+ return false;
+ }
+ elements.zip(expressions).all(function( pair, index )
+ {
+ var element = $(pair.first()), expression = pair.last();
+ if ( element.match(expression) ) return true;
+ this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' +
+ element.inspect());
+ }.bind(this)) && this.pass();
+ },
+ assertElementMatches: function( element, expression )
+ {
+ this.assertElementsMatch([element], expression);
+ },
+ benchmark: function( operation, iterations )
+ {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date()) - startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' + iterations + ' iterations in ' + (timeTaken / 1000) +
+ 's');
+ return timeTaken;
+ },
+ _isVisible: function( element )
+ {
+ element = $(element);
+ if ( !element.parentNode ) return true;
+ this.assertNotNull(element);
+ if ( element.style && Element.getStyle(element, 'display') == 'none' )
+ return false;
+
+ return this._isVisible(element.parentNode);
+ },
+ assertNotVisible: function( element )
+ {
+ this.assert(!this._isVisible(element), Test.Unit.inspect(element) +
+ " was not hidden and didn't have a hidden parent either. " +
+ ("" || arguments[1]));
+ },
+ assertVisible: function( element )
+ {
+ this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
+ },
+ benchmark: function( operation, iterations )
+ {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date()) - startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' + iterations + ' iterations in ' + (timeTaken / 1000) +
+ 's');
+ return timeTaken;
+ }
+}
+
+Test.Unit.Testcase = Class.create();
+Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
+ initialize: function( name, test, setup, teardown )
+ {
+ Test.Unit.Assertions.prototype.initialize.bind(this)();
+ this.name = name;
+
+ if ( typeof test == 'string' )
+ {
+ test = test.gsub(/(\.should[^\(]+\()/, '#{0}this,');
+ test = test.gsub(/(\.should[^\(]+)\(this,\)/, '#{1}(this)');
+ this.test = function()
+ {
+ eval('with(this){' + test + '}');
+ }
+ }
+ else
+ {
+ this.test = test || function()
+ {
+ };
+ }
+
+ this.setup = setup || function()
+ {
+ };
+ this.teardown = teardown || function()
+ {
+ };
+ this.isWaiting = false;
+ this.timeToWait = 1000;
+ },
+ wait: function( time, nextPart )
+ {
+ this.isWaiting = true;
+ this.test = nextPart;
+ this.timeToWait = time;
+ },
+ run: function()
+ {
+ try
+ {
+ try
+ {
+ if ( !this.isWaiting ) this.setup.bind(this)();
+ this.isWaiting = false;
+ this.test.bind(this)();
+ }
+ finally
+ {
+ if ( !this.isWaiting )
+ {
+ this.teardown.bind(this)();
+ }
+ }
+ }
+ catch( e )
+ {
+ this.error(e);
+ }
+ }
+});
+
+// *EXPERIMENTAL* BDD-style testing to please non-technical folk
+// This draws many ideas from RSpec http://rspec.rubyforge.org/
+
+Test.setupBDDExtensionMethods = function()
+{
+ var METHODMAP = {
+ shouldEqual: 'assertEqual',
+ shouldNotEqual: 'assertNotEqual',
+ shouldEqualEnum: 'assertEnumEqual',
+ shouldBeA: 'assertType',
+ shouldNotBeA: 'assertNotOfType',
+ shouldBeAn: 'assertType',
+ shouldNotBeAn: 'assertNotOfType',
+ shouldBeNull: 'assertNull',
+ shouldNotBeNull: 'assertNotNull',
+
+ shouldBe: 'assertReturnsTrue',
+ shouldNotBe: 'assertReturnsFalse',
+ shouldRespondTo: 'assertRespondsTo'
+ };
+ Test.BDDMethods = {};
+ for ( m in METHODMAP )
+ {
+ Test.BDDMethods[m] =
+ eval('function(){' + 'var args = $A(arguments);' + 'var scope = args.shift();' + 'scope.' + METHODMAP[m] +
+ '.apply(scope,(args || []).concat([this])); }');
+ }
+ [Array.prototype, String.prototype, Number.prototype].each(function( p )
+ {
+ Object.extend(p, Test.BDDMethods)
+ });
+}
+
+Test.context = function( name, spec, log )
+{
+ Test.setupBDDExtensionMethods();
+
+ var compiledSpec = {};
+ var titles = {};
+ for ( specName in spec )
+ {
+ switch ( specName )
+ {
+ case "setup":
+ case "teardown":
+ compiledSpec[specName] = spec[specName];
+ break;
+ default:
+ var testName = 'test' + specName.gsub(/\s+/, '-').camelize();
+ var body = spec[specName].toString().split('\n').slice(1);
+ if ( /^\{/.test(body[0]) ) body = body.slice(1);
+ body.pop();
+ body = body.map(function( statement )
+ {
+ return statement.strip()
+ });
+ compiledSpec[testName] = body.join('\n');
+ titles[testName] = specName;
+ }
+ }
+ new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
+}; \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/checkboxlist.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/checkboxlist.ftl
new file mode 100644
index 000000000..75d8c6d82
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/checkboxlist.ftl
@@ -0,0 +1,39 @@
+<@ww.iterator value="parameters.list">
+ <#if parameters.listKey?exists>
+ <#assign itemKey = stack.findValue(parameters.listKey)/>
+ <#else>
+ <#assign itemKey = stack.findValue('top')/>
+ </#if>
+ <#if parameters.listValue?exists>
+ <#assign itemValue = stack.findString(parameters.listValue)/>
+ <#else>
+ <#assign itemValue = stack.findString('top')/>
+ </#if>
+<input type="checkbox" name="${parameters.name?html}" id="${parameters.id?html}${itemKey?html}"<#rt/>
+<#if tag.contains(parameters.nameValue, itemKey)>
+ checked="checked"<#rt/>
+</#if>
+<#if itemKey?exists>
+ value="${itemKey?html}"<#rt/>
+</#if>
+<#if parameters.disabled?default(false)>
+ disabled="disabled"<#rt/>
+</#if>
+<#if parameters.tabindex?exists>
+ tabindex="${parameters.tabindex?html}"<#rt/>
+</#if>
+<#if parameters.cssClass?exists>
+ class="${parameters.cssClass?html}"<#rt/>
+</#if>
+<#if parameters.cssStyle?exists>
+ style="${parameters.cssStyle?html}"<#rt/>
+</#if>
+<#if parameters.title?exists>
+ title="${parameters.title?html}"<#rt/>
+</#if>
+<#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
+/><#rt/>
+<label for="${parameters.id?html}${itemKey?html}"><#rt/>
+ ${itemValue}<#t/>
+</label><br/>
+</@ww.iterator>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/radiomap.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/radiomap.ftl
new file mode 100644
index 000000000..89ef578d1
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/radiomap.ftl
@@ -0,0 +1,39 @@
+<@ww.iterator value="parameters.list">
+ <#if parameters.listKey?exists>
+ <#assign itemKey = stack.findValue(parameters.listKey)/>
+ <#else>
+ <#assign itemKey = stack.findValue('top')/>
+ </#if>
+ <#if parameters.listValue?exists>
+ <#assign itemValue = stack.findString(parameters.listValue)/>
+ <#else>
+ <#assign itemValue = stack.findString('top')/>
+ </#if>
+<input type="radio" name="${parameters.name?html}" id="${parameters.id?html}${itemKey?html}"<#rt/>
+<#if tag.contains(parameters.nameValue, itemKey)>
+ checked="checked"<#rt/>
+</#if>
+<#if itemKey?exists>
+ value="${itemKey?html}"<#rt/>
+</#if>
+<#if parameters.disabled?default(false)>
+ disabled="disabled"<#rt/>
+</#if>
+<#if parameters.tabindex?exists>
+ tabindex="${parameters.tabindex?html}"<#rt/>
+</#if>
+<#if parameters.cssClass?exists>
+ class="${parameters.cssClass?html}"<#rt/>
+</#if>
+<#if parameters.cssStyle?exists>
+ style="${parameters.cssStyle?html}"<#rt/>
+</#if>
+<#if parameters.title?exists>
+ title="${parameters.title?html}"<#rt/>
+</#if>
+<#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
+/><#rt/>
+<label for="${parameters.id?html}${itemKey?html}"><#rt/>
+ ${itemValue}<#t/>
+</label><br/>
+</@ww.iterator>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/theme.properties b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/theme.properties
new file mode 100644
index 000000000..0f2fddc8c
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/archiva/theme.properties
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+parent = xhtml
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a-close.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a-close.ftl
new file mode 100644
index 000000000..706f1f49f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a-close.ftl
@@ -0,0 +1 @@
+</a><#rt/> \ No newline at end of file
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a.ftl
new file mode 100644
index 000000000..1b41b312f
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/a.ftl
@@ -0,0 +1,22 @@
+<a<#rt/>
+<#if parameters.id?if_exists != "">
+ id="${parameters.id?html}"<#rt/>
+</#if>
+<#if parameters.href?if_exists != "">
+ href="${parameters.href}"<#rt/>
+</#if>
+<#if parameters.tabindex?exists>
+ tabindex="${parameters.tabindex?html}"<#rt/>
+</#if>
+<#if parameters.cssClass?exists>
+ class="${parameters.cssClass?html}"<#rt/>
+</#if>
+<#if parameters.cssStyle?exists>
+ style="${parameters.cssStyle?html}"<#rt/>
+</#if>
+<#if parameters.title?exists>
+ title="${parameters.title?html}"<#rt/>
+</#if>
+<#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
+<#include "/${parameters.templateDir}/simple/common-attributes.ftl" />
+><#rt/>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionerror.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionerror.ftl
new file mode 100644
index 000000000..74c313652
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionerror.ftl
@@ -0,0 +1,7 @@
+<#if (actionErrors?exists && actionErrors?size > 0)>
+ <ul>
+ <#list actionErrors as error>
+ <li><span class="errorMessage">${error}</span></li>
+ </#list>
+ </ul>
+</#if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionmessage.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionmessage.ftl
new file mode 100644
index 000000000..384b75558
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/actionmessage.ftl
@@ -0,0 +1,7 @@
+<#if (actionMessages?exists && actionMessages?size > 0)>
+ <ul>
+ <#list actionMessages as message>
+ <li><span class="actionMessage">${message}</span></li>
+ </#list>
+ </ul>
+</#if>
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/hidden.ftl b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/hidden.ftl
new file mode 100644
index 000000000..c97423fe9
--- /dev/null
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/template/xhtml/hidden.ftl
@@ -0,0 +1,15 @@
+<input type="hidden"<#rt/>
+ name="${parameters.name?default("")?html}"<#rt/>
+<#if parameters.nameValue?exists>
+ value="<@ww.property value="parameters.nameValue"/>"<#rt/>
+</#if>
+<#if parameters.id?exists>
+ id="${parameters.id?html}"<#rt/>
+</#if>
+<#if parameters.cssClass?exists>
+ class="${parameters.cssClass?html}"<#rt/>
+</#if>
+<#if parameters.cssStyle?exists>
+ style="${parameters.cssStyle?html}"<#rt/>
+</#if>
+/>