diff --git a/frontend-js/src/main/js/Admin.js b/frontend-js/src/main/js/Admin.js index 376df411df584851aad80a2fa4e09f04b30b67c1..ad8a602d79cbe9eb8d7655984fdc4271bd92fffa 100644 --- a/frontend-js/src/main/js/Admin.js +++ b/frontend-js/src/main/js/Admin.js @@ -1,185 +1,173 @@ -"use strict"; - -/* exported logger */ - -var Promise = require("bluebird"); - -var CustomMapOptions = require('./map/CustomMapOptions'); -var GuiUtils = require('./gui/leftPanel/GuiUtils'); -var ObjectWithListeners = require('./ObjectWithListeners'); - -var ConfigurationAdminPanel = require('./gui/admin/ConfigurationAdminPanel'); -var GenomeAdminPanel = require('./gui/admin/GenomeAdminPanel'); -var MapsAdminPanel = require('./gui/admin/MapsAdminPanel'); -var UsersAdminPanel = require('./gui/admin/UsersAdminPanel'); - -// noinspection JSUnusedLocalSymbols -var logger = require('./logger'); -var Functions = require('./Functions'); - -/** - * Default constructor. - * - * @param {CustomMapOptions} options - * object representing all parameters needed for map creation - */ -function Admin(options) { - var self = this; - self._panels = []; - self._tabIdCount = 0; - if (!(options instanceof CustomMapOptions)) { - options = new CustomMapOptions(options); - } - self.setElement(options.getElement()); - - self.setConfiguration(options.getConfiguration()); - self.setServerConnector(options.getServerConnector()); - self.setGuiUtils(new GuiUtils()); - self._createGui(); -} - -Admin.prototype = Object.create(ObjectWithListeners.prototype); -Admin.prototype.constructor = ObjectWithListeners; - -Admin.prototype._createGui = function () { - var self = this; - self.getElement().innerHTML = ""; - - var panels = [{ - name: "PROJECTS", - panelClass: MapsAdminPanel - }, { - name: "USERS", - panelClass: UsersAdminPanel - }, { - name: "CONFIGURATION", - panelClass: ConfigurationAdminPanel - }, { - name: "GENOMES", - panelClass: GenomeAdminPanel - }]; - - var tabDiv = Functions.createElement({ - type: "div", - name: "tabView", - className: "tabbable boxed parentTabs" - }); - self.getElement().appendChild(tabDiv); - - var tabMenuDiv = Functions.createElement({ - type: "ul", - className: "nav nav-tabs" - }); - tabDiv.appendChild(tabMenuDiv); - - var tabContentDiv = Functions.createElement({ - type: "div", - className: "tab-content" - }); - tabDiv.appendChild(tabContentDiv); - - for (var i = 0; i < panels.length; i++) { - self.addTab(panels[i], tabMenuDiv, tabContentDiv); - } - self.addLogoutButton(tabMenuDiv); -}; - -Admin.prototype.addLogoutButton = function (navElement) { - var self = this; - var logoutLink = self.getGuiUtils().createLogoutLink(); - - var navLi = document.createElement("li"); - navLi.appendChild(logoutLink); - navLi.style.cssFloat = "right"; - - navElement.appendChild(navLi); -}; - -Admin.prototype.addTab = function (params, navElement, contentElement) { - var self = this; - - var tabId = "admin_panel_tab_" + this._tabIdCount; - self._tabIdCount++; - - var navLi = self.getGuiUtils().createTabMenuObject({ - id: tabId, - name: params.name, - navigationBar: navElement - }); - navElement.appendChild(navLi); - - var contentDiv = self.getGuiUtils().createTabContentObject({ - id: tabId, - navigationObject: navLi - }); - - contentElement.appendChild(contentDiv); - - this._panels.push(new params.panelClass({ - element: contentDiv, - name: params.name, - configuration: self.getConfiguration(), - serverConnector: self.getServerConnector() - })); -}; - -Admin.prototype.setElement = function (element) { - this._element = element; -}; -Admin.prototype.getElement = function () { - return this._element; -}; - -Admin.prototype.init = function () { - var promises = []; - for (var i = 0; i < this._panels.length; i++) { - promises.push(this._panels[i].init()); - } - return Promise.all(promises).then(function () { - $(window).trigger('resize'); - }); -}; - -Admin.prototype.setConfiguration = function (configuration) { - this._configuration = configuration; -}; - -Admin.prototype.getConfiguration = function () { - return this._configuration; -}; - -Admin.prototype.setGuiUtils = function (guiUtils) { - this._guiUtils = guiUtils; -}; - -Admin.prototype.getGuiUtils = function () { - return this._guiUtils; -}; - -Admin.prototype.destroy = function () { - var self = this; - var promises = []; - for (var i = 0; i < self._panels.length; i++) { - promises.push(self._panels[i].destroy()); - } - return Promise.all(promises); -}; - -/** - * - * @param {ServerConnector} serverConnector - */ -Admin.prototype.setServerConnector = function (serverConnector) { - this._serverConnector = serverConnector; -}; - -/** - * - * @returns {ServerConnector} - */ -Admin.prototype.getServerConnector = function () { - return this._serverConnector; -}; - - -module.exports = Admin; +"use strict"; + +/* exported logger */ + +var Promise = require("bluebird"); + +var CustomMapOptions = require('./map/CustomMapOptions'); +var AbstractGuiElement = require('./gui/AbstractGuiElement'); + +var ConfigurationAdminPanel = require('./gui/admin/ConfigurationAdminPanel'); +var GenomeAdminPanel = require('./gui/admin/GenomeAdminPanel'); +var MapsAdminPanel = require('./gui/admin/MapsAdminPanel'); +var UsersAdminPanel = require('./gui/admin/UsersAdminPanel'); + +// noinspection JSUnusedLocalSymbols +var logger = require('./logger'); +var GuiUtils = require('./gui/leftPanel/GuiUtils'); + +/** + * Default constructor. + * + * @param {CustomMapOptions} options + * object representing all parameters needed for map creation + * @constructor + */ +function Admin(options) { + var self = this; + if (!(options instanceof CustomMapOptions)) { + options = new CustomMapOptions(options); + } + + self.setElement(options.getElement()); + self.setConfiguration(options.getConfiguration()); + self.setServerConnector(options.getServerConnector()); + + self._createGui(); +} + +Admin.prototype = Object.create(AbstractGuiElement.prototype); +Admin.prototype.constructor = AbstractGuiElement; + +/** + * + * @private + */ +Admin.prototype._createGui = function () { + var self = this; + self.getElement().innerHTML = ""; + self.getGuiUtils().initTabContent(self); + + var panels = [{ + name: "PROJECTS", + panelClass: MapsAdminPanel + }, { + name: "USERS", + panelClass: UsersAdminPanel + }, { + name: "CONFIGURATION", + panelClass: ConfigurationAdminPanel + }, { + name: "GENOMES", + panelClass: GenomeAdminPanel + }]; + + for (var i = 0; i < panels.length; i++) { + self.getGuiUtils().addTab(self, panels[i]); + } + self.addLogoutButton($(this.getElement()).find("> .parentTabs > .nav-tabs")[0]); +}; + +/** + * + * @param navElement + */ +Admin.prototype.addLogoutButton = function (navElement) { + var self = this; + var logoutLink = self.getGuiUtils().createLogoutLink(); + + var navLi = document.createElement("li"); + navLi.appendChild(logoutLink); + navLi.style.cssFloat = "right"; + + navElement.appendChild(navLi); +}; + +/** + * + * @param {HTMLElement} element + */ +Admin.prototype.setElement = function (element) { + this._element = element; +}; +/** + * + * @returns {HTMLElement} + */ +Admin.prototype.getElement = function () { + return this._element; +}; + +/** + * + * @returns {Promise} + */ +Admin.prototype.init = function () { + var promises = []; + for (var i = 0; i < this._panels.length; i++) { + promises.push(this._panels[i].init()); + } + return Promise.all(promises).then(function () { + $(window).trigger('resize'); + }); +}; + +/** + * + * @param {Configuration} configuration + */ +Admin.prototype.setConfiguration = function (configuration) { + this._configuration = configuration; +}; + +/** + * + * @returns {Configuration} + */ +Admin.prototype.getConfiguration = function () { + return this._configuration; +}; + +/** + * + * @returns {Promise} + */ +Admin.prototype.destroy = function () { + var self = this; + var promises = []; + for (var i = 0; i < self._panels.length; i++) { + promises.push(self._panels[i].destroy()); + } + return Promise.all(promises); +}; + +/** + * + * @param {ServerConnector} serverConnector + */ +Admin.prototype.setServerConnector = function (serverConnector) { + this._serverConnector = serverConnector; +}; + +/** + * + * @returns {ServerConnector} + */ +Admin.prototype.getServerConnector = function () { + return this._serverConnector; +}; + +/** + * + * @returns {GuiUtils} + */ +Admin.prototype.getGuiUtils = function () { + var self = this; + if (self._guiUtils === undefined) { + self._guiUtils = new GuiUtils(self.getConfiguration()); + } + return this._guiUtils; +}; + + +module.exports = Admin; diff --git a/frontend-js/src/main/js/gui/AbstractGuiElement.js b/frontend-js/src/main/js/gui/AbstractGuiElement.js index b859caede9c7adb19bd2abff6323d3f55b38429f..6183c5953282cb47688ef0caac0f67ace4e61bae 100644 --- a/frontend-js/src/main/js/gui/AbstractGuiElement.js +++ b/frontend-js/src/main/js/gui/AbstractGuiElement.js @@ -7,6 +7,7 @@ var PanelControlElementType = require('./PanelControlElementType'); // noinspection JSUnusedLocalSymbols var logger = require('../logger'); +var Functions = require('../Functions'); /** * @@ -221,5 +222,4 @@ AbstractGuiElement.prototype.askConfirmRemoval = function (params) { }) }; - module.exports = AbstractGuiElement; diff --git a/frontend-js/src/main/js/gui/Panel.js b/frontend-js/src/main/js/gui/Panel.js index 75ebb3459b1ea5d8f6aa595dc1caf6b2f584d5bd..ae0f4900331f9769f5c8d93ec74ac02b5512d7af 100644 --- a/frontend-js/src/main/js/gui/Panel.js +++ b/frontend-js/src/main/js/gui/Panel.js @@ -16,7 +16,7 @@ var xss = require('xss'); * @param {Configuration} [params.configuration] * @param {HTMLElement} params.element * @param {Project} params.project - * @param {CustomMap} params.customMap + * @param {CustomMap} [params.customMap] * @param {string} params.panelName * @param {boolean} params.scrollable * @param {string} [params.helpTip] diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js index 37c7cb0f4c0e25753841dfdb4462072ee0cd6b74..87cf701f2818916178676825f3f045fad5710767 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js +++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js @@ -1,950 +1,1015 @@ -"use strict"; - -/* exported logger */ - -var Alias = require('../../map/data/Alias'); -var ConfigurationType = require('../../ConfigurationType'); -var IdentifiedElement = require('../../map/data/IdentifiedElement'); -var SearchBioEntityGroup = require('../../map/data/SearchBioEntityGroup'); - - -var GuiConnector = require('../../GuiConnector'); -var AbstractGuiElement = require('../AbstractGuiElement'); -var Functions = require('../../Functions'); - -var logger = require('../../logger'); -var xss = require('xss'); - -var Promise = require('bluebird'); - -var tabIdCounter = 0; - -/** - * - * @param {Configuration} configuration - * @constructor - */ -function GuiUtils(configuration) { - var self = this; - self.setConfiguration(configuration); -} - -GuiUtils.prototype = Object.create(AbstractGuiElement.prototype); -GuiUtils.prototype.constructor = GuiUtils; - -/** - * - * @param {Configuration} configuration - */ -GuiUtils.prototype.setConfiguration = function (configuration) { - this._configuration = configuration; -}; - -/** - * - * @returns {Configuration} - */ -GuiUtils.prototype.getConfiguration = function () { - return this._configuration; -}; - -/** - * - * @param {string} value - * @returns {HTMLSpanElement} - */ -GuiUtils.prototype.createLabel = function (value) { - var result = document.createElement("span"); - result.innerHTML = value; - result.className = "minerva-label"; - return result; -}; - -/** - * - * @param {Object} modification - * @param {string} [modification.name] - * @param {string} modification.type - * @param {string} [modification.state] - * - * @returns {HTMLElement| null} - */ -GuiUtils.prototype.createModificationRow = function (modification) { - var self = this; - var row = null; - var name = modification.name; - var desc = undefined; - if (modification.state !== undefined && modification.state !== null) { - var modificationStateType = self.getConfiguration().getModificationStateTypeByName(modification.state); - var state = modificationStateType.getCommonName(); - - if (name !== null && name !== undefined && name !== "") { - desc = state + " at position " + name + ", "; - } else { - desc = state + ","; - } - } else if (name !== null && name !== undefined && name !== "" && - (modification.type === "BINDING_REGION" || - modification.type === "CODING_REGION" || - modification.type === "PROTEIN_BINDING_DOMAIN" || - modification.type === "TRANSCRIPTION_SITE_LEFT" || - modification.type === "TRANSCRIPTION_SITE_RIGHT" || - modification.type === "REGULATORY_REGION" - )) { - desc = name + ","; - } - - if (desc !== undefined) { - row = Functions.createElement({ - type: "li" - }); - row.appendChild(self.createLabelText(desc)); - } - return row; -}; - -/** - * - * @param {string} label - * @param {Object[]} value - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createPostTranslationalModifications = function (label, value) { - var result = document.createElement("div"); - var count = 0; - if (value !== undefined && value.length > 0) { - var self = this; - var userFriendlyLabel = label + ": "; - if (label === "RESIDUE") { - userFriendlyLabel = "Posttranslational modifications: " - } else if (label === "BINDING_REGION") { - userFriendlyLabel = "Binding regions: " - } else if (label === "CODING_REGION") { - userFriendlyLabel = "Coding regions: " - } else if (label === "PROTEIN_BINDING_DOMAIN") { - userFriendlyLabel = "Protein binding domains: " - } else if (label === "TRANSCRIPTION_SITE_LEFT") { - userFriendlyLabel = "Transcription sites (left): " - } else if (label === "TRANSCRIPTION_SITE_RIGHT") { - userFriendlyLabel = "Transcription sites (right): " - } else if (label === "TRANSCRIPTION_SITE") { - userFriendlyLabel = "Transcription sites: " - } else if (label === "MODIFICATION_SITE") { - userFriendlyLabel = "Modification sites: " - } - result.appendChild(self.createLabel(userFriendlyLabel)); - result.appendChild(self.createNewLine()); - var list = Functions.createElement({ - type: "ul" - }); - for (var i = 0; i < value.length; i++) { - var modification = value[i]; - var row = self.createModificationRow(modification, self); - if (row !== null) { - list.appendChild(row); - count++; - } - } - result.appendChild(list); - } - if (count > 0) { - return result; - } else { - return document.createElement("div"); - } -}; - -/** - * - * @returns {HTMLHRElement} - */ -GuiUtils.prototype.createSeparator = function () { - return document.createElement("hr"); -}; - -/** - * - * @param {number} [count] - * @returns {HTMLParagraphElement} - */ -GuiUtils.prototype.createNewLine = function (count) { - if (count === undefined) { - count = 0; - } - var result = document.createElement("p"); - if (count > 0) { - result.style.height = ((count - 1) * 10) + "px"; - } - return result; -}; - -/** - * - * @param {string} [url] - * @param {string} name - * @returns {HTMLElement} - */ -GuiUtils.prototype.createLink = function (url, name) { - if (url === null || url === undefined) { - logger.warn("URL not defined for: \"" + name + "\" link"); - return Functions.createElement({type: "span", content: name}); - } - var link = document.createElement("a"); - link.href = url; - link.innerHTML = name; - link.target = "_blank"; - link.style.textDecoration = "underline"; - return link; -}; - -/** - * - * @param {Annotation} annotation - * @param {boolean} [showType=false] - * @returns {HTMLElement} - */ -GuiUtils.prototype.createAnnotationLink = function (annotation, showType) { - var self = this; - var name, type, hint; - var article = annotation.getArticle(); - if (article !== undefined) { - - hint = article.getTitle() + " " + article.getAuthors().join(", ") + ", " + article.getYear() + ", " - + article.getJournal(); - type = "PUBMED"; - name = article.getId(); - } else { - //replace encoded parts of uri (like %2F - > "/") - name = decodeURIComponent(annotation.getResource()); - var miriamType = self.getConfiguration().getMiriamTypeByName(annotation.getType()); - if (miriamType === null) { - logger.warn("Unknown miriam type: " + annotation.getType()); - type = annotation.getType(); - } else { - type = miriamType.getCommonName(); - } - } - var link; - if (showType) { - link = self.createLink(annotation.getLink(), type + " (" + name + ")"); - } else { - link = self.createLink(annotation.getLink(), name); - } - if (hint !== undefined) { - var div = document.createElement("div"); - div.title = hint; - div.appendChild(link); - return div; - } else { - return link; - } -}; - -/** - * - * @param {string} label - * @param {Annotation[]} [value] - * @param {Object} [options] - * @param {boolean} [options.inline] - * - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createAnnotations = function (label, value, options) { - var self = this; - - var inline = false; - if (options !== undefined) { - if (options.inline !== undefined) { - inline = options.inline; - } - } - var result = document.createElement("div"); - result.appendChild(self.createLabel(label)); - if (value !== undefined && value.length > 0) { - if (!inline) { - result.appendChild(self.createNewLine()); - } - result.appendChild(self.createAnnotationList(value, options)); - } else { - result.appendChild(self.createLabelText("No annotations")); - } - return result; -}; - -/** - * - * @param {boolean} inline - * @param {string} annotatorClass - * @param {Object.<string, Annotator>} annotatorsClassMapping - * @param {boolean} groupAnnotations - * @returns {HTMLElement} - */ -function createGroupContainer(inline, annotatorClass, annotatorsClassMapping, groupAnnotations) { - var automaticallyAnnotated = !(annotatorClass === undefined || annotatorClass === "undefined" || annotatorClass === null || annotatorClass === ""); - var groupContainer = (inline ? document.createElement("span") : document.createElement("div")); - var descContainer = (inline ? document.createElement("span") : document.createElement("div")); - - if (groupAnnotations) { - var annotatorName = automaticallyAnnotated ? annotatorsClassMapping[annotatorClass].getName() : "Annotated by curator"; - if (inline) { - descContainer.innerHTML = 'Source: ' + annotatorName + ': '; - } else { - descContainer.innerHTML = 'Source: ' + annotatorName; - - if (automaticallyAnnotated) { - var annotatorDescription = annotatorsClassMapping[annotatorClass].getDescription(); - if (annotatorDescription) { - var tooltipContainer = Functions.createElement({ - type: "span" - }); - tooltipContainer.appendChild(Functions.createElement({ - type: "span", - className: "glyphicon glyphicon-question-sign tooltip-icon" - })); - tooltipContainer.appendChild(Functions.createElement({ - type: "span", - className: "annotator-tooltip", - content: annotatorsClassMapping[annotatorClass].getDescription() - })); - - descContainer.appendChild(tooltipContainer); - } - } - } - descContainer.className = "minerva-annotation-group-header"; - if (!inline) groupContainer.className = "minerva-annotation-group"; - groupContainer.appendChild(descContainer); - } - return groupContainer; -} - -/** - * - * @param {Annotation[]} annotations - * @param {Object} [options] - * @param {boolean} [options.showType = true] - * @param {boolean} [options.inline = false] - * @param {boolean} [options.groupAnnotations = true] - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createAnnotationList = function (annotations, options) { - var showType = true; - var inline = false; - var groupAnnotations = true; - if (options !== undefined) { - if (options.showType !== undefined) { - showType = options.showType; - } - if (options.inline !== undefined) { - inline = options.inline; - } - if (options.groupAnnotations !== undefined) { - groupAnnotations = options.groupAnnotations; - } - } - - var self = this; - var result = document.createElement("div"); - - var annotators = this.getConfiguration().getAnnotators(); - var annotatorsClassMapping = {}; - var grouppedAnnotations = {}; - var i; - if (groupAnnotations) { - for (i = 0; i < annotators.length; i++) { - annotatorsClassMapping[annotators[i].getClassName()] = annotators[i]; - } - - for (i = 0; i < annotations.length; i++) { - var clazz = annotations[i].getAnnotatorClassName(); - if (!(clazz in grouppedAnnotations)) grouppedAnnotations[clazz] = []; - grouppedAnnotations[clazz].push(annotations[i]) - } - } else { - annotatorsClassMapping["undefined"] = { - getName: function () { - return "" - } - }; - grouppedAnnotations["undefined"] = annotations; - } - - // = annotatorClasName ? annotatorsClassMapping[annotatorClasName].getName() : "Annotated by curator"; - - var cntAnnotations = 0; - - Object.keys(grouppedAnnotations).sort().forEach(function (annotatorClass) { - var groupContainer = createGroupContainer(inline, annotatorClass, annotatorsClassMapping, groupAnnotations); - - var par; - if (inline) { - par = document.createElement("span"); - par.innerHTML = "("; - groupContainer.appendChild(par); - } - - grouppedAnnotations[annotatorClass] = grouppedAnnotations[annotatorClass].sort(function (a, b) { - var aType = a.getType().toUpperCase(); - var bType = b.getType().toUpperCase(); - if (aType < bType) return -1; - else if (aType > bType) return 1; - else return 0; - }); - - for (var j = 0; j < grouppedAnnotations[annotatorClass].length; j++) { - - cntAnnotations += 1; - - var element = grouppedAnnotations[annotatorClass][j]; - var link = self.createAnnotationLink(element, showType); - if (inline) { - if (j > 0) { - var coma = document.createElement("span"); - coma.innerHTML = ", "; - groupContainer.appendChild(coma); - } - groupContainer.appendChild(link); - } else { - - var row = document.createElement("div"); - row.style.height = "26px"; - if (j % 2 === 0) { - row.className = "minerva-annotation-row-odd"; - } else { - row.className = "minerva-annotation-row-even"; - } - - var header = document.createElement("div"); - header.style.width = "28px"; - header.style.float = "left"; - header.innerHTML = "[" + cntAnnotations + "]"; - row.appendChild(header); - - var body = document.createElement("div"); - body.style.float = "left"; - body.appendChild(link); - row.appendChild(body); - groupContainer.appendChild(row); - } - } - - if (inline) { - par = document.createElement("span"); - par.innerHTML = ")"; - groupContainer.appendChild(par); - } - - result.appendChild(groupContainer); - }); - - return result; -}; - -/** - * - * @param {string} [value] - * @returns {HTMLSpanElement} - */ -GuiUtils.prototype.createLabelText = function (value) { - var result = document.createElement("span"); - if (value !== undefined) { - result.innerHTML = value; - } - return result; -}; - -/** - * - * @param {string} [value] - * @returns {HTMLInputElement} - */ -GuiUtils.prototype.createInputText = function (value) { - var result = document.createElement("input"); - result.setAttribute('type', 'text'); - - if (value !== undefined) { - result.setAttribute('value', value); - } - return result; -}; - -/** - * - * @param {string} [value] - * @returns {HTMLTextAreaElement} - */ -GuiUtils.prototype.createTextArea = function (value) { - var result = document.createElement("textarea"); - - if (value !== undefined) { - result.setAttribute('value', value); - result.innerHTML = value; - } - return result; -}; - -/** - * - * @param {string} label - * @param {string|number} [value] - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createParamLine = function (label, value) { - var result = document.createElement("div"); - if (value !== undefined && value !== null && value !== "") { - var self = this; - result.appendChild(self.createLabel(label)); - result.appendChild(self.createLabelText(value)); - } - return result; -}; - -/** - * - * @param {string} [icon] - * @param {function} [onclickFunction] - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createIcon = function (icon, onclickFunction) { - var result = document.createElement("div"); - if (icon !== undefined && icon !== null) { - var img = document.createElement("img"); - img.src = GuiConnector.getImgPrefix() + icon; - img.style.float = "left"; - img.hspace = 5; - if (onclickFunction !== undefined) { - img.onclick = onclickFunction; - } - result.appendChild(img); - } - return result; -}; - -/** - * - * @param {string} label - * @param {string[]} [value] - * - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createArrayParamLine = function (label, value) { - var result = document.createElement("div"); - if (value !== undefined && value.length > 0) { - var self = this; - result.appendChild(self.createLabel(label)); - result.appendChild(self.createLabelText(value.join(", "))); - } - return result; -}; - -/** - * - * @param {string} label - * @param {number} [modelId] - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createSubMapLink = function (label, modelId) { - var self = this; - var result = document.createElement("div"); - if (modelId !== undefined) { - var button = document.createElement("button"); - var model = self.getMap().getSubmapById(modelId).getModel(); - - button.innerHTML = model.getName(); - button.onclick = function () { - return self.getMap().openSubmap(modelId); - }; - result.appendChild(this.createLabel(label)); - result.appendChild(button); - } - return result; -}; - -/** - * - * @param {Array<string|HTMLElement>} elements - * @returns {HTMLElement} - */ -GuiUtils.prototype.createTableRow = function (elements) { - var row = Functions.createElement({ - type: "div", - style: "display: table-row;" - }); - - for (var i = 0; i < elements.length; i++) { - var cell = Functions.createElement({ - type: "div", - style: "display: table-cell;" - }); - if (Functions.isDomElement(elements[i])) { - cell.appendChild(elements[i]); - } else { - cell.innerHTML = elements[i]; - } - row.appendChild(cell); - } - return row; -}; - -/** - * - * @param {Reaction|SearchBioEntityGroup} params.reaction - * @param {string} [params.icon] - * @param {boolean} [params.showTitle] - * - * @returns {Promise<HTMLDivElement>} - */ -GuiUtils.prototype.createReactionElement = function (params) { - var reaction = params.reaction; - var showTitle = ((params.showTitle === undefined) || params.showTitle); - var self = this; - var div = document.createElement("div"); - - if (showTitle) { - div.appendChild(self.createLabel("Reaction: " + reaction.getReactionId())); - if (reaction.getModelId() !== self.getMap().getId()) { - div.appendChild(self.createSubMapLink("In submap: ", reaction.getModelId())); - } - } - - if (reaction.getLinkedSubmodelId() !== null && reaction.getLinkedSubmodelId() !== undefined) { - div.appendChild(self.createSubMapLink("Associated submap: ", reaction.getLinkedSubmodelId())); - } - if (showTitle) { - div.appendChild(self.createNewLine()); - } - - if (self.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).getValue().toLowerCase() === "true") { - div.appendChild(self.createParamLine("Type: ", reaction.getType())); - } - div.appendChild(self.createParamLine("Symbol: ", reaction.getSymbol())); - div.appendChild(self.createParamLine("Abbreviation: ", reaction.getAbbreviation())); - div.appendChild(self.createParamLine("Formula: ", reaction.getFormula())); - div.appendChild(self.createParamLine("Mechanical Confidence Score: ", reaction.getMechanicalConfidenceScore())); - div.appendChild(self.createParamLine("Lower Bound: ", reaction.getLowerBound())); - div.appendChild(self.createParamLine("Upper Bound: ", reaction.getUpperBound())); - div.appendChild(self.createParamLine("Gene Protein Reaction: ", reaction.getGeneProteinReaction())); - div.appendChild(self.createParamLine("Subsystem: ", reaction.getSubsystem())); - div.appendChild(self.createArrayParamLine("Synonyms: ", reaction.getSynonyms())); - div.appendChild(self.createParamLine("Description: ", reaction.getDescription())); - div.appendChild(self.createAnnotations("Annotations: ", reaction.getReferences())); - return Promise.resolve(div); -}; - -/** - * - * @param {Object[]} modifications - * - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createModifications = function (modifications) { - var self = this; - var result = document.createElement("div"); - var modificationsByType = []; - if (modifications !== undefined) { - for (var i = 0; i < modifications.length; i++) { - var modification = modifications[i]; - if (modificationsByType[modification.type] === undefined) { - modificationsByType[modification.type] = []; - } - modificationsByType[modification.type].push(modification); - } - for (var key in modificationsByType) { - if (modificationsByType.hasOwnProperty(key)) { - result.appendChild(self.createPostTranslationalModifications(key, modificationsByType[key])); - } - } - } - return result; -}; - -/** - * - * @param {Alias|SearchBioEntityGroup} params.alias - * @param {string} [params.icon] - * @param {boolean} [params.showTitle] - * - * @returns {Promise<HTMLDivElement>} - */ -GuiUtils.prototype.createAliasElement = function (params) { - var alias = params.alias; - var icon = params.icon; - var showTitle = ((params.showTitle === undefined) || params.showTitle); - var self = this; - var div = document.createElement("div"); - - if (showTitle) { - if (icon !== undefined) { - div.appendChild(this.createIcon(icon, function () { - return self.getMap().openSubmap(alias.getModelId()).then(function () { - if (alias instanceof Alias) { - return self.getMap().getSubmapById(alias.getModelId()).fitBounds([alias]); - } else { - return self.getMap().getSubmapById(alias.getModelId()).fitBounds(alias.getBioEntities()); - } - }); - })); - } - - div.appendChild(this.createParamLine(alias.getType() + ": ", alias.getName())); - if (alias.getModelId() !== self.getMap().getId()) { - div.appendChild(self.createSubMapLink("In submap: ", alias.getModelId())); - } - } - if (alias.getLinkedSubmodelId() !== undefined) { - div.appendChild(self.createSubMapLink("Associated submap: ", alias.getLinkedSubmodelId())); - } - if (alias instanceof SearchBioEntityGroup && alias.getBioEntities().length > 1) { - div.appendChild(self.createLabelText("Group of " + alias.getBioEntities().length + " elements.")); - } - if (showTitle) { - div.appendChild(self.createNewLine(3)); - } - - var promise = Promise.resolve(); - if (alias.getCompartmentId() !== undefined) { - promise = self.getMap().getModel().getByIdentifiedElement(new IdentifiedElement({ - type: "ALIAS", - id: alias.getCompartmentId(), - modelId: alias.getModelId() - }), true).then(function (compartment) { - div.appendChild(self.createParamLine("Compartment: ", compartment.getName())); - }) - } - - return promise.then(function () { - - div.appendChild(self.createParamLine("Full name: ", alias.getFullName())); - div.appendChild(self.createParamLine("Symbol: ", alias.getSymbol())); - div.appendChild(self.createParamLine("Abbreviation: ", alias.getAbbreviation())); - div.appendChild(self.createParamLine("Formula: ", alias.getFormula())); - div.appendChild(self.createArrayParamLine("Former symbols: ", alias.getFormerSymbols())); - div.appendChild(self.createModifications(alias.getOther('modifications'))); - div.appendChild(self.createParamLine("Charge: ", alias.getCharge())); - div.appendChild(self.createArrayParamLine("Synonyms: ", alias.getSynonyms())); - div.appendChild(self.createLabelText(alias.getDescription())); - div.appendChild(self.createAnnotations("Annotations: ", alias.getReferences())); - - return div; - }) -}; - -/** - * - * @param {SearchBioEntityGroup} group - * @returns {Promise<HTMLDivElement>} - */ -GuiUtils.prototype.createSearchBioEntityGroupElement = function (group) { - if (group.getBioEntities()[0] instanceof Alias) { - return this.createAliasElement({alias: group, icon: group.getIcon()}); - } else { - return this.createReactionElement({reaction: group, icon: group.getIcon()}); - } -}; - -/** - * - * @returns {HTMLAnchorElement} - */ -GuiUtils.prototype.createLogoutLink = function () { - var logoutLink = document.createElement("a"); - logoutLink.href = "#"; - logoutLink.innerHTML = "LOGOUT"; - logoutLink.id = "logoutLink"; - logoutLink.onclick = function () { - return ServerConnector.logout(); - }; - return logoutLink; -}; - -/** - * - * @param {string} params.name - * @param {string} params.id - * @param {HTMLElement} params.navigationBar - * - * @returns {HTMLLIElement} - */ -GuiUtils.prototype.createTabMenuObject = function (params) { - var name = params.name; - var id = params.id; - var navigationBar = params.navigationBar; - - var navClass = ''; - if (navigationBar.children.length === 0) { - navClass = "active"; - } - - var navLi = document.createElement("li"); - navLi.className = navClass; - - var navLink = document.createElement("a"); - navLink.href = "#" + id; - if (name !== undefined) { - navLink.innerHTML = name; - } - navLink.onclick = function () { - $(this).tab('show'); - }; - navLi.appendChild(navLink); - if (name !== undefined) { - navLink.innerHTML = name; - } - return navLi; -}; - -/** - * - * @param {string} params.id - * @param {HTMLElement} params.navigationObject - * - * @returns {HTMLDivElement} - */ -GuiUtils.prototype.createTabContentObject = function (params) { - var navigationObject = params.navigationObject; - var tabId = params.id; - var result = document.createElement("div"); - result.style.height = "100%"; - - var contentClass = 'tab-pane'; - if (navigationObject.className === "active") { - contentClass = "tab-pane active"; - } - - result.className = contentClass; - result.id = tabId; - return result; -}; - -/** - * - * @param {HTMLElement} [params.element] - * @param {string} params.id - * - * @returns {{element: HTMLElement, menu: HTMLElement, content: HTMLElement, tabId: *}} - */ -GuiUtils.prototype.createTabDiv = function (params) { - var tabDiv = Functions.createElement({ - type: "div", - name: "tabView", - className: "tabbable boxed parentTabs" - }); - - var tabMenuDiv = Functions.createElement({ - type: "ul", - className: "nav nav-tabs" - }); - tabDiv.appendChild(tabMenuDiv); - - var tabContentDiv = Functions.createElement({ - type: "div", - className: "tab-content" - }); - tabDiv.appendChild(tabContentDiv); - - if (params.element !== undefined) { - params.element.appendChild(tabDiv); - } - - return { - element: tabDiv, - menu: tabMenuDiv, - content: tabContentDiv, - tabId: params.id - } -}; - -GuiUtils.prototype.createTab = function (params) { - var tabData = params.tabData; - - var tabId = tabData.tabId + "_tab_" + tabIdCounter; - tabIdCounter++; - - var navClass = ''; - var contentClass = 'tab-pane'; - if (tabData.menu.children.length === 0) { - navClass = "active"; - contentClass = "tab-pane active"; - } - - var navLi = document.createElement("li"); - navLi.className = navClass; - - var navLink = document.createElement("a"); - navLink.href = "#" + tabId; - - navLink.innerHTML = params.title; - - navLink.onclick = function () { - $(this).tab('show'); - }; - navLi.appendChild(navLink); - tabData.menu.appendChild(navLi); - - var contentDiv = document.createElement("div"); - contentDiv.style.height = "100%"; - contentDiv.className = contentClass; - contentDiv.id = tabId; - - if (Functions.isDomElement(params.content)) { - contentDiv.appendChild(params.content); - } else { - contentDiv.innerHTML = params.content; - } - tabData.content.appendChild(contentDiv); - - $(contentDiv).css("overflow", "auto"); - $(contentDiv).css("height", "calc(100vh - " + $(contentDiv).offset().top + "px)"); - - return { - title: navLink, - content: contentDiv - } -}; - -/** - * - * @param {string} toolTip - * @param {boolean} [useXss=false] - * @returns {HTMLElement} - */ -GuiUtils.prototype.createHelpButton = function (toolTip, useXss) { - var helpContent; - if (useXss) { - helpContent = xss(toolTip); - } else { - helpContent = toolTip; - } - - var helpTipButton = Functions.createElement({ - type: "button", - className: "minerva-help-button", - content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>', - xss: false - }); - var helpDialogDiv = undefined; - helpTipButton.onclick = function () { - if (helpDialogDiv === undefined) { - helpDialogDiv = Functions.createElement({ - type: "div", - content: helpContent, - xss: false - }); - $(helpDialogDiv).dialog({ - close: function () { - $(this).dialog('destroy').remove(); - helpDialogDiv = undefined; - }, - position: { - my: "left top", - at: "left bottom", - of: helpTipButton - } - }); - $('.ui-dialog').find("a").blur(); - } - }; - return helpTipButton; -}; - -module.exports = GuiUtils; +"use strict"; + +/* exported logger */ + +var Alias = require('../../map/data/Alias'); +var ConfigurationType = require('../../ConfigurationType'); +var IdentifiedElement = require('../../map/data/IdentifiedElement'); +var SearchBioEntityGroup = require('../../map/data/SearchBioEntityGroup'); + + +var GuiConnector = require('../../GuiConnector'); +var AbstractGuiElement = require('../AbstractGuiElement'); +var Functions = require('../../Functions'); + +var logger = require('../../logger'); +var xss = require('xss'); + +var Promise = require('bluebird'); + +var tabIdCounter = 0; + +/** + * + * @param {Configuration} configuration + * @constructor + */ +function GuiUtils(configuration) { + var self = this; + self.setConfiguration(configuration); +} + +GuiUtils.prototype = Object.create(AbstractGuiElement.prototype); +GuiUtils.prototype.constructor = GuiUtils; + +/** + * + * @param {Configuration} configuration + */ +GuiUtils.prototype.setConfiguration = function (configuration) { + this._configuration = configuration; +}; + +/** + * + * @returns {Configuration} + */ +GuiUtils.prototype.getConfiguration = function () { + return this._configuration; +}; + +/** + * + * @param {string} value + * @returns {HTMLSpanElement} + */ +GuiUtils.prototype.createLabel = function (value) { + var result = document.createElement("span"); + result.innerHTML = value; + result.className = "minerva-label"; + return result; +}; + +/** + * + * @param {Object} modification + * @param {string} [modification.name] + * @param {string} modification.type + * @param {string} [modification.state] + * + * @returns {HTMLElement| null} + */ +GuiUtils.prototype.createModificationRow = function (modification) { + var self = this; + var row = null; + var name = modification.name; + var desc = undefined; + if (modification.state !== undefined && modification.state !== null) { + var modificationStateType = self.getConfiguration().getModificationStateTypeByName(modification.state); + var state = modificationStateType.getCommonName(); + + if (name !== null && name !== undefined && name !== "") { + desc = state + " at position " + name + ", "; + } else { + desc = state + ","; + } + } else if (name !== null && name !== undefined && name !== "" && + (modification.type === "BINDING_REGION" || + modification.type === "CODING_REGION" || + modification.type === "PROTEIN_BINDING_DOMAIN" || + modification.type === "TRANSCRIPTION_SITE_LEFT" || + modification.type === "TRANSCRIPTION_SITE_RIGHT" || + modification.type === "REGULATORY_REGION" + )) { + desc = name + ","; + } + + if (desc !== undefined) { + row = Functions.createElement({ + type: "li" + }); + row.appendChild(self.createLabelText(desc)); + } + return row; +}; + +/** + * + * @param {string} label + * @param {Object[]} value + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createPostTranslationalModifications = function (label, value) { + var result = document.createElement("div"); + var count = 0; + if (value !== undefined && value.length > 0) { + var self = this; + var userFriendlyLabel = label + ": "; + if (label === "RESIDUE") { + userFriendlyLabel = "Posttranslational modifications: " + } else if (label === "BINDING_REGION") { + userFriendlyLabel = "Binding regions: " + } else if (label === "CODING_REGION") { + userFriendlyLabel = "Coding regions: " + } else if (label === "PROTEIN_BINDING_DOMAIN") { + userFriendlyLabel = "Protein binding domains: " + } else if (label === "TRANSCRIPTION_SITE_LEFT") { + userFriendlyLabel = "Transcription sites (left): " + } else if (label === "TRANSCRIPTION_SITE_RIGHT") { + userFriendlyLabel = "Transcription sites (right): " + } else if (label === "TRANSCRIPTION_SITE") { + userFriendlyLabel = "Transcription sites: " + } else if (label === "MODIFICATION_SITE") { + userFriendlyLabel = "Modification sites: " + } + result.appendChild(self.createLabel(userFriendlyLabel)); + result.appendChild(self.createNewLine()); + var list = Functions.createElement({ + type: "ul" + }); + for (var i = 0; i < value.length; i++) { + var modification = value[i]; + var row = self.createModificationRow(modification, self); + if (row !== null) { + list.appendChild(row); + count++; + } + } + result.appendChild(list); + } + if (count > 0) { + return result; + } else { + return document.createElement("div"); + } +}; + +/** + * + * @returns {HTMLHRElement} + */ +GuiUtils.prototype.createSeparator = function () { + return document.createElement("hr"); +}; + +/** + * + * @param {number} [count] + * @returns {HTMLParagraphElement} + */ +GuiUtils.prototype.createNewLine = function (count) { + if (count === undefined) { + count = 0; + } + var result = document.createElement("p"); + if (count > 0) { + result.style.height = ((count - 1) * 10) + "px"; + } + return result; +}; + +/** + * + * @param {string} [url] + * @param {string} name + * @returns {HTMLElement} + */ +GuiUtils.prototype.createLink = function (url, name) { + if (url === null || url === undefined) { + logger.warn("URL not defined for: \"" + name + "\" link"); + return Functions.createElement({type: "span", content: name}); + } + var link = document.createElement("a"); + link.href = url; + link.innerHTML = name; + link.target = "_blank"; + link.style.textDecoration = "underline"; + return link; +}; + +/** + * + * @param {Annotation} annotation + * @param {boolean} [showType=false] + * @returns {HTMLElement} + */ +GuiUtils.prototype.createAnnotationLink = function (annotation, showType) { + var self = this; + var name, type, hint; + var article = annotation.getArticle(); + if (article !== undefined) { + + hint = article.getTitle() + " " + article.getAuthors().join(", ") + ", " + article.getYear() + ", " + + article.getJournal(); + type = "PUBMED"; + name = article.getId(); + } else { + //replace encoded parts of uri (like %2F - > "/") + name = decodeURIComponent(annotation.getResource()); + var miriamType = self.getConfiguration().getMiriamTypeByName(annotation.getType()); + if (miriamType === null) { + logger.warn("Unknown miriam type: " + annotation.getType()); + type = annotation.getType(); + } else { + type = miriamType.getCommonName(); + } + } + var link; + if (showType) { + link = self.createLink(annotation.getLink(), type + " (" + name + ")"); + } else { + link = self.createLink(annotation.getLink(), name); + } + if (hint !== undefined) { + var div = document.createElement("div"); + div.title = hint; + div.appendChild(link); + return div; + } else { + return link; + } +}; + +/** + * + * @param {string} label + * @param {Annotation[]} [value] + * @param {Object} [options] + * @param {boolean} [options.inline] + * + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createAnnotations = function (label, value, options) { + var self = this; + + var inline = false; + if (options !== undefined) { + if (options.inline !== undefined) { + inline = options.inline; + } + } + var result = document.createElement("div"); + result.appendChild(self.createLabel(label)); + if (value !== undefined && value.length > 0) { + if (!inline) { + result.appendChild(self.createNewLine()); + } + result.appendChild(self.createAnnotationList(value, options)); + } else { + result.appendChild(self.createLabelText("No annotations")); + } + return result; +}; + +/** + * + * @param {boolean} inline + * @param {string} annotatorClass + * @param {Object.<string, Annotator>} annotatorsClassMapping + * @param {boolean} groupAnnotations + * @returns {HTMLElement} + */ +function createGroupContainer(inline, annotatorClass, annotatorsClassMapping, groupAnnotations) { + var automaticallyAnnotated = !(annotatorClass === undefined || annotatorClass === "undefined" || annotatorClass === null || annotatorClass === ""); + var groupContainer = (inline ? document.createElement("span") : document.createElement("div")); + var descContainer = (inline ? document.createElement("span") : document.createElement("div")); + + if (groupAnnotations) { + var annotatorName = automaticallyAnnotated ? annotatorsClassMapping[annotatorClass].getName() : "Annotated by curator"; + if (inline) { + descContainer.innerHTML = 'Source: ' + annotatorName + ': '; + } else { + descContainer.innerHTML = 'Source: ' + annotatorName; + + if (automaticallyAnnotated) { + var annotatorDescription = annotatorsClassMapping[annotatorClass].getDescription(); + if (annotatorDescription) { + var tooltipContainer = Functions.createElement({ + type: "span" + }); + tooltipContainer.appendChild(Functions.createElement({ + type: "span", + className: "glyphicon glyphicon-question-sign tooltip-icon" + })); + tooltipContainer.appendChild(Functions.createElement({ + type: "span", + className: "annotator-tooltip", + content: annotatorsClassMapping[annotatorClass].getDescription() + })); + + descContainer.appendChild(tooltipContainer); + } + } + } + descContainer.className = "minerva-annotation-group-header"; + if (!inline) groupContainer.className = "minerva-annotation-group"; + groupContainer.appendChild(descContainer); + } + return groupContainer; +} + +/** + * + * @param {Annotation[]} annotations + * @param {Object} [options] + * @param {boolean} [options.showType = true] + * @param {boolean} [options.inline = false] + * @param {boolean} [options.groupAnnotations = true] + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createAnnotationList = function (annotations, options) { + var showType = true; + var inline = false; + var groupAnnotations = true; + if (options !== undefined) { + if (options.showType !== undefined) { + showType = options.showType; + } + if (options.inline !== undefined) { + inline = options.inline; + } + if (options.groupAnnotations !== undefined) { + groupAnnotations = options.groupAnnotations; + } + } + + var self = this; + var result = document.createElement("div"); + + var annotators = this.getConfiguration().getAnnotators(); + var annotatorsClassMapping = {}; + var grouppedAnnotations = {}; + var i; + if (groupAnnotations) { + for (i = 0; i < annotators.length; i++) { + annotatorsClassMapping[annotators[i].getClassName()] = annotators[i]; + } + + for (i = 0; i < annotations.length; i++) { + var clazz = annotations[i].getAnnotatorClassName(); + if (!(clazz in grouppedAnnotations)) grouppedAnnotations[clazz] = []; + grouppedAnnotations[clazz].push(annotations[i]) + } + } else { + annotatorsClassMapping["undefined"] = { + getName: function () { + return "" + } + }; + grouppedAnnotations["undefined"] = annotations; + } + + // = annotatorClasName ? annotatorsClassMapping[annotatorClasName].getName() : "Annotated by curator"; + + var cntAnnotations = 0; + + Object.keys(grouppedAnnotations).sort().forEach(function (annotatorClass) { + var groupContainer = createGroupContainer(inline, annotatorClass, annotatorsClassMapping, groupAnnotations); + + var par; + if (inline) { + par = document.createElement("span"); + par.innerHTML = "("; + groupContainer.appendChild(par); + } + + grouppedAnnotations[annotatorClass] = grouppedAnnotations[annotatorClass].sort(function (a, b) { + var aType = a.getType().toUpperCase(); + var bType = b.getType().toUpperCase(); + if (aType < bType) return -1; + else if (aType > bType) return 1; + else return 0; + }); + + for (var j = 0; j < grouppedAnnotations[annotatorClass].length; j++) { + + cntAnnotations += 1; + + var element = grouppedAnnotations[annotatorClass][j]; + var link = self.createAnnotationLink(element, showType); + if (inline) { + if (j > 0) { + var coma = document.createElement("span"); + coma.innerHTML = ", "; + groupContainer.appendChild(coma); + } + groupContainer.appendChild(link); + } else { + + var row = document.createElement("div"); + row.style.height = "26px"; + if (j % 2 === 0) { + row.className = "minerva-annotation-row-odd"; + } else { + row.className = "minerva-annotation-row-even"; + } + + var header = document.createElement("div"); + header.style.width = "28px"; + header.style.float = "left"; + header.innerHTML = "[" + cntAnnotations + "]"; + row.appendChild(header); + + var body = document.createElement("div"); + body.style.float = "left"; + body.appendChild(link); + row.appendChild(body); + groupContainer.appendChild(row); + } + } + + if (inline) { + par = document.createElement("span"); + par.innerHTML = ")"; + groupContainer.appendChild(par); + } + + result.appendChild(groupContainer); + }); + + return result; +}; + +/** + * + * @param {string} [value] + * @returns {HTMLSpanElement} + */ +GuiUtils.prototype.createLabelText = function (value) { + var result = document.createElement("span"); + if (value !== undefined) { + result.innerHTML = value; + } + return result; +}; + +/** + * + * @param {string} [value] + * @returns {HTMLInputElement} + */ +GuiUtils.prototype.createInputText = function (value) { + var result = document.createElement("input"); + result.setAttribute('type', 'text'); + + if (value !== undefined) { + result.setAttribute('value', value); + } + return result; +}; + +/** + * + * @param {string} [value] + * @returns {HTMLTextAreaElement} + */ +GuiUtils.prototype.createTextArea = function (value) { + var result = document.createElement("textarea"); + + if (value !== undefined) { + result.setAttribute('value', value); + result.innerHTML = value; + } + return result; +}; + +/** + * + * @param {string} label + * @param {string|number} [value] + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createParamLine = function (label, value) { + var result = document.createElement("div"); + if (value !== undefined && value !== null && value !== "") { + var self = this; + result.appendChild(self.createLabel(label)); + result.appendChild(self.createLabelText(value)); + } + return result; +}; + +/** + * + * @param {string} [icon] + * @param {function} [onclickFunction] + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createIcon = function (icon, onclickFunction) { + var result = document.createElement("div"); + if (icon !== undefined && icon !== null) { + var img = document.createElement("img"); + img.src = GuiConnector.getImgPrefix() + icon; + img.style.float = "left"; + img.hspace = 5; + if (onclickFunction !== undefined) { + img.onclick = onclickFunction; + } + result.appendChild(img); + } + return result; +}; + +/** + * + * @param {string} label + * @param {string[]} [value] + * + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createArrayParamLine = function (label, value) { + var result = document.createElement("div"); + if (value !== undefined && value.length > 0) { + var self = this; + result.appendChild(self.createLabel(label)); + result.appendChild(self.createLabelText(value.join(", "))); + } + return result; +}; + +/** + * + * @param {string} label + * @param {number} [modelId] + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createSubMapLink = function (label, modelId) { + var self = this; + var result = document.createElement("div"); + if (modelId !== undefined) { + var button = document.createElement("button"); + var model = self.getMap().getSubmapById(modelId).getModel(); + + button.innerHTML = model.getName(); + button.onclick = function () { + return self.getMap().openSubmap(modelId); + }; + result.appendChild(this.createLabel(label)); + result.appendChild(button); + } + return result; +}; + +/** + * + * @param {Array<string|HTMLElement>} elements + * @returns {HTMLElement} + */ +GuiUtils.prototype.createTableRow = function (elements) { + var row = Functions.createElement({ + type: "div", + style: "display: table-row;" + }); + + for (var i = 0; i < elements.length; i++) { + var cell = Functions.createElement({ + type: "div", + style: "display: table-cell;" + }); + if (Functions.isDomElement(elements[i])) { + cell.appendChild(elements[i]); + } else { + cell.innerHTML = elements[i]; + } + row.appendChild(cell); + } + return row; +}; + +/** + * + * @param {Reaction|SearchBioEntityGroup} params.reaction + * @param {string} [params.icon] + * @param {boolean} [params.showTitle] + * + * @returns {Promise<HTMLDivElement>} + */ +GuiUtils.prototype.createReactionElement = function (params) { + var reaction = params.reaction; + var showTitle = ((params.showTitle === undefined) || params.showTitle); + var self = this; + var div = document.createElement("div"); + + if (showTitle) { + div.appendChild(self.createLabel("Reaction: " + reaction.getReactionId())); + if (reaction.getModelId() !== self.getMap().getId()) { + div.appendChild(self.createSubMapLink("In submap: ", reaction.getModelId())); + } + } + + if (reaction.getLinkedSubmodelId() !== null && reaction.getLinkedSubmodelId() !== undefined) { + div.appendChild(self.createSubMapLink("Associated submap: ", reaction.getLinkedSubmodelId())); + } + if (showTitle) { + div.appendChild(self.createNewLine()); + } + + if (self.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).getValue().toLowerCase() === "true") { + div.appendChild(self.createParamLine("Type: ", reaction.getType())); + } + div.appendChild(self.createParamLine("Symbol: ", reaction.getSymbol())); + div.appendChild(self.createParamLine("Abbreviation: ", reaction.getAbbreviation())); + div.appendChild(self.createParamLine("Formula: ", reaction.getFormula())); + div.appendChild(self.createParamLine("Mechanical Confidence Score: ", reaction.getMechanicalConfidenceScore())); + div.appendChild(self.createParamLine("Lower Bound: ", reaction.getLowerBound())); + div.appendChild(self.createParamLine("Upper Bound: ", reaction.getUpperBound())); + div.appendChild(self.createParamLine("Gene Protein Reaction: ", reaction.getGeneProteinReaction())); + div.appendChild(self.createParamLine("Subsystem: ", reaction.getSubsystem())); + div.appendChild(self.createArrayParamLine("Synonyms: ", reaction.getSynonyms())); + div.appendChild(self.createParamLine("Description: ", reaction.getDescription())); + div.appendChild(self.createAnnotations("Annotations: ", reaction.getReferences())); + return Promise.resolve(div); +}; + +/** + * + * @param {Object[]} modifications + * + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createModifications = function (modifications) { + var self = this; + var result = document.createElement("div"); + var modificationsByType = []; + if (modifications !== undefined) { + for (var i = 0; i < modifications.length; i++) { + var modification = modifications[i]; + if (modificationsByType[modification.type] === undefined) { + modificationsByType[modification.type] = []; + } + modificationsByType[modification.type].push(modification); + } + for (var key in modificationsByType) { + if (modificationsByType.hasOwnProperty(key)) { + result.appendChild(self.createPostTranslationalModifications(key, modificationsByType[key])); + } + } + } + return result; +}; + +/** + * + * @param {Alias|SearchBioEntityGroup} params.alias + * @param {string} [params.icon] + * @param {boolean} [params.showTitle] + * + * @returns {Promise<HTMLDivElement>} + */ +GuiUtils.prototype.createAliasElement = function (params) { + var alias = params.alias; + var icon = params.icon; + var showTitle = ((params.showTitle === undefined) || params.showTitle); + var self = this; + var div = document.createElement("div"); + + if (showTitle) { + if (icon !== undefined) { + div.appendChild(this.createIcon(icon, function () { + return self.getMap().openSubmap(alias.getModelId()).then(function () { + if (alias instanceof Alias) { + return self.getMap().getSubmapById(alias.getModelId()).fitBounds([alias]); + } else { + return self.getMap().getSubmapById(alias.getModelId()).fitBounds(alias.getBioEntities()); + } + }); + })); + } + + div.appendChild(this.createParamLine(alias.getType() + ": ", alias.getName())); + if (alias.getModelId() !== self.getMap().getId()) { + div.appendChild(self.createSubMapLink("In submap: ", alias.getModelId())); + } + } + if (alias.getLinkedSubmodelId() !== undefined) { + div.appendChild(self.createSubMapLink("Associated submap: ", alias.getLinkedSubmodelId())); + } + if (alias instanceof SearchBioEntityGroup && alias.getBioEntities().length > 1) { + div.appendChild(self.createLabelText("Group of " + alias.getBioEntities().length + " elements.")); + } + if (showTitle) { + div.appendChild(self.createNewLine(3)); + } + + var promise = Promise.resolve(); + if (alias.getCompartmentId() !== undefined) { + promise = self.getMap().getModel().getByIdentifiedElement(new IdentifiedElement({ + type: "ALIAS", + id: alias.getCompartmentId(), + modelId: alias.getModelId() + }), true).then(function (compartment) { + div.appendChild(self.createParamLine("Compartment: ", compartment.getName())); + }) + } + + return promise.then(function () { + + div.appendChild(self.createParamLine("Full name: ", alias.getFullName())); + div.appendChild(self.createParamLine("Symbol: ", alias.getSymbol())); + div.appendChild(self.createParamLine("Abbreviation: ", alias.getAbbreviation())); + div.appendChild(self.createParamLine("Formula: ", alias.getFormula())); + div.appendChild(self.createArrayParamLine("Former symbols: ", alias.getFormerSymbols())); + div.appendChild(self.createModifications(alias.getOther('modifications'))); + div.appendChild(self.createParamLine("Charge: ", alias.getCharge())); + div.appendChild(self.createArrayParamLine("Synonyms: ", alias.getSynonyms())); + div.appendChild(self.createLabelText(alias.getDescription())); + div.appendChild(self.createAnnotations("Annotations: ", alias.getReferences())); + + return div; + }) +}; + +/** + * + * @param {SearchBioEntityGroup} group + * @returns {Promise<HTMLDivElement>} + */ +GuiUtils.prototype.createSearchBioEntityGroupElement = function (group) { + if (group.getBioEntities()[0] instanceof Alias) { + return this.createAliasElement({alias: group, icon: group.getIcon()}); + } else { + return this.createReactionElement({reaction: group, icon: group.getIcon()}); + } +}; + +/** + * + * @returns {HTMLAnchorElement} + */ +GuiUtils.prototype.createLogoutLink = function () { + var logoutLink = document.createElement("a"); + logoutLink.href = "#"; + logoutLink.innerHTML = "LOGOUT"; + logoutLink.id = "logoutLink"; + logoutLink.onclick = function () { + return ServerConnector.logout(); + }; + return logoutLink; +}; + +/** + * + * @param {string} params.name + * @param {string} params.id + * @param {HTMLElement} params.navigationBar + * + * @returns {HTMLLIElement} + */ +GuiUtils.prototype.createTabMenuObject = function (params) { + var name = params.name; + var id = params.id; + var navigationBar = params.navigationBar; + + var navClass = ''; + if (navigationBar.children.length === 0) { + navClass = "active"; + } + + var navLi = document.createElement("li"); + navLi.className = navClass; + + var navLink = document.createElement("a"); + navLink.href = "#" + id; + if (name !== undefined) { + navLink.innerHTML = name; + } + navLink.onclick = function () { + $(this).tab('show'); + }; + navLi.appendChild(navLink); + if (name !== undefined) { + navLink.innerHTML = name; + } + return navLi; +}; + +/** + * + * @param {string} params.id + * @param {HTMLElement} params.navigationObject + * + * @returns {HTMLDivElement} + */ +GuiUtils.prototype.createTabContentObject = function (params) { + var navigationObject = params.navigationObject; + var tabId = params.id; + var result = document.createElement("div"); + result.style.height = "100%"; + + var contentClass = 'tab-pane'; + if (navigationObject.className === "active") { + contentClass = "tab-pane active"; + } + + result.className = contentClass; + result.id = tabId; + return result; +}; + +/** + * + * @param {HTMLElement} [params.element] + * @param {string} params.id + * + * @returns {{element: HTMLElement, menu: HTMLElement, content: HTMLElement, tabId: *}} + */ +GuiUtils.prototype.createTabDiv = function (params) { + var tabDiv = Functions.createElement({ + type: "div", + name: "tabView", + className: "tabbable boxed parentTabs" + }); + + var tabMenuDiv = Functions.createElement({ + type: "ul", + className: "nav nav-tabs" + }); + tabDiv.appendChild(tabMenuDiv); + + var tabContentDiv = Functions.createElement({ + type: "div", + className: "tab-content" + }); + tabDiv.appendChild(tabContentDiv); + + if (params.element !== undefined) { + params.element.appendChild(tabDiv); + } + + return { + element: tabDiv, + menu: tabMenuDiv, + content: tabContentDiv, + tabId: params.id + } +}; + +GuiUtils.prototype.createTab = function (params) { + var tabData = params.tabData; + + var tabId = tabData.tabId + "_tab_" + tabIdCounter; + tabIdCounter++; + + var navClass = ''; + var contentClass = 'tab-pane'; + if (tabData.menu.children.length === 0) { + navClass = "active"; + contentClass = "tab-pane active"; + } + + var navLi = document.createElement("li"); + navLi.className = navClass; + + var navLink = document.createElement("a"); + navLink.href = "#" + tabId; + + navLink.innerHTML = params.title; + + navLink.onclick = function () { + $(this).tab('show'); + }; + navLi.appendChild(navLink); + tabData.menu.appendChild(navLi); + + var contentDiv = document.createElement("div"); + contentDiv.style.height = "100%"; + contentDiv.className = contentClass; + contentDiv.id = tabId; + + if (Functions.isDomElement(params.content)) { + contentDiv.appendChild(params.content); + } else { + contentDiv.innerHTML = params.content; + } + tabData.content.appendChild(contentDiv); + + $(contentDiv).css("overflow", "auto"); + $(contentDiv).css("height", "calc(100vh - " + $(contentDiv).offset().top + "px)"); + + return { + title: navLink, + content: contentDiv + } +}; + +/** + * + * @param {string} toolTip + * @param {boolean} [useXss=false] + * @returns {HTMLElement} + */ +GuiUtils.prototype.createHelpButton = function (toolTip, useXss) { + var helpContent; + if (useXss) { + helpContent = xss(toolTip); + } else { + helpContent = toolTip; + } + + var helpTipButton = Functions.createElement({ + type: "button", + className: "minerva-help-button", + content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>', + xss: false + }); + var helpDialogDiv = undefined; + helpTipButton.onclick = function () { + if (helpDialogDiv === undefined) { + helpDialogDiv = Functions.createElement({ + type: "div", + content: helpContent, + xss: false + }); + $(helpDialogDiv).dialog({ + close: function () { + $(this).dialog('destroy').remove(); + helpDialogDiv = undefined; + }, + position: { + my: "left top", + at: "left bottom", + of: helpTipButton + } + }); + $('.ui-dialog').find("a").blur(); + } + }; + return helpTipButton; +}; + +/** + * @param {AbstractGuiElement} abstractGuiElement + */ +GuiUtils.prototype.initTabContent = function (abstractGuiElement) { + if (abstractGuiElement._panels !== undefined) { + throw new Error("Tabs were already initialized"); + } + + abstractGuiElement._panels = []; + abstractGuiElement._tabIdCount = 0; + + var tabDiv = Functions.createElement({ + type: "div", + name: "tabView", + className: "tabbable boxed parentTabs" + }); + abstractGuiElement.getElement().appendChild(tabDiv); + + tabDiv.appendChild(Functions.createElement({ + type: "ul", + className: "nav nav-tabs" + })); + + tabDiv.appendChild(Functions.createElement({ + type: "div", + className: "tab-content" + })); +}; + +/** + * + * @param {AbstractGuiElement} abstractGuiElement + * @param {Object} params + * @param {string} params.name + * @param {function} params.panelClass + */ +GuiUtils.prototype.addTab = function (abstractGuiElement, params) { + var tabId = "admin_panel_tab_" + abstractGuiElement._tabIdCount; + abstractGuiElement._tabIdCount++; + + var navElement = $(abstractGuiElement.getElement()).find("> .parentTabs > .nav-tabs")[0]; + var contentElement = $(abstractGuiElement.getElement()).find("> .parentTabs > .tab-content")[0]; + + var navLi = this.createTabMenuObject({ + id: tabId, + name: params.name, + navigationBar: navElement + }); + navElement.appendChild(navLi); + + var contentDiv = this.createTabContentObject({ + id: tabId, + navigationObject: navLi + }); + + contentElement.appendChild(contentDiv); + + abstractGuiElement._panels.push(new params.panelClass({ + element: contentDiv, + name: params.name, + configuration: this.getConfiguration(), + serverConnector: abstractGuiElement.getServerConnector() + })); +}; + +module.exports = GuiUtils;