From b7b14d2407bca8a0f51c9ea3b9bf245959151fa7 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Fri, 9 Feb 2018 14:08:47 +0100 Subject: [PATCH] visualzization of functions for kinetic law added --- frontend-js/src/main/css/global.css | 5 + frontend-js/src/main/js/Functions.js | 4 + frontend-js/src/main/js/ServerConnector.js | 20 ++ .../src/main/js/gui/leftPanel/GuiUtils.js | 6 +- frontend-js/src/main/js/map/CustomMap.js | 4 +- .../src/main/js/map/data/KineticLaw.js | 1 - frontend-js/src/main/js/map/data/MapModel.js | 241 ++++++++++-------- .../main/js/map/window/ReactionInfoWindow.js | 41 ++- .../src/test/js/ServerConnector-test.js | 7 + frontend-js/src/test/js/helper.js | 30 +++ .../src/test/js/map/data/KineticLaw-test.js | 2 +- .../js/map/window/ReactionInfoWindow-test.js | 29 ++- .../all/functions/5/token=MOCK_TOKEN_ID& | 1 + 13 files changed, 269 insertions(+), 122 deletions(-) create mode 100644 frontend-js/testFiles/apiCalls/projects/sample/models/all/functions/5/token=MOCK_TOKEN_ID& diff --git a/frontend-js/src/main/css/global.css b/frontend-js/src/main/css/global.css index 83c544eb80..dab4b9ec0f 100644 --- a/frontend-js/src/main/css/global.css +++ b/frontend-js/src/main/css/global.css @@ -517,6 +517,11 @@ h1 { padding: 2px; } +.borderTable div[style*="display: table-cell"] { + padding: 2px; + border: 1px solid black; +} + .minerva-datatable-toolbar { float: left; } \ No newline at end of file diff --git a/frontend-js/src/main/js/Functions.js b/frontend-js/src/main/js/Functions.js index 6932f32af5..2a12658649 100644 --- a/frontend-js/src/main/js/Functions.js +++ b/frontend-js/src/main/js/Functions.js @@ -315,6 +315,10 @@ Functions.removeChildren = function (element) { } }; +/** + * + * @returns Promise resolved after javascript is loaded + */ Functions.loadScript = function (url) { return new Promise(function (resolve) { var scriptExists = false; diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index a76aedaa23..e19e237c9e 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -30,6 +30,7 @@ var Project = require('./map/data/Project'); var ProjectStatistics = require('./map/data/ProjectStatistics'); var Reaction = require('./map/data/Reaction'); var ReferenceGenome = require('./map/data/ReferenceGenome'); +var SbmlFunction = require('./map/data/SbmlFunction'); var SecurityError = require('./SecurityError'); var SessionData = require('./SessionData'); var User = require('./map/data/User'); @@ -349,6 +350,12 @@ ServerConnector.getMeshUrl = function (queryParams, filterParams) { }); }; +ServerConnector.getSbmlFunctionUrl = function (queryParams, filterParams) { + return this.getApiUrl({ + url: this.getModelsUrl(queryParams) + "functions/" + queryParams.functionId, + params: filterParams + }); +}; ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) { var version = this.getIdOrAsterisk(queryParams.version); @@ -1843,4 +1850,17 @@ ServerConnector.getMesh = function (params) { }); }; +ServerConnector.getSbmlFunction = function (params) { + var self = this; + if (params === undefined) { + params = {}; + } + return self.getProjectId(params.projectId).then(function (result) { + params.projectId = result; + return self.sendGetRequest(self.getSbmlFunctionUrl(params)); + }).then(function (content) { + return new SbmlFunction(JSON.parse(content)); + }); +}; + module.exports = ServerConnector; diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js index daa4b747f7..ea45176d13 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js +++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js @@ -314,7 +314,11 @@ GuiUtils.prototype.createTableRow = function (elements) { type: "div", style: "display: table-cell;" }); - cell.appendChild(elements[i]); + if (Functions.isDomElement(elements[i])) { + cell.appendChild(elements[i]); + } else { + cell.innerHTML = elements[i]; + } row.appendChild(cell); } return row; diff --git a/frontend-js/src/main/js/map/CustomMap.js b/frontend-js/src/main/js/map/CustomMap.js index 2dcf1c7a9f..e3b7e7cdeb 100644 --- a/frontend-js/src/main/js/map/CustomMap.js +++ b/frontend-js/src/main/js/map/CustomMap.js @@ -813,7 +813,7 @@ CustomMap.prototype.getOverlayDataForAlias = function (alias, general) { * @param general * if true then all elements will be returned, if false then only ones * available right now in the overlay - * @returns data from all {@link OverlayCollection} for a given alias + * @returns Promise of data from all {@link OverlayCollection} for a given alias */ CustomMap.prototype.getOverlayDataForReaction = function (reaction, general) { var identifiedElement = new IdentifiedElement(reaction); @@ -839,7 +839,7 @@ CustomMap.prototype.getOverlayDataForPoint = function (point, general) { * * @param identifiedElement * {@link IdentifiedElement} for which overlay data will be returned - * @returns data from all {@link OverlayCollection} for a given + * @returns Promise of data from all {@link OverlayCollection} for a given * {@link IdentifiedElement} */ CustomMap.prototype.getOverlayDataForIdentifiedElement = function (identifiedElement, general) { diff --git a/frontend-js/src/main/js/map/data/KineticLaw.js b/frontend-js/src/main/js/map/data/KineticLaw.js index 39c9b02470..fb4ecc6deb 100644 --- a/frontend-js/src/main/js/map/data/KineticLaw.js +++ b/frontend-js/src/main/js/map/data/KineticLaw.js @@ -5,7 +5,6 @@ function KineticLaw(jsonObject) { self.setParameterIds(jsonObject.parameterIds); self.setFunctionIds(jsonObject.functionIds); self.setDefinition(jsonObject.definition); - self.setDefinition(jsonObject.definition); self.setMathMlPresentation(jsonObject.mathMlPresentation); } diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js index 7bbd84fc8d..53e0a82877 100644 --- a/frontend-js/src/main/js/map/data/MapModel.js +++ b/frontend-js/src/main/js/map/data/MapModel.js @@ -15,7 +15,7 @@ var Reaction = require('./Reaction'); /** * Default constructor. - * + * */ function MapModel(configuration) { @@ -45,6 +45,8 @@ function MapModel(configuration) { this._submodels = []; + this._sbmlFunctions = []; + if (configuration !== undefined) { if (configuration instanceof MapModel) { this.setId(configuration.getId()); @@ -86,12 +88,12 @@ function MapModel(configuration) { /** * Returns list of {@link LayoutData} on this model. - * + * * @returns {Array} with list of {@link LayoutData} on this model */ -MapModel.prototype.getLayoutsData = function() { +MapModel.prototype.getLayoutsData = function () { var result = []; - for ( var id in this._layoutsData) { + for (var id in this._layoutsData) { if (this._layoutsData.hasOwnProperty(id)) { result.push(this._layoutsData[id]); } @@ -99,23 +101,23 @@ MapModel.prototype.getLayoutsData = function() { return result; }; -MapModel.prototype.getLayouts = function() { +MapModel.prototype.getLayouts = function () { return this.getLayoutsData(); }; /** * Return list of all aliases that were added to the model. */ -MapModel.prototype.getAliases = function(params) { +MapModel.prototype.getAliases = function (params) { var self = this; return ServerConnector.getAliases({ - columns : "id,modelId", - type : params.type, - modelId : self.getId(), - includedCompartmentIds : params.includedCompartmentIds, - excludedCompartmentIds : params.excludedCompartmentIds, + columns: "id,modelId", + type: params.type, + modelId: self.getId(), + includedCompartmentIds: params.includedCompartmentIds, + excludedCompartmentIds: params.excludedCompartmentIds, - }).then(function(lightAliases) { + }).then(function (lightAliases) { var identifiedElements = []; for (var i = 0; i < lightAliases.length; i++) { self.addAlias(lightAliases[i]); @@ -127,12 +129,12 @@ MapModel.prototype.getAliases = function(params) { /** * Returns {@link Alias} by identifier. - * + * * @param id * identifier of the {@link Alias} * @returns {@link Alias} by identifier */ -MapModel.prototype.getAliasById = function(id, complete) { +MapModel.prototype.getAliasById = function (id, complete) { var self = this; if (complete) { return this.getCompleteAliasById(id); @@ -141,21 +143,21 @@ MapModel.prototype.getAliasById = function(id, complete) { return Promise.resolve(self._aliases[id]); } else { return self.getMissingElements({ - aliasIds : [ id ] - }).then(function() { + aliasIds: [id] + }).then(function () { return self._aliases[id]; }); } }; -MapModel.prototype.getCompleteAliasById = function(id) { +MapModel.prototype.getCompleteAliasById = function (id) { var self = this; if (self._aliases[id] !== undefined && self._aliases[id].isComplete()) { return Promise.resolve(self._aliases[id]); } else { return ServerConnector.getAliases({ - ids : id - }).then(function(aliases) { + ids: id + }).then(function (aliases) { if (self._aliases[id] === undefined) { self._aliases[id] = aliases[0]; } else { @@ -168,12 +170,12 @@ MapModel.prototype.getCompleteAliasById = function(id) { /** * Returns {@link Reaction} by identifier. - * + * * @param id * identifier of the {@link Reaction} * @returns {@link Reaction} by identifier */ -MapModel.prototype.getReactionById = function(id, complete) { +MapModel.prototype.getReactionById = function (id, complete) { var self = this; if (complete) { return this.getCompleteReactionById(id); @@ -182,14 +184,14 @@ MapModel.prototype.getReactionById = function(id, complete) { return Promise.resolve(self._reactions[id]); } else { return self.getMissingElements({ - reactionIds : [ id ] - }).then(function() { + reactionIds: [id] + }).then(function () { return self._reactions[id]; }); } }; -MapModel.prototype._getMissingReactionsElementIds = function(reactions) { +MapModel.prototype._getMissingReactionsElementIds = function (reactions) { var self = this; var result = []; var ids = []; @@ -211,19 +213,19 @@ MapModel.prototype._getMissingReactionsElementIds = function(reactions) { return result; }; -MapModel.prototype.getCompleteReactionById = function(id) { +MapModel.prototype.getCompleteReactionById = function (id) { var self = this; if (self._reactions[id] instanceof Reaction && self._reactions[id].isComplete()) { return Promise.resolve(self._reactions[id]); } else { var result; - return self.getReactionById(id).then(function(result) { - var ids = self._getMissingReactionsElementIds([ result ]); + return self.getReactionById(id).then(function (result) { + var ids = self._getMissingReactionsElementIds([result]); return self.getMissingElements({ - aliasIds : ids, - complete : true + aliasIds: ids, + complete: true }); - }).then(function() { + }).then(function () { var i; result = self._reactions[id]; for (i = 0; i < result.getReactants().length; i++) { @@ -246,7 +248,7 @@ MapModel.prototype.getCompleteReactionById = function(id) { } }; -MapModel.prototype.getMissingElements = function(elements) { +MapModel.prototype.getMissingElements = function (elements) { var self = this; var layouts = this._getLayouts(); @@ -293,8 +295,8 @@ MapModel.prototype.getMissingElements = function(elements) { var reactionPromise = null; if (reactionIds.length > 0) { reactionPromise = ServerConnector.getReactions({ - ids : reactionIds, - complete : elements.complete + ids: reactionIds, + complete: elements.complete }); } @@ -302,19 +304,19 @@ MapModel.prototype.getMissingElements = function(elements) { if (aliasIds.length > 0) { if (elements.complete) { aliasPromise = ServerConnector.getAliases({ - ids : aliasIds + ids: aliasIds }); } else { aliasPromise = ServerConnector.getAliases({ - ids : aliasIds, - columns : "id,bounds,modelId" + ids: aliasIds, + columns: "id,bounds,modelId" }); } } var result = []; - return Promise.all([ reactionPromise, aliasPromise ]).then(function(values) { + return Promise.all([reactionPromise, aliasPromise]).then(function (values) { var i; var reactions = values[0]; var aliases = values[1]; @@ -337,30 +339,30 @@ MapModel.prototype.getMissingElements = function(elements) { } if (ids.length > 0) { return self.getMissingElements({ - aliasIds : ids, - complete : true + aliasIds: ids, + complete: true }); } else { return Promise.resolve([]); } - }).then(function() { + }).then(function () { return result; }); }; /** * Returns layout data for a given layout identifier. - * + * * @param layoutId * layout identifier * @returns {LayoutData} for a given layout identifier */ -MapModel.prototype.getLayoutDataById = function(layoutId) { +MapModel.prototype.getLayoutDataById = function (layoutId) { var self = this; if (self._layoutsData[layoutId] !== undefined) { return Promise.resolve(self._layoutsData[layoutId]); } else { - return ServerConnector.getOverlayById(layoutId).then(function(layout) { + return ServerConnector.getOverlayById(layoutId).then(function (layout) { self.addLayout(layout); return self._layoutsData[layoutId]; }); @@ -369,11 +371,11 @@ MapModel.prototype.getLayoutDataById = function(layoutId) { /** * Adds information about alias. - * + * * @param aliasData * raw data about alias */ -MapModel.prototype.addAlias = function(aliasData) { +MapModel.prototype.addAlias = function (aliasData) { var alias = aliasData; if (!(aliasData instanceof Alias)) { alias = new Alias(aliasData); @@ -391,11 +393,11 @@ MapModel.prototype.addAlias = function(aliasData) { /** * Adds information about reaction. - * + * * @param reactionData * raw data about reaction */ -MapModel.prototype.addReaction = function(reactionData) { +MapModel.prototype.addReaction = function (reactionData) { var reaction = null; if (reactionData instanceof Reaction) { reaction = reactionData; @@ -415,12 +417,12 @@ MapModel.prototype.addReaction = function(reactionData) { /** * Returns {@link PointData} for a given point on the map. - * + * * @param point * {@link google.maps.Point} where we are requesting data * @returns {@link PointData} for a given point on the map */ -MapModel.prototype.getPointDataByPoint = function(inputPoint) { +MapModel.prototype.getPointDataByPoint = function (inputPoint) { if (inputPoint instanceof google.maps.Point) { var point = this._roundPoint(inputPoint); var id = this._pointToId(point); @@ -438,13 +440,13 @@ MapModel.prototype.getPointDataByPoint = function(inputPoint) { /** * Returns point where x and y coordinate are rounded to 2 decimal places. - * + * * @param point * input point * @returns {google.maps.Point} point where x and y coordinate are rounded to 2 * decimal places */ -MapModel.prototype._roundPoint = function(point) { +MapModel.prototype._roundPoint = function (point) { var x = parseFloat(point.x).toFixed(2); var y = parseFloat(point.y).toFixed(2); return new google.maps.Point(x, y); @@ -452,12 +454,12 @@ MapModel.prototype._roundPoint = function(point) { /** * Transform point into string identifier. - * + * * @param point * {google.maps.Point} to transform * @returns {String} string identifier for a given point */ -MapModel.prototype._pointToId = function(point) { +MapModel.prototype._pointToId = function (point) { if (point instanceof google.maps.Point) { return "(" + point.x + ", " + point.y + ")"; } else { @@ -465,75 +467,75 @@ MapModel.prototype._pointToId = function(point) { } }; -MapModel.prototype.getId = function() { +MapModel.prototype.getId = function () { return this.id; }; -MapModel.prototype.setId = function(id) { +MapModel.prototype.setId = function (id) { this.id = parseInt(id); }; -MapModel.prototype.getWidth = function() { +MapModel.prototype.getWidth = function () { return this._width; }; -MapModel.prototype.setWidth = function(width) { +MapModel.prototype.setWidth = function (width) { this._width = width; }; -MapModel.prototype.getHeight = function() { +MapModel.prototype.getHeight = function () { return this._height; }; -MapModel.prototype.setHeight = function(height) { +MapModel.prototype.setHeight = function (height) { this._height = height; }; -MapModel.prototype.getName = function() { +MapModel.prototype.getName = function () { return this._name; }; -MapModel.prototype.setName = function(name) { +MapModel.prototype.setName = function (name) { this._name = name; }; -MapModel.prototype.getMinZoom = function() { +MapModel.prototype.getMinZoom = function () { return this._minZoom; }; -MapModel.prototype.setMinZoom = function(minZoom) { +MapModel.prototype.setMinZoom = function (minZoom) { this._minZoom = minZoom; }; -MapModel.prototype.getDefaultZoomLevel = function() { +MapModel.prototype.getDefaultZoomLevel = function () { return this._defaultZoomLevel; }; -MapModel.prototype.setDefaultZoomLevel = function(defaultZoomLevel) { +MapModel.prototype.setDefaultZoomLevel = function (defaultZoomLevel) { this._defaultZoomLevel = defaultZoomLevel; }; -MapModel.prototype.getDefaultCenterX = function() { +MapModel.prototype.getDefaultCenterX = function () { return this._defaultCenterX; }; -MapModel.prototype.setDefaultCenterX = function(defaultCenterX) { +MapModel.prototype.setDefaultCenterX = function (defaultCenterX) { this._defaultCenterX = defaultCenterX; }; -MapModel.prototype.getDefaultCenterY = function() { +MapModel.prototype.getDefaultCenterY = function () { return this._defaultCenterY; }; -MapModel.prototype.setDefaultCenterY = function(defaultCenterY) { +MapModel.prototype.setDefaultCenterY = function (defaultCenterY) { this._defaultCenterY = defaultCenterY; }; -MapModel.prototype.getSubmodelType = function() { +MapModel.prototype.getSubmodelType = function () { return this._submodelType; }; -MapModel.prototype.setSubmodelType = function(submodelType) { +MapModel.prototype.setSubmodelType = function (submodelType) { this._submodelType = submodelType; }; @@ -548,7 +550,7 @@ function createLatLng(param) { } } -MapModel.prototype.setCenterLatLng = function(centerLatLng) { +MapModel.prototype.setCenterLatLng = function (centerLatLng) { var newVal = createLatLng(centerLatLng); if (newVal === null) { logger.warn("centerLatLng is invalid"); @@ -557,11 +559,11 @@ MapModel.prototype.setCenterLatLng = function(centerLatLng) { } }; -MapModel.prototype.getCenterLatLng = function() { +MapModel.prototype.getCenterLatLng = function () { return this._centerLatLng; }; -MapModel.prototype.setTopLeftLatLng = function(topLeftLatLng) { +MapModel.prototype.setTopLeftLatLng = function (topLeftLatLng) { var newVal = createLatLng(topLeftLatLng); if (newVal === null) { logger.warn("topLeftLatLng is invalid"); @@ -570,11 +572,11 @@ MapModel.prototype.setTopLeftLatLng = function(topLeftLatLng) { } }; -MapModel.prototype.getTopLeftLatLng = function() { +MapModel.prototype.getTopLeftLatLng = function () { return this._topLeftLatLng; }; -MapModel.prototype.setBottomRightLatLng = function(bottomRightLatLng) { +MapModel.prototype.setBottomRightLatLng = function (bottomRightLatLng) { var newVal = createLatLng(bottomRightLatLng); if (newVal === null) { logger.warn("bottomRightLatLng is invalid"); @@ -583,31 +585,31 @@ MapModel.prototype.setBottomRightLatLng = function(bottomRightLatLng) { } }; -MapModel.prototype.getBottomRightLatLng = function() { +MapModel.prototype.getBottomRightLatLng = function () { return this._bottomRightLatLng; }; -MapModel.prototype.getMaxZoom = function() { +MapModel.prototype.getMaxZoom = function () { return this._maxZoom; }; -MapModel.prototype.setMaxZoom = function(maxZoom) { +MapModel.prototype.setMaxZoom = function (maxZoom) { this._maxZoom = maxZoom; }; -MapModel.prototype.getTileSize = function() { +MapModel.prototype.getTileSize = function () { return this._tileSize; }; -MapModel.prototype.getPictureSize = function() { +MapModel.prototype.getPictureSize = function () { return Math.max(this.getWidth(), this.getHeight()); }; -MapModel.prototype.setTileSize = function(tileSize) { +MapModel.prototype.setTileSize = function (tileSize) { this._tileSize = tileSize; }; -MapModel.prototype.addLayouts = function(layouts) { +MapModel.prototype.addLayouts = function (layouts) { if (layouts === undefined) { logger.warn("Layouts are undefined..."); } else { @@ -616,7 +618,7 @@ MapModel.prototype.addLayouts = function(layouts) { } } }; -MapModel.prototype.addLayout = function(layout) { +MapModel.prototype.addLayout = function (layout) { var layoutData = null; if (layout instanceof LayoutData) { layoutData = layout; @@ -631,7 +633,7 @@ MapModel.prototype.addLayout = function(layout) { } }; -MapModel.prototype.addSubmodels = function(submodels) { +MapModel.prototype.addSubmodels = function (submodels) { if (submodels !== undefined) { for (var i = 0; i < submodels.length; i++) { this.addSubmodel(submodels[i]); @@ -639,18 +641,18 @@ MapModel.prototype.addSubmodels = function(submodels) { } }; -MapModel.prototype.addSubmodel = function(submodel) { +MapModel.prototype.addSubmodel = function (submodel) { if (!(submodel instanceof MapModel)) { submodel = new MapModel(submodel); } this._submodels.push(submodel); }; -MapModel.prototype.getSubmodels = function() { +MapModel.prototype.getSubmodels = function () { return this._submodels; }; -MapModel.prototype.getSubmodelById = function(id) { +MapModel.prototype.getSubmodelById = function (id) { if (this.getId() === id) { return this; } @@ -662,9 +664,9 @@ MapModel.prototype.getSubmodelById = function(id) { return null; }; -MapModel.prototype._getLayouts = function() { +MapModel.prototype._getLayouts = function () { var result = []; - for ( var id in this._layoutsData) { + for (var id in this._layoutsData) { if (this._layoutsData.hasOwnProperty(id)) { result.push(this._layoutsData[id]); } @@ -672,7 +674,7 @@ MapModel.prototype._getLayouts = function() { return result; }; -MapModel.prototype.getByIdentifiedElement = function(ie, complete) { +MapModel.prototype.getByIdentifiedElement = function (ie, complete) { var self = this; if (ie.getType() === "ALIAS") { return self.getAliasById(ie.getId(), complete); @@ -691,7 +693,7 @@ MapModel.prototype.getByIdentifiedElement = function(ie, complete) { } }; -MapModel.prototype.getByIdentifiedElements = function(identifiedElements, complete) { +MapModel.prototype.getByIdentifiedElements = function (identifiedElements, complete) { var self = this; var missingAliases = []; var missingReactions = []; @@ -710,10 +712,10 @@ MapModel.prototype.getByIdentifiedElements = function(identifiedElements, comple } return self.getMissingElements({ - aliasIds : missingAliases, - reactionIds : missingReactions, - complete : complete - }).then(function() { + aliasIds: missingAliases, + reactionIds: missingReactions, + complete: complete + }).then(function () { var promises = []; for (var i = 0; i < identifiedElements.length; i++) { promises.push(self.getByIdentifiedElement(identifiedElements[i], complete)); @@ -723,7 +725,7 @@ MapModel.prototype.getByIdentifiedElements = function(identifiedElements, comple }; -MapModel.prototype.isAvailable = function(ie, complete) { +MapModel.prototype.isAvailable = function (ie, complete) { var element; if (ie.getType() === "ALIAS") { element = this._aliases[ie.getId()]; @@ -749,11 +751,11 @@ MapModel.prototype.isAvailable = function(ie, complete) { } }; -MapModel.prototype.getReactionsForElement = function(element, complete) { - return this.getReactionsForElements([ element ], complete); +MapModel.prototype.getReactionsForElement = function (element, complete) { + return this.getReactionsForElements([element], complete); }; -MapModel.prototype.getReactionsForElements = function(elements, complete) { +MapModel.prototype.getReactionsForElements = function (elements, complete) { var self = this; var ids = []; var i; @@ -777,8 +779,8 @@ MapModel.prototype.getReactionsForElements = function(elements, complete) { var result = []; return ServerConnector.getReactions({ modelId: self.getId(), - participantId : ids - }).then(function(reactions) { + participantId: ids + }).then(function (reactions) { result = reactions; for (var i = 0; i < reactions.length; i++) { @@ -792,10 +794,10 @@ MapModel.prototype.getReactionsForElements = function(elements, complete) { } var ids = self._getMissingReactionsElementIds(reactions); return self.getMissingElements({ - aliasIds : ids, - complete : true + aliasIds: ids, + complete: true }); - }).then(function() { + }).then(function () { var promises = []; for (var i = 0; i < result.length; i++) { promises.push(self.getCompleteReactionById(result[i].getId())); @@ -804,25 +806,42 @@ MapModel.prototype.getReactionsForElements = function(elements, complete) { }); }; -MapModel.prototype.getCompartments = function() { +MapModel.prototype.getCompartments = function () { var self = this; var promise = Promise.resolve(); if (self._compartments === undefined) { promise = ServerConnector.getAliases({ - columns : "id,bounds,modelId", - type : "Compartment", - modelId : self.getId() - }).then(function(compartments) { + columns: "id,bounds,modelId", + type: "Compartment", + modelId: self.getId() + }).then(function (compartments) { self._compartments = []; for (var i = 0; i < compartments.length; i++) { self._compartments.push(new IdentifiedElement(compartments[i])); } }); } - return promise.then(function() { + return promise.then(function () { return self.getByIdentifiedElements(self._compartments, true); }); }; +MapModel.prototype.addSbmlFunction = function (sbmlFunction) { + this._sbmlFunctions[sbmlFunction.getId()] = sbmlFunction; +}; + +MapModel.prototype.getSbmlFunctionById = function (id) { + var self = this; + if (self._sbmlFunctions[id] !== undefined) { + return Promise.resolve(self._sbmlFunctions[id]); + } else { + return ServerConnector.getSbmlFunction({modelId: self.getId(), functionId: id}).then(function (sbmlFunction) { + self.addSbmlFunction(sbmlFunction); + return sbmlFunction; + }) + } +}; + + module.exports = MapModel; diff --git a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js index 346eab845d..b32de18635 100644 --- a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js +++ b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js @@ -3,6 +3,7 @@ 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'); @@ -30,9 +31,9 @@ function ReactionInfoWindow(params) { content: this.content, position: latLng }); - if (params.reaction.getKineticLaw()!==undefined) { + if (params.reaction.getKineticLaw() !== undefined) { self.addListener("onShow", function () { - return MathJax.Hub.Queue(["Typeset",MathJax.Hub]); + return MathJax.Hub.Queue(["Typeset", MathJax.Hub]); }); } self.googleInfowindow.open(self.getCustomMap().getGoogleMap(), self.getGoogleMarker()); @@ -44,7 +45,7 @@ ReactionInfoWindow.prototype.constructor = ReactionInfoWindow; /** * Methods that creates and return html code with the content of the window. * - * @returns {String} representing html code for content of the info window + * @returns Promise representing html code for content of the info window */ ReactionInfoWindow.prototype.createContentDiv = function () { var self = this; @@ -71,12 +72,44 @@ ReactionInfoWindow.prototype.createContentDiv = function () { })); 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)); + return Promise.resolve(result); }); } }; +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; +}; + ReactionInfoWindow.prototype.init = function () { var self = this; return AbstractInfoWindow.prototype.init.call(this).then(function () { @@ -87,7 +120,7 @@ ReactionInfoWindow.prototype.init = function () { /** * Returns array with data taken from all known {@link OverlayCollection}. * - * @returns array with data from {@link OverlayCollection} + * @returns Promise of an array with data from {@link OverlayCollection} */ ReactionInfoWindow.prototype.getOverlaysData = function (general) { return this.getCustomMap().getTopMap().getOverlayDataForReaction(this.getReactionData(), general); diff --git a/frontend-js/src/test/js/ServerConnector-test.js b/frontend-js/src/test/js/ServerConnector-test.js index b674de121f..e0fc3fd77b 100644 --- a/frontend-js/src/test/js/ServerConnector-test.js +++ b/frontend-js/src/test/js/ServerConnector-test.js @@ -378,5 +378,12 @@ describe('ServerConnector', function () { }); }); + it('getSbmlFunction', function () { + return ServerConnector.getSbmlFunction({functionId: 5}).then(function (sbmlFunction) { + assert.equal("fun", sbmlFunction.getName()); + assert.equal(5, sbmlFunction.getId()); + }); + }); + }); diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js index 80d1efba9d..9996400b76 100644 --- a/frontend-js/src/test/js/helper.js +++ b/frontend-js/src/test/js/helper.js @@ -13,6 +13,7 @@ var CustomMap = require("../../main/js/map/CustomMap"); var CustomMapOptions = require("../../main/js/map/CustomMapOptions"); var DrugDbOverlay = require("../../main/js/map/overlay/DrugDbOverlay"); var IdentifiedElement = require("../../main/js/map/data/IdentifiedElement"); +var KineticLaw = require("../../main/js/map/data/KineticLaw"); var LayoutAlias = require("../../main/js/map/data/LayoutAlias"); var LayoutData = require("../../main/js/map/data/LayoutData"); var LayoutReaction = require("../../main/js/map/data/LayoutReaction"); @@ -21,6 +22,7 @@ var Model = require("../../main/js/map/data/MapModel"); var AbstractDbOverlay = require("../../main/js/map/overlay/AbstractDbOverlay"); var Project = require("../../main/js/map/data/Project"); var Reaction = require("../../main/js/map/data/Reaction"); +var SbmlFunction = require("../../main/js/map/data/SbmlFunction"); var SearchDbOverlay = require("../../main/js/map/overlay/SearchDbOverlay"); var User = require("../../main/js/map/data/User"); @@ -397,6 +399,34 @@ Helper.prototype.readFile = function (filename) { }); }; +Helper.prototype.createSbmlFunction = function () { + return new SbmlFunction({ + "functionId": "fun", + "name": "fun name", + "definition": "<lambda>" + + "<bvar><ci> x </ci></bvar>" + + "<bvar><ci> y </ci></bvar>" + + "<apply><plus/><ci> x </ci><ci> y </ci><cn type=\"integer\"> 2 </cn></apply>" + + "</lambda>\n\n", + "arguments": ["x", "y"], + "id": this.idCounter++ + }); +}; + +Helper.prototype.createKineticLaw = function () { + return new KineticLaw({ + "parameterIds": [], + "definition": '<math xmlns="http://www.w3.org/1998/Math/MathML">' + + '<apply xmlns="http://www.w3.org/1998/Math/MathML">' + + '<divide/><apply><times/><ci>ca1</ci><apply><plus/><ci>sa1</ci><ci>sa2</ci></apply></apply><cn type=\"integer\"> 2 </cn>' + + '</apply></math>', + "functionIds": [] + }); +}; + + + + Helper.EPSILON = 1e-6; module.exports = Helper; diff --git a/frontend-js/src/test/js/map/data/KineticLaw-test.js b/frontend-js/src/test/js/map/data/KineticLaw-test.js index ea819abb40..878706ca2f 100644 --- a/frontend-js/src/test/js/map/data/KineticLaw-test.js +++ b/frontend-js/src/test/js/map/data/KineticLaw-test.js @@ -5,7 +5,7 @@ var chai = require('chai'); var assert = chai.assert; var logger = require('../../logger'); -describe('Comment', function () { +describe('KineticLaw', function () { beforeEach(function () { logger.flushBuffer(); }); diff --git a/frontend-js/src/test/js/map/window/ReactionInfoWindow-test.js b/frontend-js/src/test/js/map/window/ReactionInfoWindow-test.js index d6ebce1267..4c36cdd7fa 100644 --- a/frontend-js/src/test/js/map/window/ReactionInfoWindow-test.js +++ b/frontend-js/src/test/js/map/window/ReactionInfoWindow-test.js @@ -37,7 +37,9 @@ describe('ReactionInfoWindow', function () { definition: '<math xmlns="http://www.w3.org/1998/Math/MathML">' + '<apply xmlns="http://www.w3.org/1998/Math/MathML">' + '<divide/><apply><times/><ci>ca1</ci><apply><plus/><ci>sa1</ci><ci>sa2</ci></apply></apply><cn type=\"integer\"> 2 </cn>' + - '</apply></math>' + '</apply></math>', + functionIds: [], + parameterIds: [] })); var reactionWindow = new ReactionInfoWindow({ reaction: reaction, @@ -59,7 +61,9 @@ describe('ReactionInfoWindow', function () { '</apply></math>', mathMlPrenestation: "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n" + "<mrow><mfrac><mrow><mrow><mi> c1 </mi><mo>â¢</mo><mfenced separators=\"\"><mrow><mi> s1 </mi><mo>+</mo><mi> s2 </mi></mrow></mfenced></mrow></mrow><mrow><mn> 2 </mn></mrow></mfrac></mrow>\n" + - "</math>\n" + "</math>\n", + functionIds: [], + parameterIds: [] })); var reactionWindow = new ReactionInfoWindow({ reaction: reaction, @@ -71,5 +75,26 @@ describe('ReactionInfoWindow', function () { assert.notOk(div.innerHTML.indexOf("apply") >= 0); }); }); + + it("with kinetic parameters", function () { + var map = helper.createCustomMap(); + var sbmlFunction = helper.createSbmlFunction(); + map.getModel().addSbmlFunction(sbmlFunction); + + var reaction = helper.createReaction(map); + reaction.setKineticLaw(helper.createKineticLaw()); + reaction.getKineticLaw().getFunctionIds().push(sbmlFunction.getId()); + + var reactionWindow = new ReactionInfoWindow({ + reaction: reaction, + map: map + }); + + return reactionWindow.createContentDiv().then(function (div) { + assert.ok(div.innerHTML.indexOf("Functions") >= 0); + assert.ok(div.innerHTML.indexOf(sbmlFunction.getName()) >= 0, "Function name doesn't exist in the output div"); + assert.ok(div.innerHTML.indexOf(sbmlFunction.getArguments()[0]) >= 0, "Function argument doesn't exist in the output div"); + }); + }); }); }); diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/functions/5/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/functions/5/token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000..6e768cd95b --- /dev/null +++ b/frontend-js/testFiles/apiCalls/projects/sample/models/all/functions/5/token=MOCK_TOKEN_ID& @@ -0,0 +1 @@ +{"functionId":"fun","name":"fun","definition":"\n<lambda>\n<bvar>\n<ci> x </ci>\n</bvar>\n<bvar>\n<ci> y </ci>\n</bvar>\n<apply>\n<plus/>\n<ci> x </ci>\n<ci> y </ci>\n<cn type=\"integer\"> 2 </cn>\n</apply>\n</lambda>\n\n","arguments":["x","y"],"id":5} \ No newline at end of file -- GitLab