diff --git a/source/meta-inf/application.xml b/source/META-INF/application.xml similarity index 100% rename from source/meta-inf/application.xml rename to source/META-INF/application.xml diff --git a/source/java/org/alfresco/web/app/context/UIContextService.java b/source/java/org/alfresco/web/app/context/UIContextService.java index d79c4f9103..20614cc0cf 100644 --- a/source/java/org/alfresco/web/app/context/UIContextService.java +++ b/source/java/org/alfresco/web/app/context/UIContextService.java @@ -94,6 +94,27 @@ public final class UIContextService implements Serializable this.registeredBeans.remove(bean); } + /** + * Returns a registered bean or null + * + * @param className (fully qualified name) + * + * @return IContextListener + */ + public IContextListener getRegisteredBean(String className) + { + IContextListener bean = null; + for (Class clazz : this.registeredBeans.keySet()) + { + if (clazz.getName().equals(className)) + { + bean = this.registeredBeans.get(clazz); + break; + } + } + return bean; + } + /** * Call to notify all register beans that the UI context has changed and they should * refresh themselves as appropriate. diff --git a/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java b/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java index e731baf1f9..e6b99efd5b 100644 --- a/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java +++ b/source/java/org/alfresco/web/bean/TemplateMailHelperBean.java @@ -34,6 +34,7 @@ import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.util.UrlUtil; import org.alfresco.web.app.Application; import org.alfresco.web.app.servlet.BaseTemplateContentServlet; import org.alfresco.web.app.servlet.FacesHelper; @@ -154,6 +155,7 @@ public class TemplateMailHelperBean implements Serializable } model.put("space", parentNodeRef); } + model.put("shareUrl", UrlUtil.getShareUrl(services.getSysAdminParams())); body = services.getTemplateService().processTemplate("freemarker", templateRef.toString(), model); } diff --git a/source/java/org/alfresco/web/bean/categories/CategoriesDialog.java b/source/java/org/alfresco/web/bean/categories/CategoriesDialog.java index 97b7744829..46878b4758 100644 --- a/source/java/org/alfresco/web/bean/categories/CategoriesDialog.java +++ b/source/java/org/alfresco/web/bean/categories/CategoriesDialog.java @@ -64,9 +64,12 @@ public class CategoriesDialog extends BaseDialogBean implements IContextListener private static final long serialVersionUID = -1254971127977205987L; public static final String KEY_CATEGORY = "category"; + public static final String KEY_CATEGORY_FLAG = "categoryFlag"; public static final String PARAM_CATEGORY_REF = "categoryRef"; + public static final String CATEGORIES_DIALOG_CLASS_NAME = "org.alfresco.web.bean.categories.CategoriesDialog"; + private static final String VIEW_ICONS = "icons"; private static final String VIEW_DETAILS = "details"; @@ -460,19 +463,20 @@ public class CategoriesDialog extends BaseDialogBean implements IContextListener } /** - * If category.equals(handler.label) then the breadcrumb reverts one step back - * (needed for deleting) - * Else current breadcrumb is updated accordingly to the current category - * (needed for editing) + * If category.equals(handler.label) then the breadcrumb reverts one step back
+ * (for deleting) + *

+ * Else current breadcrumb is updated accordingly to the current category
+ * (for editing) */ - protected void removeFromBreadcrumb(String category) + protected void removeFromBreadcrumb(String categoryToRemove, String categoryFlag) { // remove this node from the breadcrumb if required List location = getLocation(); CategoryBreadcrumbHandler handler = (CategoryBreadcrumbHandler) location.get(location.size() - 1); // see if the current breadcrumb location is our Category - if (category.equals(handler.label)) + if (categoryToRemove.equals(handler.label)) { location.remove(location.size() - 1); @@ -483,14 +487,20 @@ public class CategoriesDialog extends BaseDialogBean implements IContextListener this.setCurrentCategory(handler.nodeRef); } } + else if (categoryFlag.equals("true")) + { + // We don't need to modify the breadcrumb, as editing/deleting is made through an icon. + // the dialog should get back to the original location. + this.setCurrentCategory(handler.nodeRef); + } else { if (getCategory() != null) { handler = new CategoryBreadcrumbHandler( getCategory().getNodeRef(), Repository.getNameForNode(getNodeService(), getCategory().getNodeRef())); - location.set(location.size() - 1, handler); - this.setCurrentCategory(handler.nodeRef); + location.set(location.size() - 1, handler); + this.setCurrentCategory(handler.nodeRef); } } } @@ -628,16 +638,22 @@ public class CategoriesDialog extends BaseDialogBean implements IContextListener @Override public void restored() { - Object categoryToRemove = FacesContext.getCurrentInstance().getExternalContext(). - getRequestMap().get(KEY_CATEGORY); - if (categoryToRemove != null) - { - if (logger.isDebugEnabled()) - logger.debug("Removing group '" + categoryToRemove + "' from breadcrumb"); - - removeFromBreadcrumb((String)categoryToRemove); - } - contextUpdated(); + Object categoryToRemove = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(KEY_CATEGORY); + Object categoryFlag = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(KEY_CATEGORY_FLAG); + if (categoryToRemove != null) + { + if (logger.isDebugEnabled()) + logger.debug("Removing group '" + categoryToRemove + "' from breadcrumb"); + if (categoryFlag != null) + { + removeFromBreadcrumb((String)categoryToRemove, (String)categoryFlag); + } + else + { + removeFromBreadcrumb((String)categoryToRemove, Boolean.FALSE.toString()); + } + } + contextUpdated(); } public String getViewMode() diff --git a/source/java/org/alfresco/web/bean/categories/DeleteCategoryDialog.java b/source/java/org/alfresco/web/bean/categories/DeleteCategoryDialog.java index 6ea518442f..e9b000fef4 100644 --- a/source/java/org/alfresco/web/bean/categories/DeleteCategoryDialog.java +++ b/source/java/org/alfresco/web/bean/categories/DeleteCategoryDialog.java @@ -36,8 +36,9 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.search.CategoryService; import org.alfresco.service.cmr.search.CategoryService.Depth; import org.alfresco.service.cmr.search.CategoryService.Mode; -import org.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.web.app.Application; +import org.alfresco.web.app.context.UIContextService; +import org.alfresco.web.bean.categories.CategoriesDialog.CategoryBreadcrumbHandler; import org.alfresco.web.bean.dialog.BaseDialogBean; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; @@ -45,14 +46,16 @@ import org.alfresco.web.ui.common.ReportedException; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.IBreadcrumbHandler; import org.alfresco.web.ui.common.component.data.UIRichList; -import org.alfresco.web.ui.repo.component.IRepoBreadcrumbHandler; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.ParameterCheck; public class DeleteCategoryDialog extends BaseDialogBean { private static final long serialVersionUID = -8929785826091612856L; + private static Log logger = LogFactory.getLog(DeleteCategoryDialog.class); + private static final String DEFAULT_OUTCOME = "finish"; private final static String MSG_DELETE_CATEGORY = "delete_category"; private final static String MSG_DELETE = "delete"; @@ -84,12 +87,14 @@ public class DeleteCategoryDialog extends BaseDialogBean /** Currently visible category Node */ private Node category = null; - private static Log logger = LogFactory.getLog(DeleteCategoryDialog.class); + private Boolean categoryFlag = false; + @Override public void init(Map parameters) { this.isFinished = false; + this.categoryFlag = false; // retrieve parameters String categoryRef = parameters.get(CategoriesDialog.PARAM_CATEGORY_REF); @@ -109,7 +114,9 @@ public class DeleteCategoryDialog extends BaseDialogBean // add the category to the request object so it gets picked up by // category dialog, this will allow it to be removed from the breadcrumb context.getExternalContext().getRequestMap().put( - CategoriesDialog.KEY_CATEGORY, this.category.getName()); + CategoriesDialog.KEY_CATEGORY, this.category.getName()); + context.getExternalContext().getRequestMap().put( + CategoriesDialog.KEY_CATEGORY_FLAG, this.categoryFlag.toString()); return outcome; } @@ -187,6 +194,16 @@ public class DeleteCategoryDialog extends BaseDialogBean this.category = category; } + public Boolean getCategoryFlag() + { + return categoryFlag; + } + + public void setCategoryFlag(Boolean categoryFlag) + { + this.categoryFlag = categoryFlag; + } + /** * @param node Set the Node to be used for the current category screen action. */ @@ -226,14 +243,6 @@ public class DeleteCategoryDialog extends BaseDialogBean */ public List getLocation() { - if (this.location == null) - { - List loc = new ArrayList(8); - CategoriesDialog categoriesDialog = new CategoriesDialog(); - loc.add(categoriesDialog.new CategoryBreadcrumbHandler(null, Application.getMessage(FacesContext.getCurrentInstance(), MSG_CATEGORIES))); - - setLocation(loc); - } return this.location; } @@ -378,24 +387,15 @@ public class DeleteCategoryDialog extends BaseDialogBean } }; NodeRef categoryNodeRef = txnHelper.doInTransaction(callback); - - // remove this node from the breadcrumb if required + + // Figure out if the deletion is made by an icon or by a list of actions + CategoriesDialog categoriesDialog = (CategoriesDialog) UIContextService.getInstance(FacesContext.getCurrentInstance()) + .getRegisteredBean(CategoriesDialog.CATEGORIES_DIALOG_CLASS_NAME); + setLocation(categoriesDialog.getLocation()); List location = getLocation(); - IBreadcrumbHandler handler = location.get(location.size() - 1); - - // see if the current breadcrumb location is our node - if (categoryNodeRef.equals(((IRepoBreadcrumbHandler) handler).getNodeRef())) - { - location.remove(location.size() - 1); - - // now work out which node to set the list to refresh against - if (location.size() != 0) - { - handler = location.get(location.size() - 1); - this.setCurrentCategory(((IRepoBreadcrumbHandler) handler).getNodeRef()); - } - } - + CategoryBreadcrumbHandler handler = (CategoryBreadcrumbHandler) location.get(location.size() - 1); + setCategoryFlag(!handler.toString().equals(getCategory().getName())); + // clear action context setActionCategory(null); } diff --git a/source/java/org/alfresco/web/bean/categories/EditCategoryDialog.java b/source/java/org/alfresco/web/bean/categories/EditCategoryDialog.java index 3d99468614..c98ca9bb1c 100644 --- a/source/java/org/alfresco/web/bean/categories/EditCategoryDialog.java +++ b/source/java/org/alfresco/web/bean/categories/EditCategoryDialog.java @@ -38,6 +38,8 @@ import org.alfresco.service.cmr.search.CategoryService.Mode; import org.alfresco.service.namespace.QName; import org.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.web.app.Application; +import org.alfresco.web.app.context.UIContextService; +import org.alfresco.web.bean.categories.CategoriesDialog.CategoryBreadcrumbHandler; import org.alfresco.web.bean.dialog.BaseDialogBean; import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; @@ -66,6 +68,8 @@ public class EditCategoryDialog extends BaseDialogBean /** Currently visible category Node */ private Node category = null; + private Boolean categoryFlag = false; + String categoryRef = null; /** Category path breadcrumb location */ @@ -85,6 +89,7 @@ public class EditCategoryDialog extends BaseDialogBean public void init(Map parameters) { this.isFinished = false; + this.categoryFlag = false; // retrieve parameters categoryRef = parameters.get(CategoriesDialog.PARAM_CATEGORY_REF); @@ -105,6 +110,8 @@ public class EditCategoryDialog extends BaseDialogBean // category dialog, this will allow it to be edited in the breadcrumb context.getExternalContext().getRequestMap().put( CategoriesDialog.KEY_CATEGORY, this.category.getName()); + context.getExternalContext().getRequestMap().put( + CategoriesDialog.KEY_CATEGORY_FLAG, this.categoryFlag.toString()); return outcome; } @@ -167,6 +174,16 @@ public class EditCategoryDialog extends BaseDialogBean this.category = category; } + public Boolean getCategoryFlag() + { + return categoryFlag; + } + + public void setCategoryFlag(Boolean categoryFlag) + { + this.categoryFlag = categoryFlag; + } + public Collection getMembers() { return members; @@ -242,14 +259,6 @@ public class EditCategoryDialog extends BaseDialogBean */ public List getLocation() { - if (this.location == null) - { - List loc = new ArrayList(8); - CategoriesDialog categoriesDialog = new CategoriesDialog(); - loc.add(categoriesDialog.new CategoryBreadcrumbHandler(null, Application.getMessage(FacesContext.getCurrentInstance(), MSG_CATEGORIES))); - - setLocation(loc); - } return this.location; } @@ -287,12 +296,22 @@ public class EditCategoryDialog extends BaseDialogBean getNodeService().setProperty(nodeRef, ContentModel.PROP_DESCRIPTION, getDescription()); } - // edit the node in the breadcrumb if required - CategoriesDialog categoriesDialog = new CategoriesDialog(); + //Figure out if the editing is made by an icon or by a list of actions + CategoriesDialog categoriesDialog = (CategoriesDialog) UIContextService.getInstance(FacesContext.getCurrentInstance()) + .getRegisteredBean(CategoriesDialog.CATEGORIES_DIALOG_CLASS_NAME); + setLocation(categoriesDialog.getLocation()); List location = getLocation(); - IBreadcrumbHandler handler = categoriesDialog.new CategoryBreadcrumbHandler(nodeRef, Repository.getNameForNode(getNodeService(), nodeRef)); - location.set(location.size() - 1, handler); - setCategory(new Node(nodeRef)); + CategoryBreadcrumbHandler handler = (CategoryBreadcrumbHandler) location.get(location.size() - 1); + if (!handler.toString().equals(getCategory().getName())) + { + setCategoryFlag(true); + } + else + { + setCategoryFlag(false); + } + Node categoryNode = new Node(nodeRef); + setCategory(categoryNode); } catch (Throwable err) { diff --git a/source/java/org/alfresco/web/bean/coci/EditOnlineDialog.java b/source/java/org/alfresco/web/bean/coci/EditOnlineDialog.java index 2a9cb24b14..934652b525 100644 --- a/source/java/org/alfresco/web/bean/coci/EditOnlineDialog.java +++ b/source/java/org/alfresco/web/bean/coci/EditOnlineDialog.java @@ -33,6 +33,7 @@ import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.UIActionLink; +import org.springframework.extensions.webscripts.ui.common.StringUtils; /** * This base dialog class provides methods for online editing. It does @@ -132,7 +133,7 @@ public class EditOnlineDialog extends CCCheckoutFileDialog else { // make content available to the html editing screen - property.setDocumentContent(reader.getContentString()); + property.setDocumentContent(StringUtils.stripUnsafeHTMLTags(reader.getContentString(), false)); property.setEditorOutput(null); // navigate to appropriate screen diff --git a/source/java/org/alfresco/web/bean/search/SearchContext.java b/source/java/org/alfresco/web/bean/search/SearchContext.java index 306cf8e366..122e8d30c2 100644 --- a/source/java/org/alfresco/web/bean/search/SearchContext.java +++ b/source/java/org/alfresco/web/bean/search/SearchContext.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -153,13 +153,12 @@ public class SearchContext implements Serializable // the QName for the well known "name" attribute String nameAttr = Repository.escapeQName(QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, ELEMENT_NAME)); + StringBuilder plBuf = new StringBuilder("("); + StringBuilder mnBuf = new StringBuilder("-("); + // match against content text String text = this.text.trim(); - StringBuilder fullTextBuf = new StringBuilder(64); - StringBuilder nameAttrBuf = new StringBuilder(128); - StringBuilder additionalAttrsBuf = new StringBuilder(128); - if (text.length() != 0 && text.length() >= minimum) { if (text.indexOf(' ') == -1 && text.charAt(0) != '"') @@ -178,15 +177,16 @@ public class SearchContext implements Serializable // prepend NOT operator if supplied if (operatorNOT) { - fullTextBuf.append(OP_NOT); - nameAttrBuf.append(OP_NOT); + processSearchTextAttribute(nameAttr, text, mode == SEARCH_FILE_NAMES_CONTENTS || mode == SEARCH_ALL, mnBuf); } - processSearchTextAttribute(nameAttr, text, nameAttrBuf, fullTextBuf); - for (QName qname : this.simpleSearchAdditionalAttrs) + // prepend AND operator if supplied + if (operatorAND) { - processSearchAttribute(qname, text, additionalAttrsBuf, false, operatorNOT); + processSearchTextAttribute(nameAttr, text, mode == SEARCH_FILE_NAMES_CONTENTS || mode == SEARCH_ALL, plBuf); } + + processSearchAdditionalAttribute(text, operatorNOT, operatorAND, mnBuf, plBuf, this.simpleSearchAdditionalAttrs); } } else @@ -196,11 +196,11 @@ public class SearchContext implements Serializable { // as a single quoted phrase String quotedSafeText = '"' + QueryParser.escape(text.substring(1, text.length() - 1)) + '"'; - fullTextBuf.append("TEXT:").append(quotedSafeText); - nameAttrBuf.append("@").append(nameAttr).append(":").append(quotedSafeText); + plBuf.append("TEXT:").append(quotedSafeText); + plBuf.append(" @").append(nameAttr).append(":").append(quotedSafeText); for (QName qname : this.simpleSearchAdditionalAttrs) { - additionalAttrsBuf.append(" @").append( + plBuf.append(" @").append( Repository.escapeQName(qname)).append(":").append(quotedSafeText); } } @@ -209,10 +209,6 @@ public class SearchContext implements Serializable // as individual search terms StringTokenizer t = new StringTokenizer(text, " "); - fullTextBuf.append('('); - nameAttrBuf.append('('); - additionalAttrsBuf.append('('); - int termCount = 0; int tokenCount = t.countTokens(); for (int i=0; i= minimum) { + StringBuilder buf = new StringBuilder(128); + if (plBuf.length() > 2) + { + buf.append(plBuf); + if (mnBuf.length() > 3) + { + buf.append(" AND "); + } + } + if (mnBuf.length() > 3) + { + buf.append(mnBuf); + } // text query for name and/or full text specified switch (mode) { case SearchContext.SEARCH_ALL: - query = '(' + fileTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + additionalAttrsQuery + ' ' + fullTextQuery + ')' + ')' + + query = '(' + fileTypeQuery + " AND " + '(' + buf + ')' + ')' + ' ' + - '(' + folderTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + additionalAttrsQuery + "))"; + '(' + folderTypeQuery + " AND " + '(' + buf + "))"; break; case SearchContext.SEARCH_FILE_NAMES: - query = fileTypeQuery + " AND " + nameAttrQuery; - break; - case SearchContext.SEARCH_FILE_NAMES_CONTENTS: - query = fileTypeQuery + " AND " + '(' + nameAttrQuery + ' ' + fullTextQuery + ')'; + query = fileTypeQuery + " AND " + '(' + buf + ')'; break; case SearchContext.SEARCH_SPACE_NAMES: - query = folderTypeQuery + " AND " + nameAttrQuery; + query = folderTypeQuery + " AND " + buf; break; default: @@ -474,19 +468,6 @@ public class SearchContext implements Serializable return query; } - /** - * Build the lucene search terms required for the specified attribute and append to a buffer. - * Supports text values with a wildcard '*' character as the prefix and/or the suffix. - * - * @param qname QName of the attribute - * @param value Non-null value of the attribute - * @param buf Buffer to append lucene terms to - */ - private static void processSearchAttribute(QName qname, String value, StringBuilder buf) - { - processSearchAttribute(qname, value, buf, true, false); - } - /** * Build the lucene search terms required for the specified attribute and append to a buffer. * Supports text values with a wildcard '*' character as the prefix and/or the suffix. @@ -497,11 +478,9 @@ public class SearchContext implements Serializable * @param andOp If true apply the '+' AND operator as the prefix to the attribute term * @param notOp If true apply the '-' NOT operator as the prefix to the attribute term */ - private static void processSearchAttribute(QName qname, String value, StringBuilder buf, boolean andOp, boolean notOp) + private static void processSearchAttribute(QName qname, String value, StringBuilder buf) { - if (andOp) buf.append('+'); - else if (notOp) buf.append('-'); - buf.append('@').append(Repository.escapeQName(qname)).append(":\"") + buf.append(" @").append(Repository.escapeQName(qname)).append(":\"") .append(SearchContext.escape(value)).append("\" "); } @@ -514,11 +493,33 @@ public class SearchContext implements Serializable * @param attrBuf Attribute search buffer to append lucene terms to * @param textBuf Text search buffer to append lucene terms to */ - private static void processSearchTextAttribute(String qname, String value, StringBuilder attrBuf, StringBuilder textBuf) + private static void processSearchTextAttribute(String qname, String value, boolean appendText, StringBuilder mnBuf) { - textBuf.append("TEXT:\"").append(SearchContext.escape(value)).append('"'); - attrBuf.append('@').append(qname).append(":\"") + mnBuf.append('@').append(qname).append(":\"") .append(SearchContext.escape(value)).append('"'); + if (appendText) + { + mnBuf.append(" TEXT:\"").append(SearchContext.escape(value)).append("\" "); + } + } + + private static void processSearchAdditionalAttribute(String value, boolean operatorNOT, boolean operatorAND, StringBuilder mnBuf, StringBuilder plBuf, + List simpleSearchAdditionalAttrs) + { + for (QName qname : simpleSearchAdditionalAttrs) + { + // prepend NOT operator if supplied + if (operatorNOT) + { + processSearchAttribute(qname, value, mnBuf); + } + + // prepend AND operator if supplied + if (operatorAND) + { + processSearchAttribute(qname, value, plBuf); + } + } } /** diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java index 5fada356b6..2355d9913b 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java @@ -834,6 +834,9 @@ public class UIUserSandboxes extends SelfRenderingComponent implements Serializa out.write(bundle.getString(MSG_ACTIONS)); out.write(""); + // assets copy to set checkbox value by node index + List assetsCopy = new ArrayList(assets); + // move conflicts to top of list if (diffCount > 0) { @@ -871,8 +874,9 @@ public class UIUserSandboxes extends SelfRenderingComponent implements Serializa out.write(id); out.write("' value='"); // the value is a username index followed by a node lookup index - out.write(Integer.toString(index) + '_' + Integer.toString(rowIndex++)); + out.write(Integer.toString(index) + '_' + Integer.toString(assetsCopy.indexOf(node))); out.write("'>"); + rowIndex++; if (isGhost == false) {