From b8e37137b39c540347ab3ef6937958999e8153ba Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Fri, 20 Jul 2018 11:44:38 +0200 Subject: [PATCH] alias info window refacored - overlay data is obtained on demand by creating chart function --- .../src/main/js/map/AbstractCustomMap.js | 21 - .../main/js/map/window/AbstractInfoWindow.js | 1486 ++++++++--------- .../src/main/js/map/window/AliasInfoWindow.js | 256 +-- .../src/main/js/map/window/PointInfoWindow.js | 126 +- .../main/js/map/window/ReactionInfoWindow.js | 528 +++--- frontend-js/src/test/js/helper.js | 7 +- frontend-js/src/test/js/map/CustomMap-test.js | 18 - .../js/map/window/AliasInfoWindow-test.js | 29 +- 8 files changed, 1225 insertions(+), 1246 deletions(-) diff --git a/frontend-js/src/main/js/map/AbstractCustomMap.js b/frontend-js/src/main/js/map/AbstractCustomMap.js index 68f84b6424..03f7119a22 100644 --- a/frontend-js/src/main/js/map/AbstractCustomMap.js +++ b/frontend-js/src/main/js/map/AbstractCustomMap.js @@ -571,27 +571,6 @@ AbstractCustomMap.prototype._openInfoWindowForAlias = function (alias, marker) { } }; -/** - * Returns promise of a list of {@link LayoutAlias} information for a given - * {@link Alias} in all currently visualized overlays. - * - * @param {number} aliasId - * identifier of the {@link Alias} - * @returns {PromiseLike<LayoutAlias[]>| Promise<LayoutAlias[]>} promise of an {Array} with list of {@link LayoutAlias} information - * for a given {@link Alias} in all currently visualized overlays - */ -AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function (aliasId) { - var self = this; - return self.getTopMap().getVisibleDataOverlays().then(function (visibleDataOverlays) { - var result = []; - for (var i = 0; i < visibleDataOverlays.length; i++) { - var overlay = visibleDataOverlays[i]; - result.push(overlay.getFullAliasById(aliasId)); - } - return Promise.all(result); - }); -}; - /** * Opens {@link ReactionInfoWindow} for given reaction identifier. * diff --git a/frontend-js/src/main/js/map/window/AbstractInfoWindow.js b/frontend-js/src/main/js/map/window/AbstractInfoWindow.js index c174f946a9..63a91ad290 100644 --- a/frontend-js/src/main/js/map/window/AbstractInfoWindow.js +++ b/frontend-js/src/main/js/map/window/AbstractInfoWindow.js @@ -1,743 +1,743 @@ -"use strict"; - -var Promise = require("bluebird"); - -var logger = require('../../logger'); -var Functions = require('../../Functions'); - -var Comment = require('../data/Comment'); -var GuiConnector = require('../../GuiConnector'); -var GuiUtils = require('../../gui/leftPanel/GuiUtils'); -var IdentifiedElement = require('../data/IdentifiedElement'); -var ObjectWithListeners = require('../../ObjectWithListeners'); -var TargettingStructure = require('../data/TargettingStructure'); - -/** - * Class representing any info window in our map. - * - * @param {IdentifiedElement} params.identifiedElement - * @param {AbstractCustomMap} params.map - * @param {Marker} params.marker - * - * @constructor - */ -function AbstractInfoWindow(params) { - // call super constructor - ObjectWithListeners.call(this); - - var self = this; - - self.setIdentifiedElement(params.identifiedElement); - - self.setCustomMap(params.map); - self.setMarker(params.marker); - - self.setContent(this.createWaitingContentDiv()); - - self._overlayFullView = []; - - self.registerPropertyType("overlayFullView"); - - self.registerListenerType("onShow"); - self.registerListenerType("onUpdate"); - - self.setGuiUtils(new GuiUtils()); - - var dbOverlaySearchChanged = function () { - return self.update(); - }; - var searchDbOverlay = params.map.getTopMap().getOverlayByName("search"); - if (searchDbOverlay !== undefined) { - searchDbOverlay.addListener("onSearch", dbOverlaySearchChanged); - } - var commentDbOverlay = params.map.getTopMap().getOverlayByName("comment"); - if (commentDbOverlay !== undefined) { - commentDbOverlay.addListener("onSearch", dbOverlaySearchChanged); - } -} - -AbstractInfoWindow.prototype = Object.create(ObjectWithListeners.prototype); -AbstractInfoWindow.prototype.constructor = AbstractInfoWindow; - -/** - * Returns <code>true</code> if overlay should visualize all possible values. - * - * @param {string} overlayName - * name of the overlay - * @returns {boolean}, <code>true</code> if overlay should visualize all possible values - */ -AbstractInfoWindow.prototype.isOverlayFullView = function (overlayName) { - if (this._overlayFullView[overlayName] === undefined) { - this._overlayFullView[overlayName] = false; - } - return this._overlayFullView[overlayName]; -}; - -/** - * Returns associative array with information if specific overlay should present - * all possible results or only specified by the data searched by user. - * - * @returns {Object.<string,boolean>} with information if specific overlay should present all - * possible results or only specified by the data searched by user - */ -AbstractInfoWindow.prototype.getOverlayFullViewArray = function () { - return this._overlayFullView; -}; - -/** - * - * @param {string} overlayName - * @param {boolean} value - * @returns {Promise} - */ -AbstractInfoWindow.prototype.setOverlayFullView = function (overlayName, value) { - var oldVal = this._overlayFullView[overlayName]; - this._overlayFullView[overlayName] = value; - if (oldVal !== value) { - return this.firePropertyChangeListener("overlayFullView", overlayName + "," + oldVal, value); - } else { - return Promise.resolve(); - } -}; - -/** - * This method checks if {@link AbstractInfoWindow} is opened. - * - * @returns {Boolean} <code>true</code> if window is opened, - * <code>false</code> otherwise - */ -AbstractInfoWindow.prototype.isOpened = function () { - if (this._infoWindow === undefined) { - return false; - } - return this._infoWindow.isOpened(); -}; - -/** - * Opens Info Window. - * - * @param {Marker} [newMarker] - * - * @returns {PromiseLike<any> | Promise<any>} - */ -AbstractInfoWindow.prototype.open = function (newMarker) { - var self = this; - var infoWindow = self._infoWindow; - if (infoWindow === null || infoWindow === undefined) { - logger.warn("Cannot open window."); - return Promise.resolve(); - } - if (newMarker !== undefined) { - infoWindow.setMarker(newMarker); - } - infoWindow.open(); - - return self.update().then(function () { - return self.callListeners("onShow"); - }); -}; - -/** - * Sets new content of the info window. - * - * @param {HTMLElement|string} content - * new content of the window - */ -AbstractInfoWindow.prototype.setContent = function (content) { - var self = this; - self._content = content; - if (self._infoWindow !== undefined) { - self._infoWindow.setContent(content); - } -}; - -/** - * Returns content visualized in the info window. - * - * @returns {string|HTMLElement} content visualized in the info window - */ -AbstractInfoWindow.prototype.getContent = function () { - return this._content; -}; - -/** - * Creates div for an overlay data. - * - * @param {AbstractDbOverlay} overlay - * corresponding overlay - * @param {BioEntity[]|Comment[]|Drug[]|MiRna[]|Chemical[]} data - * data taken from overlay - * @returns {HTMLElement} div for given overlay data - */ -AbstractInfoWindow.prototype.createOverlayInfoDiv = function (overlay, data) { - var alias = this.alias; - if (alias !== undefined) { - if (alias.getType() !== undefined) { - if (overlay.name === "drug") { - if (alias.getType().toUpperCase() === "RNA" || // - alias.getType().toUpperCase() === "PROTEIN" || // - alias.getType().toUpperCase() === "GENE") { - return this._createDrugInfoDiv(overlay, data); - } else { - return null; - } - } else if (overlay.name === "chemical") { - if (this.alias.getType().toUpperCase() === "RNA" || // - alias.getType().toUpperCase() === "PROTEIN" || // - alias.getType().toUpperCase() === "GENE") { - return this._createChemicalInfoDiv(overlay, data); - } else { - return null; - } - } else if (overlay.name === "mirna") { - if (alias.getType().toUpperCase() === "RNA" || // - alias.getType().toUpperCase() === "PROTEIN" || // - alias.getType().toUpperCase() === "GENE") { - return this._createMiRnaInfoDiv(overlay, data); - } else { - return null; - } - - } else if (overlay.name === "comment") { - return this._createCommentInfoDiv(overlay, data); - } else { - logger.warn("Unknown overlay data for AliasInfoWindow: " + overlay.name); - return this._createDefaultInfoDiv(overlay, data); - } - } else { - logger.debug(alias); - throw new Error("Cannot customize info window. Alias type is unknown "); - } - } else { - if (overlay.getName() === "comment") { - return this._createCommentInfoDiv(overlay, data); - } else { - logger.debug("Cannot customize info window. Alias not defined. Overlay: " + overlay.getName()); - return null; - } - } -}; - -/** - * Creates and returns div for drug overlay information. - * - * @param {AbstractDbOverlay} overlay - * @param {Drug[]} data - * data taken from drug overlay - * @returns {HTMLElement} div for drug overlay information - * @private - */ -AbstractInfoWindow.prototype._createDrugInfoDiv = function (overlay, data) { - return this._createTargetInfoDiv({ - overlay: overlay, - data: data, - name: "Interacting drugs" - }); -}; - -/** - * Creates and returns div for comment overlay information. - * - * @param {AbstractDbOverlay} overlay - * @param {Comment[]} data - * data taken from comment overlay - * @returns {HTMLElement} div for comment overlay information - */ -AbstractInfoWindow.prototype._createCommentInfoDiv = function (overlay, data) { - if (data.length === 0 || data[0] === undefined) { - return null; - } - var result = document.createElement("div"); - - var titleElement = document.createElement("h3"); - titleElement.innerHTML = "Comments"; - result.appendChild(titleElement); - for (var i = 0; i < data.length; i++) { - var comment = data[i]; - if (comment instanceof Comment) { - if (!comment.isRemoved()) { - result.appendChild(document.createElement("hr")); - var commentId = document.createElement("div"); - commentId.innerHTML = '#' + comment.getId(); - result.appendChild(commentId); - result.appendChild(document.createElement("br")); - var commentContent = Functions.createElement({type: "div", content: comment.getContent(), xss: true}); - - result.appendChild(commentContent); - } - } else { - throw new Error("Invalid comment data: " + comment); - } - } - - return result; -}; - -/** - * Creates and returns div for unknown overlay. - * - * @param {AbstractDbOverlay} overlay - * @param {Array} data - * data taken from overlay - * @returns {HTMLElement} div for overlay information - */ - -AbstractInfoWindow.prototype._createDefaultInfoDiv = function (overlay, data) { - var divElement = document.createElement("div"); - var count = 0; - - var titleElement = document.createElement("h3"); - var title = document.createTextNode(overlay.getName()); - titleElement.appendChild(title); - divElement.appendChild(titleElement); - for (var searchId in data) { - if (data.hasOwnProperty(searchId) && data[searchId] !== undefined && data[searchId] !== null) { - count++; - var resultTitleElement = document.createElement("h4"); - var resultTitle = document.createTextNode(searchId); - resultTitleElement.appendChild(resultTitle); - divElement.appendChild(resultTitleElement); - - var keys = Object.keys(data[searchId]); - for (var i = 0; i < keys.length; i++) { - var resultValElement = document.createElement("p"); - var resultVal = document.createTextNode(keys[i] + ": " + data[searchId][keys[i]]); - resultValElement.appendChild(resultVal); - divElement.appendChild(resultValElement); - } - } - } - - if (count === 0) { - divElement = null; - } - return divElement; -}; - -/** - * Returns Marker object where this info window is attached. - * - * @returns {Marker} object where this info window is attached - */ -AbstractInfoWindow.prototype.getMarker = function () { - return this._marker; -}; - -/** - * - * @param {Marker} marker - */ -AbstractInfoWindow.prototype.setMarker = function (marker) { - this._marker = marker; - if (this._infoWindow !== undefined) { - this._infoWindow.setMarker(marker); - } -}; - -/** - * Returns {@link AbstractCustomMap} where this window is presented. - * - * @returns {AbstractCustomMap} where this window is presented - */ -AbstractInfoWindow.prototype.getCustomMap = function () { - return this.customMap; -}; - -/** - * - * @param {AbstractCustomMap} map - */ -AbstractInfoWindow.prototype.setCustomMap = function (map) { - if (map === undefined) { - throw new Error("Map must be defined"); - } - this.customMap = map; -}; - -/** - * Returns html DOM object with content that should presented when waiting for - * some data from server. - * - * @returns {HTMLElement} html with content that should presented when waiting for - * some data from server - */ -AbstractInfoWindow.prototype.createWaitingContentDiv = function () { - var result = document.createElement("div"); - var img = document.createElement("img"); - img.src = GuiConnector.getImgPrefix() + GuiConnector.getLoadingImg(); - var message = document.createElement("h4"); - message.innerHTML = "loading..."; - result.appendChild(img); - result.appendChild(message); - return result; -}; - -/** - * This is a generic method that updates content of the window. - * - * @returns {Promise|PromiseLike} - * @private - */ -AbstractInfoWindow.prototype._updateContent = function () { - var contentDiv = null; - var self = this; - - if (!self.isOpened()) { - return Promise.resolve(); - } else { - self.setContent(self.createWaitingContentDiv()); - - return self.createContentDiv().then(function (content) { - contentDiv = content; - return self.createOverlaysDiv(); - }).then(function (overlaysDiv) { - if (overlaysDiv !== undefined && overlaysDiv !== null) { - contentDiv.appendChild(overlaysDiv); - } - self.setContent(contentDiv); - return self.callListeners("onUpdate"); - }).then(function () { - return contentDiv; - }); - } -}; - -/** - * Creates and returns div with overlays content. - * - * @returns {Promise<HTMLElement>} with html representing data taken from - * {@link AbstractDbOverlay} for this window - */ -AbstractInfoWindow.prototype.createOverlaysDiv = function () { - var self = this; - var result = document.createElement("div"); - return this.getOverlaysData(self.getOverlayFullViewArray()).then(function (overlayData) { - for (var i = 0; i < overlayData.length; i++) { - var overlay = overlayData[i].overlay; - var data = overlayData[i].data; - var overlayInfo = self.createOverlayInfoDiv(overlay, data); - if (overlayInfo !== null) { - result.appendChild(overlayInfo); - } - } - return result; - }); -}; - -// noinspection JSUnusedLocalSymbols -/** - * Returns array with data taken from all known {@link AbstractDbOverlay}. - * - * @param {Object.<string,boolean>} general - * if true then all elements will be returned, if false then only ones - * available right now in the overlay - * - * @returns {Promise} array with data from {@link AbstractDbOverlay} - */ -AbstractInfoWindow.prototype.getOverlaysData = function (general) { - throw new Error("Not implemented"); -}; - -/** - * Abstract method (to be implemented by subclasses) for updating content. - * - * @returns {Promise} - */ -AbstractInfoWindow.prototype.update = function () { - return this._updateContent(); -}; - -/** - * - * @param {string} params.name - * @param {AbstractDbOverlay} params.overlay - * @param {Array} params.data - * @returns {HTMLElement} - * @private - */ -AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) { - var overlay = params.overlay; - var data = params.data; - var name = params.name; - - var self = this; - var result = document.createElement("div"); - - var titleElement = document.createElement("h3"); - titleElement.innerHTML = name; - result.appendChild(titleElement); - if (overlay.allowGeneralSearch()) { - var checkboxDiv = document.createElement("div"); - checkboxDiv.style.float = "right"; - - var checkbox = document.createElement("input"); - checkbox.id = "checkbox-" + name + "-" + this.getElementType() + "-" + this.getElementId(); - checkbox.type = "checkbox"; - checkbox.checked = self.isOverlayFullView(overlay.getName()); - checkbox.onclick = function () { - return self.setOverlayFullView(overlay.getName(), this.checked).then(null, GuiConnector.alert); - }; - - checkboxDiv.appendChild(checkbox); - - var description = document.createElement("div"); - description.style.float = "right"; - description.innerHTML = "Show all"; - checkboxDiv.appendChild(description); - result.appendChild(checkboxDiv); - } - var count = 0; - for (var dataId in data) { - if (data.hasOwnProperty(dataId)) { - count++; - } - } - - var table = self._createTableForTargetDiv(data, overlay); - - if (count === 0 && !overlay.allowGeneralSearch() && !this.isOverlayFullView(overlay.getName())) { - result = null; - } - if (result !== null) { - result.appendChild(table); - } - return result; -}; - -/** - * - * @param {Array} data - * @param {AbstractDbOverlay} overlay - * @returns {HTMLElement} - * @private - */ -AbstractInfoWindow.prototype._createTableForTargetDiv = function (data, overlay) { - var self = this; - var table = document.createElement("table"); - table.className = "minerva-window-drug-table"; - var header = document.createElement("tr"); - var headerCol = document.createElement("th"); - headerCol.innerHTML = "Name"; - header.appendChild(headerCol); - headerCol = document.createElement("th"); - headerCol.innerHTML = "References"; - header.appendChild(headerCol); - - var cell; - table.appendChild(header); - var row; - - var onclick = function () { - // ';' enforces single query (in case there are ',' characters in the name) - return overlay.searchByQuery(this.innerHTML + ";"); - }; - - var count = 0; - for (var searchId in data) { - if (data.hasOwnProperty(searchId)) { - - row = document.createElement("tr"); - var nameContent = searchId; - var annotations = []; - if (typeof data[searchId] === "string") { - nameContent = data[searchId]; - } else if (data[searchId] instanceof TargettingStructure) { - nameContent = data[searchId].getName(); - var targets = data[searchId].getTargetsForIdentifiedElement(self.getIdentifiedElement()); - for (var i = 0; i < targets.length; i++) { - var references = targets[i].getReferences(); - for (var j = 0; j < references.length; j++) { - annotations.push(references[j]); - } - } - } - var link = Functions.createElement({ - type: "a", - onclick: onclick, - href: "#", - content: nameContent - }); - - var nameTd = Functions.createElement({ - type: "td" - }); - nameTd.appendChild(link); - row.appendChild(nameTd); - - var referencesCell = Functions.createElement({ - type: "td" - }); - referencesCell.appendChild(self.getGuiUtils().createAnnotationList(annotations, {groupAnnotations: false})); - - row.appendChild(referencesCell); - - table.appendChild(row); - count++; - } - } - - if (self.isOverlayFullView(overlay.getName()) && count === 0) { - row = document.createElement("tr"); - cell = document.createElement("td"); - cell.colSpan = 2; - cell.innerHTML = "No results available"; - row.appendChild(cell); - table.appendChild(row); - } - - if (!self.isOverlayFullView(overlay.getName()) && count === 0 && overlay.allowGeneralSearch()) { - row = document.createElement("tr"); - cell = document.createElement("td"); - cell.colSpan = 2; - cell.innerHTML = "Search for available targets"; - row.appendChild(cell); - table.appendChild(row); - } - return table; -}; - -/** - * - * @returns {PromiseLike<any> | Promise<any>} - */ -AbstractInfoWindow.prototype.init = function () { - var self = this; - var promises = [ - // default settings of visualizing full information about elements - this.setOverlayFullView("drug", false), - this.setOverlayFullView("chemical", false), - this.setOverlayFullView("mirna", false), - this.setOverlayFullView("search", false), - // only all comments should be visible from the beginning - this.setOverlayFullView("comment", true) - ]; - - return Promise.all(promises).then(function () { - // listener called when user want to see all data about specific data overlay - var onOverlayFullViewChanged = function (e) { - var self = e.object; - // first change the content of the element - return self.update().then(function () { - if (e.newVal) { - var element = new IdentifiedElement({ - objectId: self.getElementId(), - modelId: self.getCustomMap().getId(), - type: self.getElementType() - }); - var topMap = self.getCustomMap().getTopMap(); - return topMap.retrieveOverlayDetailDataForElement(element, self.getOverlayFullViewArray()); - } - }); - - }; - - self.addPropertyChangeListener("overlayFullView", onOverlayFullViewChanged); - - self._infoWindow = self.getCustomMap().getMapCanvas().createInfoWindow({ - content: self.content, - position: self.getPosition(), - marker: self._marker - }); - - return ServerConnector.getConfiguration(); - }).then(function (configuration) { - self.getGuiUtils().setConfiguration(configuration); - self.getGuiUtils().setMap(self.getCustomMap()); - }); -}; - -/** - * - * @param {GuiUtils} guiUtils - */ -AbstractInfoWindow.prototype.setGuiUtils = function (guiUtils) { - this._guiUtils = guiUtils; -}; - -/** - * - * @returns {GuiUtils} - */ -AbstractInfoWindow.prototype.getGuiUtils = function () { - return this._guiUtils; -}; - -/** - * Creates and returns DOM div for chemical overlay information. - * - * @param {AbstractDbOverlay} overlay - * @param {Chemical[]} data - * data taken from chemical overlay - * @returns {HTMLElement} element with a div for comment overlay information - * @private - */ -AbstractInfoWindow.prototype._createChemicalInfoDiv = function (overlay, data) { - return this._createTargetInfoDiv({ - overlay: overlay, - data: data, - name: "Interacting chemicals" - }); -}; - -/** - * Creates and returns DOM div for mi rna overlay information. - * - * @param {AbstractDbOverlay} overlay - * @param {MiRna[]} data - * data taken from mi rna overlay - * @returns {HTMLElement} DOM element with a div for comment overlay information - */ -AbstractInfoWindow.prototype._createMiRnaInfoDiv = function (overlay, data) { - return this._createTargetInfoDiv({ - overlay: overlay, - data: data, - name: "Interacting Micro RNAs" - }); -}; - -/** - * - * @param {IdentifiedElement} identifiedElement - */ -AbstractInfoWindow.prototype.setIdentifiedElement = function (identifiedElement) { - if (identifiedElement === undefined) { - throw new Error("identifiedElement cannot be undefined"); - } - this._identifiedElement = identifiedElement; -}; - -/** - * - * @returns {IdentifiedElement} - */ -AbstractInfoWindow.prototype.getIdentifiedElement = function () { - return this._identifiedElement; -}; - - -/** - * Method returning identifier of the object for which this window was created. - * - * @returns {string|number} - */ -AbstractInfoWindow.prototype.getElementId = function () { - return this.getIdentifiedElement().getId(); -}; - -/** - * Method returning type of the object for which this window was created. - * - * @returns {string} - */ -AbstractInfoWindow.prototype.getElementType = function () { - return this.getIdentifiedElement().getType(); -}; - -/** - * @returns {Point} - */ -AbstractInfoWindow.prototype.getPosition = function () { - throw new Error("Not Implemented"); -}; - -module.exports = AbstractInfoWindow; +"use strict"; + +var Promise = require("bluebird"); + +var logger = require('../../logger'); +var Functions = require('../../Functions'); + +var Comment = require('../data/Comment'); +var GuiConnector = require('../../GuiConnector'); +var GuiUtils = require('../../gui/leftPanel/GuiUtils'); +var IdentifiedElement = require('../data/IdentifiedElement'); +var ObjectWithListeners = require('../../ObjectWithListeners'); +var TargettingStructure = require('../data/TargettingStructure'); + +/** + * Class representing any info window in our map. + * + * @param {IdentifiedElement} params.identifiedElement + * @param {AbstractCustomMap} params.map + * @param {Marker} params.marker + * + * @constructor + */ +function AbstractInfoWindow(params) { + // call super constructor + ObjectWithListeners.call(this); + + var self = this; + + self.setIdentifiedElement(params.identifiedElement); + + self.setCustomMap(params.map); + self.setMarker(params.marker); + + self.setContent(this.createWaitingContentDiv()); + + self._overlayFullView = []; + + self.registerPropertyType("overlayFullView"); + + self.registerListenerType("onShow"); + self.registerListenerType("onUpdate"); + + self.setGuiUtils(new GuiUtils()); + + var dbOverlaySearchChanged = function () { + return self.update(); + }; + var searchDbOverlay = params.map.getTopMap().getOverlayByName("search"); + if (searchDbOverlay !== undefined) { + searchDbOverlay.addListener("onSearch", dbOverlaySearchChanged); + } + var commentDbOverlay = params.map.getTopMap().getOverlayByName("comment"); + if (commentDbOverlay !== undefined) { + commentDbOverlay.addListener("onSearch", dbOverlaySearchChanged); + } +} + +AbstractInfoWindow.prototype = Object.create(ObjectWithListeners.prototype); +AbstractInfoWindow.prototype.constructor = AbstractInfoWindow; + +/** + * Returns <code>true</code> if overlay should visualize all possible values. + * + * @param {string} overlayName + * name of the overlay + * @returns {boolean}, <code>true</code> if overlay should visualize all possible values + */ +AbstractInfoWindow.prototype.isOverlayFullView = function (overlayName) { + if (this._overlayFullView[overlayName] === undefined) { + this._overlayFullView[overlayName] = false; + } + return this._overlayFullView[overlayName]; +}; + +/** + * Returns associative array with information if specific overlay should present + * all possible results or only specified by the data searched by user. + * + * @returns {Object.<string,boolean>} with information if specific overlay should present all + * possible results or only specified by the data searched by user + */ +AbstractInfoWindow.prototype.getOverlayFullViewArray = function () { + return this._overlayFullView; +}; + +/** + * + * @param {string} overlayName + * @param {boolean} value + * @returns {Promise} + */ +AbstractInfoWindow.prototype.setOverlayFullView = function (overlayName, value) { + var oldVal = this._overlayFullView[overlayName]; + this._overlayFullView[overlayName] = value; + if (oldVal !== value) { + return this.firePropertyChangeListener("overlayFullView", overlayName + "," + oldVal, value); + } else { + return Promise.resolve(); + } +}; + +/** + * This method checks if {@link AbstractInfoWindow} is opened. + * + * @returns {Boolean} <code>true</code> if window is opened, + * <code>false</code> otherwise + */ +AbstractInfoWindow.prototype.isOpened = function () { + if (this._infoWindow === undefined) { + return false; + } + return this._infoWindow.isOpened(); +}; + +/** + * Opens Info Window. + * + * @param {Marker} [newMarker] + * + * @returns {PromiseLike<any> | Promise<any>} + */ +AbstractInfoWindow.prototype.open = function (newMarker) { + var self = this; + var infoWindow = self._infoWindow; + if (infoWindow === null || infoWindow === undefined) { + logger.warn("Cannot open window."); + return Promise.resolve(); + } + if (newMarker !== undefined) { + infoWindow.setMarker(newMarker); + } + infoWindow.open(); + + return self.update().then(function () { + return self.callListeners("onShow"); + }); +}; + +/** + * Sets new content of the info window. + * + * @param {HTMLElement|string} content + * new content of the window + */ +AbstractInfoWindow.prototype.setContent = function (content) { + var self = this; + self._content = content; + if (self._infoWindow !== undefined) { + self._infoWindow.setContent(content); + } +}; + +/** + * Returns content visualized in the info window. + * + * @returns {string|HTMLElement} content visualized in the info window + */ +AbstractInfoWindow.prototype.getContent = function () { + return this._content; +}; + +/** + * Creates div for an overlay data. + * + * @param {AbstractDbOverlay} overlay + * corresponding overlay + * @param {BioEntity[]|Comment[]|Drug[]|MiRna[]|Chemical[]} data + * data taken from overlay + * @returns {HTMLElement} div for given overlay data + */ +AbstractInfoWindow.prototype.createOverlayInfoDiv = function (overlay, data) { + var alias = this.alias; + if (alias !== undefined) { + if (alias.getType() !== undefined) { + if (overlay.name === "drug") { + if (alias.getType().toUpperCase() === "RNA" || // + alias.getType().toUpperCase() === "PROTEIN" || // + alias.getType().toUpperCase() === "GENE") { + return this._createDrugInfoDiv(overlay, data); + } else { + return null; + } + } else if (overlay.name === "chemical") { + if (this.alias.getType().toUpperCase() === "RNA" || // + alias.getType().toUpperCase() === "PROTEIN" || // + alias.getType().toUpperCase() === "GENE") { + return this._createChemicalInfoDiv(overlay, data); + } else { + return null; + } + } else if (overlay.name === "mirna") { + if (alias.getType().toUpperCase() === "RNA" || // + alias.getType().toUpperCase() === "PROTEIN" || // + alias.getType().toUpperCase() === "GENE") { + return this._createMiRnaInfoDiv(overlay, data); + } else { + return null; + } + + } else if (overlay.name === "comment") { + return this._createCommentInfoDiv(overlay, data); + } else { + logger.warn("Unknown overlay data for AliasInfoWindow: " + overlay.name); + return this._createDefaultInfoDiv(overlay, data); + } + } else { + logger.debug(alias); + throw new Error("Cannot customize info window. Alias type is unknown "); + } + } else { + if (overlay.getName() === "comment") { + return this._createCommentInfoDiv(overlay, data); + } else { + logger.debug("Cannot customize info window. Alias not defined. Overlay: " + overlay.getName()); + return null; + } + } +}; + +/** + * Creates and returns div for drug overlay information. + * + * @param {AbstractDbOverlay} overlay + * @param {Drug[]} data + * data taken from drug overlay + * @returns {HTMLElement} div for drug overlay information + * @private + */ +AbstractInfoWindow.prototype._createDrugInfoDiv = function (overlay, data) { + return this._createTargetInfoDiv({ + overlay: overlay, + data: data, + name: "Interacting drugs" + }); +}; + +/** + * Creates and returns div for comment overlay information. + * + * @param {AbstractDbOverlay} overlay + * @param {Comment[]} data + * data taken from comment overlay + * @returns {HTMLElement} div for comment overlay information + */ +AbstractInfoWindow.prototype._createCommentInfoDiv = function (overlay, data) { + if (data.length === 0 || data[0] === undefined) { + return null; + } + var result = document.createElement("div"); + + var titleElement = document.createElement("h3"); + titleElement.innerHTML = "Comments"; + result.appendChild(titleElement); + for (var i = 0; i < data.length; i++) { + var comment = data[i]; + if (comment instanceof Comment) { + if (!comment.isRemoved()) { + result.appendChild(document.createElement("hr")); + var commentId = document.createElement("div"); + commentId.innerHTML = '#' + comment.getId(); + result.appendChild(commentId); + result.appendChild(document.createElement("br")); + var commentContent = Functions.createElement({type: "div", content: comment.getContent(), xss: true}); + + result.appendChild(commentContent); + } + } else { + throw new Error("Invalid comment data: " + comment); + } + } + + return result; +}; + +/** + * Creates and returns div for unknown overlay. + * + * @param {AbstractDbOverlay} overlay + * @param {Array} data + * data taken from overlay + * @returns {HTMLElement} div for overlay information + */ + +AbstractInfoWindow.prototype._createDefaultInfoDiv = function (overlay, data) { + var divElement = document.createElement("div"); + var count = 0; + + var titleElement = document.createElement("h3"); + var title = document.createTextNode(overlay.getName()); + titleElement.appendChild(title); + divElement.appendChild(titleElement); + for (var searchId in data) { + if (data.hasOwnProperty(searchId) && data[searchId] !== undefined && data[searchId] !== null) { + count++; + var resultTitleElement = document.createElement("h4"); + var resultTitle = document.createTextNode(searchId); + resultTitleElement.appendChild(resultTitle); + divElement.appendChild(resultTitleElement); + + var keys = Object.keys(data[searchId]); + for (var i = 0; i < keys.length; i++) { + var resultValElement = document.createElement("p"); + var resultVal = document.createTextNode(keys[i] + ": " + data[searchId][keys[i]]); + resultValElement.appendChild(resultVal); + divElement.appendChild(resultValElement); + } + } + } + + if (count === 0) { + divElement = null; + } + return divElement; +}; + +/** + * Returns Marker object where this info window is attached. + * + * @returns {Marker} object where this info window is attached + */ +AbstractInfoWindow.prototype.getMarker = function () { + return this._marker; +}; + +/** + * + * @param {Marker} marker + */ +AbstractInfoWindow.prototype.setMarker = function (marker) { + this._marker = marker; + if (this._infoWindow !== undefined) { + this._infoWindow.setMarker(marker); + } +}; + +/** + * Returns {@link AbstractCustomMap} where this window is presented. + * + * @returns {AbstractCustomMap} where this window is presented + */ +AbstractInfoWindow.prototype.getCustomMap = function () { + return this.customMap; +}; + +/** + * + * @param {AbstractCustomMap} map + */ +AbstractInfoWindow.prototype.setCustomMap = function (map) { + if (map === undefined) { + throw new Error("Map must be defined"); + } + this.customMap = map; +}; + +/** + * Returns html DOM object with content that should presented when waiting for + * some data from server. + * + * @returns {HTMLElement} html with content that should presented when waiting for + * some data from server + */ +AbstractInfoWindow.prototype.createWaitingContentDiv = function () { + var result = document.createElement("div"); + var img = document.createElement("img"); + img.src = GuiConnector.getImgPrefix() + GuiConnector.getLoadingImg(); + var message = document.createElement("h4"); + message.innerHTML = "loading..."; + result.appendChild(img); + result.appendChild(message); + return result; +}; + +/** + * This is a generic method that updates content of the window. + * + * @returns {Promise|PromiseLike} + * @private + */ +AbstractInfoWindow.prototype._updateContent = function () { + var contentDiv = null; + var self = this; + + if (!self.isOpened()) { + return Promise.resolve(); + } else { + self.setContent(self.createWaitingContentDiv()); + + return self.createContentDiv().then(function (content) { + contentDiv = content; + return self.createDbOverlaysDiv(); + }).then(function (overlaysDiv) { + if (overlaysDiv !== undefined && overlaysDiv !== null) { + contentDiv.appendChild(overlaysDiv); + } + self.setContent(contentDiv); + return self.callListeners("onUpdate"); + }).then(function () { + return contentDiv; + }); + } +}; + +/** + * Creates and returns div with overlays content. + * + * @returns {Promise<HTMLElement>} with html representing data taken from + * {@link AbstractDbOverlay} for this window + */ +AbstractInfoWindow.prototype.createDbOverlaysDiv = function () { + var self = this; + var result = document.createElement("div"); + return this.getDbOverlaysData(self.getOverlayFullViewArray()).then(function (overlayData) { + for (var i = 0; i < overlayData.length; i++) { + var overlay = overlayData[i].overlay; + var data = overlayData[i].data; + var overlayInfo = self.createOverlayInfoDiv(overlay, data); + if (overlayInfo !== null) { + result.appendChild(overlayInfo); + } + } + return result; + }); +}; + +// noinspection JSUnusedLocalSymbols +/** + * Returns array with data taken from all known {@link AbstractDbOverlay}. + * + * @param {Object.<string,boolean>} general + * if true then all elements will be returned, if false then only ones + * available right now in the overlay + * + * @returns {Promise} array with data from {@link AbstractDbOverlay} + */ +AbstractInfoWindow.prototype.getDbOverlaysData = function (general) { + throw new Error("Not implemented"); +}; + +/** + * Abstract method (to be implemented by subclasses) for updating content. + * + * @returns {Promise} + */ +AbstractInfoWindow.prototype.update = function () { + return this._updateContent(); +}; + +/** + * + * @param {string} params.name + * @param {AbstractDbOverlay} params.overlay + * @param {Array} params.data + * @returns {HTMLElement} + * @private + */ +AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) { + var overlay = params.overlay; + var data = params.data; + var name = params.name; + + var self = this; + var result = document.createElement("div"); + + var titleElement = document.createElement("h3"); + titleElement.innerHTML = name; + result.appendChild(titleElement); + if (overlay.allowGeneralSearch()) { + var checkboxDiv = document.createElement("div"); + checkboxDiv.style.float = "right"; + + var checkbox = document.createElement("input"); + checkbox.id = "checkbox-" + name + "-" + this.getElementType() + "-" + this.getElementId(); + checkbox.type = "checkbox"; + checkbox.checked = self.isOverlayFullView(overlay.getName()); + checkbox.onclick = function () { + return self.setOverlayFullView(overlay.getName(), this.checked).then(null, GuiConnector.alert); + }; + + checkboxDiv.appendChild(checkbox); + + var description = document.createElement("div"); + description.style.float = "right"; + description.innerHTML = "Show all"; + checkboxDiv.appendChild(description); + result.appendChild(checkboxDiv); + } + var count = 0; + for (var dataId in data) { + if (data.hasOwnProperty(dataId)) { + count++; + } + } + + var table = self._createTableForTargetDiv(data, overlay); + + if (count === 0 && !overlay.allowGeneralSearch() && !this.isOverlayFullView(overlay.getName())) { + result = null; + } + if (result !== null) { + result.appendChild(table); + } + return result; +}; + +/** + * + * @param {Array} data + * @param {AbstractDbOverlay} overlay + * @returns {HTMLElement} + * @private + */ +AbstractInfoWindow.prototype._createTableForTargetDiv = function (data, overlay) { + var self = this; + var table = document.createElement("table"); + table.className = "minerva-window-drug-table"; + var header = document.createElement("tr"); + var headerCol = document.createElement("th"); + headerCol.innerHTML = "Name"; + header.appendChild(headerCol); + headerCol = document.createElement("th"); + headerCol.innerHTML = "References"; + header.appendChild(headerCol); + + var cell; + table.appendChild(header); + var row; + + var onclick = function () { + // ';' enforces single query (in case there are ',' characters in the name) + return overlay.searchByQuery(this.innerHTML + ";"); + }; + + var count = 0; + for (var searchId in data) { + if (data.hasOwnProperty(searchId)) { + + row = document.createElement("tr"); + var nameContent = searchId; + var annotations = []; + if (typeof data[searchId] === "string") { + nameContent = data[searchId]; + } else if (data[searchId] instanceof TargettingStructure) { + nameContent = data[searchId].getName(); + var targets = data[searchId].getTargetsForIdentifiedElement(self.getIdentifiedElement()); + for (var i = 0; i < targets.length; i++) { + var references = targets[i].getReferences(); + for (var j = 0; j < references.length; j++) { + annotations.push(references[j]); + } + } + } + var link = Functions.createElement({ + type: "a", + onclick: onclick, + href: "#", + content: nameContent + }); + + var nameTd = Functions.createElement({ + type: "td" + }); + nameTd.appendChild(link); + row.appendChild(nameTd); + + var referencesCell = Functions.createElement({ + type: "td" + }); + referencesCell.appendChild(self.getGuiUtils().createAnnotationList(annotations, {groupAnnotations: false})); + + row.appendChild(referencesCell); + + table.appendChild(row); + count++; + } + } + + if (self.isOverlayFullView(overlay.getName()) && count === 0) { + row = document.createElement("tr"); + cell = document.createElement("td"); + cell.colSpan = 2; + cell.innerHTML = "No results available"; + row.appendChild(cell); + table.appendChild(row); + } + + if (!self.isOverlayFullView(overlay.getName()) && count === 0 && overlay.allowGeneralSearch()) { + row = document.createElement("tr"); + cell = document.createElement("td"); + cell.colSpan = 2; + cell.innerHTML = "Search for available targets"; + row.appendChild(cell); + table.appendChild(row); + } + return table; +}; + +/** + * + * @returns {PromiseLike<any> | Promise<any>} + */ +AbstractInfoWindow.prototype.init = function () { + var self = this; + var promises = [ + // default settings of visualizing full information about elements + this.setOverlayFullView("drug", false), + this.setOverlayFullView("chemical", false), + this.setOverlayFullView("mirna", false), + this.setOverlayFullView("search", false), + // only all comments should be visible from the beginning + this.setOverlayFullView("comment", true) + ]; + + return Promise.all(promises).then(function () { + // listener called when user want to see all data about specific data overlay + var onOverlayFullViewChanged = function (e) { + var self = e.object; + // first change the content of the element + return self.update().then(function () { + if (e.newVal) { + var element = new IdentifiedElement({ + objectId: self.getElementId(), + modelId: self.getCustomMap().getId(), + type: self.getElementType() + }); + var topMap = self.getCustomMap().getTopMap(); + return topMap.retrieveOverlayDetailDataForElement(element, self.getOverlayFullViewArray()); + } + }); + + }; + + self.addPropertyChangeListener("overlayFullView", onOverlayFullViewChanged); + + self._infoWindow = self.getCustomMap().getMapCanvas().createInfoWindow({ + content: self.content, + position: self.getPosition(), + marker: self._marker + }); + + return ServerConnector.getConfiguration(); + }).then(function (configuration) { + self.getGuiUtils().setConfiguration(configuration); + self.getGuiUtils().setMap(self.getCustomMap()); + }); +}; + +/** + * + * @param {GuiUtils} guiUtils + */ +AbstractInfoWindow.prototype.setGuiUtils = function (guiUtils) { + this._guiUtils = guiUtils; +}; + +/** + * + * @returns {GuiUtils} + */ +AbstractInfoWindow.prototype.getGuiUtils = function () { + return this._guiUtils; +}; + +/** + * Creates and returns DOM div for chemical overlay information. + * + * @param {AbstractDbOverlay} overlay + * @param {Chemical[]} data + * data taken from chemical overlay + * @returns {HTMLElement} element with a div for comment overlay information + * @private + */ +AbstractInfoWindow.prototype._createChemicalInfoDiv = function (overlay, data) { + return this._createTargetInfoDiv({ + overlay: overlay, + data: data, + name: "Interacting chemicals" + }); +}; + +/** + * Creates and returns DOM div for mi rna overlay information. + * + * @param {AbstractDbOverlay} overlay + * @param {MiRna[]} data + * data taken from mi rna overlay + * @returns {HTMLElement} DOM element with a div for comment overlay information + */ +AbstractInfoWindow.prototype._createMiRnaInfoDiv = function (overlay, data) { + return this._createTargetInfoDiv({ + overlay: overlay, + data: data, + name: "Interacting Micro RNAs" + }); +}; + +/** + * + * @param {IdentifiedElement} identifiedElement + */ +AbstractInfoWindow.prototype.setIdentifiedElement = function (identifiedElement) { + if (identifiedElement === undefined) { + throw new Error("identifiedElement cannot be undefined"); + } + this._identifiedElement = identifiedElement; +}; + +/** + * + * @returns {IdentifiedElement} + */ +AbstractInfoWindow.prototype.getIdentifiedElement = function () { + return this._identifiedElement; +}; + + +/** + * Method returning identifier of the object for which this window was created. + * + * @returns {string|number} + */ +AbstractInfoWindow.prototype.getElementId = function () { + return this.getIdentifiedElement().getId(); +}; + +/** + * Method returning type of the object for which this window was created. + * + * @returns {string} + */ +AbstractInfoWindow.prototype.getElementType = function () { + return this.getIdentifiedElement().getType(); +}; + +/** + * @returns {Point} + */ +AbstractInfoWindow.prototype.getPosition = function () { + throw new Error("Not Implemented"); +}; + +module.exports = AbstractInfoWindow; diff --git a/frontend-js/src/main/js/map/window/AliasInfoWindow.js b/frontend-js/src/main/js/map/window/AliasInfoWindow.js index 0bc086e396..53ec9cda23 100644 --- a/frontend-js/src/main/js/map/window/AliasInfoWindow.js +++ b/frontend-js/src/main/js/map/window/AliasInfoWindow.js @@ -36,10 +36,7 @@ function AliasInfoWindow(params) { this.setAlias(params.alias); var overlayListChanged = function () { - return self.getCustomMap().getAliasVisibleLayoutsData(self.getAlias().getId()).then(function (layoutAliases) { - self.layoutAliases = layoutAliases; - return self.update(); - }); + return self.update(); }; var dbOverlaySearchChanged = function () { @@ -97,99 +94,107 @@ AliasInfoWindow.prototype.init = function () { * Creates and returns chart representing data related to alias on different * overlays. * + * @param {DataOverlay[]} params.overlays + * * @returns {PromiseLike<HTMLElement>} html element representing chart with data related to alias * on different overlays */ -AliasInfoWindow.prototype.createChartDiv = function () { +AliasInfoWindow.prototype.createChartDiv = function (params) { + var overlays = params.overlays; + var result = document.createElement("div"); - var rows = []; + var promises = []; var self = this; - return Promise.each(self.layoutAliases, function (data, i) { - var rowDiv = document.createElement("div"); - if (i % 2 === 0) { - rowDiv.className = "mapChartRowEvenDiv"; - } else { - rowDiv.className = "mapChartRowOddDiv"; - } - rowDiv.style.position = "relative"; - var nameDiv = document.createElement("div"); - nameDiv.className = "mapChartNameDiv"; - nameDiv.innerHTML = self.layoutNames[i] + " "; - rowDiv.appendChild(nameDiv); - - rows[i] = rowDiv; - if (data !== undefined && data !== null) { - return Functions.overlayToColor(data).then(function (color) { - var value = parseFloat(data.value); - var description = data.description; - if (description === null || description === undefined || description === "") { - description = ""; - if (!isNaN(value)) { - description = value.toFixed(2); + + overlays.forEach(function (overlay, i) { + promises.push(overlay.getFullAliasById(self.getAlias().getId()).then(function (data) { + var rowDiv = document.createElement("div"); + if (i % 2 === 0) { + rowDiv.className = "mapChartRowEvenDiv"; + } else { + rowDiv.className = "mapChartRowOddDiv"; + } + rowDiv.style.position = "relative"; + var nameDiv = document.createElement("div"); + nameDiv.className = "mapChartNameDiv"; + nameDiv.innerHTML = overlays[i].getName() + " "; + rowDiv.appendChild(nameDiv); + + if (data !== undefined && data !== null) { + return Functions.overlayToColor(data).then(function (color) { + var value = parseFloat(data.value); + var description = data.description; + if (description === null || description === undefined || description === "") { + description = ""; + if (!isNaN(value)) { + description = value.toFixed(2); + } } - } - var leftMarginDiv = document.createElement("div"); - leftMarginDiv.innerHTML = " "; - leftMarginDiv.style.float = "left"; - var centerBarDiv = document.createElement("div"); - centerBarDiv.style.width = "1px"; - centerBarDiv.style.float = "left"; - centerBarDiv.style.background = "#000000"; - centerBarDiv.innerHTML = " "; - - var rightBarDiv = document.createElement("div"); - rightBarDiv.innerHTML = " "; - rightBarDiv.style.float = "left"; - rightBarDiv.style.background = color; - rightBarDiv.style.width = Math.abs(value * 100) + "px"; - var offset = 100; - var descDiv = document.createElement("div"); - descDiv.style.float = "right"; - descDiv.style.textAlign = "right"; - descDiv.style.position = "absolute"; - descDiv.style.right = "0"; - descDiv.innerHTML = "<span>" + description + "</span>"; - if (!isNaN(value)) { - if (value > 0) { - offset = 100; - leftMarginDiv.style.width = offset + "px"; + var leftMarginDiv = document.createElement("div"); + leftMarginDiv.innerHTML = " "; + leftMarginDiv.style.float = "left"; + var centerBarDiv = document.createElement("div"); + centerBarDiv.style.width = "1px"; + centerBarDiv.style.float = "left"; + centerBarDiv.style.background = "#000000"; + centerBarDiv.innerHTML = " "; + + var rightBarDiv = document.createElement("div"); + rightBarDiv.innerHTML = " "; + rightBarDiv.style.float = "left"; + rightBarDiv.style.background = color; + rightBarDiv.style.width = Math.abs(value * 100) + "px"; + var offset = 100; + var descDiv = document.createElement("div"); + descDiv.style.float = "right"; + descDiv.style.textAlign = "right"; + descDiv.style.position = "absolute"; + descDiv.style.right = "0"; + descDiv.innerHTML = "<span>" + description + "</span>"; + if (!isNaN(value)) { + if (value > 0) { + offset = 100; + leftMarginDiv.style.width = offset + "px"; - rightBarDiv.style.textAlign = "right"; + rightBarDiv.style.textAlign = "right"; + + rowDiv.appendChild(leftMarginDiv); + rowDiv.appendChild(centerBarDiv); + rowDiv.appendChild(rightBarDiv); + } else { + offset = 100 + (value * 100); + leftMarginDiv.style.width = offset + "px"; + + rowDiv.appendChild(leftMarginDiv); + rowDiv.appendChild(rightBarDiv); + rowDiv.appendChild(centerBarDiv); + } - rowDiv.appendChild(leftMarginDiv); - rowDiv.appendChild(centerBarDiv); - rowDiv.appendChild(rightBarDiv); } else { - offset = 100 + (value * 100); + offset = 100; leftMarginDiv.style.width = offset + "px"; - + leftMarginDiv.style.background = color; + rightBarDiv.style.width = offset + "px"; + rightBarDiv.style.background = color; + rightBarDiv.style.textAlign = "right"; rowDiv.appendChild(leftMarginDiv); - rowDiv.appendChild(rightBarDiv); rowDiv.appendChild(centerBarDiv); + rowDiv.appendChild(rightBarDiv); } - - } else { - offset = 100; - leftMarginDiv.style.width = offset + "px"; - leftMarginDiv.style.background = color; - rightBarDiv.style.width = offset + "px"; - rightBarDiv.style.background = color; - rightBarDiv.style.textAlign = "right"; - rowDiv.appendChild(leftMarginDiv); - rowDiv.appendChild(centerBarDiv); - rowDiv.appendChild(rightBarDiv); - } - rowDiv.appendChild(descDiv); - }); - } else { - var emptyDiv = document.createElement("div"); - emptyDiv.innerHTML = " "; - emptyDiv.style.float = "left"; - emptyDiv.style.width = "201px"; - rowDiv.appendChild(emptyDiv); - return Promise.resolve(); - } - }).then(function () { + rowDiv.appendChild(descDiv); + return rowDiv; + }); + } else { + var emptyDiv = document.createElement("div"); + emptyDiv.innerHTML = " "; + emptyDiv.style.float = "left"; + emptyDiv.style.width = "201px"; + rowDiv.appendChild(emptyDiv); + return rowDiv; + } + })); + }); + return Promise.all(promises).then(function (rows) { for (var i = 0; i < rows.length; i++) { result.appendChild(rows[i]); } @@ -215,18 +220,14 @@ AliasInfoWindow.prototype.createContentDiv = function () { result.appendChild(overlayDiv); - return self.getCustomMap().getAliasVisibleLayoutsData(alias.getId()).then(function (layoutAliases) { - self.layoutAliases = layoutAliases; - return self.getCustomMap().getTopMap().getVisibleDataOverlays(); - }).then(function (dataOverlays) { - self.layoutNames = []; - for (var i = 0; i < dataOverlays.length; i++) { - self.layoutNames.push(dataOverlays[i].getName()); - } - return self.createChartDiv(); + var overlays; + + return self.getCustomMap().getTopMap().getVisibleDataOverlays().then(function (dataOverlays) { + overlays = dataOverlays; + return self.createChartDiv({overlays: overlays}); }).then(function (chartDiv) { overlayDiv.appendChild(chartDiv); - return self.createGenomicDiv(); + return self.createGenomicDiv({overlays: overlays}); }).then(function (genomicDiv) { overlayDiv.appendChild(genomicDiv); return result; @@ -245,15 +246,19 @@ AliasInfoWindow.prototype.createContentDiv = function () { * * @returns {Promise} array with data from {@link AbstractDbOverlay} */ -AliasInfoWindow.prototype.getOverlaysData = function (general) { +AliasInfoWindow.prototype.getDbOverlaysData = function (general) { return this.getCustomMap().getTopMap().getOverlayDataForAlias(this.getAlias(), general); }; /** * - * @returns {PromiseLike<HTMLElement>} + * @param {DataOverlay[]} params.overlays + * + * @returns {Promise|PromiseLike} */ -AliasInfoWindow.prototype.createGenomicDiv = function () { +AliasInfoWindow.prototype.createGenomicDiv = function (params) { + var overlays = params.overlays; + var self = this; var result = document.createElement("div"); @@ -285,34 +290,41 @@ AliasInfoWindow.prototype.createGenomicDiv = function () { var globalGeneVariants = []; - return Promise.each( - self.layoutAliases, - function (data) { + var promises = []; + var overlaysData = []; + + overlays.forEach(function (overlay) { + promises.push(overlay.getFullAliasById(self.getAlias().getId())); + }); + return Promise.all(promises).then(function (result) { + promises = []; + overlaysData = result; + for (var i = 0; i < overlaysData.length; i++) { + var data = overlaysData[i]; if (data !== null && data !== undefined && data.getType() === LayoutAlias.GENETIC_VARIANT) { geneticInformation = true; - return Promise.each(data.getGeneVariants(), function (variant) { + promises.push(Promise.each(data.getGeneVariants(), function (variant) { return self.getCustomMap().getTopMap().getReferenceGenome(variant.getReferenceGenomeType(), - variant.getReferenceGenomeVersion()).then( - function (genome) { - if (genome.getUrl() !== null && genome.getUrl() !== undefined) { - if (genomes[genome.getUrl()] === undefined) { - genomes[genome.getUrl()] = genome; - genomeUrls.push(genome.getUrl()); - } - } else { - logger.warn("Genome for " + variant.getReferenceGenomeType() + "," - + variant.getReferenceGenomeVersion() + " not loaded"); + variant.getReferenceGenomeVersion()).then(function (genome) { + if (genome.getUrl() !== null && genome.getUrl() !== undefined) { + if (genomes[genome.getUrl()] === undefined) { + genomes[genome.getUrl()] = genome; + genomeUrls.push(genome.getUrl()); } - }, - function () { + } else { logger.warn("Genome for " + variant.getReferenceGenomeType() + "," + variant.getReferenceGenomeVersion() + " not loaded"); + } + }, function () { + logger.warn("Genome for " + variant.getReferenceGenomeType() + "," + + variant.getReferenceGenomeVersion() + " not loaded"); - }); - }); - + }); + })); } - }).then(function () { + } + return Promise.all(promises); + }).then(function () { for (var i = 0; i < genomeUrls.length; i++) { var genome = genomes[genomeUrls[i]]; pileupSource.splice(0, 0, { @@ -334,7 +346,8 @@ AliasInfoWindow.prototype.createGenomicDiv = function () { }); } } - return Promise.each(self.layoutAliases, function (data, i) { + for (i = 0; i < overlaysData.length; i++) { + var data = overlaysData[i]; globalGeneVariants[i] = []; if (data !== null && data !== undefined && data.getType() === LayoutAlias.GENETIC_VARIANT) { var geneVariants = data.getGeneVariants(); @@ -349,13 +362,12 @@ AliasInfoWindow.prototype.createGenomicDiv = function () { pileupRange.stop = Math.max(pileupRange.stop, variant.getPosition() + length); } } - }); - }).then(function () { + } if (geneticInformation) { if (genomeUrls.length === 0) { contentElement.innerHTML = "No reference genome data available on minerva platform"; } else { - for (var i = 0; i < self.layoutAliases.length; i++) { + for (i = 0; i < overlaysData.length; i++) { if (globalGeneVariants[i].length > 0) { var vcfContent = self.createVcfString(globalGeneVariants[i]); pileupSource.push({ @@ -363,7 +375,7 @@ AliasInfoWindow.prototype.createGenomicDiv = function () { data: pileup.formats.vcf({ content: vcfContent }), - name: self.layoutNames[i] + ' - Variants', + name: overlays[i].getName() + ' - Variants', options: { variantHeightByFrequency: true } diff --git a/frontend-js/src/main/js/map/window/PointInfoWindow.js b/frontend-js/src/main/js/map/window/PointInfoWindow.js index dc1c2d7f8b..bf263c8e7a 100644 --- a/frontend-js/src/main/js/map/window/PointInfoWindow.js +++ b/frontend-js/src/main/js/map/window/PointInfoWindow.js @@ -1,63 +1,63 @@ -"use strict"; - -var Promise = require("bluebird"); - -var AbstractInfoWindow = require('./AbstractInfoWindow'); -var IdentifiedElement = require('../data/IdentifiedElement'); - -/** - * - * @param {IdentifiedElement} [params.identifiedElement] - * @param {AbstractCustomMap} params.map - * @param {Marker} params.marker - * @param {PointData} params.point - * - * @constructor - * @extends AbstractInfoWindow - */ -function PointInfoWindow(params) { - if (params.identifiedElement === undefined) { - params.identifiedElement = new IdentifiedElement(params.point); - } - // call super constructor - AbstractInfoWindow.call(this, params); - - this.pointData = params.point; - -} - -PointInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype); -PointInfoWindow.prototype.constructor = PointInfoWindow; - -/** - * - * @returns {PromiseLike<HTMLElement>} - */ -PointInfoWindow.prototype.createContentDiv = function () { - var result = document.createElement("div"); - var title = document.createElement("h3"); - title.innerHTML = "Point: " + this.pointData.getPoint(); - result.appendChild(title); - - return Promise.resolve(result); -}; - -/** - * - * @param {Object.<string,boolean>} general - * @returns {Promise} - */ -PointInfoWindow.prototype.getOverlaysData = function (general) { - return this.getCustomMap().getTopMap().getOverlayDataForPoint(this.pointData, general); -}; - -/** - * - * @returns {Point} - */ -PointInfoWindow.prototype.getPosition = function () { - return this.pointData.getPoint(); -}; - - -module.exports = PointInfoWindow; +"use strict"; + +var Promise = require("bluebird"); + +var AbstractInfoWindow = require('./AbstractInfoWindow'); +var IdentifiedElement = require('../data/IdentifiedElement'); + +/** + * + * @param {IdentifiedElement} [params.identifiedElement] + * @param {AbstractCustomMap} params.map + * @param {Marker} params.marker + * @param {PointData} params.point + * + * @constructor + * @extends AbstractInfoWindow + */ +function PointInfoWindow(params) { + if (params.identifiedElement === undefined) { + params.identifiedElement = new IdentifiedElement(params.point); + } + // call super constructor + AbstractInfoWindow.call(this, params); + + this.pointData = params.point; + +} + +PointInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype); +PointInfoWindow.prototype.constructor = PointInfoWindow; + +/** + * + * @returns {PromiseLike<HTMLElement>} + */ +PointInfoWindow.prototype.createContentDiv = function () { + var result = document.createElement("div"); + var title = document.createElement("h3"); + title.innerHTML = "Point: " + this.pointData.getPoint(); + result.appendChild(title); + + return Promise.resolve(result); +}; + +/** + * + * @param {Object.<string,boolean>} general + * @returns {Promise} + */ +PointInfoWindow.prototype.getDbOverlaysData = function (general) { + return this.getCustomMap().getTopMap().getOverlayDataForPoint(this.pointData, general); +}; + +/** + * + * @returns {Point} + */ +PointInfoWindow.prototype.getPosition = function () { + return this.pointData.getPoint(); +}; + + +module.exports = PointInfoWindow; diff --git a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js index cca0f9d2c8..bd6b7c493c 100644 --- a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js +++ b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js @@ -1,264 +1,264 @@ -"use strict"; - -var Promise = require("bluebird"); - -var AbstractInfoWindow = require('./AbstractInfoWindow'); -var GuiUtils = require('../../gui/leftPanel/GuiUtils'); -var IdentifiedElement = require('../data/IdentifiedElement'); -var Reaction = require('../data/Reaction'); -var Functions = require('../../Functions'); -var logger = require('../../logger'); - -/** - * Class representing info window that should be opened when clicking on - * reaction. - */ -/** - * - * @param {IdentifiedElement} [params.identifiedElement] - * @param {AbstractCustomMap} params.map - * @param {Marker} params.marker - * @param {Reaction} params.reaction - * - * @constructor - * @extends AbstractInfoWindow - */ -function ReactionInfoWindow(params) { - if (params.identifiedElement === undefined) { - params.identifiedElement = new IdentifiedElement(params.reaction); - } - // call super constructor - AbstractInfoWindow.call(this, params); - - var self = this; - - self.setReactionData(params.reaction); - if (params.reaction.getKineticLaw() !== undefined) { - self.addListener("onShow", function () { - return MathJax.Hub.Queue(["Typeset", MathJax.Hub]); - }); - } -} - -ReactionInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype); -ReactionInfoWindow.prototype.constructor = ReactionInfoWindow; - -/** - * Methods that creates and return html code with the content of the window. - * - * @returns {Promise} representing html code for content of the info window - */ -ReactionInfoWindow.prototype.createContentDiv = function () { - var self = this; - var reaction = self.getReactionData(); - var result = document.createElement("div"); - var title = document.createElement("h3"); - title.innerHTML = "Reaction: " + reaction.getReactionId(); - result.appendChild(title); - - return self.createKineticsDiv(reaction, result).then(function () { - result.appendChild(self.createElementsDiv(reaction)); - return result; - }); -}; - -/** - * - * @param {Reaction} reaction - * @param {HTMLElement} result - * @returns {Promise} - */ -ReactionInfoWindow.prototype.createKineticsDiv = function (reaction, result) { - var self = this; - if (reaction.getKineticLaw() === undefined) { - return Promise.resolve(); - } else { - var kineticLaw = reaction.getKineticLaw(); - return Functions.loadScript('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML').then(function () { - return MathJax.Hub.Config({ - tex2jax: { - skipTags: ["script", "noscript", "style", "textarea", "pre", "code"] - } - }); - }).then(function () { - - result.appendChild(Functions.createElement({type: "h4", content: "Kinetic law"})); - - if (kineticLaw.getMathMlPresentation() !== undefined) { - result.appendChild(Functions.createElement({ - type: "div", - content: kineticLaw.getMathMlPresentation(), - xss: false - })); - } else { - - result.appendChild(Functions.createElement({ - type: "div", - content: "<p>Problematic MathML</p>" - })); - logger.warn("Problematic MathML: " + kineticLaw.getDefinition()); - } - var promises = []; - for (var i = 0; i < kineticLaw.getFunctionIds().length; i++) { - promises.push(self.getCustomMap().getModel().getSbmlFunctionById(kineticLaw.getFunctionIds()[i])); - } - return Promise.all(promises); - }).then(function (functions) { - result.appendChild(self.createSbmlFunctionDiv(functions)); - - var promises = []; - for (var i = 0; i < kineticLaw.getParameterIds().length; i++) { - promises.push(self.getCustomMap().getModel().getSbmlParameterById(kineticLaw.getParameterIds()[i])); - } - return Promise.all(promises); - }).then(function (parameters) { - result.appendChild(self.createSbmlParameterDiv(parameters)); - }); - } -}; - -/** - * - * @param {SbmlFunction[]} functions - * @returns {HTMLElement} - */ -ReactionInfoWindow.prototype.createSbmlFunctionDiv = function (functions) { - var result = Functions.createElement({type: "div"}); - if (functions.length > 0) { - result.appendChild(Functions.createElement({type: "h5", content: "Functions: "})); - var guiUtils = new GuiUtils(); - var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); - table.appendChild(guiUtils.createTableRow(["Name", "Definition", "Arguments"])); - for (var i = 0; i < functions.length; i++) { - var sbmlFunction = functions[i]; - var mathML; - if (sbmlFunction.getMathMlPresentation() !== undefined) { - mathML = sbmlFunction.getMathMlPresentation(); - } else { - mathML = "<p>Problematic MathML</p>"; - logger.warn("Problematic MathML: " + sbmlFunction.getDefinition()); - } - var functionArguments = sbmlFunction.getArguments().join(", "); - table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), mathML, functionArguments])); - } - result.appendChild(table); - } - return result; -}; - -/** - * - * @param {SbmlParameter[]} parameters - * @returns {HTMLElement} - */ -ReactionInfoWindow.prototype.createSbmlParameterDiv = function (parameters) { - var result = Functions.createElement({type: "div"}); - if (parameters.length > 0) { - result.appendChild(Functions.createElement({type: "h5", content: "Parameters: "})); - var guiUtils = new GuiUtils(); - var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); - table.appendChild(guiUtils.createTableRow(["Name", "parameterId", "Value", "Global"])); - for (var i = 0; i < parameters.length; i++) { - var sbmlFunction = parameters[i]; - table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), sbmlFunction.getParameterId(), sbmlFunction.getValue(), sbmlFunction.getGlobal()])); - } - result.appendChild(table); - } - return result; -}; - -/** - * - * @param {Reaction} reaction - * @returns {HTMLElement} - */ -ReactionInfoWindow.prototype.createElementsDiv = function (reaction) { - var result = Functions.createElement({type: "div"}); - result.appendChild(Functions.createElement({type: "h5", content: "Elements: "})); - var guiUtils = new GuiUtils(); - var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); - table.appendChild(guiUtils.createTableRow(["Name", "Role", "elementId", "Constant", "Boundary condition", "Initial concentration", "Initial amount", "Stoichiometry"])); - var elements = reaction.getReactants(); - var i, element; - - function createRow(node, title) { - var element = node.getAlias(); - var stoichiometry = node.getStoichiometry(); - if (stoichiometry === undefined) { - stoichiometry = ""; - } - return guiUtils.createTableRow([element.getName(), title, element.getElementId(), element.getConstant(), element.getBoundaryCondition(), element.getInitialConcentration(), element.getInitialAmount(), stoichiometry]) - } - - for (i = 0; i < elements.length; i++) { - element = elements[i].getAlias(); - table.appendChild(createRow(elements[i], "Reactant")); - } - elements = reaction.getProducts(); - for (i = 0; i < elements.length; i++) { - element = elements[i].getAlias(); - table.appendChild(createRow(elements[i], "Product")); - } - elements = reaction.getModifiers(); - for (i = 0; i < elements.length; i++) { - element = elements[i].getAlias(); - table.appendChild(createRow(elements[i], "Modifier")); - } - result.appendChild(table); - return result; -}; - -/** - * - * @returns {PromiseLike<any> | Promise<any>} - */ -ReactionInfoWindow.prototype.init = function () { - var self = this; - return Promise.resolve().then(function () { - return AbstractInfoWindow.prototype.init.call(self); - }).then(function () { - return self.update(); - }); -}; - -/** - * Returns array with data taken from all known {@link AbstractDbOverlay}. - * - * @param {Object.<string,boolean>} general - * @returns {Promise} of an array with data from {@link AbstractDbOverlay} - */ -ReactionInfoWindow.prototype.getOverlaysData = function (general) { - return this.getCustomMap().getTopMap().getOverlayDataForReaction(this.getReactionData(), general); -}; - -/** - * - * @returns {Reaction} - */ -ReactionInfoWindow.prototype.getReactionData = function () { - return this._reactionData; -}; - -/** - * - * @param {Reaction} reactionData - */ -ReactionInfoWindow.prototype.setReactionData = function (reactionData) { - if (reactionData === undefined || reactionData === null) { - throw new Error("Reaction must be specified"); - } else if (reactionData instanceof Reaction) { - this._reactionData = reactionData; - } else { - throw new Error("Parameter must be of Reaction type, but found" + reactionData); - } -}; - -/** - * - * @returns {Point} - */ -ReactionInfoWindow.prototype.getPosition = function () { - return this.getReactionData().getCenter(); -}; - -module.exports = ReactionInfoWindow; +"use strict"; + +var Promise = require("bluebird"); + +var AbstractInfoWindow = require('./AbstractInfoWindow'); +var GuiUtils = require('../../gui/leftPanel/GuiUtils'); +var IdentifiedElement = require('../data/IdentifiedElement'); +var Reaction = require('../data/Reaction'); +var Functions = require('../../Functions'); +var logger = require('../../logger'); + +/** + * Class representing info window that should be opened when clicking on + * reaction. + */ +/** + * + * @param {IdentifiedElement} [params.identifiedElement] + * @param {AbstractCustomMap} params.map + * @param {Marker} params.marker + * @param {Reaction} params.reaction + * + * @constructor + * @extends AbstractInfoWindow + */ +function ReactionInfoWindow(params) { + if (params.identifiedElement === undefined) { + params.identifiedElement = new IdentifiedElement(params.reaction); + } + // call super constructor + AbstractInfoWindow.call(this, params); + + var self = this; + + self.setReactionData(params.reaction); + if (params.reaction.getKineticLaw() !== undefined) { + self.addListener("onShow", function () { + return MathJax.Hub.Queue(["Typeset", MathJax.Hub]); + }); + } +} + +ReactionInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype); +ReactionInfoWindow.prototype.constructor = ReactionInfoWindow; + +/** + * Methods that creates and return html code with the content of the window. + * + * @returns {Promise} representing html code for content of the info window + */ +ReactionInfoWindow.prototype.createContentDiv = function () { + var self = this; + var reaction = self.getReactionData(); + var result = document.createElement("div"); + var title = document.createElement("h3"); + title.innerHTML = "Reaction: " + reaction.getReactionId(); + result.appendChild(title); + + return self.createKineticsDiv(reaction, result).then(function () { + result.appendChild(self.createElementsDiv(reaction)); + return result; + }); +}; + +/** + * + * @param {Reaction} reaction + * @param {HTMLElement} result + * @returns {Promise} + */ +ReactionInfoWindow.prototype.createKineticsDiv = function (reaction, result) { + var self = this; + if (reaction.getKineticLaw() === undefined) { + return Promise.resolve(); + } else { + var kineticLaw = reaction.getKineticLaw(); + return Functions.loadScript('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML').then(function () { + return MathJax.Hub.Config({ + tex2jax: { + skipTags: ["script", "noscript", "style", "textarea", "pre", "code"] + } + }); + }).then(function () { + + result.appendChild(Functions.createElement({type: "h4", content: "Kinetic law"})); + + if (kineticLaw.getMathMlPresentation() !== undefined) { + result.appendChild(Functions.createElement({ + type: "div", + content: kineticLaw.getMathMlPresentation(), + xss: false + })); + } else { + + result.appendChild(Functions.createElement({ + type: "div", + content: "<p>Problematic MathML</p>" + })); + logger.warn("Problematic MathML: " + kineticLaw.getDefinition()); + } + var promises = []; + for (var i = 0; i < kineticLaw.getFunctionIds().length; i++) { + promises.push(self.getCustomMap().getModel().getSbmlFunctionById(kineticLaw.getFunctionIds()[i])); + } + return Promise.all(promises); + }).then(function (functions) { + result.appendChild(self.createSbmlFunctionDiv(functions)); + + var promises = []; + for (var i = 0; i < kineticLaw.getParameterIds().length; i++) { + promises.push(self.getCustomMap().getModel().getSbmlParameterById(kineticLaw.getParameterIds()[i])); + } + return Promise.all(promises); + }).then(function (parameters) { + result.appendChild(self.createSbmlParameterDiv(parameters)); + }); + } +}; + +/** + * + * @param {SbmlFunction[]} functions + * @returns {HTMLElement} + */ +ReactionInfoWindow.prototype.createSbmlFunctionDiv = function (functions) { + var result = Functions.createElement({type: "div"}); + if (functions.length > 0) { + result.appendChild(Functions.createElement({type: "h5", content: "Functions: "})); + var guiUtils = new GuiUtils(); + var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); + table.appendChild(guiUtils.createTableRow(["Name", "Definition", "Arguments"])); + for (var i = 0; i < functions.length; i++) { + var sbmlFunction = functions[i]; + var mathML; + if (sbmlFunction.getMathMlPresentation() !== undefined) { + mathML = sbmlFunction.getMathMlPresentation(); + } else { + mathML = "<p>Problematic MathML</p>"; + logger.warn("Problematic MathML: " + sbmlFunction.getDefinition()); + } + var functionArguments = sbmlFunction.getArguments().join(", "); + table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), mathML, functionArguments])); + } + result.appendChild(table); + } + return result; +}; + +/** + * + * @param {SbmlParameter[]} parameters + * @returns {HTMLElement} + */ +ReactionInfoWindow.prototype.createSbmlParameterDiv = function (parameters) { + var result = Functions.createElement({type: "div"}); + if (parameters.length > 0) { + result.appendChild(Functions.createElement({type: "h5", content: "Parameters: "})); + var guiUtils = new GuiUtils(); + var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); + table.appendChild(guiUtils.createTableRow(["Name", "parameterId", "Value", "Global"])); + for (var i = 0; i < parameters.length; i++) { + var sbmlFunction = parameters[i]; + table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), sbmlFunction.getParameterId(), sbmlFunction.getValue(), sbmlFunction.getGlobal()])); + } + result.appendChild(table); + } + return result; +}; + +/** + * + * @param {Reaction} reaction + * @returns {HTMLElement} + */ +ReactionInfoWindow.prototype.createElementsDiv = function (reaction) { + var result = Functions.createElement({type: "div"}); + result.appendChild(Functions.createElement({type: "h5", content: "Elements: "})); + var guiUtils = new GuiUtils(); + var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"}); + table.appendChild(guiUtils.createTableRow(["Name", "Role", "elementId", "Constant", "Boundary condition", "Initial concentration", "Initial amount", "Stoichiometry"])); + var elements = reaction.getReactants(); + var i, element; + + function createRow(node, title) { + var element = node.getAlias(); + var stoichiometry = node.getStoichiometry(); + if (stoichiometry === undefined) { + stoichiometry = ""; + } + return guiUtils.createTableRow([element.getName(), title, element.getElementId(), element.getConstant(), element.getBoundaryCondition(), element.getInitialConcentration(), element.getInitialAmount(), stoichiometry]) + } + + for (i = 0; i < elements.length; i++) { + element = elements[i].getAlias(); + table.appendChild(createRow(elements[i], "Reactant")); + } + elements = reaction.getProducts(); + for (i = 0; i < elements.length; i++) { + element = elements[i].getAlias(); + table.appendChild(createRow(elements[i], "Product")); + } + elements = reaction.getModifiers(); + for (i = 0; i < elements.length; i++) { + element = elements[i].getAlias(); + table.appendChild(createRow(elements[i], "Modifier")); + } + result.appendChild(table); + return result; +}; + +/** + * + * @returns {PromiseLike<any> | Promise<any>} + */ +ReactionInfoWindow.prototype.init = function () { + var self = this; + return Promise.resolve().then(function () { + return AbstractInfoWindow.prototype.init.call(self); + }).then(function () { + return self.update(); + }); +}; + +/** + * Returns array with data taken from all known {@link AbstractDbOverlay}. + * + * @param {Object.<string,boolean>} general + * @returns {Promise} of an array with data from {@link AbstractDbOverlay} + */ +ReactionInfoWindow.prototype.getDbOverlaysData = function (general) { + return this.getCustomMap().getTopMap().getOverlayDataForReaction(this.getReactionData(), general); +}; + +/** + * + * @returns {Reaction} + */ +ReactionInfoWindow.prototype.getReactionData = function () { + return this._reactionData; +}; + +/** + * + * @param {Reaction} reactionData + */ +ReactionInfoWindow.prototype.setReactionData = function (reactionData) { + if (reactionData === undefined || reactionData === null) { + throw new Error("Reaction must be specified"); + } else if (reactionData instanceof Reaction) { + this._reactionData = reactionData; + } else { + throw new Error("Parameter must be of Reaction type, but found" + reactionData); + } +}; + +/** + * + * @returns {Point} + */ +ReactionInfoWindow.prototype.getPosition = function () { + return this.getReactionData().getCenter(); +}; + +module.exports = ReactionInfoWindow; diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js index 30002e661c..11fc0efa18 100644 --- a/frontend-js/src/test/js/helper.js +++ b/frontend-js/src/test/js/helper.js @@ -223,9 +223,11 @@ Helper.prototype.createAlias = function (map) { /** * * @param {Alias} [alias] + * @param {string} [type] + * * @returns {LayoutAlias} */ -Helper.prototype.createLayoutAlias = function (alias) { +Helper.prototype.createLayoutAlias = function (alias, type) { var id; var modelId; if (alias instanceof Alias) { @@ -242,7 +244,8 @@ Helper.prototype.createLayoutAlias = function (alias) { a: 23 }, modelId: modelId, - geneVariations: [] + geneVariations: [], + type: type }); }; diff --git a/frontend-js/src/test/js/map/CustomMap-test.js b/frontend-js/src/test/js/map/CustomMap-test.js index 353d80e088..880efabfaa 100644 --- a/frontend-js/src/test/js/map/CustomMap-test.js +++ b/frontend-js/src/test/js/map/CustomMap-test.js @@ -634,24 +634,6 @@ describe('CustomMap', function () { }); }); - it("getAliasVisibleLayoutsData", function () { - var mockObject = helper.createCustomMap(); - - var alias = helper.createAlias(); - mockObject.getModel().addAlias(alias); - - var layout = helper.createOverlay(); - layout.setInputDataAvailable(true); - layout.setInitialized(true); - mockObject.getProject().addDataOverlay(layout); - - return mockObject.openDataOverlay(layout.getId()).then(function () { - return mockObject.getAliasVisibleLayoutsData(alias.getId()); - }).then(function (layoutAliases) { - assert.equal(layoutAliases.length, 1); - }); - }); - it("changed coordinates in map", function () { var map = helper.createCustomMap(); var oldCenter = map.getCenter(); diff --git a/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js b/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js index 627d901f4e..c7dec871f2 100644 --- a/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js +++ b/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js @@ -246,9 +246,9 @@ describe('AliasInfoWindow', function () { }); return win.init(); }).then(function () { - win.layoutAliases = [layoutAlias]; - win.layoutNames = ["xxx"]; - return win.createGenomicDiv(); + var overlay = helper.createOverlay(); + overlay.addAlias(layoutAlias); + return win.createGenomicDiv({overlays: [overlay]}); }).then(function (div) { assert.ok(div); assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1); @@ -281,9 +281,9 @@ describe('AliasInfoWindow', function () { }).then(function () { var layoutAlias = helper.createLayoutAlias(alias); layoutAlias.setType(LayoutAlias.GENETIC_VARIANT); - win.layoutAliases = [layoutAlias]; - win.layoutNames = ["xxx"]; - return win.createGenomicDiv(); + var overlay = helper.createOverlay(); + overlay.addAlias(layoutAlias); + return win.createGenomicDiv({overlays: [overlay]}); }).then(function (div) { assert.ok(div); win.destroy(); @@ -312,8 +312,8 @@ describe('AliasInfoWindow', function () { }); return win.init(); }).then(function () { - win.layoutAliases = [undefined]; - return win.createGenomicDiv(); + var overlays = [helper.createOverlay()]; + return win.createGenomicDiv({overlays: overlays}); }).then(function (div) { assert.ok(div); assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1); @@ -350,8 +350,9 @@ describe('AliasInfoWindow', function () { }); return win.init(); }).then(function () { - win.layoutAliases = [layoutAlias]; - return win.createGenomicDiv(); + var overlay = helper.createOverlay(); + overlay.addAlias(layoutAlias); + return win.createGenomicDiv({overlays: [overlay]}); }).then(function (div) { assert.ok(div); assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") >= -1); @@ -392,9 +393,11 @@ describe('AliasInfoWindow', function () { map: map, marker: helper.createMarker({element: alias, map: map}) }); - aliasWindow.layoutAliases = [helper.createLayoutAlias(alias), null]; - aliasWindow.layoutNames = ["x", "y"]; - return aliasWindow.createChartDiv(); + var overlay = helper.createOverlay(); + overlay.addAlias(helper.createLayoutAlias(alias, LayoutAlias.GENERIC)); + var overlays = [overlay, helper.createOverlay()]; + + return aliasWindow.createChartDiv({overlays: overlays}); }).then(function (div) { assert.ok(div); }); -- GitLab