Merged from BRANCHES/DEV/KEVINR:

. NodeInfo panel and Ajax client library
 - Rewrite of Node Info panel
 - Alfresco common DOM methods refactored into namespaced object (YUI/Dojo style) Alfresco.Dom
 - Addition of useful DOM and 'smart' alignment method to common.js
 - OpenSearch now uses additional namespace for it's global method handlers: Alfresco.OpenSearchEngine
 - Temporary icons added for pop-up node info panel
. Additional FreeMarker model API method "cropContent(contentprop, length)" to return the first N bytes of a content stream - auto converted to plain/text from all supported transformation mimetypes
. DownloadContentServlet now handles ContentIOException more gracefully
. AbstractContentReader fixed to handle empty file data when requesting N characters from a content stream

. Yahoo scripts move to PageTag rendering as appropriate
. Refactoring of existing ajax components that output Yahoo scripts

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5253 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2007-03-01 17:24:08 +00:00
parent 2c1fe352a3
commit a4aa830af2
13 changed files with 509 additions and 413 deletions

View File

@@ -41,6 +41,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
@@ -260,17 +261,16 @@ public abstract class BaseDownloadContentServlet extends BaseServlet
{
reader.getContent( res.getOutputStream() );
}
catch (SocketException e)
catch (SocketException e1)
{
if (e.getMessage().contains("ClientAbortException"))
{
// the client cut the connection - our mission was accomplished apart from a little error message
logger.error("Client aborted stream read:\n node: " + nodeRef + "\n content: " + reader);
}
else
{
throw e;
}
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
}
catch (Throwable err)

View File

@@ -25,16 +25,22 @@
package org.alfresco.web.bean.ajax;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.repo.template.AbsoluteUrlMethod;
import org.alfresco.repo.template.CropContentMethod;
import org.alfresco.repo.template.UrlEncodeMethod;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -47,7 +53,6 @@ import org.apache.commons.logging.LogFactory;
public class NodeInfoBean
{
private NodeService nodeService;
private ContentService contentService;
private static final Log logger = LogFactory.getLog(NodeInfoBean.class);
@@ -62,44 +67,17 @@ public class NodeInfoBean
FacesContext context = FacesContext.getCurrentInstance();
ResponseWriter out = context.getResponseWriter();
String nodeRef = (String)context.getExternalContext().getRequestParameterMap().get("noderef");
if (nodeRef == null || nodeRef.length() == 0)
String strNodeRef = (String)context.getExternalContext().getRequestParameterMap().get("noderef");
if (strNodeRef == null || strNodeRef.length() == 0)
{
throw new IllegalArgumentException("'noderef' parameter is missing");
}
NodeRef repoNode = new NodeRef(nodeRef);
if (this.nodeService.exists(repoNode))
NodeRef nodeRef = new NodeRef(strNodeRef);
if (this.nodeService.exists(nodeRef))
{
// get the client side node representation and its properties
Node clientNode = new Node(repoNode);
Map props = clientNode.getProperties();
// get the content size
Object content = props.get(ContentModel.PROP_CONTENT);
// start the containing table
out.write("<table cellpadding='3' cellspacing='0'>");
// write out information about the node as table rows
out.write("<tr><td colspan='2' class='mainSubTitle'>Summary</td></tr>");
// add debug information to the summary if debug is enabled
if (logger.isDebugEnabled())
{
writeRow(out, "Id:", clientNode.getId());
writeRow(out, "Type:", clientNode.getType().toPrefixString());
}
writeRow(out, "Description:", (String)props.get(ContentModel.PROP_DESCRIPTION));
writeRow(out, "Title:", (String)props.get(ContentModel.PROP_TITLE));
writeRow(out, "Created:", props.get("created").toString());
writeRow(out, "Modified:", props.get("modified").toString());
// close the <table> and <div> tags
out.write("<table>");
Repository.getServiceRegistry(context).getTemplateService().processTemplate(
null, "/alfresco/templates/client/summary_panel.ftl", getModel(nodeRef), out);
}
else
{
@@ -107,45 +85,45 @@ public class NodeInfoBean
}
}
// ------------------------------------------------------------------------------
// Bean getters and setters
/**
* @param nodeService The NodeService to set.
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
// ------------------------------------------------------------------------------
// Helper methods
/**
* Writes a table row with the given data
*
* @param nameColumn The name of the data item
* @param dataColumn The data
*/
protected void writeRow(ResponseWriter out, String nameColumn, String dataColumn)
throws IOException
private Map<String, Object> getModel(NodeRef nodeRef)
{
out.write("<tr><td>");
out.write(nameColumn);
out.write("</td><td>");
if (dataColumn != null)
{
out.write(dataColumn);
}
else
{
out.write("&nbsp;");
}
out.write("</td></tr>");
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
// create api methods
model.put("date", new Date());
model.put("cropContent", new CropContentMethod());
model.put("absurl", new AbsoluteUrlMethod(context.getExternalContext().getRequestContextPath()));
model.put("node", new TemplateNode(
nodeRef,
Repository.getServiceRegistry(context),
this.imageResolver));
return model;
}
/** Template Image resolver helper */
private TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(FacesContext.getCurrentInstance(), filename, small);
}
};
}

