Improvements, fixes and tweaks to Share Search component and services:

- Much improved layout and CSS (as per visuals)
 - I18N of various messages in Search component and removal of hardcoded message strings from repo search service output
 - Code cleanup of repo search service and removal of obsolete data values
 - Fixes to a number of encoding issues passing search terms on URL to search page and service URLs
 - Blogs, forums, wiki and Calendar entries now shown with appropriate (placeholder!) icons and "Type" field
 - "Type" details field added to all results
 - Support for AND, OR and NOT between multiple search terms (note that OR is default as before)
  - Searches such as "alfresco and enterprise" or "alfresco not eating" are supported
 - Support for * and ? within terms
  - Searches such as "alf*" and "*look" and "a?fes?o" are supported
 - Much improved error handling and reslience for broken query strings or failed parsing
json.status.ftl fixed to output valid JSON - was not parsing

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10773 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2008-09-05 11:03:58 +00:00
parent 8d0b3f8ba6
commit cdc0ccf4ef
2 changed files with 85 additions and 71 deletions

View File

@@ -98,7 +98,7 @@ function getDocumentItem(siteId, containerId, restOfPath, node)
{ {
// PENDING: how to handle comments? the document should // PENDING: how to handle comments? the document should
// be returned instead // be returned instead
// check whether we already processed this document // check whether we already processed this document
if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString())) if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString()))
{ {
@@ -107,42 +107,33 @@ function getDocumentItem(siteId, containerId, restOfPath, node)
addToProcessed(siteId + containerId, "" + node.nodeRef.toString()); addToProcessed(siteId + containerId, "" + node.nodeRef.toString());
// check whether this is a folder or a file // check whether this is a folder or a file
var item = null;
if (node.isContainer) if (node.isContainer)
{ {
var item = {}; item = {};
item.site = getSiteData(siteId); item.site = getSiteData(siteId);
item.container = containerId; item.container = containerId;
item.nodeRef = node.nodeRef.toString(); item.nodeRef = node.nodeRef.toString();
item.type = "folder"; item.type = "folder";
item.icon32 = node.icon32;
item.qnamePath = node.qnamePath;
item.tags = (node.tags != null) ? node.tags : []; item.tags = (node.tags != null) ? node.tags : [];
item.name = node.name; item.name = node.name;
item.displayName = "Folder: " + node.name; // PENDING: node.name.replace(message("coci_service.working_copy_label"), ''); // ${item.name?replace(workingCopyLabel, "")?html}", item.displayName = node.name; // PENDING: node.name.replace(message("coci_service.working_copy_label"), ''); // ${item.name?replace(workingCopyLabel, "")?html}",
item.browseUrl = containerId + "#path=" + encodeURIComponent(getSpaceNamePath(siteId, containerId, node)); item.browseUrl = containerId + "#path=" + encodeURIComponent(getSpaceNamePath(siteId, containerId, node));
return item;
// PENDING - return a folder result
return null;
} }
else if (node.isDocument) else if (node.isDocument)
{ {
var item = {}; item = {};
item.site = getSiteData(siteId); item.site = getSiteData(siteId);
item.container = containerId; item.container = containerId;
item.nodeRef = node.nodeRef.toString(); item.nodeRef = node.nodeRef.toString();
item.type = "file"; item.type = "file";
item.icon32 = node.icon32;
item.qnamePath = node.qnamePath;
item.tags = (node.tags != null) ? node.tags : []; item.tags = (node.tags != null) ? node.tags : [];
item.name = node.name; item.name = node.name;
item.displayName = "Document: " + node.name; // PENDING: node.name.replace(message("coci_service.working_copy_label"), ''); // ${item.name?replace(workingCopyLabel, "")?html}", item.displayName = node.name; // PENDING: node.name.replace(message("coci_service.working_copy_label"), ''); // ${item.name?replace(workingCopyLabel, "")?html}",
item.browseUrl = "document-details?nodeRef=" + node.nodeRef.toString(); item.browseUrl = "document-details?nodeRef=" + node.nodeRef.toString();
return item;
}
else
{
return null;
} }
return item;
} }
function getBlogPostItem(siteId, containerId, restOfPath, node) function getBlogPostItem(siteId, containerId, restOfPath, node)
@@ -181,12 +172,10 @@ function getBlogPostItem(siteId, containerId, restOfPath, node)
item.container = containerId; item.container = containerId;
item.nodeRef = child.nodeRef.toString(); item.nodeRef = child.nodeRef.toString();
item.type = "blogpost"; item.type = "blogpost";
item.icon32 = child.icon32;
item.qnamePath = child.qnamePath;
item.tags = (child.tags != null) ? child.tags : []; item.tags = (child.tags != null) ? child.tags : [];
item.name = child.name; item.name = child.name;
item.displayName = "Blog post: " + child.properties["cm:title"]; item.displayName = child.properties["cm:title"];
item.browseUrl = "blog-postview?container=" + containerId + "&postId=" + child.name; item.browseUrl = "blog-postview?container=" + containerId + "&postId=" + child.name;
return item; return item;
} }
@@ -211,23 +200,20 @@ function getForumPostItem(siteId, containerId, restOfPath, node)
} }
addToProcessed(siteId + containerId, "" + topicNode.nodeRef.toString()); addToProcessed(siteId + containerId, "" + topicNode.nodeRef.toString());
// find the first post, which contains the post title // find the first post, which contains the post title
// PENDING: error prone // PENDING: error prone
var postNode = topicNode.childAssocs["cm:contains"][0]; var postNode = topicNode.childAssocs["cm:contains"][0];
// child is our blog post // child is our forum post
var item = {}; var item = {};
item.site = getSiteData(siteId); item.site = getSiteData(siteId);
item.container = containerId; item.container = containerId;
item.nodeRef = topicNode.nodeRef.toString(); item.nodeRef = topicNode.nodeRef.toString();
item.type = "topicpost"; item.type = "topicpost";
item.icon32 = topicNode.icon32;
item.qnamePath = topicNode.qnamePath;
item.tags = (topicNode.tags != null) ? topicNode.tags : []; item.tags = (topicNode.tags != null) ? topicNode.tags : [];
item.name = topicNode.name; item.name = topicNode.name;
item.displayName = "Forum topic: " + postNode.properties["cm:title"]; item.displayName = postNode.properties["cm:title"];
item.browseUrl = "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name; item.browseUrl = "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name;
return item; return item;
} }
@@ -252,11 +238,9 @@ function getCalendarItem(siteId, containerId, restOfPath, node)
item.container = containerId; item.container = containerId;
item.nodeRef = node.nodeRef.toString(); item.nodeRef = node.nodeRef.toString();
item.type = "calendarevent"; item.type = "calendarevent";
item.icon32 = node.icon32;
item.qnamePath = node.qnamePath;
item.tags = (node.tags != null) ? node.tags : []; item.tags = (node.tags != null) ? node.tags : [];
item.name = node.name; item.name = node.name;
item.displayName = "Calendar event: " + node.properties["ia:whatEvent"]; item.displayName = node.properties["ia:whatEvent"];
item.browseUrl = containerId; // this is "calendar" item.browseUrl = containerId; // this is "calendar"
return item; return item;
@@ -265,7 +249,7 @@ function getCalendarItem(siteId, containerId, restOfPath, node)
function getWikiItem(siteId, containerId, restOfPath, node) function getWikiItem(siteId, containerId, restOfPath, node)
{ {
// only process documents // only process documents
if (! node.isDocument) if (!node.isDocument)
{ {
return null; return null;
} }
@@ -282,11 +266,9 @@ function getWikiItem(siteId, containerId, restOfPath, node)
item.container = containerId; item.container = containerId;
item.nodeRef = node.nodeRef.toString(); item.nodeRef = node.nodeRef.toString();
item.type = "wikipage"; item.type = "wikipage";
item.icon32 = node.icon32;
item.qnamePath = node.qnamePath;
item.tags = (node.tags != null) ? node.tags : []; item.tags = (node.tags != null) ? node.tags : [];
item.name = node.name; item.name = node.name;
item.displayName = "Wiki page: " + node.properties["cm:name"]; // cm:title at some point? item.displayName = node.properties["cm:name"]; // cm:title at some point?
item.browseUrl = "wiki-page?title=" + node.properties["cm:name"]; item.browseUrl = "wiki-page?title=" + node.properties["cm:name"];
return item; return item;
@@ -336,12 +318,14 @@ function splitQNamePath(node)
{ {
return null; return null;
} }
var tmp = path.substring(SITES_SPACE_QNAME_PATH.length); var tmp = path.substring(SITES_SPACE_QNAME_PATH.length);
var pos = tmp.indexOf('/'); var pos = tmp.indexOf('/');
if (pos < 1) if (pos < 1)
{ {
return null; return null;
} }
var siteId = tmp.substring(0, pos); var siteId = tmp.substring(0, pos);
siteId = siteId.substring(siteId.indexOf(":") + 1); siteId = siteId.substring(siteId.indexOf(":") + 1);
tmp = tmp.substring(pos + 1); tmp = tmp.substring(pos + 1);
@@ -350,6 +334,7 @@ function splitQNamePath(node)
{ {
return null; return null;
} }
var containerId = tmp.substring(0, pos); var containerId = tmp.substring(0, pos);
containerId = containerId.substring(containerId.indexOf(":") + 1); containerId = containerId.substring(containerId.indexOf(":") + 1);
var restOfPath = tmp.substring(pos + 1); var restOfPath = tmp.substring(pos + 1);
@@ -364,7 +349,7 @@ function splitQNamePath(node)
*/ */
function processResults(nodes, maxResults) function processResults(nodes, maxResults)
{ {
var results = new Array(); var results = new Array(nodes.length);
var added = 0; var added = 0;
for (var x=0; x < nodes.length && added < maxResults; x++) for (var x=0; x < nodes.length && added < maxResults; x++)
@@ -372,16 +357,14 @@ function processResults(nodes, maxResults)
// for each node we extract the site/container qname path and then // for each node we extract the site/container qname path and then
// let the per-container helper function decide what to do // let the per-container helper function decide what to do
var parts = splitQNamePath(nodes[x]); var parts = splitQNamePath(nodes[x]);
if (parts == null) if (parts != null)
{ {
continue; var item = getItem(parts[0], parts[1], parts[2], nodes[x]);
} if (item != null)
{
var item = getItem(parts[0], parts[1], parts[2], nodes[x]); results.push(item);
if (item != null) added++;
{ }
results.push(item);
added++;
} }
} }
@@ -390,7 +373,12 @@ function processResults(nodes, maxResults)
}); });
} }
/* Create collection of documents */ /**
* Return Search results with the given search terms
* Terms are split on whitespace characters.
*
* AND, OR and NOT are supported keyboard as their Lucene equivilent.
*/
function getSearchResults(term, maxResults, siteId, containerId) function getSearchResults(term, maxResults, siteId, containerId)
{ {
var path = SITES_SPACE_QNAME_PATH; // "/app:company_home/st:sites/"; var path = SITES_SPACE_QNAME_PATH; // "/app:company_home/st:sites/";
@@ -410,32 +398,64 @@ function getSearchResults(term, maxResults, siteId, containerId)
{ {
path += "*/"; path += "*/";
} }
var luceneQuery = "+PATH:\"" + path + "/*\""; var luceneQuery = ""
if (term != null && term.length > 0) if (term != null && term.length != 0)
{ {
// TODO: do smarter term pre-processing. For now we simply take all words, // TODO: Perform smarter term processing. For now we simply split on whitespace
// which ignores * and quotes // which ignores quoted phrases that may be present.
var terms = term.split(/\W/); var terms = term.split(/\s/);
for (var x=0; x < terms.length; x++) for (var x=0; x < terms.length; x++)
{ {
var t = terms[x]; var t = terms[x];
if (t.length < 1) // remove quotes - TODO: add support for quoted terms later
t = t.replace(/\"/g, "");
if (t.length != 0)
{ {
continue; switch (t.toLowerCase())
{
case "and":
if (x < terms.length - 1 && terms[x + 1].length != 0)
{
luceneQuery += "AND ";
}
break;
case "or":
break;
case "not":
if (x < terms.length - 1 && terms[x + 1].length != 0)
{
luceneQuery += "NOT ";
}
break;
default:
luceneQuery += "(TEXT:\"" + t + "\"" + // full text
" @cm\\:name:\"" + t + "\"" + // name property
" PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(t) + "/member\"" + // tags
") ";
}
} }
luceneQuery += " +(" +
" TEXT:\"" + t + "\"" + // full text
" @cm\\:name:\"*" + t + "*\"" + // name property
" PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(t) + "/member\"" +
" )";
} }
} }
var nodes = search.luceneSearch(luceneQuery); var nodes;
// if we processed the search terms, then suffix the PATH query
if (luceneQuery.length != 0)
{
luceneQuery = "+PATH:\"" + path + "/*\" +(" + luceneQuery + ")";
nodes = search.luceneSearch(luceneQuery);
}
else
{
// failed to process the search string - empty list returned
nodes = new Array();
}
return processResults(nodes, maxResults); return processResults(nodes, maxResults);
} }
@@ -448,7 +468,6 @@ function main()
var maxResults = (args["maxResults"] != undefined) ? parseInt(args["maxResults"]) : DEFAULT_MAX_RESULTS; var maxResults = (args["maxResults"] != undefined) ? parseInt(args["maxResults"]) : DEFAULT_MAX_RESULTS;
model.data = getSearchResults(term, maxResults, siteId, containerId); model.data = getSearchResults(term, maxResults, siteId, containerId);
var x=0;
} }
main(); main();

View File

@@ -6,15 +6,10 @@
{ {
"index": ${item_index}, "index": ${item_index},
"nodeRef" : "${item.nodeRef}", "nodeRef" : "${item.nodeRef}",
"qnamePath" : "${item.qnamePath}",
"type": "${item.type}", "type": "${item.type}",
"icon32": "${item.icon32}",
"name" : "${item.name!''}", "name" : "${item.name!''}",
"displayName": "${item.displayName!''}", "displayName": "${item.displayName!''}",
"tags" : [<#list item.tags as tag>"${tag}"<#if tag_has_next>,</#if></#list>], "tags" : [<#list item.tags as tag>"${tag}"<#if tag_has_next>,</#if></#list>],
<#if item.downloadUrl??>
"downloadUrl" : "${item.downloadUrl}",
</#if>
<#if item.browseUrl??> <#if item.browseUrl??>
"browseUrl" : "${item.browseUrl}", "browseUrl" : "${item.browseUrl}",
</#if> </#if>
@@ -27,4 +22,4 @@
</#list> </#list>
] ]
} }
</#escape> </#escape>