| author | Andrew Eisenberg | 2012-02-02 16:32:24 (EST) |
|---|---|---|
| committer | John Arthorne | 2012-02-02 16:32:24 (EST) |
| commit | 07335a519d7aa649fed734d62455083df6cf493d (patch) (side-by-side diff) | |
| tree | ccafc872ed212f798f85a82f1dc0b063b6806f56 | |
| parent | 71fb205e87e3b18d3d3769036b95e4e03743aad6 (diff) | |
| download | org.eclipse.orion.client-07335a519d7aa649fed734d62455083df6cf493d.zip org.eclipse.orion.client-07335a519d7aa649fed734d62455083df6cf493d.tar.gz org.eclipse.orion.client-07335a519d7aa649fed734d62455083df6cf493d.tar.bz2 | |
Next step in search render refactoring
Change the API for the render function so that favorites can use it. Also, add a transformer for search results so that they conform to the new api of the render function. Create test cases. Delete commented code Reformat
6 files changed, 192 insertions, 151 deletions
diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/jsTestSuite.js b/bundles/org.eclipse.orion.client.core/web/js-tests/jsTestSuite.js index 8418f08..48b0a7a 100644 --- a/bundles/org.eclipse.orion.client.core/web/js-tests/jsTestSuite.js +++ b/bundles/org.eclipse.orion.client.core/web/js-tests/jsTestSuite.js @@ -57,7 +57,8 @@ BootstrapTest.prototype.testBootstrap = function(queue) { "/js-tests/editor/test.html", "/js-tests/textview/test.html", "/js-tests/jsContentAssist/test.html", - "/js-tests/contentTypes/test.html" + "/js-tests/contentTypes/test.html", + "/js-tests/searchRendering/test.html" ]).then(noop, errback); }); }); diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/test.html b/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/test.html new file mode 100644 index 0000000..458c27b --- a/dev/null +++ b/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/test.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> + <script type="text/javascript" src="../../orion/plugin.js"></script> + <script type="text/javascript" src="../../requirejs/require.js"></script> + <script type="text/javascript"> + require({ + baseUrl: '../..', + packages: [ + { + name: 'dojo', + location: 'org.dojotoolkit/dojo', + main: 'lib/main-browser', + lib: '.' + }, + { + name: 'dijit', + location: 'org.dojotoolkit/dijit', + main: 'lib/main', + lib: '.' + }, + { + name: 'dojox', + location: 'org.dojotoolkit/dojox', + main: 'lib/main', + lib: '.' + } + ], + paths: { + text: 'requirejs/text', + i18n: 'requirejs/i18n' + } + }); + + window.onload = function() { + require(["orion/test","./testcase"], function(test, testcase) { + test.run(testcase); + }); + }; + </script> +</head> +<body> +<p dojoAttachPoint="results" id="results"></p> +</body> +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/testcase.js b/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/testcase.js new file mode 100644 index 0000000..cb8bb22 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.core/web/js-tests/searchRendering/testcase.js @@ -0,0 +1,58 @@ +/******************************************************************************* + * @license + * Copyright (c) 2011 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: VMware - initial API and implementation + * Andrew Eisenberg - initial API and implementation + ******************************************************************************/ +/*global define XPathResult DOMParser*/ +define(["orion/assert", "orion/serviceregistry", "orion/searchRenderer"], + function(assert, mServiceregistry, mSearchRenderer) { + var tests = {}; + + tests.testEmptyRendererWithQueryName = function() { + var renderer = mSearchRenderer.makeRenderFunction(dojo.query("#results")[0], false, function(results) { + assert.equal(results.innerHTML, "<div>No matches found for <b>No results</b></div>"); + }, true); + renderer([], "No results"); + }; + tests.testEmptyRendererNoName = function() { + var renderer = mSearchRenderer.makeRenderFunction(dojo.query("#results")[0], false, function(results) { + assert.equal(results.innerHTML, ""); + }, true); + renderer([]); + }; + tests.testExternalResource = function() { + var renderer = mSearchRenderer.makeRenderFunction(dojo.query("#results")[0], false, function(results) { + assert.equal(results.innerHTML, "<table><tbody><tr><td><a href=\"http://eclipse.org\">link</a></td></tr></tbody></table>"); + }, true); + renderer([{ + name: 'link', + path: 'http://eclipse.org', + isExternalResource: true + }]); + }; + tests.testDirectory = function() { + var renderer = mSearchRenderer.makeRenderFunction(dojo.query("#results")[0], false, function(results) { + assert.equal(results.innerHTML, "<table><tbody><tr><td><a href=\"../../navigate/table.html#foo/blap\">link</a></td></tr></tbody></table>"); + }, true); + renderer([{ + name: 'link', + path: 'foo/blap', + directory: true + }]); + }; + tests.testFile = function() { + var renderer = mSearchRenderer.makeRenderFunction(dojo.query("#results")[0], false, function(results) { + assert.equal(results.innerHTML, "<table><tbody><tr><td><a href=\"../../edit/edit.html#foo/blap.js\">link</a></td></tr></tbody></table>"); + }, true); + renderer([{ + name: 'link', + path: 'foo/blap.js', + }]); + }; + return tests; +}); diff --git a/bundles/org.eclipse.orion.client.core/web/orion/searchClient.js b/bundles/org.eclipse.orion.client.core/web/orion/searchClient.js index 3155b44..d32db87 100644 --- a/bundles/org.eclipse.orion.client.core/web/orion/searchClient.js +++ b/bundles/org.eclipse.orion.client.core/web/orion/searchClient.js @@ -48,7 +48,25 @@ define(['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searchRen var qObj = mSearchUtils.parseQueryStr(query); try { this._fileService.search(qObj.location, query).then(function(jsonData) { - renderer(jsonData); + /** + * transforms the jsonData so that the result is understandable by the + * renderer + * jsonData.response.docs{ Name, Location, Directory, LineNumber } + */ + var transform = function(jsonData) { + var transformed = []; + for (var i=0; i < jsonData.response.docs.length; i++) { + var hit = jsonData.response.docs[i]; + transformed.push({name: hit.Name, + path: hit.Location, + directory: hit.Directory, + lineNumber: hit.LineNumber}); + } + return transformed; + }; + var token = jsonData.responseHeader.params.q; + token= token.substring(token.indexOf("}")+1); + renderer(transform(jsonData), token); }); } catch(error){ diff --git a/bundles/org.eclipse.orion.client.core/web/orion/searchRenderer.js b/bundles/org.eclipse.orion.client.core/web/orion/searchRenderer.js index d8d7f26..7e5e521 100644 --- a/bundles/org.eclipse.orion.client.core/web/orion/searchRenderer.js +++ b/bundles/org.eclipse.orion.client.core/web/orion/searchRenderer.js @@ -25,18 +25,21 @@ define( ['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searc * Create a renderer to display search results. * @public * @param {DOMNode} resultsNode Node under which results will be added. - * @param {Boolean} [generateHeading] generate a heading for the results + * @param {String} [heading] the heading text (HTML), or null if none required * @param {Function(DOMNode)} [onResultReady] If any results were found, this is called on the resultsNode. * @param {Boolean} [hideSummaries] Don't show the summary of what matched beside each result. * @returns a render function. */ - function makeRenderFunction(resultsNode, generateHeading, onResultReady, hideSummaries) { - + function makeRenderFunction(resultsNode, heading, onResultReady, hideSummaries) { + /** - * Displays search results under the given DOM node. - * @param {?} jsonData the results of the search. + * Displays links to resources under the given DOM node. + * @param [{name, path, lineNumber, directory, isExternalResource}] resources array of resources. + * Both directory and isExternalResource cannot be true at the same time. + * @param Strimg queryName (Optional) a human readable name to display when there are no matches. If + * not used, then there is nothing displayed for no matches */ - function render(jsonData) { + function render(resources, queryName) { //Helper function to append a path String to the end of a search result dom node var appendPath = (function() { @@ -46,17 +49,17 @@ define( ['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searc //containing some deferred work we need to do if we see the same name again. var namesSeenMap = {}; - function doAppend(domElement, hit) { - var path = hit.Path; - path = path.substring(0, path.length-hit.Name.length-1); + function doAppend(domElement, resource) { + var path = resource.path; + path = path.substring(0, path.length-resource.name.length-1); domElement.appendChild(document.createTextNode(' - ' + path + ' ')); } - function appendPath(domElement, hit) { - var name = hit.Name; + function appendPath(domElement, resource) { + var name = resource.name; if (namesSeenMap.hasOwnProperty(name)) { //Seen the name before - doAppend(domElement, hit); + doAppend(domElement, resource); var deferred = namesSeenMap[name]; if (typeof(deferred)==='function') { //We have seen the name before, but prior element left some deferred processing @@ -65,7 +68,7 @@ define( ['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searc } } else { //Not seen before, so, if we see it again in future we must append the path - namesSeenMap[name] = function() { doAppend(domElement, hit); }; + namesSeenMap[name] = function() { doAppend(domElement, resource); }; } } return appendPath; @@ -73,44 +76,43 @@ define( ['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searc var foundValidHit = false; dojo.empty(resultsNode); - var token = jsonData.responseHeader.params.q; - token= token.substring(token.indexOf("}")+1); - if (jsonData.response.numFound > 0) { + if (resources.length > 0) { var table = document.createElement('table'); - for (var i=0; i < jsonData.response.docs.length; i++) { - var hit = jsonData.response.docs[i]; -//TODO: // ignore hits in the file that launched the search -//TODO: if (!hit.Directory && hit.Location !== excludeFile) { - var col; - if (!foundValidHit) { - foundValidHit = true; - if (generateHeading) { - var heading = table.insertRow(0); - col = heading.insertCell(0); - col.innerHTML = "<h2>Search Results On</h2>"; - } - } - var row = table.insertRow(-1); - col = row.insertCell(0); - col.colspan = 2; - var hitLink = document.createElement('a'); - dojo.place(document.createTextNode(hit.Name), hitLink); - if (hit.LineNumber) { // FIXME LineNumber === 0 - dojo.place(document.createTextNode(' (Line ' + hit.LineNumber + ')'), hitLink); + for (var i=0; i < resources.length; i++) { + var resource = resources[i]; + var col; + if (!foundValidHit) { + foundValidHit = true; + if (heading) { + var headingRow = table.insertRow(0); + col = headingRow.insertCell(0); + col.innerHTML = heading; } - var loc = hit.Location; - hitLink.setAttribute('href', require.toUrl("edit/edit.html") + "#" + loc); - col.appendChild(hitLink); - appendPath(col, hit); - - if (!hideSummaries && jsonData.highlighting && jsonData.highlighting[hit.Id] && jsonData.highlighting[hit.Id].Text) { - var highlightText = jsonData.highlighting[hit.Id].Text[0]; - var highlight = table.insertRow(-1); - col = highlight.insertCell(0); - col.colspan = 2; - dojo.place(this.formatHighlight(highlightText), col, "only"); + } + var row = table.insertRow(-1); + col = row.insertCell(0); + col.colspan = 2; + var resourceLink = document.createElement('a'); + dojo.place(document.createTextNode(resource.name), resourceLink); + if (resource.LineNumber) { // FIXME LineNumber === 0 + dojo.place(document.createTextNode(' (Line ' + resource.LineNumber + ')'), resourceLink); + } + var loc = resource.location; + if (resource.isExternalResource) { + // should open link in new tab, but for now, follow the behavior of navoutliner.js + loc = resource.path; + } else { + loc = resource.directory ? + require.toUrl("navigate/table.html") + "#" + resource.path : + require.toUrl("edit/edit.html") + "#" + resource.path; + if (loc === "#") { + loc = ""; } -//TODO: } + } + + resourceLink.setAttribute('href', loc); + col.appendChild(resourceLink); + appendPath(col, resource); } dojo.place(table, resultsNode, "last"); if (typeof(onResultReady) === "function") { @@ -118,70 +120,18 @@ define( ['require', 'dojo', 'dijit', 'orion/auth', 'orion/util', 'orion/searc } } if (!foundValidHit) { - var div = dojo.place("<div>No matches found for </div>", resultsNode, "only"); - var b = dojo.create("b", null, div, "last"); - dojo.place(document.createTextNode(token), b, "only"); + // only display no matches found if we have a proper name + if (queryName) { + var div = dojo.place("<div>No matches found for </div>", resultsNode, "only"); + var b = dojo.create("b", null, div, "last"); + dojo.place(document.createTextNode(queryName), b, "only"); + if (typeof(onResultReady) === "function") { + onResultReady(resultsNode); + } + } } } return render; } -// Renderer.prototype = /**@lends orion.searchClient.Searcher.prototype*/ { -// handleError: function(response, resultsNode) { -// throw "Is anybody using this?"; -// console.error(response); -// var errorText = document.createTextNode(response); -// dojo.place(errorText, resultsNode, "only"); -// return response; -// }, -// setLocationByMetaData: function(meta){ -// var locationName = "root"; -// if(meta && meta.Directory && meta.Location && meta.Parents){ -// this.setLocationByURL(meta.Location); -// locationName = meta.Name; -// } -// var searchInputDom = dojo.byId("search"); -// if(searchInputDom && searchInputDom.placeholder){ -// if(locationName.length > 13){ -// searchInputDom.placeholder = "Search " + locationName.substring(0, 10) + "..."; -// } else { -// searchInputDom.placeholder = "Search " + locationName; -// } -// } -// if(searchInputDom && searchInputDom.title){ -// searchInputDom.title = "Type a keyword or wild card to search in " + locationName; -// } -// }, -// setLocationByURL: function(locationURL){ -// this.location = locationURL; -// }, - -// This doesn't appear to be used at all. -// /** -// * Creates a div representing the highlight snippet of a search result. -// * @param {String} str The highlight string we got from the server -// * @return {DomNode} -// * @private -// */ -// function formatHighlight(str) { -// var start = "##match", -// end = "match##", -// array = str.split(/(##match|match##)/), -// div = dojo.create("div"), -// bold; -// for (var i=0; i < array.length; i++) { -// var token = array[i]; -// if (token === start) { -// bold = dojo.create("b"); -// } else if (token === end) { -// dojo.place(bold, div, "last"); -// bold = null; -// } else { -// dojo.place(document.createTextNode(token), (bold || div), "last"); -// } -// } -// return div; -// } -// -// }; return {makeRenderFunction:makeRenderFunction}; });
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/OpenResourceDialog.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/OpenResourceDialog.js index 82e7b23..e2868af 100644 --- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/OpenResourceDialog.js +++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/OpenResourceDialog.js @@ -13,10 +13,9 @@ /*jslint browser:true*/ /*global define orion window dojo dijit*/ -define(['require', 'dojo', 'dijit', "orion/util", 'orion/searchRenderer', 'dijit/Dialog', 'dijit/form/TextBox', +define(['require', 'dojo', 'dijit', "orion/util", 'orion/searchRenderer', 'orion/favorites', 'dijit/Dialog', 'dijit/form/TextBox', 'orion/widgets/_OrionDialogMixin', 'text!orion/widgets/templates/OpenResourceDialog.html'], - function(require, dojo, dijit, mUtil, mSearchRenderer) { - + function(require, dojo, dijit, mUtil, mSearchRenderer, mFavorites) { /** * Usage: <code>new widgets.OpenResourceDialog(options).show();</code> * @@ -52,6 +51,10 @@ var OpenResourceDialog = dojo.declare("orion.widgets.OpenResourceDialog", [dijit throw new Error("Missing required argument: serviceRegistry"); } this.favService = serviceRegistry.getService("orion.core.favorite"); + if (!this.favService) { + new mFavorites.FavoritesService({serviceRegistry: serviceRegistry}); + this.favService = serviceRegistry.getService("orion.core.favorite"); + } }, /** @private */ @@ -158,49 +161,15 @@ var OpenResourceDialog = dojo.declare("orion.widgets.OpenResourceDialog", [dijit */ showFavorites: function() { var that = this; - + var renderFunction = mSearchRenderer.makeRenderFunction(that.favresults, false, dojo.hitch(that, that.decorateResult), true); return function(favs) { if (favs.navigator) { favs = favs.navigator; } - if (favs.length > 0) { - var table = document.createElement('table'); - for (var i=0; i < favs.length; i++) { - var fav = favs[i]; - var col; - var row = table.insertRow(-1); - col = row.insertCell(0); - col.colspan = 2; - var image = new Image(); - dojo.addClass(image, "commandSprite"); - dojo.addClass(image, "core-sprite-makeFavorite"); - dojo.addClass(image, "commandImage"); - // without an image, chrome will draw a border (?) - image.src = require.toUrl("images/none.png"); - col.appendChild(image); - var favLink = document.createElement('a'); - dojo.style(favLink, "verticalAlign", "middle"); - dojo.place(document.createTextNode(fav.name), favLink); - - var loc; - if (fav.isExternalResource) { - // should open link in new tab, but for now, follow the behavior of navoutliner.js - loc = fav.path; - } else { - loc = fav.directory ? require.toUrl("navigate/table.html") + "#" + fav.path : require.toUrl("edit/edit.html") + "#" + fav.path; - if (loc === "#") { - loc = ""; - } - } - favLink.setAttribute('href', loc); - col.appendChild(favLink); - } - dojo.place(table, that.favresults, "only"); + renderFunction(favs); + if (favs && favs.length > 0) { dojo.place("<hr/>", that.favresults, "last"); - } else { - dojo.empty(that.favresults); } - that.decorateResult(that.favresults); }; }, |

