. Soft Delete UI checkpoint

- List of deleted items for an individual user
  - Object details page for a deleted item
  - Reworking of some of the Deleted Items UI
  - Filter by user/date HTML complete (no implementation yet)
  - Recover a single item to a specific location
  - I18N messages added for sys:archive aspect and properties

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2817 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-05-10 17:12:37 +00:00
parent b9da374553
commit 0b58f9ff7f
9 changed files with 533 additions and 97 deletions

View File

@@ -778,13 +778,15 @@ manage_deleted_items=Manage Deleted Items
manage_deleted_items_description=Remove or recover previously deleted items
recover_all_items=Recover All Items
delete_all_items=Delete All Items
deleted_items_info=Use the Search to find specific named deleted items and use the Filters to reduce the list.
deleted_items_info=Use the Search to find deleted items by name or content and use the filters to reduce the list.
original_location=Original Location
deleted_date=Date Deleted
deleted_user=Deleted by User
recover=Recover
clear_search_results=Clear Search Results
search_deleted_items=Search Deleted Items
search_deleted_items_name=Search by Name
search_deleted_items_text=Search by Content
deleted_items_for=for ''{0}''
delete_item=Delete Item
delete_item_info=Permanently delete an item from the deleted file store
delete_item_confirm=Are you sure you want to permanently delete \"{0}\" from the deleted file store? The item cannot be recovered once this action has been performed.
@@ -809,6 +811,10 @@ recovered_item_permission=Failed to recover the item \"{0}\" as you do not have
recovered_item_integrity=Failed to recover the item \"{0}\" as there is now an item in the original parent folder with the same name, please select a new folder destination.
recovered_item_failure=Failed to recover the item \"{0}\" due to error: {1}
delete_item_success=The item \"{0}\" has been permanently deleted.
title_deleted_item_details=Deleted Item Details
deleteditem_details_description=Details of the deleted item
alternative_destination=You may select a destination where you wish the recovered items to be placed. If you do not select a destination, the original location of the item is used. Recovery of an item may fail if the destination does not exist or you do not have permission to add items there.
deleted_when=When
# Admin Console messages
title_admin_console=Administration Console

View File

@@ -133,4 +133,11 @@
</property-sheet>
</config>
<config evaluator="aspect-name" condition="sys:archived">
<property-sheet>
<show-property name="sys:archivedBy" />
<show-property name="sys:archivedDate" />
</property-sheet>
</config>
</alfresco-config>

View File