View File

@@ -96,9 +96,6 @@ public final class Utils
private static final String DEFAULT_FILE_IMAGE16 = IMAGE_PREFIX16 + "_default" + IMAGE_POSTFIX;
private static final String DEFAULT_FILE_IMAGE32 = IMAGE_PREFIX32 + "_default" + IMAGE_POSTFIX;
private static final String DOJO_SCRIPTS_WRITTEN = "_alfDojoScriptsWritten";
private static final String YAHOO_SCRIPTS_WRITTEN = "_alfYahooScriptsWritten";
private static final Map<String, String> s_fileExtensionMap = new HashMap<String, String>(89, 1.0f);
private static Log logger = LogFactory.getLog(Utils.class);
@@ -1291,96 +1288,4 @@ public final class Utils
return description;
}
/**
* Writes the script tags for including dojo support, ensuring they
* only get written once per page render.
*
* @param context Faces context
* @param out The response writer
*/
@SuppressWarnings("unchecked")
public static void writeDojoScripts(FacesContext context, ResponseWriter out)
throws IOException
{
Object present = context.getExternalContext().getRequestMap().get(DOJO_SCRIPTS_WRITTEN);
if (present == null)
{
// write out the scripts
// out.write("<script type=\"text/javascript\">");
// out.write("var djConfig = {isDebug: true, debugAtAllCosts: true };");
// out.write("</script>\n");
out.write("\n<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/dojo/dojo.js\"> </script>\n");
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/common.js\"> </script>\n");
// set the context path
out.write("<script type=\"text/javascript\">\n");
out.write("setContextPath('");
out.write(context.getExternalContext().getRequestContextPath());
out.write("');\n</script>\n");
// add marker to request
context.getExternalContext().getRequestMap().put(DOJO_SCRIPTS_WRITTEN, Boolean.TRUE);
}
}
/**
* Writes the scripts tags for using the Yahoo UI toolkit, ensuring they
* only get written once per page render.
* <p>
* A comma separated list of scripts can also be passed to determine
* which components are to be used, again these are only written once per page.
*
* @param context Faces context
* @param out The response writer
* @param scripts Comma separated list of scripts to include, if null the
* base yahoo.js script only is included.
*/
@SuppressWarnings("unchecked")
public static void writeYahooScripts(FacesContext context, ResponseWriter out,
String scripts) throws IOException
{
Object present = context.getExternalContext().getRequestMap().get(YAHOO_SCRIPTS_WRITTEN);
if (present == null)
{
// TODO: use the scripts parameter to determine which scripts to output
// also add an ajax debug flag to the config and output relevant file
// base yahoo file
out.write("\n<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/yahoo/yahoo/yahoo-min.js\"> </script>\n");
// io handling (AJAX)
out.write("\n<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/yahoo/connection/connection-min.js\"> </script>\n");
// event handling
out.write("\n<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/yahoo/event/event-min.js\"> </script>\n");
// common alfresco util methods
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/common.js\"> </script>\n");
// set the context path
out.write("<script type=\"text/javascript\">\n");
out.write("setContextPath('");
out.write(context.getExternalContext().getRequestContextPath());
out.write("');\n</script>\n");
// add marker to request
context.getExternalContext().getRequestMap().put(YAHOO_SCRIPTS_WRITTEN, Boolean.TRUE);
}
}
}

View File

@@ -69,10 +69,9 @@ public class UINodeInfo extends SelfRenderingComponent
@Override
public Object saveState(FacesContext context)
{
Object values[] = new Object[8];
// standard component attributes are saved by the super class
values[0] = super.saveState(context);
values[1] = this.value;
Object values[] = new Object[] {
super.saveState(context),
this.value};
return values;
}
@@ -87,19 +86,15 @@ public class UINodeInfo extends SelfRenderingComponent
{
ResponseWriter out = context.getResponseWriter();
// output the scripts required by the component (checks are
// made to make sure the scripts are only written once)
Utils.writeDojoScripts(context, out);
// write out the JavaScript specific to the NodeInfo component,
// again, make sure it's only done once
// make sure it's only done once
Object present = context.getExternalContext().getRequestMap().
get(NODE_INFO_SCRIPTS_WRITTEN);
if (present == null)
{
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/node-info.js\"> </script>\n");
out.write("/scripts/ajax/node-info.js\"></script>");
context.getExternalContext().getRequestMap().put(
NODE_INFO_SCRIPTS_WRITTEN, Boolean.TRUE);
@@ -107,12 +102,11 @@ public class UINodeInfo extends SelfRenderingComponent
// wrap the child components in a <span> that has the onmouseover
// event which kicks off the request for node information
String id = (String)this.getValue();
out.write("<span onmouseover=\"showNodeInfo('");
out.write(Repository.getStoreRef().toString());
out.write("/");
out.write(id);
out.write("', this)\" onmouseout=\"hideNodeInfo()\">");
// we key the node info panel by the noderef string of the current node
String noderef = Repository.getStoreRef().toString() + '/' + (String)this.getValue();
out.write("<span onclick=\"AlfNodeInfoMgr.toggle('");
out.write(noderef);
out.write("',this);\">");
}
}

