From cdc0ccf4efbeb45e4a72c26f63ea69bc6510b996 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Fri, 5 Sep 2008 11:03:58 +0000 Subject: [PATCH] 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 --- .../alfresco/slingshot/search/search.get.js | 149 ++++++++++-------- .../slingshot/search/search.get.json.ftl | 7 +- 2 files changed, 85 insertions(+), 71 deletions(-) diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js index f82b54d486..e2e5eede41 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js +++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.js @@ -98,7 +98,7 @@ function getDocumentItem(siteId, containerId, restOfPath, node) { // PENDING: how to handle comments? the document should // be returned instead - + // check whether we already processed this document if (checkProcessed(siteId + containerId, "" + node.nodeRef.toString())) { @@ -107,42 +107,33 @@ function getDocumentItem(siteId, containerId, restOfPath, node) addToProcessed(siteId + containerId, "" + node.nodeRef.toString()); // check whether this is a folder or a file + var item = null; if (node.isContainer) { - var item = {}; + item = {}; item.site = getSiteData(siteId); item.container = containerId; item.nodeRef = node.nodeRef.toString(); item.type = "folder"; - item.icon32 = node.icon32; - item.qnamePath = node.qnamePath; item.tags = (node.tags != null) ? node.tags : []; 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)); - return item; - // PENDING - return a folder result - return null; } else if (node.isDocument) { - var item = {}; + item = {}; item.site = getSiteData(siteId); item.container = containerId; item.nodeRef = node.nodeRef.toString(); item.type = "file"; - item.icon32 = node.icon32; - item.qnamePath = node.qnamePath; item.tags = (node.tags != null) ? node.tags : []; 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(); - return item; - } - else - { - return null; } + + return item; } function getBlogPostItem(siteId, containerId, restOfPath, node) @@ -181,12 +172,10 @@ function getBlogPostItem(siteId, containerId, restOfPath, node) item.container = containerId; item.nodeRef = child.nodeRef.toString(); item.type = "blogpost"; - item.icon32 = child.icon32; - item.qnamePath = child.qnamePath; item.tags = (child.tags != null) ? child.tags : []; item.name = child.name; - item.displayName = "Blog post: " + child.properties["cm:title"]; - item.browseUrl = "blog-postview?container=" + containerId + "&postId=" + child.name; + item.displayName = child.properties["cm:title"]; + item.browseUrl = "blog-postview?container=" + containerId + "&postId=" + child.name; return item; } @@ -211,23 +200,20 @@ function getForumPostItem(siteId, containerId, restOfPath, node) } addToProcessed(siteId + containerId, "" + topicNode.nodeRef.toString()); - // find the first post, which contains the post title // PENDING: error prone var postNode = topicNode.childAssocs["cm:contains"][0]; - // child is our blog post + // child is our forum post var item = {}; item.site = getSiteData(siteId); item.container = containerId; item.nodeRef = topicNode.nodeRef.toString(); item.type = "topicpost"; - item.icon32 = topicNode.icon32; - item.qnamePath = topicNode.qnamePath; item.tags = (topicNode.tags != null) ? topicNode.tags : []; item.name = topicNode.name; - item.displayName = "Forum topic: " + postNode.properties["cm:title"]; - item.browseUrl = "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name; + item.displayName = postNode.properties["cm:title"]; + item.browseUrl = "discussions-topicview?container=" + containerId + "&topicId=" + topicNode.name; return item; } @@ -252,11 +238,9 @@ function getCalendarItem(siteId, containerId, restOfPath, node) item.container = containerId; item.nodeRef = node.nodeRef.toString(); item.type = "calendarevent"; - item.icon32 = node.icon32; - item.qnamePath = node.qnamePath; item.tags = (node.tags != null) ? node.tags : []; item.name = node.name; - item.displayName = "Calendar event: " + node.properties["ia:whatEvent"]; + item.displayName = node.properties["ia:whatEvent"]; item.browseUrl = containerId; // this is "calendar" return item; @@ -265,7 +249,7 @@ function getCalendarItem(siteId, containerId, restOfPath, node) function getWikiItem(siteId, containerId, restOfPath, node) { // only process documents - if (! node.isDocument) + if (!node.isDocument) { return null; } @@ -282,11 +266,9 @@ function getWikiItem(siteId, containerId, restOfPath, node) item.container = containerId; item.nodeRef = node.nodeRef.toString(); item.type = "wikipage"; - item.icon32 = node.icon32; - item.qnamePath = node.qnamePath; item.tags = (node.tags != null) ? node.tags : []; 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"]; return item; @@ -336,12 +318,14 @@ function splitQNamePath(node) { return null; } + var tmp = path.substring(SITES_SPACE_QNAME_PATH.length); var pos = tmp.indexOf('/'); if (pos < 1) { return null; } + var siteId = tmp.substring(0, pos); siteId = siteId.substring(siteId.indexOf(":") + 1); tmp = tmp.substring(pos + 1); @@ -350,6 +334,7 @@ function splitQNamePath(node) { return null; } + var containerId = tmp.substring(0, pos); containerId = containerId.substring(containerId.indexOf(":") + 1); var restOfPath = tmp.substring(pos + 1); @@ -364,7 +349,7 @@ function splitQNamePath(node) */ function processResults(nodes, maxResults) { - var results = new Array(); + var results = new Array(nodes.length); var added = 0; 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 // let the per-container helper function decide what to do 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) - { - results.push(item); - added++; + var item = getItem(parts[0], parts[1], parts[2], nodes[x]); + if (item != null) + { + 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) { var path = SITES_SPACE_QNAME_PATH; // "/app:company_home/st:sites/"; @@ -410,32 +398,64 @@ function getSearchResults(term, maxResults, siteId, containerId) { path += "*/"; } - - var luceneQuery = "+PATH:\"" + path + "/*\""; - if (term != null && term.length > 0) + + var luceneQuery = "" + if (term != null && term.length != 0) { - // TODO: do smarter term pre-processing. For now we simply take all words, - // which ignores * and quotes - var terms = term.split(/\W/); - + // TODO: Perform smarter term processing. For now we simply split on whitespace + // which ignores quoted phrases that may be present. + var terms = term.split(/\s/); + for (var x=0; x < terms.length; 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); } @@ -448,7 +468,6 @@ function main() var maxResults = (args["maxResults"] != undefined) ? parseInt(args["maxResults"]) : DEFAULT_MAX_RESULTS; model.data = getSearchResults(term, maxResults, siteId, containerId); - var x=0; } -main(); +main(); \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.json.ftl index 65cac0b920..792b7217ae 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.json.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/search/search.get.json.ftl @@ -6,15 +6,10 @@ { "index": ${item_index}, "nodeRef" : "${item.nodeRef}", - "qnamePath" : "${item.qnamePath}", "type": "${item.type}", - "icon32": "${item.icon32}", "name" : "${item.name!''}", "displayName": "${item.displayName!''}", "tags" : [<#list item.tags as tag>"${tag}"<#if tag_has_next>,], - <#if item.downloadUrl??> - "downloadUrl" : "${item.downloadUrl}", - <#if item.browseUrl??> "browseUrl" : "${item.browseUrl}", @@ -27,4 +22,4 @@ ] } - + \ No newline at end of file