. Saved Searches UI improvements as suggested by Linton

. Fix to quoted term search to allow quoted string of a single word only e.g. "baboon" (not very useful, but should at least work…!)
. Checkpoint of the Templating language enhancements ready for the addition of saved search support

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2124 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-01-17 11:57:32 +00:00
parent 97b2aaac93
commit e7ce03d4cf
14 changed files with 644 additions and 190 deletions

View File

@@ -19,13 +19,10 @@ package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -34,22 +31,16 @@ import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.template.DateCompareMethod;
import org.alfresco.repo.template.HasAspectMethod;
import org.alfresco.repo.template.I18NMessageMethod;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.component.template.DefaultModelHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
@@ -232,48 +223,17 @@ public class TemplateContentServlet extends HttpServlet
*/
private Object getModel(ServiceRegistry services, HttpSession session, NodeRef nodeRef)
{
// create FreeMarker default model and merge
Map root = new HashMap(11, 1.0f);
// supply the CompanyHome space as "companyhome"
NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver);
root.put("companyhome", companyRootNode);
// supply the users Home Space as "userhome"
User user = Application.getCurrentUser(session);
NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId());
TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver);
root.put("userhome", userRootNode);
// build FreeMarker default model and merge
Map root = DefaultModelHelper.buildDefaultModel(services, Application.getCurrentUser(session));
// put the current NodeRef in as "space" and "document"
TemplateNode node = new TemplateNode(nodeRef, services, imageResolver);
TemplateNode node = new TemplateNode(nodeRef, services, DefaultModelHelper.imageResolver);
root.put("space", node);
root.put("document", node);
// supply the current user Node as "person"
root.put("person", new TemplateNode(user.getPerson(), services, imageResolver));
// current date/time is useful to have and isn't supplied by FreeMarker by default
root.put("date", new Date());
// add custom method objects
root.put("hasAspect", new HasAspectMethod());
root.put("message", new I18NMessageMethod());
root.put("dateCompare", new DateCompareMethod());
return root;
}
/** Template Image resolver helper */
private TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(filename, small);
}
};
/**
* Helper to generate a URL to process a template against a node.
* <p>

View File

@@ -55,17 +55,20 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.CachingDateFormat;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.SearchContext.RangeProperties;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.alfresco.web.config.ClientConfigElement.CustomProperty;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.common.component.UIPanel.ExpandedEvent;
import org.alfresco.web.ui.repo.component.UICategorySelector;
import org.alfresco.web.ui.repo.component.UISearchCustomProperties;
@@ -81,6 +84,8 @@ import org.alfresco.web.ui.repo.component.UISearchCustomProperties;
*/
public class AdvancedSearchBean
{
private static final String OUTCOME_BROWSE = "browse";
/**
* Default constructor
*/
@@ -207,6 +212,22 @@ public class AdvancedSearchBean
{
this.editSearchName = editSearchName;
}
/**
* @return Returns the searchSaveGlobal.
*/
public boolean isSearchSaveGlobal()
{
return this.searchSaveGlobal;
}
/**
* @param searchSaveGlobal The searchSaveGlobal to set.
*/
public void setSearchSaveGlobal(boolean searchSaveGlobal)
{
this.searchSaveGlobal = searchSaveGlobal;
}
/**
* @return Returns the folder to search, null for all.
@@ -256,6 +277,38 @@ public class AdvancedSearchBean
this.mode = mode;
}
/**
* @return Returns the savedSearchMode.
*/
public String getSavedSearchMode()
{
return this.savedSearchMode;
}
/**
* @param savedSearchMode The savedSearchMode to set.
*/
public void setSavedSearchMode(String savedSearchMode)
{
this.savedSearchMode = savedSearchMode;
}
/**
* @return Returns the allow Edit mode.
*/
public boolean isAllowEdit()
{
return (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false);
}
/**
* @param allowEdit The allow Edit mode to set.
*/
public void setAllowEdit(boolean allowEdit)
{
// dummy method for Bean interface compliance
}
/**
* @return Returns the text to search for.
*/
@@ -754,56 +807,74 @@ public class AdvancedSearchBean
// this causes the browse screen to switch into search results view
this.navigator.setSearchContext(search);
return "browse";
return OUTCOME_BROWSE;
}
/**
* Action handler called to initiate the saved search screen
* Action handler called to initiate the saved search screen for Create
*/
public String saveSearch()
public String saveNewSearch()
{
this.searchDescription = null;
this.searchName = null;
this.searchSaveGlobal = false;
return "saveNewSearch";
}
/**
* Action handler called to initiate the saved search screen for Edit
*/
public String saveEditSearch()
{
this.searchDescription = null;
this.searchName = null;
this.editSearchName = null;
if (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false)
// load previously selected search for overwrite
try
{
// load previous for overwrite
try
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch);
Node searchNode = new Node(searchRef);
if (this.nodeService.exists(searchRef) && searchNode.hasPermission(PermissionService.WRITE))
{
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch);
Node searchNode = new Node(searchRef);
if (this.nodeService.exists(searchRef) && searchNode.hasPermission(PermissionService.WRITE))
{
Node node = new Node(searchRef);
this.searchName = node.getName();
this.editSearchName = this.searchName;
this.searchDescription = (String)node.getProperties().get(ContentModel.PROP_DESCRIPTION);
}
else
{
// unable to overwrite existing saved search
this.savedSearch = null;
}
Node node = new Node(searchRef);
this.searchName = node.getName();
this.editSearchName = this.searchName;
this.searchDescription = (String)node.getProperties().get(ContentModel.PROP_DESCRIPTION);
}
catch (Throwable err)
else
{
// unable to overwrite existing saved search for some other reason
// unable to overwrite existing saved search
this.savedSearch = null;
}
}
catch (Throwable err)
{
// unable to overwrite existing saved search for some other reason
this.savedSearch = null;
}
return "saveSearch";
return "saveEditSearch";
}
/**
* Action handler called to save the current search
* Action handler called to save a new search
*/
public String saveSearchOK()
public String saveNewSearchOK()
{
String outcome = "browse";
String outcome = OUTCOME_BROWSE;
NodeRef searchesRef;
if (isSearchSaveGlobal() == true)
{
searchesRef = getGlobalSearchesRef();
}
else
{
searchesRef = getUserSearchesRef();
}
NodeRef searchesRef = getSavedSearchesRef();
SearchContext search = this.navigator.getSearchContext();
if (searchesRef != null && search != null)
{
@@ -814,45 +885,19 @@ public class AdvancedSearchBean
tx = Repository.getUserTransaction(context);
tx.begin();
Map<QName, Serializable> props = null;
// handle Edit e.g. Overwrite of existing search
// detect if was previously selected saved search (e.g. NodeRef not null)
boolean edit = false;
if (this.savedSearch != null && NO_SELECTION.equals(this.savedSearch) == false)
{
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch);
edit = (this.nodeService.exists(searchRef));
}
// create new content node as the saved search object
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2, 1.0f);
props.put(ContentModel.PROP_NAME, this.searchName);
props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription);
ChildAssociationRef childRef = this.nodeService.createNode(
searchesRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(this.searchName)),
ContentModel.TYPE_CONTENT,
props);
ContentService contentService = Repository.getServiceRegistry(context).getContentService();
ContentWriter writer;
if (edit)
{
// edit existing saved search
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch);
props = this.nodeService.getProperties(searchRef);
props.put(ContentModel.PROP_NAME, this.searchName);
props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription);
this.nodeService.setProperties(searchRef, props);
writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true);
}
else
{
// create new content node as the saved search object
props = new HashMap<QName, Serializable>(2, 1.0f);
props.put(ContentModel.PROP_NAME, this.searchName);
props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription);
ChildAssociationRef childRef = this.nodeService.createNode(
searchesRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(this.searchName)),
ContentModel.TYPE_CONTENT,
props);
writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true);
}
ContentWriter writer = contentService.getWriter(childRef.getChildRef(), ContentModel.PROP_CONTENT, true);
// get a writer to our new node ready for XML content
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
@@ -878,6 +923,61 @@ public class AdvancedSearchBean
return outcome;
}
/**
* Action handler called to save an existing search
*/
public String saveEditSearchOK()
{
String outcome = OUTCOME_BROWSE;
SearchContext search = this.navigator.getSearchContext();
if (search != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// handle Edit e.g. Overwrite of existing search
// detect if was previously selected saved search (e.g. NodeRef not null)
NodeRef searchRef = new NodeRef(Repository.getStoreRef(), this.savedSearch);
if (this.nodeService.exists(searchRef))
{
Map<QName, Serializable> props = this.nodeService.getProperties(searchRef);
props.put(ContentModel.PROP_NAME, this.searchName);
props.put(ContentModel.PROP_DESCRIPTION, this.searchDescription);
this.nodeService.setProperties(searchRef, props);
ContentService contentService = Repository.getServiceRegistry(context).getContentService();
ContentWriter writer = contentService.getWriter(searchRef, ContentModel.PROP_CONTENT, true);
// get a writer to our new node ready for XML content
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
writer.setEncoding("UTF-8");
// output an XML serialized version of the SearchContext object
writer.putContent(search.toXML());
tx.commit();
}
this.cachedSavedSearches.clear();
this.savedSearch = null;
}
catch (Throwable e)
{
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_SAVE_SEARCH), e.getMessage()), e);
outcome = null;
}
}
return outcome;
}
/**
* @return list of saved searches as SelectItem objects
*/
@@ -887,26 +987,35 @@ public class AdvancedSearchBean
if (savedSearches == null)
{
FacesContext fc = FacesContext.getCurrentInstance();
String xpath = ".//*";
ServiceRegistry services = Repository.getServiceRegistry(fc);
NodeRef searchesRef = getSavedSearchesRef();
// get the searches list from the current user or global searches location
NodeRef searchesRef = null;
if (SAVED_SEARCHES_USER.equals(getSavedSearchMode()) == true)
{
searchesRef = getUserSearchesRef();
}
else if (SAVED_SEARCHES_GLOBAL.equals(getSavedSearchMode()) == true)
{
searchesRef = getGlobalSearchesRef();
}
// read the content nodes under the folder
if (searchesRef != null)
{
List<NodeRef> results = searchService.selectNodes(
searchesRef,
xpath,
null,
namespaceService,
false);
savedSearches = new ArrayList<SelectItem>(results.size() + 1);
if (results.size() != 0)
DictionaryService dd = services.getDictionaryService();
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(
searchesRef,
ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL);
savedSearches = new ArrayList<SelectItem>(childRefs.size() + 1);
if (childRefs.size() != 0)
{
DictionaryService dd = services.getDictionaryService();
for (NodeRef ref : results)
for (ChildAssociationRef ref : childRefs)
{
Node childNode = new Node(ref);
Node childNode = new Node(ref.getChildRef());
if (dd.isSubClass(childNode.getType(), ContentModel.TYPE_CONTENT))
{
savedSearches.add(new SelectItem(childNode.getId(), childNode.getName()));
@@ -920,7 +1029,7 @@ public class AdvancedSearchBean
}
else
{
// handle missing folder case
// handle missing/access denied folder case
savedSearches = new ArrayList<SelectItem>(1);
}
@@ -935,6 +1044,25 @@ public class AdvancedSearchBean
return savedSearches;
}
/**
* Change the current saved searches list mode based on user selection
*/
public void savedSearchModeChanged(ActionEvent event)
{
UIModeList savedModeList = (UIModeList)event.getComponent();
// get the saved searches list mode
String viewMode = savedModeList.getValue().toString();
// persist
setSavedSearchMode(viewMode);
// clear existing caches and values
// the values will be re-queried when the client requests the saved searches list
this.cachedSavedSearches.clear();
this.savedSearch = null;
}
/**
* Action handler called when a saved search is selected by the user
*/
@@ -1142,9 +1270,66 @@ public class AdvancedSearchBean
/**
* @return the cached reference to the shared Saved Searches folder
*/
private NodeRef getSavedSearchesRef()
private NodeRef getUserSearchesRef()
{
if (savedSearchesRef == null)
if (userSearchesRef == null)
{
NodeRef globalRef = getGlobalSearchesRef();
if (globalRef != null)
{
FacesContext fc = FacesContext.getCurrentInstance();
User user = Application.getCurrentUser(fc);
String xpath = NamespaceService.APP_MODEL_PREFIX + ":" + QName.createValidLocalName(user.getUserName());
List<NodeRef> results = null;
try
{
results = searchService.selectNodes(
globalRef,
xpath,
null,
namespaceService,
false);
}
catch (AccessDeniedException err)
{
// ignore and return null
}
if (results != null)
{
if (results.size() == 1)
{
userSearchesRef = results.get(0);
}
else if (results.size() == 0)
{
// attempt to create folder for this user for first time
// create the preferences Node for this user
Map<QName, Serializable> props = new HashMap<QName, Serializable>(2, 1.0f);
props.put(ContentModel.PROP_NAME, user.getUserName());
ChildAssociationRef childRef = nodeService.createNode(
globalRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, QName.createValidLocalName(user.getUserName())),
ContentModel.TYPE_FOLDER,
props);
userSearchesRef = childRef.getChildRef();
}
}
}
}
return userSearchesRef;
}
/**
* @return the cached reference to the global Saved Searches folder
*/
private NodeRef getGlobalSearchesRef()
{
if (globalSearchesRef == null)
{
FacesContext fc = FacesContext.getCurrentInstance();
String xpath = Application.getRootPath(fc) + "/" +
@@ -1169,11 +1354,11 @@ public class AdvancedSearchBean
if (results != null && results.size() == 1)
{
savedSearchesRef = results.get(0);
globalSearchesRef = results.get(0);
}
}
return savedSearchesRef;
return globalSearchesRef;
}
/**
@@ -1292,7 +1477,10 @@ public class AdvancedSearchBean
private static final String LOOKIN_ALL = "all";
private static final String LOOKIN_OTHER = "other";
private static final String NO_SELECTION = "none";
private static final String SAVED_SEARCHES_USER = "user";
private static final String SAVED_SEARCHES_GLOBAL = "global";
private static final String NO_SELECTION = "NONE";
/** The NodeService to be used by the bean */
private NodeService nodeService;
@@ -1379,11 +1567,24 @@ public class AdvancedSearchBean
private boolean modifiedDateChecked = false;
private boolean createdDateChecked = false;
private NodeRef savedSearchesRef = null;
/** cached ref to the global saved searches folder */
private NodeRef globalSearchesRef = null;
/** cached ref to the current users saved searches folder */
private NodeRef userSearchesRef = null;
/** ID to the last selected saved search */
private String savedSearch = null;
/** ModeList component value for selecting user/global searches */
private String savedSearchMode = SAVED_SEARCHES_USER;
/** name of the saved search to edit */
private String editSearchName = null;
/** form field for saving search as user/global */
private boolean searchSaveGlobal = false;
/** auto-expiring cache of the list of saved searches */
private ExpiringValueCache<List<SelectItem>> cachedSavedSearches = new ExpiringValueCache<List<SelectItem>>();
}

View File

@@ -138,7 +138,7 @@ public final class SearchContext implements Serializable
if (text.length() != 0 && text.length() >= minimum)
{
if (text.indexOf(' ') == -1)
if (text.indexOf(' ') == -1 && text.charAt(0) != '"')
{
// simple single word text search
if (text.charAt(0) != '*')

View File

@@ -0,0 +1,107 @@
/*
* 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.
*/
package org.alfresco.web.ui.repo.component.template;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.template.DateCompareMethod;
import org.alfresco.repo.template.HasAspectMethod;
import org.alfresco.repo.template.I18NMessageMethod;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.common.Utils;
/**
* Helper class to generate the default template model.
* <p>
* See {@link http://www.alfresco.org/mediawiki/index.php/Template_Guide}
*
* @author Kevin Roast
*/
public class DefaultModelHelper
{
/**
* Private Constructor
*/
private DefaultModelHelper()
{
}
/**
* Construct the default FreeMarker template model.
* <p>
* Other root level objects such as the current Space or Document are generally
* added by the appropriate bean responsible for provided access to those nodes.
* <p>
* See {@link http://www.alfresco.org/mediawiki/index.php/Template_Guide}
*
* @return Map containing the default model.
*/
public static Map buildDefaultModel(ServiceRegistry services, User user)
{
if (services == null)
{
throw new IllegalArgumentException("ServiceRegistry is mandatory.");
}
if (user == null)
{
throw new IllegalArgumentException("Current User is mandatory.");
}
// create FreeMarker default model and merge
Map root = new HashMap(16, 1.0f);
// supply the CompanyHome space as "companyhome"
NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver);
root.put("companyhome", companyRootNode);
// supply the users Home Space as "userhome"
NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId());
TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver);
root.put("userhome", userRootNode);
// supply the current user Node as "person"
root.put("person", new TemplateNode(user.getPerson(), services, imageResolver));
// current date/time is useful to have and isn't supplied by FreeMarker by default
root.put("date", new Date());
// add custom method objects
root.put("hasAspect", new HasAspectMethod());
root.put("message", new I18NMessageMethod());
root.put("dateCompare", new DateCompareMethod());
return root;
}
/** Template Image resolver helper */
public static TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(filename, small);
}
};
}