@@ -49,7 +49,9 @@ import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.QNameNodeMap;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.wizard.NewSpaceWizard;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.Utils.URLMode;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
@@ -58,6 +60,8 @@ import org.alfresco.web.ui.common.component.data.UIRichList;
*/
public class TrashcanBean implements IContextListener
{
private static final String MSG_DELETED_ITEMS_FOR = "deleted_items_for";
private static final String MSG_DELETED_ITEMS = "deleted_items";
private static final String MSG_RECOVERED_ITEM_INTEGRITY = "recovered_item_integrity";
private static final String MSG_RECOVERED_ITEM_PERMISSION = "recovered_item_permission";
private static final String MSG_RECOVERED_ITEM_PARENT = "recovered_item_parent";
@@ -69,11 +73,15 @@ public class TrashcanBean implements IContextListener
private static final String RICHLIST_ID = "trashcan-list";
private static final String RICHLIST_MSG_ID = "trashcan" + ':' + RICHLIST_ID;
private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME);
private final static String NAME_ATTR = Repository.escapeQName(ContentModel.PROP_NAME);
private final static String USER_ATTR = Repository.escapeQName(ContentModel.PROP_ARCHIVED_BY);
private final static String SEARCH_ALL = "PARENT:\"%s\" AND ASPECT:\"%s\"";
private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":*%s* TEXT:%s)";
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND (@" + NAME_ATTR + ":\"%s\" TEXT:\"%s\")";
private final static String SEARCH_NAME = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":*%s*";
private final static String SEARCH_TEXT = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:%s";
private final static String SEARCH_NAME_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND @" + NAME_ATTR + ":\"%s\"";
private final static String SEARCH_TEXT_QUOTED = "PARENT:\"%s\" AND ASPECT:\"%s\" AND TEXT:\"%s\"";
private final static String SEARCH_USERPREFIX = "@" + USER_ATTR + ":%s AND ";
/** NodeService bean reference */
protected NodeService nodeService;
@@ -96,6 +104,8 @@ public class TrashcanBean implements IContextListener
/** We show an empty list until a Search or Show All is executed */
private boolean showItems = false;
private boolean fullTextSearch = false;
/** Currently listed items */
private List<Node> listedItems = Collections.<Node>emptyList();
@@ -105,6 +115,9 @@ public class TrashcanBean implements IContextListener
/** Root node to the spaces store archive store*/
private NodeRef archiveRootRef = null;
/** Alternative destination for recovered items */
private NodeRef destination = null;
// ------------------------------------------------------------------------------
// Bean property getters and setters
@@ -173,6 +186,67 @@ public class TrashcanBean implements IContextListener
this.searchText = searchText;
}
/**
* @return Returns the alternative destination to use if recovery fails.
*/
public NodeRef getDestination()
{
return this.destination;
}
/**
* @param destination The alternative destination to use if recovery fails.
*/
public void setDestination(NodeRef destination)
{
this.destination = destination;
}
/**
* @return Message to display in the title of the panel area
*/
public String getPanelMessage()
{
FacesContext fc = FacesContext.getCurrentInstance();
String msg = Application.getMessage(fc, MSG_DELETED_ITEMS);
if (isAdminUser() == false)
{
msg = msg + ' ' + MessageFormat.format(
Application.getMessage(fc, MSG_DELETED_ITEMS_FOR), Application.getCurrentUser(fc).getUserName());
}
return msg;
}
/**
* Returns the URL to the content for the current document item
*
* @return Content url to the current document item
*/
public String getItemBrowserUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_INLINE);
}
/**
* Returns the download URL to the content for the current document item
*
* @return Download url to the current document item
*/
public String getItemDownloadUrl()
{
return Utils.generateURL(FacesContext.getCurrentInstance(), getItem(), URLMode.HTTP_DOWNLOAD);
}
/**
* Return the Alfresco NodeRef URL for the current item node
*
* @return the Alfresco NodeRef URL
*/
public String getItemNodeRefUrl()
{
return getItem().getNodeRef().toString();
}
/**
* @return Returns the listed items.
*/
@@ -244,27 +318,24 @@ public class TrashcanBean implements IContextListener
{
QName type = this.nodeService.getType(nodeRef);
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("isFolder", resolverIsFolder);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
this.dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
{
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("typeIcon", this.resolverSmallIcon);
itemNodes.add(node);
}
else
{
MapNode node = new MapNode(nodeRef, this.nodeService, false);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("displayPath", resolverDisplayPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("typeIcon", this.resolverFileType16);
itemNodes.add(node);
}
itemNodes.add(node);
}
}
}
@@ -292,15 +363,12 @@ public class TrashcanBean implements IContextListener
private NodePropertyResolver resolverLocationPath = new NodePropertyResolver() {
public Object get(Node node) {
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
//return nodeService.getPath(childRef.getChildRef());
return (Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH);
}
};
private NodePropertyResolver resolverDisplayPath = new NodePropertyResolver() {
public Object get(Node node) {
//ChildAssociationRef childRef = (ChildAssociationRef)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
return Repository.getDisplayPath((Path)node.getProperties().get(ContentModel.PROP_ARCHIVED_ORIGINAL_PATH));
}
};
@@ -319,6 +387,20 @@ public class TrashcanBean implements IContextListener
}
};
private NodePropertyResolver resolverFileType32 = new NodePropertyResolver() {
public Object get(Node node) {
return Utils.getFileTypeImage(node.getName(), false);
}
};
private NodePropertyResolver resolverLargeIcon = new NodePropertyResolver() {
public Object get(Node node) {
QNameNodeMap props = (QNameNodeMap)node.getProperties();
String icon = (String)props.getRaw("app:icon");
return "/images/icons/" + (icon != null ? icon : NewSpaceWizard.SPACE_ICON_DEFAULT) + ".gif";
}
};
private NodePropertyResolver resolverDeletedDate = new NodePropertyResolver() {
public Object get(Node node) {
return node.getProperties().get(ContentModel.PROP_ARCHIVED_DATE);
@@ -331,23 +413,42 @@ public class TrashcanBean implements IContextListener
}
};
private NodePropertyResolver resolverIsFolder = new NodePropertyResolver() {
public Object get(Node node) {
return dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER);
}
};
// ------------------------------------------------------------------------------
// Action handlers
// TODO:
// need the following Action Handlers:
// deleteItemOK, recoverItemOK, deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
// deleteAllItemsOK, recoverAllItemsOK, recoverListedItemsOK, deleteListedItemsOK
/**
* Search the deleted item store by name
*/
public void search(ActionEvent event)
public void searchName(ActionEvent event)
{
// simply clear the current list and refresh the screen
// the search query text will be found and processed by the getItems() method
contextUpdated();
this.showItems = true;
this.fullTextSearch = false;
}
/**
* Search the deleted item store by text
*/
public void searchContent(ActionEvent event)
{
// simply clear the current list and refresh the screen
// the search query text will be found and processed by the getItems() method
contextUpdated();
this.showItems = true;
this.fullTextSearch = true;
}
/**
@@ -376,11 +477,24 @@ public class TrashcanBean implements IContextListener
NodeRef ref = new NodeRef(getArchiveRootRef().getStoreRef(), id);
Node node = new Node(ref);
// resolve icon in-case one has not been set
//node.addPropertyResolver("icon", this.resolverSpaceIcon);
node.addPropertyResolver("locationPath", resolverLocationPath);
node.addPropertyResolver("deletedDate", resolverDeletedDate);
node.addPropertyResolver("deletedBy", resolverDeletedBy);
node.addPropertyResolver("isFolder", resolverIsFolder);
if (this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_FOLDER) == true &&
this.dictionaryService.isSubClass(node.getType(), ContentModel.TYPE_SYSTEM_FOLDER) == false)
{
node.addPropertyResolver("icon", this.resolverLargeIcon);
}
else
{
node.addPropertyResolver("icon", this.resolverFileType32);
}
// prepare a node for the action context
setItem(node);
setDestination(null);
}
catch (InvalidNodeRefException refErr)
{
@@ -397,6 +511,9 @@ public class TrashcanBean implements IContextListener
contextUpdated();
}
/**
* Delete single item OK button handler
*/
public String deleteItemOK()
{
Node item = getItem();
@@ -421,6 +538,9 @@ public class TrashcanBean implements IContextListener
return OUTCOME_DIALOGCLOSE;
}
/**
* Recover single item OK button handler
*/
public String recoverItemOK()
{
String outcome = null;
@@ -434,7 +554,16 @@ public class TrashcanBean implements IContextListener
String msg;
FacesMessage errorfacesMsg = null;
RestoreNodeReport report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
// restore the node - the user may have requested a restore to a different parent
RestoreNodeReport report;
if (this.destination == null)
{
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef());
}
else
{
report = this.nodeArchiveService.restoreArchivedNode(item.getNodeRef(), this.destination, null, null);
}
switch (report.getStatus())
{
case SUCCESS:
@@ -496,7 +625,7 @@ public class TrashcanBean implements IContextListener
*/
public void resetAll(ActionEvent event)
{
// TODO: reset all filter and search
// TODO: reset all filters
}
/**
@@ -540,16 +669,43 @@ public class TrashcanBean implements IContextListener
String safeText = QueryParser.escape(this.searchText);
if (safeText.indexOf(' ') == -1)
{
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
if (this.fullTextSearch)
{
query = String.format(SEARCH_TEXT, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
else
{
query = String.format(SEARCH_NAME, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
}
else
{
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText, safeText);
if (this.fullTextSearch)
{
query = String.format(SEARCH_TEXT_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
else
{
query = String.format(SEARCH_NAME_QUOTED, archiveRootRef, ContentModel.ASPECT_ARCHIVED, safeText);
}
}
}
if (isAdminUser() == false)
{
// prefix username clause
String username = Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
query = String.format(SEARCH_USERPREFIX, username) + query;
}
return query;
}
private boolean isAdminUser()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).isAdmin();
}
// ------------------------------------------------------------------------------
// IContextListener implementation

View File

@@ -92,70 +92,73 @@ public class NodePathLinkRenderer extends BaseRenderer
{
path = (Path)val;
}
else
else if (val != null)
{
throw new IllegalArgumentException("UINodePath component 'value' property must resolve to a NodeRef or Path!");
}
boolean isBreadcrumb = false;
Boolean breadcrumb = (Boolean)component.getAttributes().get("breadcrumb");
if (breadcrumb != null)
if (val != null)
{
isBreadcrumb = breadcrumb.booleanValue();
}
boolean isDisabled = false;
Boolean disabled = (Boolean)component.getAttributes().get("disabled");
if (disabled != null)
{
isDisabled = disabled.booleanValue();
}
boolean showLeaf = false;
Boolean showLeafBool = (Boolean)component.getAttributes().get("showLeaf");
if (showLeafBool != null)
{
showLeaf = showLeafBool.booleanValue();
}
// use Spring JSF integration to get the node service bean
NodeService service = getNodeService(context);
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
tx.begin();
if (path == null)
boolean isBreadcrumb = false;
Boolean breadcrumb = (Boolean)component.getAttributes().get("breadcrumb");
if (breadcrumb != null)
{
path = service.getPath(nodeRef);
isBreadcrumb = breadcrumb.booleanValue();
}
if (isBreadcrumb == false || isDisabled == true)
boolean isDisabled = false;
Boolean disabled = (Boolean)component.getAttributes().get("disabled");
if (disabled != null)
{
out.write(buildPathAsSingular(context, component, path, showLeaf, isDisabled));
}
else
{
out.write(buildPathAsBreadcrumb(context, component, path, showLeaf));
isDisabled = disabled.booleanValue();
}
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (AccessDeniedException accessErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Throwable err)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
throw new RuntimeException(err);
boolean showLeaf = false;
Boolean showLeafBool = (Boolean)component.getAttributes().get("showLeaf");
if (showLeafBool != null)
{
showLeaf = showLeafBool.booleanValue();
}
// use Spring JSF integration to get the node service bean
NodeService service = getNodeService(context);
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
tx.begin();
if (path == null)
{
path = service.getPath(nodeRef);
}
if (isBreadcrumb == false || isDisabled == true)
{
out.write(buildPathAsSingular(context, component, path, showLeaf, isDisabled));
}
else
{
out.write(buildPathAsBreadcrumb(context, component, path, showLeaf));
}
tx.commit();
}
catch (InvalidNodeRefException refErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (AccessDeniedException accessErr)
{
// this error simple means we cannot output the path
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
catch (Throwable err)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
throw new RuntimeException(err);
}
}
}

View File

@@ -923,6 +923,10 @@
<from-outcome>deleteListedItems</from-outcome>
<to-view-id>/jsp/trashcan/delete-listed.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>itemDetails</from-outcome>
<to-view-id>/jsp/trashcan/item-details.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

View File

@@ -393,6 +393,15 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl
padding-top: 3px;
}
.filterBorders
{
padding: 2px;
background-color: #cddbe8;
border-width: 1px;
border-style: solid;
border-color: #003366;
}
.wizardSectionHeading
{
padding: 2px;

View File

@@ -0,0 +1,201 @@
<%--
Copyright (C) 2005 Alfresco, Inc.
Licensed under the Mozilla Public License version 1.1
with a permitted attribution clause. You may obtain a
copy of the License at
http://www.alfresco.org/legal/license.txt
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://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %>
<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %>
<%@ page buffer="64kb" contentType="text/html;charset=UTF-8" %>
<%@ page isELIgnored="false" %>
<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %>
<r:page titleId="title_deleted_item_details">
<f:view>
<%-- load a bundle of properties with I18N strings --%>
<f:loadBundle basename="alfresco.messages.webclient" var="msg"/>
<h:form acceptCharset="UTF-8" id="deleteditem-details">
<%-- Main outer table --%>
<table cellspacing="0" cellpadding="2">
<%-- Title bar --%>
<tr>
<td colspan="2">
<%@ include file="../parts/titlebar.jsp" %>
</td>
</tr>
<%-- Main area --%>
<tr valign="top">
<%-- Shelf --%>
<td>
<%@ include file="../parts/shelf.jsp" %>
</td>
<%-- Work Area --%>
<td width="100%">
<table cellspacing="0" cellpadding="0" width="100%">
<%-- Breadcrumb --%>
<%@ include file="../parts/breadcrumb.jsp" %>
<%-- Status and Actions --%>
<tr>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_4.gif)" width="4"></td>
<td bgcolor="#EEEEEE">
<%-- Status and Actions inner contents table --%>
<%-- Generally this consists of an icon, textual summary and actions for the current object --%>
<table cellspacing="4" cellpadding="0" width="100%">
<tr>
<td width="32">
<img src="<%=request.getContextPath()%>/images/icons/details_large.gif" width=32 height=32>
</td>
<td>
<div class="mainTitle">
<h:outputText value="#{msg.details_of}" /> '<h:outputText value="#{TrashcanBean.item.name}" />'
</div>
<div class="mainSubText">
<h:outputText value="#{msg.original_location}" />: <r:nodePath value="#{TrashcanBean.item.properties.locationPath}" breadcrumb="true" actionListener="#{BrowseBean.clickSpacePath}" />
</div>
<div class="mainSubText"><h:outputText value="#{msg.deleteditem_details_description}" /></div>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with gradient shadow --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_7.gif" width="4" height="9"></td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/statuspanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/statuspanel_9.gif" width="4" height="9"></td>
</tr>
<%-- Details --%>
<tr valign=top>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_4.gif)" width="4"></td>
<td>
<table cellspacing="0" cellpadding="3" border="0" width="100%">
<tr>
<td width="100%" valign="top">
<a:panel label="#{msg.view_links}" id="link-panel" progressive="true"
border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE">
<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
<tr>
<td>
<a:actionLink value="#{msg.view_in_browser}" href="#{TrashcanBean.itemBrowserUrl}" target="new" id="link1" rendered="#{TrashcanBean.item.properties.isFolder == false}" />
</td>
<td>
<a:actionLink value="#{msg.download_content}" href="#{TrashcanBean.itemDownloadUrl}" target="new" id="link2" rendered="#{TrashcanBean.item.properties.isFolder == false}" />
</td>
<td>
<a href='<a:outputText value="#{TrashcanBean.itemNodeRefUrl}" id="out1" />' onclick="return false;"><a:outputText value="#{msg.noderef_link}" id="out4" /></a>
</td>
</tr>
</table>
</a:panel>
<div style="padding:4px"></div>
<a:panel label="#{msg.properties}" id="properties-panel" progressive="true"
border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td width=80 align=center>
<%-- icon image for the object --%>
<table cellspacing=0 cellpadding=0 border=0>
<tr>
<td>
<div style="border: thin solid #CCCCCC; padding:4px">
<a:actionLink id="logo-content" value="#{TrashcanBean.item.name}" href="#{TrashcanBean.itemDownloadUrl}" target="new" rendered="#{TrashcanBean.item.properties.isFolder == false}"
image="#{TrashcanBean.item.properties.icon}" showLink="false" />
<a:actionLink id="logo-folder" value="#{TrashcanBean.item.name}" rendered="#{TrashcanBean.item.properties.isFolder == true}"
image="#{TrashcanBean.item.properties.icon}" showLink="false" />
</div>
</td>
<td><img src="<%=request.getContextPath()%>/images/parts/rightSideShadow42.gif" width=6 height=42></td>
</tr>
<tr>
<td colspan=2><img src="<%=request.getContextPath()%>/images/parts/bottomShadow42.gif" width=48 height=5></td>
</tr>
</table>
</td>
<td>
<%-- properties for the item --%>
<r:propertySheetGrid id="item-props" value="#{TrashcanBean.item}" var="itemProps"
columns="1" mode="view" labelStyleClass="propertiesLabel" externalConfig="true" />
<h:messages globalOnly="true" id="props-msgs" styleClass="errorMessage" layout="table" />
<h:message for="item-props" styleClass="statusMessage" />
</td>
</tr>
</table>
</a:panel>
</td>
<td valign="top">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %>
<table cellpadding="1" cellspacing="1" border="0" width="100%">
<tr>
<td align="center">
<h:commandButton value="#{msg.close}" action="dialog:close" styleClass="wizardButton" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %>
<div style="padding:4px"></div>
<%-- Item Actions --%>
<a:panel label="#{msg.actions}" id="actions-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" style="text-align:center;white-space:nowrap" progressive="true">
<a:actionLink value="#{msg.recover}" image="/images/icons/recover.gif" action="dialog:recoverItem" padding="3">
<f:param name="id" value="#{TrashcanBean.item.id}" />
</a:actionLink>
<a:actionLink value="#{msg.delete}" image="/images/icons/delete.gif" action="dialog:deleteItem" padding="3">
<f:param name="id" value="#{TrashcanBean.item.id}" />
</a:actionLink>
</a:panel>
</td>
</tr>
</table>
</td>
<td style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_6.gif)" width="4"></td>
</tr>
<%-- separator row with bottom panel graphics --%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_7.gif" width="4" height="4"></td>
<td width="100%" align="center" style="background-image: url(<%=request.getContextPath()%>/images/parts/whitepanel_8.gif)"></td>
<td><img src="<%=request.getContextPath()%>/images/parts/whitepanel_9.gif" width="4" height="4"></td>
</tr>
</table>
</td>
</tr>
</table>
</h:form>
</f:view>
</r:page>

View File

@@ -98,14 +98,41 @@
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
<table cellpadding="2" cellspacing="2" border="0">
<tr>
<td class="mainSubTitle">
<td colspan=2 class="mainSubTitle">
<h:outputFormat value="#{msg.recover_item_confirm}">
<f:param value="#{TrashcanBean.item.name}"/>
</h:outputFormat>
</td>
</tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr>
<td colspan=2>
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td valign=top style="padding-top:2px" width=20><h:graphicImage url="/images/icons/info_icon.gif" width="16" height="16"/></td>
<td class="mainSubText">
<h:outputText value="#{msg.alternative_destination}" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %>
</td>
</tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr>
<td>
<h:outputText value="#{msg.destination}" />:&nbsp;
</td>
<td width=100%>
<r:spaceSelector id="space-selector" label="#{msg.select_destination_prompt}"
value="#{TrashcanBean.destination}" styleClass="selector" />
</td>
</tr>
<tr><td colspan=2 class="paddingRow"></td></tr>
<tr>
<td colspan=2>
<%-- Error Messages --%>
<%-- messages tag to show messages not handled by other specific message tags --%>
<h:messages globalOnly="true" styleClass="errorMessage" layout="table" />

View File

@@ -40,11 +40,13 @@
{
if (document.getElementById("trashcan:search-text").value.length == 0)
{
document.getElementById("trashcan:search-btn").disabled = true;
document.getElementById("trashcan:search-btn1").disabled = true;
document.getElementById("trashcan:search-btn2").disabled = true;
}
else
{
document.getElementById("trashcan:search-btn").disabled = false;
document.getElementById("trashcan:search-btn1").disabled = false;
document.getElementById("trashcan:search-btn2").disabled = false;
}
}
</script>
@@ -123,7 +125,7 @@
<td width="100%" valign="top">
<%-- Deleted Items List --%>
<a:panel id="trashcan-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" styleClass="mainSubTitle" label="#{msg.deleted_items}">
<a:panel id="trashcan-panel" border="white" bgcolor="white" titleBorder="blue" titleBgcolor="#D3E6FE" styleClass="mainSubTitle" label="#{TrashcanBean.panelMessage}">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "yellowInner", "#ffffcc"); %>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
@@ -139,18 +141,35 @@
<%-- Search controls --%>
<div style="padding: 4px;"></div>
<h:inputText id="search-text" value="#{TrashcanBean.searchText}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;
<h:commandButton id="search-btn" value="#{msg.search_deleted_items}" actionListener="#{TrashcanBean.search}" disabled="true" />&nbsp;
<h:commandButton id="search-btn1" value="#{msg.search_deleted_items_name}" actionListener="#{TrashcanBean.searchName}" disabled="true" />&nbsp;
<h:commandButton id="search-btn2" value="#{msg.search_deleted_items_text}" actionListener="#{TrashcanBean.searchContent}" disabled="true" />&nbsp;
<h:commandButton id="clear-btn" value="#{msg.show_all}" actionListener="#{TrashcanBean.clearSearch}" />
<div style="padding: 4px;"></div>
<%-- Filter controls --%>
<table cellspacing=2 cellpadding=0 width=100%>
<tr>
<td>...TODO: Date filter here...</td>
<td class="filterBorders" width=100%>
<table cellspacing=2 cellpadding=0 width=100%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/icons/filter.gif" width=16 height=16></td>
<td style="padding-left:8px"><nobr><h:outputText value="#{msg.deleted_when}" />:</nobr></td>
<td style="padding-left:12px" width=100%><b>All</b>&nbsp;&nbsp;Today&nbsp;&nbsp;This&nbsp;&nbsp;Week&nbsp;&nbsp;This Month</td>
</tr>
</table>
</td>
<td align=right><h:commandButton id="reset-btn" value="#{msg.resetall}" actionListener="#{TrashcanBean.resetAll}" /></td>
</tr>
<tr>
<td>...TODO: Username filter here - admin only...</td>
<td class="filterBorders" width=100%>
<table cellspacing=2 cellpadding=0 width=100%>
<tr>
<td><img src="<%=request.getContextPath()%>/images/icons/filter.gif" width=16 height=16></td>
<td style="padding-left:8px"><nobr><h:outputText value="#{msg.deleted_user}" />:</nobr></td>
<td style="padding-left:12px" width=100%><b>All</b>&nbsp;&nbsp;User&nbsp;<h:inputText id="user-search" size="12" maxlength="100" style="font-size:10px" onkeyup="" /></td>
</tr>
</table>
</td>
<td></td>
</tr>
</table>
@@ -158,9 +177,9 @@
<%-- TODO: only show user filter for admin user --%>
<div style="padding: 4px;"></div>
<%-- Recover Listed Items button --%>
<h:commandButton value="#{msg.recover_listed_items}" action="dialog:recoverListedItems" />&nbsp;
<h:commandButton value="#{msg.delete_listed_items}" action="dialog:deleteListedItems" />
<%-- Recover Listed Items actions --%>
<a:actionLink value="#{msg.recover_listed_items}" image="/images/icons/recover_all.gif" action="dialog:recoverListedItems" />&nbsp;
<a:actionLink value="#{msg.delete_listed_items}" image="/images/icons/delete_all.gif" action="dialog:deleteListedItems"/>
<div style="padding: 4px;"></div>
<a:richList id="trashcan-list" binding="#{TrashcanBean.itemsRichList}" viewMode="details" pageSize="10"
@@ -168,14 +187,18 @@
value="#{TrashcanBean.items}" var="r" initialSortColumn="deletedDate" initialSortDescending="true">
<%-- Primary column showing item name --%>
<a:column primary="true" width="200" style="padding:2px;text-align:left">
<a:column primary="true" width="150" style="padding:2px;text-align:left">
<f:facet name="header">
<a:sortLink label="#{msg.name}" value="name" mode="case-insensitive" styleClass="header"/>
</f:facet>
<f:facet name="small-icon">
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" image="#{r.typeIcon}" showLink="false" styleClass="inlineAction" />
<a:actionLink value="#{r.name}" action="dialog:itemDetails" actionListener="#{TrashcanBean.setupItemAction}" image="#{r.typeIcon}" showLink="false" styleClass="inlineAction">
<f:param name="id" value="#{r.id}" />
</a:actionLink>
</f:facet>
<a:actionLink value="#{r.name}" href="#{r.url}" target="new" />
<a:actionLink value="#{r.name}" action="dialog:itemDetails" actionListener="#{TrashcanBean.setupItemAction}">
<f:param name="id" value="#{r.id}" />
</a:actionLink>
</a:column>
<%-- Original Location Path column --%>
@@ -183,11 +206,11 @@
<f:facet name="header">
<a:sortLink label="#{msg.original_location}" value="displayPath" styleClass="header"/>
</f:facet>
<r:nodePath value="#{r.locationPath}" actionListener="#{BrowseBean.clickSpacePath}" />
<r:nodePath value="#{r.locationPath}" actionListener="#{BrowseBean.clickSpacePath}" showLeaf="#{r.isFolder == false}" />
</a:column>
<%-- Deleted Date column --%>
<a:column style="text-align:left">
<a:column style="text-align:left;white-space:nowrap">
<f:facet name="header">
<a:sortLink label="#{msg.deleted_date}" value="deletedDate" styleClass="header"/>
</f:facet>