diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index 01fb6ac66af71844c1e447fd3fe7a5488b948237..cf8845a05b967228219011bea2d6f1b99c961813 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -23,6 +23,7 @@ var LayoutAlias = require('./map/data/LayoutAlias'); var LayoutData = require('./map/data/LayoutData'); var LayoutReaction = require('./map/data/LayoutReaction'); var MapModel = require('./map/data/MapModel'); +var Mesh = require('./map/data/Mesh'); var MiRna = require('./map/data/MiRna'); var NetworkError = require('./NetworkError'); var Project = require('./map/data/Project'); @@ -341,6 +342,12 @@ ServerConnector.getProjectLogsUrl = function (queryParams, filterParams) { params: filterParams }); }; +ServerConnector.getMeshUrl = function (queryParams, filterParams) { + return this.getApiUrl({ + type: "mesh/" + queryParams.id, + params: filterParams + }); +}; ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) { @@ -1355,7 +1362,7 @@ ServerConnector.login = function (login, password) { ServerConnector.logout = function () { var self = this; - return self.sendGetRequest(self.logoutUrl()).then(function(){ + return self.sendGetRequest(self.logoutUrl()).then(function () { self.getSessionData().setToken(undefined); self.getSessionData().setLogin(undefined); window.location.reload(false); @@ -1824,4 +1831,14 @@ ServerConnector.getProjectLogs = function (params) { }); }; +ServerConnector.getMesh = function (params) { + var self = this; + if (params === undefined) { + params = {}; + } + return self.sendGetRequest(self.getMeshUrl(params)).then(function (content) { + return new Mesh(JSON.parse(content)); + }); +}; + module.exports = ServerConnector; diff --git a/frontend-js/src/main/js/gui/Panel.js b/frontend-js/src/main/js/gui/Panel.js index f609e491b91d8971eceb01ac0d4d3da6051bf6bd..4300b8c822b54650fc2287d0dc7b254478ef689d 100644 --- a/frontend-js/src/main/js/gui/Panel.js +++ b/frontend-js/src/main/js/gui/Panel.js @@ -11,41 +11,40 @@ var Functions = require('../Functions'); var logger = require('../logger'); function Panel(params) { - AbstractGuiElement.call(this, params); - - var self = this; - - self.setParent(params.parent); - var configuration = params.configuration; - if (params.configuration === undefined) { - configuration = self.getMap().getConfiguration(); - } - var guiUtils = new GuiUtils(configuration); - self.setGuiUtils(guiUtils); - if (self.getMap() !== undefined) { - this.getGuiUtils().setMap(self.getMap()); - } - self.setPanelName(params.panelName); - - if (params.scrollable) { - $(self.getElement()).addClass("pre-scrollable"); - } else { - $(self.getElement()).css("overflow-y", "auto"); - } - - $(self.getElement()).css("position", "relative"); - if (params.helpTip !== undefined) { - self.createHelpButton(); - self.setHelpTip(params.helpTip); - } - - GuiConnector.addWindowResizeEvent(function () { - self.onresize(); - }); - - $("a[href='#" + self.getElement().id + "']").on('shown.bs.tab', function () { - self.onresize(); - }); + AbstractGuiElement.call(this, params); + + var self = this; + + self.setParent(params.parent); + var configuration = params.configuration; + if (params.configuration === undefined) { + configuration = self.getMap().getConfiguration(); + } + var guiUtils = new GuiUtils(configuration); + self.setGuiUtils(guiUtils); + if (self.getMap() !== undefined) { + this.getGuiUtils().setMap(self.getMap()); + } + self.setPanelName(params.panelName); + + if (params.scrollable) { + $(self.getElement()).addClass("pre-scrollable"); + } else { + $(self.getElement()).css("overflow-y", "auto"); + } + + $(self.getElement()).css("position", "relative"); + if (params.helpTip !== undefined) { + self.setHelpTip(params.helpTip); + } + + GuiConnector.addWindowResizeEvent(function () { + self.onresize(); + }); + + $("a[href='#" + self.getElement().id + "']").on('shown.bs.tab', function () { + self.onresize(); + }); } @@ -53,249 +52,252 @@ Panel.prototype = Object.create(AbstractGuiElement.prototype); Panel.prototype.constructor = Panel; Panel.prototype.createHelpButton = function () { - var self = this; - var helpTipButton = Functions.createElement({ - type: "button", - className: "minerva-help-button", - content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>', + var self = this; + var helpTipButton = Functions.createElement({ + type: "button", + className: "minerva-help-button", + content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>', + }); + helpTipButton.onclick = function () { + var helpDialogDiv = Functions.createElement({ + type: "div", + content: self.getHelpTip(), }); - helpTipButton.onclick = function () { - var helpDialogDiv = Functions.createElement({ - type: "div", - content: self.getHelpTip(), - }); - $(helpDialogDiv).dialog({ - close: function () { - $(this).dialog('destroy').remove(); - }, - position: { - my: "left top", - at: "left bottom", - of: helpTipButton - }, - }); - $('.ui-dialog').find("a").blur(); - }; - self.getElement().appendChild(helpTipButton); + $(helpDialogDiv).dialog({ + close: function () { + $(this).dialog('destroy').remove(); + }, + position: { + my: "left top", + at: "left bottom", + of: helpTipButton + }, + }); + $('.ui-dialog').find("a").blur(); + }; + self.getElement().appendChild(helpTipButton); }; Panel.prototype.disablePanel = function (message) { - var self = this; + var self = this; - var searchQueryElement = self.getControlElement(PanelControlElementType.SEARCH_DIV); - var searchResultsElement = self.getControlElement(PanelControlElementType.SEARCH_RESULTS_DIV); + var searchQueryElement = self.getControlElement(PanelControlElementType.SEARCH_DIV); + var searchResultsElement = self.getControlElement(PanelControlElementType.SEARCH_RESULTS_DIV); - searchQueryElement.style.visibility = "hidden"; - searchResultsElement.style.visibility = "hidden"; - var hideReasonDiv = document.createElement("div"); - hideReasonDiv.className = "searchPanel"; + searchQueryElement.style.visibility = "hidden"; + searchResultsElement.style.visibility = "hidden"; + var hideReasonDiv = document.createElement("div"); + hideReasonDiv.className = "searchPanel"; - var center = document.createElement("center"); - var messageDiv = document.createElement("h4"); - messageDiv.innerHTML = message; - center.appendChild(messageDiv); - hideReasonDiv.appendChild(center); + var center = document.createElement("center"); + var messageDiv = document.createElement("h4"); + messageDiv.innerHTML = message; + center.appendChild(messageDiv); + hideReasonDiv.appendChild(center); - self.getElement().insertBefore(hideReasonDiv, searchQueryElement); + self.getElement().insertBefore(hideReasonDiv, searchQueryElement); }; Panel.prototype.isDisabled = function () { - var self = this; - var searchQueryElement = self.getControlElement(PanelControlElementType.SEARCH_DIV); - return searchQueryElement.style.visibility === "hidden"; + var self = this; + var searchQueryElement = self.getControlElement(PanelControlElementType.SEARCH_DIV); + return searchQueryElement.style.visibility === "hidden"; }; Panel.prototype.setMap = function (map) { - this._map = map; + this._map = map; }; Panel.prototype.getMap = function () { - return this._map; + return this._map; }; Panel.prototype.setPanelName = function (panelName) { - this._panelName = panelName; + this._panelName = panelName; }; Panel.prototype.getPanelName = function () { - return this._panelName; + return this._panelName; }; Panel.prototype.setElement = function (element) { - if (element === undefined || element === null) { - throw new Error("DOM Element must be defined"); - } - this._element = element; + if (element === undefined || element === null) { + throw new Error("DOM Element must be defined"); + } + this._element = element; }; Panel.prototype.getElement = function () { - return this._element; + return this._element; }; Panel.prototype.getElementByName = function (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 = this.getElementByName(child, name); - if (res !== undefined) { - return res; - } - } + if (element !== undefined) { + if (element.getAttribute("name") === name) { + return element; } - return undefined; + var children = element.children; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var res = this.getElementByName(child, name); + if (res !== undefined) { + return res; + } + } + } + return undefined; }; Panel.prototype.getDialogDiv = function (id) { - var dialogs = this.getElementByName(this.getElement(), "dialogs"); - if (dialogs === undefined) { - dialogs = document.createElement("div"); - dialogs.setAttribute("name", "dialogs"); - this.getElement().appendChild(dialogs); + var dialogs = this.getElementByName(this.getElement(), "dialogs"); + if (dialogs === undefined) { + dialogs = document.createElement("div"); + dialogs.setAttribute("name", "dialogs"); + this.getElement().appendChild(dialogs); - this._dialogs = []; - } + this._dialogs = []; + } - var dialogDiv = this._dialogs[id]; + var dialogDiv = this._dialogs[id]; - if (dialogDiv === undefined) { - dialogDiv = document.createElement("div"); - dialogDiv.className = "ui-widget"; - dialogDiv.setAttribute("name", "dialog-" + id); + if (dialogDiv === undefined) { + dialogDiv = document.createElement("div"); + dialogDiv.className = "ui-widget"; + dialogDiv.setAttribute("name", "dialog-" + id); - var contentDiv = document.createElement("div"); - contentDiv.setAttribute("name", "content"); - dialogDiv.appendChild(contentDiv); + var contentDiv = document.createElement("div"); + contentDiv.setAttribute("name", "content"); + dialogDiv.appendChild(contentDiv); - dialogs.appendChild(dialogDiv); + dialogs.appendChild(dialogDiv); - this._dialogs[id] = dialogDiv; - } - return dialogDiv; + this._dialogs[id] = dialogDiv; + } + return dialogDiv; }; Panel.prototype.assignDialogOptions = function (div, params) { - var dialog = $(div); - for (var key in params) { - if (params.hasOwnProperty(key)) { - if (key === "id") { - div.setAttribute("name", "dialog-" + params[key]); - } else if (key === "modal") { - dialog.dialog('option', 'modal', params[key]); - } else if (key === "buttons") { - dialog.dialog('option', 'buttons', params[key]); - } else if (key === "className") { - dialog.dialog('option', 'dialogClass', params[key]); - } else if (key === "title") { - dialog.dialog('option', 'title', params[key]); - } else { - throw new Error("Unknown dialog param: " + key + " - " + params[key]); - } - } + var dialog = $(div); + for (var key in params) { + if (params.hasOwnProperty(key)) { + if (key === "id") { + div.setAttribute("name", "dialog-" + params[key]); + } else if (key === "modal") { + dialog.dialog('option', 'modal', params[key]); + } else if (key === "buttons") { + dialog.dialog('option', 'buttons', params[key]); + } else if (key === "className") { + dialog.dialog('option', 'dialogClass', params[key]); + } else if (key === "title") { + dialog.dialog('option', 'title', params[key]); + } else { + throw new Error("Unknown dialog param: " + key + " - " + params[key]); + } } + } }; Panel.prototype.openDialog = function (content, options) { - if (options === undefined) { - options = {}; - } - - if (options.id === undefined) { - logger.warn("Id of dialog is not defined"); - } - - var div = this.getDialogDiv(options.id); - - var contentDiv = this.getElementByName(div, "content"); - while (contentDiv.hasChildNodes()) { - contentDiv.removeChild(contentDiv.lastChild); - } - contentDiv.appendChild(content); - contentDiv.style.display = "block"; - - $(div).dialog({ - close: function () { - contentDiv.style.display = "none"; - $(this).dialog('destroy'); - }, - dialogClass: options.className, - }); - - this.assignDialogOptions(div, options); - - $(div).dialog("open"); + if (options === undefined) { + options = {}; + } + + if (options.id === undefined) { + logger.warn("Id of dialog is not defined"); + } + + var div = this.getDialogDiv(options.id); + + var contentDiv = this.getElementByName(div, "content"); + while (contentDiv.hasChildNodes()) { + contentDiv.removeChild(contentDiv.lastChild); + } + contentDiv.appendChild(content); + contentDiv.style.display = "block"; + + $(div).dialog({ + close: function () { + contentDiv.style.display = "none"; + $(this).dialog('destroy'); + }, + dialogClass: options.className, + }); + + this.assignDialogOptions(div, options); + + $(div).dialog("open"); }; Panel.prototype.init = function () { - throw new Error(this.getPanelName() + " Not implemented"); + throw new Error(this.getPanelName() + " Not implemented"); }; Panel.prototype.setParent = function (parent) { - this._parent = parent; + this._parent = parent; }; Panel.prototype.getParent = function () { - return this._parent; + return this._parent; }; Panel.prototype.setGuiUtils = function (guiUtils) { - this._guiUtils = guiUtils; + this._guiUtils = guiUtils; }; Panel.prototype.getGuiUtils = function () { - return this._guiUtils; + return this._guiUtils; }; Panel.prototype.setHelpTip = function (helpTip) { - this._helpTip = helpTip; + if (this._helpTip === undefined && helpTip !== undefined) { + this.createHelpButton(); + } + this._helpTip = helpTip; }; Panel.prototype.getHelpTip = function () { - return this._helpTip; + return this._helpTip; }; Panel.prototype.onresize = function () { - var self = this; - var footerPosition = window.innerHeight; - - // compute the width (we can only compute it for visible elements) - var size = 100000; - - if ($(self.getElement()).is(":visible")) { - - $(".pre-scrollable", self.getElement()).each(function (index, element) { - if ($(element).is(":visible")) { - size = Math.min(size, footerPosition - $(element).offset().top); - } - }); - if ($(self.getElement()).hasClass("pre-scrollable") && $(self.getElement()).is(":visible")) { - size = Math.min(size, footerPosition - $(self.getElement()).offset().top); - } - if (size !== 100000) { - $(".pre-scrollable", self.getElement()).each(function (index, element) { - $(element).css('max-height', size); - $(element).css('height', size); - }); - } - if ($(self.getElement()).hasClass("pre-scrollable") && $(self.getElement()).is(":visible")) { - $(self.getElement()).css('max-height', size); - $(self.getElement()).css('height', size); - } + var self = this; + var footerPosition = window.innerHeight; + + // compute the width (we can only compute it for visible elements) + var size = 100000; + + if ($(self.getElement()).is(":visible")) { + + $(".pre-scrollable", self.getElement()).each(function (index, element) { + if ($(element).is(":visible")) { + size = Math.min(size, footerPosition - $(element).offset().top); + } + }); + if ($(self.getElement()).hasClass("pre-scrollable") && $(self.getElement()).is(":visible")) { + size = Math.min(size, footerPosition - $(self.getElement()).offset().top); + } + if (size !== 100000) { + $(".pre-scrollable", self.getElement()).each(function (index, element) { + $(element).css('max-height', size); + $(element).css('height', size); + }); + } + if ($(self.getElement()).hasClass("pre-scrollable") && $(self.getElement()).is(":visible")) { + $(self.getElement()).css('max-height', size); + $(self.getElement()).css('height', size); } + } }; Panel.prototype.destroy = function () { - for (var id in this._dialogs) { - if (this._dialogs.hasOwnProperty(id)) { - var div = this._dialogs[id]; - if ($(div).hasClass("ui-dialog-content")) { - $(div).dialog("destroy"); - } - } + for (var id in this._dialogs) { + if (this._dialogs.hasOwnProperty(id)) { + var div = this._dialogs[id]; + if ($(div).hasClass("ui-dialog-content")) { + $(div).dialog("destroy"); + } } + } }; module.exports = Panel; diff --git a/frontend-js/src/main/js/gui/leftPanel/ChemicalPanel.js b/frontend-js/src/main/js/gui/leftPanel/ChemicalPanel.js index 400bc92d614e20b519e8afa1369a7f3b1bd6b55a..62807c1756f8995196f2583eaac8646b9d470865 100644 --- a/frontend-js/src/main/js/gui/leftPanel/ChemicalPanel.js +++ b/frontend-js/src/main/js/gui/leftPanel/ChemicalPanel.js @@ -3,26 +3,23 @@ var Promise = require("bluebird"); /* exported logger */ +// noinspection JSUnusedLocalSymbols var logger = require('../../logger'); var AbstractDbPanel = require('./AbstractDbPanel'); var PanelControlElementType = require('../PanelControlElementType'); + function ChemicalPanel(params) { + var self = this; params.panelName = "chemical"; - params.helpTip = '<p>source: Comparative Toxicogenomics Database <a target="_ctd" href="http://ctdbase.org/">ctdbase.org</a></p>' - + '<p>only associations between genes and chemicals with direct evidence to ' - + 'Parkinson Disease (<a href="http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300" target="_blank">D010300</a>) are displayed</p>' - + '<p>use only the full name of chemicals according to <a target="_ctd_chemicals" href="http://ctdbase.org/voc.go?type=chem"> ctdbase/chem</a> for search</p>' - + 'if the chemical name includes comma(s), place a semicolon behind the name to avoid a segmentation of the name</p>' - + '<p>separate multiple search by semicolon'; params.placeholder = "full chemical name (CTD)"; - AbstractDbPanel.call(this, params); + AbstractDbPanel.call(self, params); - if (this.getMap().getProject().getDisease() === undefined) { - this.disablePanel("DISEASE NOT DEFINED FOR PROJECT. PLEASE, DEFINE IT IN THE ADMIN SECTION."); + if (self.getMap().getProject().getDisease() === undefined) { + self.disablePanel("DISEASE NOT DEFINED FOR PROJECT. PLEASE, DEFINE IT IN THE ADMIN SECTION."); } } @@ -30,47 +27,49 @@ ChemicalPanel.prototype = Object.create(AbstractDbPanel.prototype); ChemicalPanel.prototype.constructor = ChemicalPanel; ChemicalPanel.prototype.createPreamble = function (chemical) { - var self = this; - var guiUtils = self.getGuiUtils(); - var result = document.createElement("div"); - if (chemical === undefined || chemical.getName() === undefined) { - result.appendChild(guiUtils.createLabel("NOT FOUND")); - } else { - result.appendChild(guiUtils.createParamLine("Chemical: ", chemical.getName())); - result.appendChild(guiUtils.createParamLine("Description: ", chemical.getDescription())); - result.appendChild(guiUtils.createArrayParamLine("Synonyms: ", chemical.getSynonyms())); - result.appendChild(guiUtils.createParamLine("Direct Evidence: ", chemical.getDirectEvidence())); - result.appendChild(guiUtils - .createAnnotations("Direct Evidence Publications: ", chemical.getDirectEvidenceReferences())); - result.appendChild(guiUtils.createAnnotations("Sources: ", chemical.getReferences())); - result.appendChild(guiUtils.createNewLine()); - } + var self = this; + var guiUtils = self.getGuiUtils(); + var result = document.createElement("div"); + if (chemical === undefined || chemical.getName() === undefined) { + result.appendChild(guiUtils.createLabel("NOT FOUND")); + } else { + result.appendChild(guiUtils.createParamLine("Chemical: ", chemical.getName())); + result.appendChild(guiUtils.createParamLine("Description: ", chemical.getDescription())); + result.appendChild(guiUtils.createArrayParamLine("Synonyms: ", chemical.getSynonyms())); + result.appendChild(guiUtils.createParamLine("Direct Evidence: ", chemical.getDirectEvidence())); + result.appendChild(guiUtils + .createAnnotations("Direct Evidence Publications: ", chemical.getDirectEvidenceReferences())); + result.appendChild(guiUtils.createAnnotations("Sources: ", chemical.getReferences())); + result.appendChild(guiUtils.createNewLine()); + } - return result; + return result; }; ChemicalPanel.prototype.createTableElement = function (target, icon) { - return this.createTargetRow(target, icon); + return this.createTargetRow(target, icon); }; ChemicalPanel.prototype.searchByQuery = function () { - var self = this; - var query = self.getControlElement(PanelControlElementType.SEARCH_INPUT).value; + var self = this; + var query = self.getControlElement(PanelControlElementType.SEARCH_INPUT).value; - return self.getOverlayDb().searchByQuery(query); + return self.getOverlayDb().searchByQuery(query); }; ChemicalPanel.prototype.init = function () { + var self = this; + return self.getToolTipForAnnotation(self.getProject().getDisease()).then(function (toolTip) { + self.setHelpTip(toolTip); var query = ServerConnector.getSessionData().getChemicalQuery(); if (query !== undefined) { - return this.getOverlayDb().searchByEncodedQuery(query); - } else { - return Promise.resolve(); + return this.getOverlayDb().searchByEncodedQuery(query); } + }); }; ChemicalPanel.prototype.destroy = function () { - return Promise.resolve(); + return Promise.resolve(); }; ChemicalPanel.prototype.getAutocomplete = function (query) { @@ -91,4 +90,23 @@ ChemicalPanel.prototype.refreshSearchAutocomplete = function () { }); }; +ChemicalPanel.prototype.getToolTipForAnnotation = function (annotation) { + var self =this; + var promise = Promise.resolve('disease'); + if (annotation !== null && annotation !== undefined) { + promise = ServerConnector.getMesh({id: annotation.getResource()}).then(function (mesh) { + return mesh.getName() + " (" + self.getGuiUtils().createAnnotationLink(annotation).outerHTML + ")"; + }); + } + return promise.then(function (diseaseString) { + var result = '<p>source: Comparative Toxicogenomics Database <a target="_ctd" href="http://ctdbase.org/">ctdbase.org</a></p>' + + '<p>only associations between genes and chemicals with direct evidence to ' + + diseaseString + ' are displayed</p>' + + '<p>use only the full name of chemicals according to <a target="_ctd_chemicals" href="http://ctdbase.org/voc.go?type=chem"> ctdbase/chem</a> for search</p>' + + 'if the chemical name includes comma(s), place a semicolon behind the name to avoid a segmentation of the name</p>' + + '<p>separate multiple search by semicolon'; + return Promise.resolve(result); + }); +}; + module.exports = ChemicalPanel; diff --git a/frontend-js/src/main/js/map/data/Mesh.js b/frontend-js/src/main/js/map/data/Mesh.js new file mode 100644 index 0000000000000000000000000000000000000000..612111fec621ccab07cc808cd37cf4125afedb83 --- /dev/null +++ b/frontend-js/src/main/js/map/data/Mesh.js @@ -0,0 +1,37 @@ +"use strict"; + +function Mesh(jsonObject) { + var self = this; + self.setSynonyms(jsonObject.synonyms); + self.setName(jsonObject.name); + self.setId(jsonObject.id); + self.setDescription(jsonObject.description); +} + +Mesh.prototype.setSynonyms = function (synonyms) { + this.synonyms = synonyms; +}; +Mesh.prototype.getSynonyms = function () { + return this.synonyms; +}; +Mesh.prototype.setName = function (name) { + this.name = name; +}; +Mesh.prototype.getName = function () { + return this.name; +}; +Mesh.prototype.setId = function (id) { + this.id = id; +}; +Mesh.prototype.getId = function () { + return this.id; +}; +Mesh.prototype.setDescription = function (description) { + this.description = description; +}; +Mesh.prototype.getDescription = function () { + return this.description; +}; + + +module.exports = Mesh; diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js index c48d2795a5734f0f466ddd8c56b95b440f6fbaa1..b674de121f0ca6cc88d50b5ae0cc0920a2776154 100644 --- a/frontend-js/src/test/js/ServerConnector-test.js +++ b/frontend-js/src/test/js/ServerConnector-test.js @@ -369,5 +369,14 @@ describe('ServerConnector', function () { }); }); + it('getMesh', function () { + return ServerConnector.getMesh({id: "D010300"}).then(function (mesh) { + assert.ok(mesh.getSynonyms().length > 0); + assert.equal("Parkinson Disease", mesh.getName()); + assert.ok(mesh.getDescription().indexOf("A progressive, degenerative ..." >= 0)); + assert.equal("D010300", mesh.getId()); + }); + }); + }); diff --git a/frontend-js/src/test/js/gui/leftPanel/ChemicalPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/ChemicalPanel-test.js index 27610bcb8971bbfdab0a452b9675258b88fd94c1..04fa6933c9db1cd02871535f59f1a8f824e573cf 100644 --- a/frontend-js/src/test/js/gui/leftPanel/ChemicalPanel-test.js +++ b/frontend-js/src/test/js/gui/leftPanel/ChemicalPanel-test.js @@ -13,7 +13,18 @@ var assert = chai.assert; var logger = require('../../logger'); describe('ChemicalPanel', function () { - function createPanel(){ + var parkinsonDiseaseAnnotation = new Annotation({ + link: "http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300", + type: "MESH_2012", + resource: "D010300" + }); + var alzheimerDiseaseAnnotation = new Annotation({ + link: "http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D000544", + type: "MESH_2012", + resource: "D000544" + }); + + function createPanel() { var map = helper.createCustomMap(); map.getModel().setId(15781); helper.createChemicalDbOverlay(map); @@ -38,11 +49,7 @@ describe('ChemicalPanel', function () { }); it('map with disease', function () { return ServerConnector.getProject().then(function (project) { - project.setDisease(new Annotation({ - link: "http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300", - type: "MESH_2012", - resource: "D010300" - })); + project.setDisease(parkinsonDiseaseAnnotation); var map = helper.createCustomMap(project); helper.createChemicalDbOverlay(map); @@ -57,6 +64,24 @@ describe('ChemicalPanel', function () { }); }); + describe('init', function () { + it('Parkinson Disease', function () { + var panel; + return ServerConnector.getProject().then(function (project) { + var map = helper.createCustomMap(project); + helper.createChemicalDbOverlay(map); + + panel = new ChemicalPanel({ + element: testDiv, + customMap: map + }); + return panel.init(); + }).then(function () { + panel.destroy(); + }); + }); + }); + describe('createPreamble', function () { it('default', function () { var map = helper.createCustomMap(); @@ -125,4 +150,32 @@ describe('ChemicalPanel', function () { }); }); + describe("getToolTipForAnnotation", function () { + it("for null argument", function () { + var panel = createPanel(); + + return panel.getToolTipForAnnotation(null).then(function (tooltip) { + assert.ok(tooltip.indexOf("Comparative Toxicogenomics Database") >= 0); + assert.equal(tooltip.indexOf("Parkinson"), -1); + }); + }); + it("for Parkinson Disease", function () { + var panel = createPanel(); + + return panel.getToolTipForAnnotation(parkinsonDiseaseAnnotation).then(function (tooltip) { + assert.ok(tooltip.indexOf("Comparative Toxicogenomics Database") >= 0); + assert.ok(tooltip.indexOf("Parkinson") >= 0); + }); + }); + it("for Alzheimer Disease", function () { + var panel = createPanel(); + + return panel.getToolTipForAnnotation(alzheimerDiseaseAnnotation).then(function (tooltip) { + assert.ok(tooltip.indexOf("Comparative Toxicogenomics Database") >= 0); + assert.equal(tooltip.indexOf("Parkinson"), -1); + }); + }); + }); + + }); diff --git a/frontend-js/src/test/js/map/data/Mesh-test.js b/frontend-js/src/test/js/map/data/Mesh-test.js new file mode 100644 index 0000000000000000000000000000000000000000..ee109bb8a340d6a37355bb49b37f4e36fc984ec8 --- /dev/null +++ b/frontend-js/src/test/js/map/data/Mesh-test.js @@ -0,0 +1,22 @@ +"use strict"; + +var Mesh = require('../../../../main/js/map/data/Mesh'); +var assert = require('assert'); + +describe('Mesh', function () { + describe("constructor", function () { + it("from json", function () { + var mesh = new Mesh({ + "synonyms": ["Parkinson's Disease"], + "name": "Parkinson Disease", + "description": "A progressive, degenerative ...", + "id": "D010300" + }); + assert.ok(mesh); + assert.equal("Parkinson's Disease",mesh.getSynonyms()[0]); + assert.equal("Parkinson Disease",mesh.getName()); + assert.equal("A progressive, degenerative ...",mesh.getDescription()); + assert.equal("D010300",mesh.getId()); + }); + }); +}); diff --git a/frontend-js/testFiles/apiCalls/mesh/D000544/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/mesh/D000544/token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..cde9de575da99c623cfcd361b13d0947c3767419 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/mesh/D000544/token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +{"synonyms":["Presenile Alzheimer Dementia","Dementias, Alzheimer","Familial Alzheimer Disease (FAD)","Alzheimer Disease, Early Onset","Dementia, Primary Senile Degenerative","Alzheimer Syndrome","Acute Confusional Senile Dementia","Alzheimer Diseases, Familial (FAD)","Alzheimer Type Senile Dementia","Dementia, Alzheimer Type","Focal Onset Alzheimer's Disease","Early Onset Alzheimer Disease","Alzheimer Dementia","Late Onset Alzheimer Disease","Alzheimer Disease, Familial (FAD)","Primary Senile Degenerative Dementia","Alzheimer Sclerosis","Presenile Dementia","Dementia, Presenile","Alzheimer Dementias","Dementia, Alzheimer","Dementia, Senile","Senile Dementia","Dementia, Alzheimer-Type (ATD)","Alzheimer Type Dementia","Alzheimer's Disease, Focal Onset","Alzheimer Disease, Late Onset","Sclerosis, Alzheimer","Alzheimer-Type Dementia (ATD)","Alzheimer's Disease","Senile Dementia, Alzheimer Type","Senile Dementia, Acute Confusional","Familial Alzheimer Diseases (FAD)","Alzheimer Type Dementia (ATD)"],"name":"Alzheimer Disease","description":"A degenerative disease of the BRAIN characterized by the insidious onset of DEMENTIA. Impairment of MEMORY, judgment, attention span, and problem solving skills are followed by severe APRAXIAS and a global loss of cognitive abilities. The condition primarily occurs after age 60, and is marked pathologically by severe cortical atrophy and the triad of SENILE PLAQUES; NEUROFIBRILLARY TANGLES; and NEUROPIL THREADS. (From Adams et al., Principles of Neurology, 6th ed, pp1049-57)","id":"D000544"} \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/mesh/D010300/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/mesh/D010300/token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..bb1bc41aaf8ff520ebdff43e454c475d4191fa8b --- /dev/null +++ b/frontend-js/testFiles/apiCalls/mesh/D010300/token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +{"synonyms":["Parkinson's Disease, Idiopathic","Primary Parkinsonism","Idiopathic Parkinson's Disease","Paralysis Agitans","Parkinsonism, Primary","Parkinson's Disease","Lewy Body Parkinson Disease","Parkinson's Disease, Lewy Body","Parkinson Disease, Idiopathic","Lewy Body Parkinson's Disease","Idiopathic Parkinson Disease"],"name":"Parkinson Disease","description":"A progressive, degenerative neurologic disease characterized by a TREMOR that is maximal at rest, retropulsion (i.e. a tendency to fall backwards), rigidity, stooped posture, slowness of voluntary movements, and a masklike facial expression. Pathologic features include loss of melanin containing neurons in the substantia nigra and other pigmented nuclei of the brainstem. LEWY BODIES are present in the substantia nigra and locus coeruleus but may also be found in a related condition (LEWY BODY DISEASE, DIFFUSE) characterized by dementia in combination with varying degrees of parkinsonism. (Adams et al., Principles of Neurology, 6th ed, p1059, pp1067-75)","id":"D010300"} \ No newline at end of file diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshController.java b/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshController.java new file mode 100644 index 0000000000000000000000000000000000000000..82d645cb8972bf78ff6ad3934872ba7999c007eb --- /dev/null +++ b/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshController.java @@ -0,0 +1,67 @@ +package lcsb.mapviewer.api.mesh; + +import java.io.IOException; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import lcsb.mapviewer.api.BaseController; +import lcsb.mapviewer.api.ObjectNotFoundException; +import lcsb.mapviewer.api.QueryException; +import lcsb.mapviewer.common.Configuration; +import lcsb.mapviewer.services.SecurityException; +import lcsb.mapviewer.services.interfaces.IUserService; +import lcsb.mapviewer.services.view.AuthenticationToken; + +@RestController +public class MeshController extends BaseController { + /** + * Default class logger. + */ + @SuppressWarnings("unused") + private Logger logger = Logger.getLogger(MeshController.class); + + @Autowired + private MeshRestImpl userRest; + + @RequestMapping(value = "/mesh/{id:.+}", method = { RequestMethod.GET }, produces = { + MediaType.APPLICATION_JSON_VALUE }) + public Map<String, Object> getMesh(// + @CookieValue(value = Configuration.AUTH_TOKEN) String token, // + @PathVariable(value = "id") String id // + ) throws Exception { + return userRest.getMesh(token, id); + } + + public MeshRestImpl getUserRest() { + return userRest; + } + + public void setUserRest(MeshRestImpl userRest) { + this.userRest = userRest; + } + +} \ No newline at end of file diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshRestImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..52ecc08744dc9efb66cc5b094fd36ddeb82cd3c9 --- /dev/null +++ b/rest-api/src/main/java/lcsb/mapviewer/api/mesh/MeshRestImpl.java @@ -0,0 +1,43 @@ +package lcsb.mapviewer.api.mesh; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import lcsb.mapviewer.annotation.data.MeSH; +import lcsb.mapviewer.annotation.services.MeSHParser; +import lcsb.mapviewer.annotation.services.annotators.AnnotatorException; +import lcsb.mapviewer.api.BaseRestImpl; +import lcsb.mapviewer.api.ObjectNotFoundException; +import lcsb.mapviewer.model.map.MiriamData; +import lcsb.mapviewer.model.map.MiriamType; + +@Transactional(value = "txManager") +public class MeshRestImpl extends BaseRestImpl { + + /** + * Default class logger. + */ + @SuppressWarnings("unused") + private Logger logger = Logger.getLogger(MeshRestImpl.class); + + @Autowired + private MeSHParser meSHParser; + + public Map<String, Object> getMesh(String token, String id) throws AnnotatorException, ObjectNotFoundException { + + MeSH mesh = meSHParser.getMeSH(new MiriamData(MiriamType.MESH_2012, id)); + if (mesh == null) { + throw new ObjectNotFoundException("Object not found: " + id); + } + Map<String, Object> result = new HashMap<>(); + result.put("name", mesh.getName()); + result.put("id", mesh.getMeSHId()); + result.put("description", mesh.getDescription()); + result.put("synonyms", mesh.getSynonyms()); + return result; + } +} diff --git a/rest-api/src/main/resources/applicationContext-rest.xml b/rest-api/src/main/resources/applicationContext-rest.xml index 60c25537166dd4558c4ede64030b9bd3478c28a6..6fc1903b43343410203cdb985420483b4c757f9e 100644 --- a/rest-api/src/main/resources/applicationContext-rest.xml +++ b/rest-api/src/main/resources/applicationContext-rest.xml @@ -27,6 +27,7 @@ <bean id="PublicationsRestImpl" class="lcsb.mapviewer.api.projects.models.publications.PublicationsRestImpl"/> <bean id="ReactionsRestImpl" class="lcsb.mapviewer.api.projects.models.bioEntities.reactions.ReactionsRestImpl"/> + <bean id="MeshRestImpl" class="lcsb.mapviewer.api.mesh.MeshRestImpl"/> <bean id="ReferenceGenomeRestImpl" class="lcsb.mapviewer.api.genomics.ReferenceGenomeRestImpl"/> <bean id="UserRestImpl" class="lcsb.mapviewer.api.users.UserRestImpl"/> diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java b/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java index f1f28f0d09000c11c4f131a8fe0914fd212f95cd..0adc758211bfb8f7542af57456fe277248c3e05d 100644 --- a/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java +++ b/rest-api/src/test/java/lcsb/mapviewer/api/AllRestTests.java @@ -7,6 +7,7 @@ import org.junit.runners.Suite.SuiteClasses; import lcsb.mapviewer.api.configuration.AllConfigurationTests; import lcsb.mapviewer.api.files.AllFileTests; import lcsb.mapviewer.api.genomics.AllGenomicsTests; +import lcsb.mapviewer.api.mesh.AllMeshTests; import lcsb.mapviewer.api.projects.AllProjectTests; import lcsb.mapviewer.api.users.AllUserTests; @@ -14,6 +15,7 @@ import lcsb.mapviewer.api.users.AllUserTests; @SuiteClasses({ AllConfigurationTests.class, // AllFileTests.class, // AllGenomicsTests.class, // + AllMeshTests.class, // AllProjectTests.class, // AllUserTests.class,// }) diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/mesh/AllMeshTests.java b/rest-api/src/test/java/lcsb/mapviewer/api/mesh/AllMeshTests.java new file mode 100644 index 0000000000000000000000000000000000000000..c17b65885c84a1fd4bc720c1ab451cae34da01b7 --- /dev/null +++ b/rest-api/src/test/java/lcsb/mapviewer/api/mesh/AllMeshTests.java @@ -0,0 +1,11 @@ +package lcsb.mapviewer.api.mesh; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ MeshRestImplTest.class }) +public class AllMeshTests { + +} diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/mesh/MeshRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/mesh/MeshRestImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..93e6211849e467387830251cf12dac5e0343ed25 --- /dev/null +++ b/rest-api/src/test/java/lcsb/mapviewer/api/mesh/MeshRestImplTest.java @@ -0,0 +1,29 @@ +package lcsb.mapviewer.api.mesh; + +import static org.junit.Assert.*; + +import java.util.Map; + +import org.apache.log4j.Logger; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import lcsb.mapviewer.annotation.services.annotators.AnnotatorException; +import lcsb.mapviewer.api.ObjectNotFoundException; +import lcsb.mapviewer.api.RestTestFunctions; + +public class MeshRestImplTest extends RestTestFunctions { + + Logger logger = Logger.getLogger(MeshRestImplTest.class); + @Autowired + MeshRestImpl meshRestImpl; + + @Test + public void test() throws ObjectNotFoundException, AnnotatorException { + Map<String, Object> result = meshRestImpl.getMesh(token.getId(), "D010300"); + assertNotNull(result); + String name =(String) result.get("name"); + assertTrue(name.toLowerCase().contains("parkinson")); + } + +}