View File

@@ -191,33 +191,11 @@ public class UITemplate extends SelfRenderingComponent
if (getEngine().equals(ENGINE_DEFAULT))
{
// create FreeMarker default model and merge
Map root = new HashMap(11, 1.0f);
FacesContext context = FacesContext.getCurrentInstance();
ServiceRegistry services = Repository.getServiceRegistry(context);
// supply the CompanyHome space as "companyhome"
NodeRef companyRootRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TemplateNode companyRootNode = new TemplateNode(companyRootRef, services, imageResolver);
root.put("companyhome", companyRootNode);
// supply the users Home Space as "userhome"
User user = Application.getCurrentUser(context);
NodeRef userRootRef = new NodeRef(Repository.getStoreRef(), user.getHomeSpaceId());
TemplateNode userRootNode = new TemplateNode(userRootRef, services, imageResolver);
root.put("userhome", userRootNode);
// supply the current user Node as "person"
root.put("person", new TemplateNode(user.getPerson(), services, imageResolver));
// current date/time is useful to have and isn't supplied by FreeMarker by default
root.put("date", new Date());
// add custom method objects
root.put("hasAspect", new HasAspectMethod());
root.put("message", new I18NMessageMethod());
root.put("dateCompare", new DateCompareMethod());
// create an instance of the default FreeMarker template object model
FacesContext fc = FacesContext.getCurrentInstance();
ServiceRegistry services = Repository.getServiceRegistry(fc);
User user = Application.getCurrentUser(fc);
Map root = DefaultModelHelper.buildDefaultModel(services, user);
// merge models
if (model instanceof Map)

View File

@@ -175,9 +175,13 @@
<to-view-id>/jsp/forums/topic.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>saveSearch</from-outcome>
<from-outcome>saveNewSearch</from-outcome>
<to-view-id>/jsp/dialog/save-search.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>saveEditSearch</from-outcome>
<to-view-id>/jsp/dialog/edit-search.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<!-- Admin Console rules -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -159,11 +159,14 @@
<%--<div style="padding-top:2px"><a:statusMessage id="status2" border="yellowInner" bgcolor="#ffffcc" binding="#{BrowseBean.statusMessage}" /></div>--%>
</td>
<td bgcolor="#465F7D" width=1></td>
<td width=100 style="padding-left:2px">
<td width=135 style="padding-left:2px">
<%-- Current object actions --%>
<h:outputText style="padding-left:20px" styleClass="mainSubTitle" value="#{msg.actions}" id="msg14" /><br>
<a:actionLink value="#{msg.new_search}" image="/images/icons/search_icon.gif" padding="4" action="advSearch" id="link20" />
<a:actionLink value="#{msg.save_search}" image="/images/icons/save_search.gif" padding="4" action="#{AdvancedSearchBean.saveSearch}" id="link20_1" />
<a:actionLink value="#{msg.save_new_search}" image="/images/icons/save_search.gif" padding="4" action="#{AdvancedSearchBean.saveNewSearch}" id="link20_1" />
<a:booleanEvaluator value="#{AdvancedSearchBean.allowEdit == true}" id="eval0">
<a:actionLink value="#{msg.save_edit_search}" image="/images/icons/edit_search.gif" padding="4" action="#{AdvancedSearchBean.saveEditSearch}" id="link20_2" />
</a:booleanEvaluator>
<a:actionLink value="#{msg.close_search}" image="/images/icons/action.gif" padding="4" actionListener="#{BrowseBean.closeSearch}" id="link21" />
</td>
</a:panel>

View File

@@ -92,14 +92,21 @@
<a:actionLink value="#{msg.resetall}" image="/images/icons/delete.gif" padding="4" actionListener="#{AdvancedSearchBean.reset}" />
</td>
<td bgcolor="#465F7D" width=1></td>
<td width=100 style="padding-left:2px">
<td width=200 style="padding-left:2px">
<%-- Available Saved Searches --%>
<h:outputText style="padding-left:20px" styleClass="mainSubTitle" value="#{msg.saved_searches}" />
<div style="padding-top:4px;white-space:nowrap">
<center><h:outputText styleClass="mainSubTitle" value="#{msg.saved_searches}" /></center>
<div style="padding-top:4px">
<a:modeList itemSpacing="3" iconColumnWidth="20" style="text-align:right" selectedStyleClass="statusListHighlight" disabledStyleClass="statusListDisabled" selectedImage="/images/icons/Details.gif"
value="#{AdvancedSearchBean.savedSearchMode}" actionListener="#{AdvancedSearchBean.savedSearchModeChanged}">
<a:listItem value="user" label="#{msg.user_searches}" />
<a:listItem value="global" label="#{msg.global_searches}" />
</a:modeList>
</div>
<div style="white-space:nowrap">
<%-- Saved Searches drop-down selector --%>
<%-- uses a nasty hack to execute an ActionListener for the drop-down
<%-- uses a nasty hack to execute an ActionListener for the drop-down.
tried using a valueChangedListener+formsubmit but the valueChangedListener
is called too late in the lifecycle for the form controls to be managed --%>
is called too late in the lifecycle for the form controls to be modified --%>
<h:selectOneMenu id="searches" value="#{AdvancedSearchBean.savedSearch}" onchange="document.forms['advsearch']['advsearch:act'].value='advsearch:show-search'; document.forms['advsearch'].submit(); return true;">
<f:selectItems value="#{AdvancedSearchBean.savedSearches}" />
</h:selectOneMenu>

View File

@@ -148,7 +148,7 @@
actionListener="#{ClipboardBean.copyNode}">
<f:param name="id" value="#{DocumentDetailsBean.id}" />
</a:actionLink>
<%-- delete --%>
<r:permissionEvaluator value="#{DocumentDetailsBean.document}" allow="Delete">
<a:booleanEvaluator value="#{DocumentDetailsBean.locked == false && DocumentDetailsBean.workingCopy == false}">

View File

@@ -0,0 +1,203 @@
<%--
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="32kb" contentType="text/html;charset=UTF-8" %>
<%@ page isELIgnored="false" %>
<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %>
<r:page titleId="title_save_search">
<script language="JavaScript1.2">
window.onload = pageLoaded;
function pageLoaded()
{
document.getElementById("save-search:name").focus();
checkButtonState();
}
function checkButtonState()
{
if (document.getElementById("save-search:name").value.length == 0 )
{
document.getElementById("save-search:ok-button").disabled = true;
}
else
{
document.getElementById("save-search:ok-button").disabled = false;
}
}
</script>
<f:view>
<%-- load a bundle of properties with I18N strings --%>
<f:loadBundle basename="alfresco.messages.webclient" var="msg"/>
<h:form acceptCharset="UTF-8" id="save-search">
<%-- 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 valign="top">
<td width="32">
<h:graphicImage id="wizard-logo" url="/images/icons/save_search_large.gif" />
</td>
<td>
<div class="mainTitle"><h:outputText value="#{msg.save_edit_search}" /></div>
<div class="mainSubText"><h:outputText value="#{msg.save_search_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:errors message="#{msg.error_wizard}" styleClass="errorMessage" />
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
<table cellpadding="2" cellspacing="2" border="0" width="100%">
<a:panel id="edit-panel" rendered="#{AdvancedSearchBean.editSearchName != null}">
<tr>
<td width="100%" valign="top" colspan="2" style="padding-bottom:6px">
<% 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:outputFormat value="#{msg.saved_search_warning}">
<f:param value="#{AdvancedSearchBean.editSearchName}" />
</h:outputFormat>
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %>
</td>
</tr>
</a:panel>
<tr>
<td colspan="2" class="wizardSectionHeading"><h:outputText value="#{msg.search_props}" /></td>
</tr>
<tr>
<td><h:outputText value="#{msg.name}" />:</td>
<td>
<h:inputText id="name" value="#{AdvancedSearchBean.searchName}" size="35" maxlength="1024"
onkeyup="javascript:checkButtonState();" onchange="javascript:checkButtonState();"/>&nbsp;*
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.description}" />:</td>
<td>
<h:inputText value="#{AdvancedSearchBean.searchDescription}" size="35" maxlength="1024" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %>
</td>
<td valign="top">
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %>
<table cellpadding="1" cellspacing="1" border="0">
<tr>
<td align="center">
<h:commandButton id="ok-button" value="#{msg.save}" action="#{AdvancedSearchBean.saveEditSearchOK}"
styleClass="wizardButton" disabled="true" />
</td>
</tr>
<tr>
<td align="center">
<h:commandButton value="#{msg.cancel}" action="browse" styleClass="wizardButton" />
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "blue"); %>
</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