View File

@@ -81,21 +81,17 @@ public class UIOpenSearch extends SelfRenderingComponent
String clientId = this.getId();
// output the scripts required by the component (checks are
// made to make sure the scripts are only written once)
Utils.writeYahooScripts(context, out, null);
// write out the JavaScript specific to the OpenSearch component,
// again, make sure it's only done once
// make sure it's only done once
Object present = context.getExternalContext().getRequestMap().get(SCRIPTS_WRITTEN);
if (present == null)
{
out.write("<link rel=\"stylesheet\" href=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/css/opensearch.css\" type=\"text/css\">\n");
out.write("/css/opensearch.css\" type=\"text/css\">");
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/opensearch.js\"> </script>\n");
out.write("/scripts/ajax/opensearch.js\"></script>");
context.getExternalContext().getRequestMap().put(SCRIPTS_WRITTEN, Boolean.TRUE);
}

View File

@@ -67,27 +67,24 @@ public class YahooTreeRenderer extends BaseRenderer
ResponseWriter out = context.getResponseWriter();
String treeContainerId = component.getClientId(context) + "Container";
// output the scripts required by the component (checks are
// made to make sure the scripts are only written once)
Utils.writeYahooScripts(context, out, null);
// write out the JavaScript specific to the Tree component,
// again, make sure it's only done once
// make sure it's only done once
Object present = context.getExternalContext().getRequestMap().
get(TREE_SCRIPTS_WRITTEN);
if (present == null)
{
String reqPath = context.getExternalContext().getRequestContextPath();
out.write("<link rel=\"stylesheet\" href=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/css/yahoo-tree.css\" type=\"text/css\" />");
out.write(reqPath);
out.write("/css/yahoo-tree.css\" type=\"text/css\">");
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/yahoo/treeview/treeview-min.js\"> </script>\n");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/treeview/treeview-min.js\"></script>");
out.write("<script type=\"text/javascript\" src=\"");
out.write(context.getExternalContext().getRequestContextPath());
out.write("/scripts/ajax/yahoo-tree.js\"> </script>\n");
out.write(reqPath);
out.write("/scripts/ajax/yahoo-tree.js\"></script>");
context.getExternalContext().getRequestMap().put(
TREE_SCRIPTS_WRITTEN, Boolean.TRUE);

View File

@@ -44,9 +44,9 @@ public class PageTag extends TagSupport
{
private static final long serialVersionUID = 8142765393181557228L;
private final static String SCRIPTS_START = "<script language=\"JavaScript1.2\" src=\"";
private final static String SCRIPTS_MENU = "/scripts/menu.js\"></script>\n";
private final static String SCRIPTS_WEBDAV = "/scripts/webdav.js\"></script>\n";
private final static String SCRIPTS_START = "<script type=\"text/javascript\" src=\"";
private final static String SCRIPTS_MENU = "/scripts/menu.js\"></script>";
private final static String SCRIPTS_WEBDAV = "/scripts/webdav.js\"></script>";
private final static String STYLES_START = "<link rel=\"stylesheet\" href=\"";
private final static String STYLES_MAIN = "/css/main.css\" TYPE=\"text/css\">\n";
@@ -148,15 +148,62 @@ public class PageTag extends TagSupport
}
String reqPath = ((HttpServletRequest)pageContext.getRequest()).getContextPath();
out.write(SCRIPTS_START);
out.write(reqPath);
out.write(SCRIPTS_MENU);
out.write(SCRIPTS_START);
out.write(reqPath);
out.write(SCRIPTS_WEBDAV);
// CSS style includes
out.write(STYLES_START);
out.write(reqPath);
out.write(STYLES_MAIN);
// menu javascript
out.write(SCRIPTS_START);
out.write(reqPath);
out.write(SCRIPTS_MENU);
// webdav javascript
out.write(SCRIPTS_START);
out.write(reqPath);
out.write(SCRIPTS_WEBDAV);
// base yahoo file
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/yahoo/yahoo-min.js\"></script>");
// io handling (AJAX)
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/connection/connection-min.js\"></script>");
// DOM handling
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/dom/dom-min.js\"></script>");
// event handling
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/event/event-min.js\"></script>");
// animation
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/animation/animation-min.js\"></script>");
// drag-drop
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/yahoo/dragdrop/dragdrop-min.js\"></script>");
// common Alfresco util methods
out.write("<script type=\"text/javascript\" src=\"");
out.write(reqPath);
out.write("/scripts/ajax/common.js\"></script>");
// set the context path used by some Alfresco script objects
out.write("<script type=\"text/javascript\">");
out.write("setContextPath('");
out.write(reqPath);
out.write("');</script>\n");
}
catch (IOException ioe)
{