From 82267aefae972054a2664f0045d26e1986b70ffc Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Tue, 10 Jan 2017 18:41:27 +0100 Subject: [PATCH] search by query added --- frontend-js/src/main/js/ServerConnector.js | 38 ++++++++++ frontend-js/src/main/js/gui/SearchPanel.js | 60 +++++++++++++++ frontend-js/src/main/js/map/CustomMap.js | 22 ++++++ frontend-js/src/main/js/map/data/MapModel.js | 52 +++++++++++++ .../main/js/map/overlay/OverlayCollection.js | 18 +++++ .../main/js/map/overlay/SearchDbOverlay.js | 74 ++++++++++++++++++- .../src/test/js/gui/SearchPanel-test.js | 19 ++++- frontend-js/src/test/js/helper.js | 13 ++++ .../js/map/overlay/OverlayCollection-test.js | 51 +++++++++++++ ...9177&projectId=sample&token=MOCK_TOKEN_ID& | 1 + ...ectId=sample&query=s1&token=MOCK_TOKEN_ID& | 1 + 11 files changed, 346 insertions(+), 3 deletions(-) create mode 100644 frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329158,329159,329169,329173,329175,329177&projectId=sample&token=MOCK_TOKEN_ID& create mode 100644 frontend-js/testFiles/apiCalls/project/getElementsByQuery/perfectMatch=false&projectId=sample&query=s1&token=MOCK_TOKEN_ID& diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index a3c34b867e..0258876860 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -736,6 +736,22 @@ ServerConnector.getClosestElementsByCoordinatesUrl = function(params) { }); }; +ServerConnector.getElementsByQueryUrl = function(params) { + var query = params.query; + var projectId = params.projectId; + var token = params.token; + var perfectMatch =params.perfectMatch; + + return this.getApiUrl({type:"project", + method:"getElementsByQuery", + params: { + projectId: projectId, + query: query, + perfectMatch: perfectMatch, + token: token}, + }); +}; + ServerConnector.getConfigurationParam = function(paramId) { var self = this; return new Promise(function(resolve, reject) { @@ -979,6 +995,28 @@ ServerConnector.getClosestElementsByCoordinates = function(params) { }); }; +ServerConnector.getElementsByQuery = function(params) { + var self = this; + return new Promise(function(resolve, reject) { + return self.getProjectId(params.projectId).then(function(result) { + params.projectId = result; + return self.getToken(); + }).then(function(token) { + params.token = token; + return self.readFile(self.getElementsByQueryUrl(params)); + }).then(function(content) { + var array=JSON.parse(content); + var result = []; + for (var i = 0; i < array.length; i++) { + result.push(new IdentifiedElement(array[i])); + } + resolve(result); + }).catch(function(exception){ + reject(exception); + }); + }); +}; + ServerConnector.addComment = function(params) { var self = this; return new Promise(function(resolve, reject) { diff --git a/frontend-js/src/main/js/gui/SearchPanel.js b/frontend-js/src/main/js/gui/SearchPanel.js index 5e9fb51b15..1c2c6c0172 100644 --- a/frontend-js/src/main/js/gui/SearchPanel.js +++ b/frontend-js/src/main/js/gui/SearchPanel.js @@ -15,6 +15,20 @@ function SearchPanel(params) { this.setMap(params.customMap); var searchDb = self.getMap().getOverlayByName('search'); + + var searchByQuery = function(){ + var query = self.getSearchInput().value; + var perfect = self.getSearchPerfectMatch().checked; + searchDb.searchByQuery(query, perfect); + }; + + self.getSearchButton().onclick= searchByQuery; + self.getSearchInput().onkeypress = function(event){ + if (event.keyCode === 13) { + searchByQuery(); + } + }; + if (searchDb === undefined) { throw new Error("Cannot find search db overlay"); } @@ -45,6 +59,15 @@ SearchPanel.prototype.setElement = function(element) { if (this.getContentElement() === undefined) { throw new Error("No tab-content div found in the search panel element"); } + if (this.getSearchButton() === undefined) { + throw new Error("No searchButton found in the search panel element"); + } + if (this.getSearchInput() === undefined) { + throw new Error("No searchInput found in the search panel element"); + } + if (this.getSearchPerfectMatch() === undefined) { + throw new Error("No searchPerfectMatch found in the search panel element"); + } }; SearchPanel.prototype.getSearchQueryElement = function() { @@ -81,6 +104,35 @@ SearchPanel.prototype.getNavElement = function() { } }; +function getElementByName(element, name) { + if (element!==undefined) { + if (element.getAttribute("name") === name) { + return element; + } + var children = element.children; + for (var i=0;i<children.length;i++) { + var child = children[i]; + var res = getElementByName(child, name); + if (res!==undefined) { + return res; + } + } + } + return undefined; +}; + +SearchPanel.prototype.getSearchButton = function() { + return getElementByName(this.getSearchQueryElement(),"searchButton"); +}; + +SearchPanel.prototype.getSearchInput = function() { + return getElementByName(this.getSearchQueryElement(),"searchInput"); +}; + +SearchPanel.prototype.getSearchPerfectMatch = function() { + return getElementByName(this.getSearchQueryElement(),"searchPerfectMatch"); +}; + SearchPanel.prototype.getContentElement = function() { var searchResultsElement = this.getSearchResultsElement(); @@ -129,9 +181,12 @@ SearchPanel.prototype.refreshSearchResults = function() { resolve(); }).catch(reject); }); + }; SearchPanel.prototype.addResultTab = function(query, elements) { + var name = JSON.parse(query).query; + var tabId = "searchTab_" + this._tabIdCount; this._tabIdCount++; @@ -146,8 +201,13 @@ SearchPanel.prototype.addResultTab = function(query, elements) { var navLi = document.createElement("li"); navLi.className = navClass; + var navLink = document.createElement("a"); navLink.href = "#" + tabId; + navLink.innerHTML = name; + navLink.onclick = function(){ + $(this).tab('show'); + } navLi.appendChild(navLink); if (query.name !== undefined) { navLink.innerHTML = query.name; diff --git a/frontend-js/src/main/js/map/CustomMap.js b/frontend-js/src/main/js/map/CustomMap.js index 689281d9de..0506155028 100644 --- a/frontend-js/src/main/js/map/CustomMap.js +++ b/frontend-js/src/main/js/map/CustomMap.js @@ -1789,4 +1789,26 @@ CustomMap.prototype.openCommentDialog = function() { }); }; +CustomMap.prototype.fetchIdentifiedElements = function(elements, complete) { + var modelIds = []; + var modelElements = []; + var i; + for (i=0;i<elements.length;i++) { + var element = elements[i]; + if (modelElements[element.getModelId()]===undefined) { + modelIds.push(element.getModelId()); + modelElements[element.getModelId()]=[]; + } + modelElements[element.getModelId()].push(element); + } + + var promises = []; + for (i=0;i<modelIds.length;i++) { + var modelId = modelIds[i]; + promises.push(this.getSubmodelById(modelId).getModel().getByIdentifiedElements(modelElements[modelId], complete)); + } + return Promise.all(promises); + +}; + module.exports = CustomMap; diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js index 5e1b186239..677febb63a 100644 --- a/frontend-js/src/main/js/map/data/MapModel.js +++ b/frontend-js/src/main/js/map/data/MapModel.js @@ -133,6 +133,7 @@ MapModel.prototype.getAliasById = function(id, complete) { }); }; + MapModel.prototype.getCompleteAliasById = function(id) { var self = this; return new Promise(function(resolve, reject) { @@ -611,4 +612,55 @@ MapModel.prototype.getByIdentifiedElement = function(ie, complete) { } }; +MapModel.prototype.getByIdentifiedElements = function(identifiedElements, complete) { + var self = this; + var missingAliases = []; + var missingReactions = []; + + for (var i=0;i<identifiedElements.length;i++) { + var ie = identifiedElements[i]; + if (!this.isAvailable(ie, complete)) { + if (ie.getType()==="ALIAS") { + missingAliases.push(ie.getId()); + } else if (ie.getType()==="REACTION") { + missingReactions.push(ie.getId()); + } else { + throw new Error("Unknown type "+ie); + } + } + } + + return new Promise(function(resolve,reject){ + return self.getMissingElements({aliasIds:missingAliases, reactionIds:missingReactions, complete: true}).then(function(){ + var promises =[]; + for (var i=0;i<identifiedElements.length;i++) { + promises.push(self.getByIdentifiedElement(identifiedElements[i])); + } + return Promise.all(promises); + }).then(function(elements){ + resolve(elements); + }).catch(reject); + }); + +}; + + +MapModel.prototype.isAvailable = function(ie, complete) { + var element; + if (ie.getType()==="ALIAS") { + element = this._aliases[ie.getId()]; + } else if (ie.getType()==="REACTION") { + element = this._reactions[ie.getId()]; + } else { + throw new Error("Unknown type: "+ie.getType(), complete); + } + if (element===undefined) { + return false; + } else if (complete) { + return element.isComplete(); + } else { + return true; + } +} + module.exports = MapModel; diff --git a/frontend-js/src/main/js/map/overlay/OverlayCollection.js b/frontend-js/src/main/js/map/overlay/OverlayCollection.js index 91961f1123..bbf070e82e 100644 --- a/frontend-js/src/main/js/map/overlay/OverlayCollection.js +++ b/frontend-js/src/main/js/map/overlay/OverlayCollection.js @@ -273,4 +273,22 @@ OverlayCollection.prototype.getIcon = function(colorId, id) { return "marker/" + this._iconType + "/" + this._iconType + "_" + color + "_" + id + ".png"; }; +OverlayCollection.prototype.splitQuery = function (query, useFullName) { + var result = []; + if (query.indexOf(";")>=0) { + result = query.split(";"); + } else { + result = query.split(","); + } + + for (var i=0;i<result.length;i++) { + result[i]=result[i].trim(); + } + if (result.length>1 && useFullName) { + result.push(query); + } + return result; +}; + + module.exports = OverlayCollection; diff --git a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js index 7d4fb9186c..d21ee6d771 100644 --- a/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js +++ b/frontend-js/src/main/js/map/overlay/SearchDbOverlay.js @@ -27,14 +27,32 @@ SearchDbOverlay.QueryType = { SEARCH_BY_QUERY : "SEARCH_BY_QUERY", }; -function encodeQuery(type, model, arg){ +function encodeQuery(type, arg0, arg1){ if (type === SearchDbOverlay.QueryType.SEARCH_BY_COORDINATES) { - return type + "_"+model.getId()+"_"+arg.x+","+arg.y; + var model = arg0; + var coordinates = arg1; + return JSON.stringify({ + type:type, + modelId:model.getId(), + coordinates: coordinates + }) + } else if (type === SearchDbOverlay.QueryType.SEARCH_BY_QUERY) { + var query = arg0; + var perfect = arg1; + return JSON.stringify({ + type:type, + query:query, + perfect: perfect + }) } else { throw new Error("Unknown query type: "+type); } } +function decodeQuery(query){ + return JSON.parse(query); +} + SearchDbOverlay.prototype.getElementsByQuery = function(query) { var self = this; return new Promise(function(resolve, reject){ @@ -109,6 +127,58 @@ SearchDbOverlay.prototype.searchByCoordinates = function(model, coordinates) { }); }; +SearchDbOverlay.prototype.searchBySingleQuery = function(originalQuery, perfect) { + var self = this; + return new Promise(function(resolve, reject) { + var query = encodeQuery(SearchDbOverlay.QueryType.SEARCH_BY_QUERY, originalQuery, perfect); + if (self._elementsByQuery[query] !== undefined) { + resolve(self._elementsByQuery[query]); + } else { + return ServerConnector.getElementsByQuery({ + query:originalQuery, + perfectMatch: perfect + }).then(function(elements) { + var result = []; + for (var i=0;i<elements.length;i++) { + result.push(new IdentifiedElement(elements[i])); + } + self._elementsByQuery[query]=result; + return self.getMap().fetchIdentifiedElements(result, true); + }).then(function(){ + resolve(self._elementsByQuery[query]); + }).catch(reject); + } + }); +}; + +SearchDbOverlay.prototype.searchByQuery = function(originalQuery, perfect) { + var self = this; + return new Promise(function(resolve, reject) { + var queries = []; + if (perfect) { + queries.push(originalQuery); + } else { + queries = self.splitQuery(originalQuery); + } + + var encodedQueries = []; + var promises = []; + for (var i=0;i<queries.length;i++) { + encodedQueries.push(encodeQuery(SearchDbOverlay.QueryType.SEARCH_BY_QUERY, queries[i], perfect)); + promises.push(self.searchBySingleQuery(queries[i], perfect)); + } + self.setQueries(encodedQueries); + + var res; + Promise.all(promises).then(function(results){ + res =results; + return self.callListeners('onSearch'); + }).then(function(){ + resolve(res); + }).catch(reject); + }); +}; + SearchDbOverlay.prototype.setQueries = function(queries){ this._queries = queries; }; diff --git a/frontend-js/src/test/js/gui/SearchPanel-test.js b/frontend-js/src/test/js/gui/SearchPanel-test.js index 75413d3dd7..5cf34a7bba 100644 --- a/frontend-js/src/test/js/gui/SearchPanel-test.js +++ b/frontend-js/src/test/js/gui/SearchPanel-test.js @@ -45,11 +45,28 @@ describe('SearchPanel', function() { return searchDbOverlay.searchByCoordinates(map.getModel(), new google.maps.Point(26547.33, 39419.29)).then( function(results) { assert.equal(logger.getWarnings().length, 0); - logger.debug(div.innerHTML); assert.ok(div.innerHTML.indexOf("Reaction") >= 0); }); }); + it('on searchResults changed 2', function() { + var div = helper.createSearchTab(); + var map = helper.createCustomMap(); + map.getModel().setId(15781); + var searchDbOverlay = helper.createSearchDbOverlay(map); + + new SearchPanel({ + element : div, + customMap : map + }); + + return searchDbOverlay.searchByQuery("s1",false).then( + function(results) { + assert.equal(logger.getWarnings().length, 0); + assert.ok(div.innerHTML.indexOf("s1") >= 0); + }); + }); + it('createAliasElement', function() { var aliasObj = { symbol : "S1_SYMB", diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js index d5ff0f4ca1..95977897de 100644 --- a/frontend-js/src/test/js/helper.js +++ b/frontend-js/src/test/js/helper.js @@ -29,6 +29,19 @@ Helper.prototype.createSearchTab = function() { searchQueryDiv.setAttribute("name", "searchQuery"); result.appendChild(searchQueryDiv); + var searchButton = document.createElement("img"); + searchButton.setAttribute("name", "searchButton"); + searchQueryDiv.appendChild(searchButton); + + var searchInput = document.createElement("input"); + searchInput.setAttribute("name", "searchInput"); + searchQueryDiv.appendChild(searchInput); + + var searchPerfectMatch = document.createElement("input"); + searchPerfectMatch.type = "checkbox"; + searchPerfectMatch.setAttribute("name", "searchPerfectMatch"); + searchQueryDiv.appendChild(searchPerfectMatch); + var searchResultsDiv = document.createElement("div"); searchResultsDiv.setAttribute("name", "searchResults"); result.appendChild(searchResultsDiv); diff --git a/frontend-js/src/test/js/map/overlay/OverlayCollection-test.js b/frontend-js/src/test/js/map/overlay/OverlayCollection-test.js index bf88db4244..ee9864aec7 100644 --- a/frontend-js/src/test/js/map/overlay/OverlayCollection-test.js +++ b/frontend-js/src/test/js/map/overlay/OverlayCollection-test.js @@ -123,4 +123,55 @@ describe('OverlayCollection', function() { assert.deepEqual([], data); }); + + it("splitQuery", function() { + var map = helper.createCustomMap(); + + var oc = helper.createDbOverlay(map); + + var result = oc.splitQuery("test q"); + assert.equal(result[0], "test q"); + }); + + it("splitQuery 2", function() { + var map = helper.createCustomMap(); + + var oc = helper.createDbOverlay(map); + + var result = oc.splitQuery("test,q"); + assert.equal(result[0], "test"); + assert.equal(result[1], "q"); + }); + + it("splitQuery 3", function() { + var map = helper.createCustomMap(); + + var oc = helper.createDbOverlay(map); + + var result = oc.splitQuery("test;q"); + assert.equal(result[0], "test"); + assert.equal(result[1], "q"); + }); + + it("splitQuery 4", function() { + var map = helper.createCustomMap(); + + var oc = helper.createDbOverlay(map); + + var result = oc.splitQuery("test;q,bla"); + assert.equal(result[0], "test"); + assert.equal(result[1], "q,bla"); + assert.equal(result.length,2) + }); + + it("splitQuery 5", function() { + var map = helper.createCustomMap(); + + var oc = helper.createDbOverlay(map); + + var result = oc.splitQuery("test;q,bla", true); + assert.equal(result[0], "test"); + assert.equal(result[1], "q,bla"); + assert.equal(result[2], "test;q,bla"); + }); }); diff --git a/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329158,329159,329169,329173,329175,329177&projectId=sample&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329158,329159,329169,329173,329175,329177&projectId=sample&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..a11f751dd6 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getElements/columns=&id=329158,329159,329169,329173,329175,329177&projectId=sample&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Unknown","name":"s11","bounds":{"x":105.0,"y":203.5,"width":70.0,"height":25.0},"id":329169},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"description of S1\r\nthird line","type":"Protein","name":"s1","bounds":{"x":12.0,"y":6.0,"width":80.0,"height":40.0},"id":329173},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Drug","name":"s10","bounds":{"x":0.0,"y":186.0,"width":80.0,"height":30.0},"id":329177},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Protein","name":"s14","bounds":{"x":279.0,"y":233.0,"width":80.0,"height":40.0},"id":329159},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Degraded","name":"s13","bounds":{"x":401.0,"y":235.0,"width":30.0,"height":30.0},"id":329175},{"formerSymbols":[],"references":[],"modelId":15781,"synonyms":[],"description":"","type":"Complex","name":"s12","bounds":{"x":271.0,"y":207.0,"width":101.0,"height":164.0},"id":329158}] \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/project/getElementsByQuery/perfectMatch=false&projectId=sample&query=s1&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/project/getElementsByQuery/perfectMatch=false&projectId=sample&query=s1&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..0a39afdd5d --- /dev/null +++ b/frontend-js/testFiles/apiCalls/project/getElementsByQuery/perfectMatch=false&projectId=sample&query=s1&token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +[{"modelId":15781,"id":329173,"type":"ALIAS"},{"modelId":15781,"id":329169,"type":"ALIAS"},{"modelId":15781,"id":329177,"type":"ALIAS"},{"modelId":15781,"id":329159,"type":"ALIAS"},{"modelId":15781,"id":329175,"type":"ALIAS"},{"modelId":15781,"id":329158,"type":"ALIAS"}] \ No newline at end of file -- GitLab