@@ -90,10 +90,10 @@
<table cellspacing="4" cellpadding="0" width="100%">
<tr valign="top">
<td width="32">
<h:graphicImage id="wizard-logo" url="/images/icons/save_search_large.gif" />
<h:graphicImage id="wizard-logo" url="/images/icons/edit_search_large.gif" />
</td>
<td>
<div class="mainTitle"><h:outputText value="#{msg.save_search}" /></div>
<div class="mainTitle"><h:outputText value="#{msg.save_new_search}" /></div>
<div class="mainSubText"><h:outputText value="#{msg.save_search_description}" /></div>
</td>
</tr>
@@ -122,25 +122,6 @@
<% PanelGenerator.generatePanelStart(out, request.getContextPath(), "white", "white"); %>
<table cellpadding="2" cellspacing="2" border="0" width="100%">
<a:panel id="edit-panel" rendered="#{AdvancedSearchBean.editSearchName != null}">
<tr>
<td width="100%" valign="top" colspan="2" style="padding-bottom:6px">
<% 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:outputFormat value="#{msg.saved_search_warning}">
<f:param value="#{AdvancedSearchBean.editSearchName}" />
</h:outputFormat>
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "yellowInner"); %>
</td>
</tr>
</a:panel>
<tr>
<td colspan="2" class="wizardSectionHeading"><h:outputText value="#{msg.search_props}" /></td>
</tr>
@@ -157,6 +138,12 @@
<h:inputText value="#{AdvancedSearchBean.searchDescription}" size="35" maxlength="1024" />
</td>
</tr>
<tr>
<td></td>
<td>
<h:selectBooleanCheckbox value="#{AdvancedSearchBean.searchSaveGlobal}" /><span style="vertical-align:20%"><h:outputText value="#{msg.save_search_global}" /></span>
</td>
</tr>
</table>
<% PanelGenerator.generatePanelEnd(out, request.getContextPath(), "white"); %>
</td>
@@ -166,7 +153,7 @@
<table cellpadding="1" cellspacing="1" border="0">
<tr>
<td align="center">
<h:commandButton id="ok-button" value="#{msg.save}" action="#{AdvancedSearchBean.saveSearchOK}"
<h:commandButton id="ok-button" value="#{msg.save}" action="#{AdvancedSearchBean.saveNewSearchOK}"
styleClass="wizardButton" disabled="true" />
</td>
</tr>