diff --git a/frontend-js/src/main/js/gui/Panel.js b/frontend-js/src/main/js/gui/Panel.js index ed0594d070b85d9cd8be94026d43f29a876800c5..8264cfbb02c1bd5471d9bc669661303138b830fa 100644 --- a/frontend-js/src/main/js/gui/Panel.js +++ b/frontend-js/src/main/js/gui/Panel.js @@ -54,29 +54,7 @@ Panel.prototype.constructor = Panel; Panel.prototype.createHelpButton = function () { var self = this; - var helpTipButton = Functions.createElement({ - type: "button", - className: "minerva-help-button", - content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>', - xss: false - }); - helpTipButton.onclick = function () { - var helpDialogDiv = Functions.createElement({ - type: "div", - content: xss(self.getHelpTip()) - }); - $(helpDialogDiv).dialog({ - close: function () { - $(this).dialog('destroy').remove(); - }, - position: { - my: "left top", - at: "left bottom", - of: helpTipButton - }, - }); - $('.ui-dialog').find("a").blur(); - }; + var helpTipButton = self.getGuiUtils().createHelpButton(self.getHelpTip()); self.getElement().appendChild(helpTipButton); }; diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js index 374bb11271c70cb492ff2de7169979cf788aab89..22d5dc4f982a105bb6dbf9aea5a5efc14de836a7 100644 --- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js +++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js @@ -10,6 +10,7 @@ var ChooseValidatorsDialog = require('./ChooseValidatorsDialog'); var GuiConnector = require('../../GuiConnector'); var OverlayParser = require('../../map/OverlayParser'); var ZipEntry = require('./ZipEntry'); +var ConfigurationType = require('../../ConfigurationType'); var Functions = require('../../Functions'); // noinspection JSUnusedLocalSymbols @@ -163,7 +164,7 @@ AddProjectDialog.prototype.createGeneralTabContent = function () { var table = new Functions.createElement({ type: "div", - style: "display:table" + style: "display:table; width:100%" }); result.appendChild(table); @@ -195,7 +196,10 @@ AddProjectDialog.prototype.createGeneralTabContent = function () { var file = e.arg; return self.setFileParserForFilename(file.name); }); - table.appendChild(self.createRow([guiUtils.createLabel("Upload file: "), fileInput])); + + var manualUrl = self.getConfiguration().getOption(ConfigurationType.USER_MANUAL_FILE).getValue(); + var help = 'File with the map. For a quick start, CellDesigner files are accepted directly. Available options and configurations of the source file are discussed in <a href="' + manualUrl + '">manual</a>.'; + table.appendChild(self.createRow([guiUtils.createLabel("Upload file: "), fileInput, guiUtils.createHelpButton(help)])); var fileFormatSelect = Functions.createElement({ type: "select", @@ -204,12 +208,38 @@ AddProjectDialog.prototype.createGeneralTabContent = function () { table.appendChild(self.createRow([guiUtils.createLabel("File format: "), fileFormatSelect])); - table.appendChild(self.createInputRow("ProjectId:", "id", "project-id")); - table.appendChild(self.createInputRow("Project name:", "NEW DISEASE MAP", "project-name")); - table.appendChild(self.createInputRow("Project Disease:", "", "project-disease")); - table.appendChild(self.createInputRow("Organism:", "", "project-organism")); - table.appendChild(self.createInputRow("Version:", "", "project-version")); - table.appendChild(self.createInputRow("Notify email:", "", "project-notify-email")); + table.appendChild(self.createInputRow({ + labelName: "ProjectId:", + defaultValue: "id", + inputName: "project-id", + help: 'A working name of the uploaded project on the MINERVA platform. Unique in the platform.' + })); + table.appendChild(self.createInputRow({ + labelName: "Project name:", + defaultValue: "NEW DISEASE MAP", + inputName: "project-name", + help: 'The name of the uploaded project displayed in the top left corner of the Admin and User panels; your official name of the project.' + })); + table.appendChild(self.createInputRow({ + labelName: "Project Disease:", + inputName: "project-disease", + help: 'Mesh ID identifying disease connected to this map (ie. for Parkinson\'s Disease it would be D010300).' + })); + table.appendChild(self.createInputRow({ + labelName: "Organism:", + inputName: "project-organism", + help: 'Taxonomy ID identifying organism for which project is dedicated (ie. for Human map it would be 9606).' + })); + table.appendChild(self.createInputRow({ + labelName: "Version:", + inputName: "project-version", + help: 'A text field displayed next to the name of your project in the User panel.' + })); + table.appendChild(self.createInputRow({ + labelName: "Notify email:", + inputName: "project-notify-email", + help: 'E-mail address that should be used for project change notifications.' + })); var showAnnotatorsButton = Functions.createElement({ type: "button", @@ -228,12 +258,49 @@ AddProjectDialog.prototype.createGeneralTabContent = function () { } }); - table.appendChild(self.createCheckboxRow("Annotate model automatically:", false, "project-annotate-automatically", [showAnnotatorsButton])); - table.appendChild(self.createCheckboxRow("Verify manual annotations:", false, "project-verify-annotations", [showValidatorsButton])); - table.appendChild(self.createCheckboxRow("Cache data:", false, "project-cache-data")); - table.appendChild(self.createCheckboxRow("Auto margin:", true, "project-auto-margin")); - table.appendChild(self.createCheckboxRow("Display as SBGN:", false, "project-sbgn-visualization")); - table.appendChild(self.createCheckboxRow("Semantic zooming:", false, "project-semantic-zooming")); + table.appendChild(self.createCheckboxRow({ + labelName: "Annotate model automatically:", + defaultValue: false, + inputName: "project-annotate-automatically", + elements: [showAnnotatorsButton], + help: 'If this checkbox is checked, elements of the uploaded map will be automatically annotated using built in ' + + 'annotators. Behavior of the annotators can be configured by clicking the Advanced button.' + })); + table.appendChild(self.createCheckboxRow({ + labelName: "Verify manual annotations:", + defaultValue: false, + inputName: "project-verify-annotations", + elements: [showValidatorsButton], + help: 'If this checkbox is checked, elements and interactions of the uploaded map will be scanned for existing ' + + 'annotations; if present these existing annotations will be validated against a set of rules. Verification rules ' + + 'can be configured by clicking the Advanced button.' + })); + table.appendChild(self.createCheckboxRow({ + labelName: "Cache data:", + defaultValue: false, + inputName: "project-cache-data", + help: 'If this checkbox is checked, all hyperlinks in the project resolved by MIRIAM repository (e.g. cross-links ' + + 'to external bioinformatics databases) are resolved and cached.' + })); + table.appendChild(self.createCheckboxRow({ + labelName: "Auto margin:", + defaultValue: true, + inputName: "project-auto-margin", + help: 'If this checkbox is checked, upon generation of the graphics, empty spaces surrounding elements and ' + + 'interactions will be cropped.' + })); + table.appendChild(self.createCheckboxRow({ + labelName: "Display as SBGN:", + defaultValue: false, + inputName: "project-sbgn-visualization", + help: 'If this checkbox is checked, the uploaded model will be displayed in SBGN format, instead of default ' + + 'CellDesigner format.' + })); + table.appendChild(self.createCheckboxRow({ + labelName: "Semantic zooming:", + defaultValue: false, + inputName: "project-semantic-zooming" + })); var saveProjectButton = Functions.createElement({ type: "button", @@ -266,42 +333,62 @@ AddProjectDialog.prototype.createGeneralTabContent = function () { return result; }; -AddProjectDialog.prototype.createInputRow = function (labelName, defaultValue, inputName) { +AddProjectDialog.prototype.createInputRow = function (params) { + if (params.defaultValue === undefined) { + params.defaultValue = ""; + } var label = new Functions.createElement({ type: "div", - style: "display:table-cell", - content: xss(labelName) + style: "display:table-cell; width:200px", + content: xss(params.labelName) }); var input = new Functions.createElement({ type: "div", style: "display:table-cell", - content: "<input name='" + xss(inputName) + "' value='" + xss(defaultValue) + "'/>", + content: "<input name='" + xss(params.inputName) + "' value='" + xss(params.defaultValue) + "' style='width:100%'/>", xss: false }); - return this.createRow([label, input]); + var elements = [label, input]; + if (params.help !== undefined) { + elements.push(guiUtils.createHelpButton(params.help)); + } + return this.createRow(elements); }; -AddProjectDialog.prototype.createCheckboxRow = function (labelName, defaultValue, inputName, elements) { - var label = new Functions.createElement({ +AddProjectDialog.prototype.createCheckboxRow = function (params) { + var labelName = params.labelName; + var defaultValue = params.defaultValue; + var inputName = params.inputName; + var elements = params.elements; + var tooltip = params.help; + if (elements === undefined) { + elements = []; + } + var label = Functions.createElement({ type: "div", - style: "display:table-cell", + style: "display:table-cell;vertical-align: middle;", content: xss(labelName) }); var checked = ""; if (defaultValue) { checked = "checked"; } - var checkbox = new Functions.createElement({ + var checkbox = Functions.createElement({ type: "div", - style: "display:table-cell", content: "<input type='checkbox' name='" + xss(inputName) + "' " + checked + "/>", + style: "float:left;", xss: false }); - var rowElements = [label, checkbox]; - if (elements !== undefined) { - for (var i = 0; i < elements.length; i++) { - rowElements.push(elements[i]); - } + var checkBoxDiv = Functions.createElement({type: "div", style: "display:table-cell; vertical-align: middle"}); + checkBoxDiv.appendChild(checkbox); + var rowElements = [label, checkBoxDiv]; + + if (tooltip !== undefined) { + rowElements.push(guiUtils.createHelpButton(tooltip)); + } + for (var i = 0; i < elements.length; i++) { + $(elements[i]).css("float", "left"); + checkBoxDiv.appendChild(elements[i]); } return this.createRow(rowElements); }; @@ -311,12 +398,16 @@ AddProjectDialog.prototype.createRow = function (elements) { type: "div", style: "display:table-row" }); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; + for (var columnNumber = 0; columnNumber < elements.length; columnNumber++) { + var element = elements[columnNumber]; if (element.tagName.toLowerCase() !== 'div') { + var style = "display:table-cell; vertical-align: middle; "; + if (columnNumber === 0) { + style += "width:200px;"; + } var labelContainer = new Functions.createElement({ type: "div", - style: "display:table-cell" + style: style }); labelContainer.appendChild(element); element = labelContainer; diff --git a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js index 81b5d6bae542c8081088977c4a7dab79563375b3..afd6e5dcb6c08212c1fa179e9c114dd76ba24f5f 100644 --- a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js +++ b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js @@ -243,7 +243,8 @@ MapsAdminPanel.prototype.onAddClicked = function () { element: Functions.createElement({ type: "div" }), - customMap: null + customMap: null, + configuration: self.getConfiguration() }); self._addDialog = dialog; return dialog.init().then(function () { diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js index e1025958df5926ab5759a6f28e577bd3fdf15a7f..7dd3c7c4bdff56a0876449784e306fdee9fdb8c2 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js +++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js @@ -9,6 +9,7 @@ var AbstractGuiElement = require('../AbstractGuiElement'); var Functions = require('../../Functions'); var logger = require('../../logger'); +var xss = require('xss'); var tabIdCounter = 0; @@ -669,4 +670,39 @@ GuiUtils.prototype.createTab = function (params) { } }; +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 + }); + helpTipButton.onclick = function () { + var helpDialogDiv = Functions.createElement({ + type: "div", + content: helpContent, + xss: false + }); + $(helpDialogDiv).dialog({ + close: function () { + $(this).dialog('destroy').remove(); + }, + position: { + my: "left top", + at: "left bottom", + of: helpTipButton + } + }); + $('.ui-dialog').find("a").blur(); + }; + return helpTipButton; +}; + module.exports = GuiUtils; diff --git a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js index 79ce43f69091a9ca4f6441b3b240ef557981bb67..f8cb0ea272c99d628743a76ebfbea90a284b45da 100644 --- a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js +++ b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js @@ -3,6 +3,7 @@ require("../../mocha-config"); var AddProjectDialog = require('../../../../main/js/gui/admin/AddProjectDialog'); +var ConfigurationType = require('../../../../main/js/ConfigurationType'); var ServerConnector = require('../../ServerConnector-mock'); var ValidationError = require('../../../../main/js/ValidationError'); @@ -14,12 +15,17 @@ var chai = require('chai'); var assert = chai.assert; describe('AddProjectDialog', function () { - it('init', function () { - helper.loginAsAdmin(); - var dialog = new AddProjectDialog({ + var createDialog = function () { + return new AddProjectDialog({ element: testDiv, - customMap: null + customMap: null, + configuration: helper.getConfiguration() }); + }; + it('init', function () { + helper.loginAsAdmin(); + var dialog = createDialog(); + var manualUrl; return dialog.init().then(function () { assert.ok(dialog.getNotifyEmail() !== ""); assert.equal(0, logger.getWarnings().length); @@ -27,12 +33,18 @@ describe('AddProjectDialog', function () { }); }); - it('onUserPreferencesChange', function () { + it('check help buttons', function () { helper.loginAsAdmin(); - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null + var dialog = createDialog(); + return dialog.init().then(function () { + assert.ok(testDiv.innerHTML.indexOf("minerva-help-button") >= 0); + return dialog.destroy(); }); + }); + + it('onUserPreferencesChange', function () { + helper.loginAsAdmin(); + var dialog = createDialog(); return dialog.init().then(function () { dialog.setCache(false); assert.notOk(dialog.isCache()); @@ -44,10 +56,7 @@ describe('AddProjectDialog', function () { describe('onFileUpload', function () { it('default', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var file = new Blob(["<node></node>"]); file.name = "test.xml"; @@ -66,10 +75,7 @@ describe('AddProjectDialog', function () { describe('setZipFileContent', function () { it('submaps', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var buf = fs.readFileSync("testFiles/map/complex_model_with_submaps.zip"); buf.name = "complex_model_with_submaps.zip"; return dialog.init().then(function () { @@ -80,10 +86,7 @@ describe('AddProjectDialog', function () { }); }); it('overlays', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var buf = fs.readFileSync("testFiles/map/complex_model_with_overlays.zip"); buf.name = "complex_model_with_overlays.zip"; return dialog.init().then(function () { @@ -100,10 +103,7 @@ describe('AddProjectDialog', function () { describe('showAnnotatorsDialog', function () { it('default', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); return dialog.showAnnotatorsDialog().then(function () { return dialog.destroy(); @@ -125,11 +125,7 @@ describe('AddProjectDialog', function () { ServerConnector.addProject = function (params) { options = params; }; - - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var file = new Blob(["<node></node>"]); file.name = "test.xml"; @@ -158,10 +154,7 @@ describe('AddProjectDialog', function () { }); it('getOrganism', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); dialog.setOrganism("9606"); assert.equal("9606", dialog.getOrganism()); return dialog.destroy(); @@ -169,10 +162,7 @@ describe('AddProjectDialog', function () { describe('checkValidity', function () { it('invalid project name', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var file = new Blob(["<node></node>"]); file.name = "test.xml"; @@ -190,10 +180,7 @@ describe('AddProjectDialog', function () { }); }); it('valid project name', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); var file = new Blob(["<node></node>"]); file.name = "test.xml"; @@ -210,20 +197,14 @@ describe('AddProjectDialog', function () { describe('isIgnoredZipEntry', function () { it('valid entry', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); assert.notOk(dialog.isIgnoredZipEntry("images/a.png")); assert.notOk(dialog.isIgnoredZipEntry("main.xml")); return dialog.destroy(); }); it('invalid MAC OS entry', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); // noinspection SpellCheckingInspection assert.ok(dialog.isIgnoredZipEntry("__MACOSX/.desc")); @@ -231,10 +212,7 @@ describe('AddProjectDialog', function () { return dialog.destroy(); }); it('invalid old MAC OS entry', function () { - var dialog = new AddProjectDialog({ - element: testDiv, - customMap: null - }); + var dialog = createDialog(); assert.ok(dialog.isIgnoredZipEntry(".DS_Store/.desc")); assert.ok(dialog.isIgnoredZipEntry(".ds_store/.desc")); @@ -242,4 +220,13 @@ describe('AddProjectDialog', function () { }); }); + describe('createInputRow', function () { + it('with help button', function () { + var dialog = createDialog(); + var row = dialog.createInputRow({help: "help me"}); + assert.ok(row.innerHTML.indexOf("minerva-help-button") >= 0); + return dialog.destroy(); + }); + }); + }); diff --git a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js index bfa7e4381fcdb56a319461502b4f00bb7169fe96..dedf1de8bb5aafdf079686b12a0b3648aedaf972 100644 --- a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js +++ b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js @@ -189,4 +189,10 @@ describe('GuiUtils', function () { }); }); + it('createHelpButton', function () { + var guiUtils = new GuiUtils(helper.getConfiguration()); + var button = guiUtils.createHelpButton("test tooltip"); + button.onclick(); + $(".ui-dialog-titlebar-close").click(); + }); });