Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

Commit 3f68e148 authored by Mikaël Salson's avatar Mikaël Salson
Browse files

merge -- Standalone segmenter page

Thanks to @tydax
parents 2228aa56 6a7342bc
LESSC=lessc
all: dark.css light.css svg.css talk.css
all: dark.css light.css svg.css talk.css segmenter_page.css
dark.css: dark.less vidjil.less
$(LESSC) dark.less dark.css
......@@ -11,11 +11,12 @@ light.css: light.less vidjil.less
talk.css: talk.less light.less vidjil.less
$(LESSC) $< $@
svg.css: svg.less vidjil.less
$(LESSC) svg.less svg.css
segmenter_page.css: segmenter_page.less vidjil.less
$(LESSC) segmenter_page.less segmenter_page.css
no:
$(MAKE) LESSC="./node lessc"
@import "light.less";
body {
line-height: 20px;
}
h1, h2, h3 {
font-weight: bold;
line-height: 40px;
}
h1, h2, div, p {
margin: 0;
padding: 0;
}
header, footer {
display: block;
}
textarea {
border: 1px solid silver;
border-radius: 0.1em;
padding: 1%;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border linear .2s, box-shadow linear .2s;
-moz-transition: border linear .2s, box-shadow linear .2s;
-o-transition: border linear .2s, box-shadow linear .2s;
transition: border linear .2s, box-shadow linear .2s;
transition-property: border, box-shadow;
transition-duration: 0.2s, 0.2s;
transition-timing-function: linear, linear;
transition-delay: 0s, 0s;
}
.flexbox {
display: -ms-Flexbox;
-ms-box-orient: horizontal;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flex;
display: flex;
-webkit-flex-flow: row wrap;
-moz-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.panel {
background: white;
border-radius: 0.1em;
margin: 0.2% 0.4%;
padding: 1%;
}
#header_panel {
padding-top: 0.4%;
position: fixed;
height: 75px;
width: 97.5%
}
#app_title {
font-size: 1.7em;
float: right;
}
#tool_title {
font-size: 1.2em;
}
#body_panel {
bottom: 175px;
max-height: 65%;
position: fixed;
top: 100px;
width: 100%;
}
.twopanels_left {
margin-right: 0.2%;
}
.twopanels_right {
margin-left: 0.2%;
}
#form_submit, #form_sequences_file {
display: inline;
}
#form_block {
height: 100%
}
#form_panel {
-webkit-flex: 1 60%;
-moz-flex: 1 60%;
-ms-flex: 1 60%;
flex: 1 60%;
height: 95%;
padding: 2%;
position: relative;
}
#form_sequences {
resize: none;
margin-top: 2%;
height: 65%;
width: 98%;
}
#scatter_panel {
-webkit-flex: 2 32%;
-moz-flex: 2 32%;
-ms-flex: 2 32%;
flex: 2 32%;
}
#segmenter_panel {
bottom: 0;
height: 144px;
position: fixed;
width: 97.2%;
}
#footer_panel {
display: inline-block;
float: right;
padding: 0.4% 1.4%;
}
#copyright {
font-size: 0.7em;
position: absolute;
bottom: 0.4%;
right: 1.2%;
text-align: right;
}
.vidjil_view {
border-radius: 0.1em;
/*border: 1px solid silver;*/
position: relative;
height: 100%;
width: 100%;
}
.invisible, .visible, .waitingResponse, .notWaitingResponse {
-moz-transition: opacity 1s, background 1s;
-webkit-transition: opacity 1s, background 1s;
transition: opacity 1s, background 1s;
}
.invisible {
opacity: 0;
}
.visible {
opacity: 1;
}
.waitingResponse {
background: whitesmoke;
}
.imgAjaxLoading {
position: absolute;
left: 50%;
top: 50%;
}
/*
/*
* Vidjil browser, main configuration file
* This file must be named 'js/conf.js' to be taken into account
* */
var config = {
/* Used for the 'align' script
/* Used for the 'align' script
* If this is not defined, the 'align' button is not available
*/
*/
"cgi_address" : "http://db.vidjil.org/cgi/", // Public test server
// "cgi_address" : "http://127.0.1.1/cgi-bin/",
......@@ -23,7 +23,7 @@ var config = {
/* 2) and 3) Static files
/* - relative paths if Vidjil browser is online on the same server
* - absolute paths to a CORS active server only if browser is offline or on another server
* - absolute paths to a CORS active server only if browser is offline or on another server
*/
/* 2) Menu with a list of static files */
......@@ -36,7 +36,7 @@ var config = {
]
},
*/
/* 3) Static file autoload, possibly with an .analysis file */
// "autoload" : "data/Stanford-S22.vidjil",
// "autoload_analysis" : "data/Stanford-S22.analysis"
......@@ -45,4 +45,8 @@ var config = {
/*
"proxy": "https://db.vidjil.org/vidjil/proxy/imgt"
*/
/* Used for the standalone segmenter page */
"segmenter_address" : "https://dev.vidjil.org/vidjil/segmenter",
}
var PROXY_ADDRESS = "https://db.vidjil.org/vidjil/proxy/imgt"
var modelRef;
/**
* Sets the model reference for the cross domain functions to use.
* @param {object} model - the model reference to pass to the cross domain functions.
*/
function setCrossDomainModel(model) {
modelRef = model;
}
//parametre IMGT par defaut
function initImgtInput() {
......@@ -210,18 +219,18 @@ function imgtPostForSegmenter(data, system, segmenter, override_imgt_options) {
logmsg += cloneIdx + ",";
//remove unneeded info coz relative to # of selected items
delete imgtArray[i]["Sequence number"];
if (typeof m.clones[cloneIdx].seg.imgt == 'undefined') {
m.clones[cloneIdx].seg.imgt = {}
m.clones[cloneIdx].seg.imgt2display = {}
if (typeof modelRef.clones[cloneIdx].seg.imgt == 'undefined') {
modelRef.clones[cloneIdx].seg.imgt = {}
modelRef.clones[cloneIdx].seg.imgt2display = {}
}
correctIMGTPositionsForInsertions(imgtArray[i]);
append_to_object(imgtArray[i], m.clones[cloneIdx].seg.imgt);
append_to_object(computeStartStop(imgtArray[i],m.clones[cloneIdx].getSequence()),
m.clones[cloneIdx].seg.imgt2display);
append_to_object(imgtArray[i], modelRef.clones[cloneIdx].seg.imgt);
append_to_object(computeStartStop(imgtArray[i],modelRef.clones[cloneIdx].getSequence()),
modelRef.clones[cloneIdx].seg.imgt2display);
//toggle save in analysis file
m.clones[cloneIdx].segEdited = true;
modelRef.clones[cloneIdx].segEdited = true;
}
m.updateElemStyle(m.getSelected());
modelRef.updateElemStyle(modelRef.getSelected());
var imgt4segButton= document.getElementById("toIMGTSeg");
if (typeof imgt4segButton != "undefined"){
......
var pfx = ["webkit", "moz", "MS", "o", ""];
/**
* Adds a retrocompatible event listener.
* @param {object} element - the element to add the event to.
* @param {string} type - the type of event to listen to.
* @param {function} callback - the function to call when the event is fired.
*/
function addPrefixedEvent(element, type, callback) {
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) {
type = type.toLowerCase();
}
element.addEventListener(pfx[p]+type, callback, false);
}
}
/**
* Removes a retrocompatible event listener.
* @param {object} element - the element to remove the event from.
* @param {string} type - the type of event to listen to.
* @param {function} callback - the function to call when the event is fired.
*/
function removePrefixedEvent(element, type, callback) {
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) {
type = type.toLowerCase();
}
element.removeEventListener(pfx[p]+type, callback, false);
}
}
......@@ -349,19 +349,19 @@ List.prototype = {
* */
resize: function () {
//hardcore resize (for firefox and ...)
//seriously 7 years after the first release of the html5 specs there is no simple way (except with chrome) to put a scrollbar inside a table-cell
document.getElementById("list_data").style.height = ""
document.getElementById("list_clones").style.height = "0px"
var data = document.getElementById("data-row").offsetHeight
//seriously 7 years after the first release of the html5 specs there is no simple way (except with chrome) to put a scrollbar inside a table-cell
document.getElementById("list_data").style.height = "";
document.getElementById("list_clones").style.height = "0px";
var data = document.getElementById(this.id_data).parentNode.offsetHeight;
if (data>100)data = 100
document.getElementById("list_data").style.height = data+"px"
var menu = document.getElementById("list_menu").offsetHeight
var list = $("#list-row").innerHeight()
document.getElementById("list_clones").style.height = (list-menu)+"px"
document.getElementById("list_data").style.height = data+"px";
var menu = document.getElementById("list_menu").offsetHeight;
var list = $("#" + this.id).parent().innerHeight();
document.getElementById("list_clones").style.height = (list-menu)+"px";
},
/**
......
......@@ -38,7 +38,7 @@ console = new Com(console)
* It keeps all the views in sync.
*/
var m = new Model();
setCrossDomainModel(m);
/* Database (optional)
* This links the model to a patient database (possibly the one defined in config.js)
......
......@@ -1828,7 +1828,7 @@ changeCloneNotation: function(cloneNotationType) {
//replace tagSeelector
var tagSelectorH = $(this.tagSelector).height()
var tagSelectorH = $(this.tagSelector).outerHeight()
var minTop = 40;
var maxTop = Math.max(40, $(window).height()-tagSelectorH);
var top = e.clientY - tagSelectorH/2;
......
......@@ -341,7 +341,7 @@ ScatterPlot.prototype = {
var self = this;
this.label_container = d3.select("#" + this.id)
.attr("class", "scatterplot")
.classed("scatterplot", true)
.append("div")
.attr("id", this.id + "_label_container")
......
......@@ -188,7 +188,7 @@ Segment.prototype = {
span.setAttribute('title', 'Send sequences to Ensembl Blast and see the results in a new tab')
span.className = "button";
span.onclick = function () {
if (m.getSelected().length > 30) {
if (self.m.getSelected().length > 30) {
console.log({"type": "flash", "msg": "A maximum of 30 clones are allowed by Blast" , "priority": 1});
} else {
self.sendTo('blast');
......
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="./images/favicon-v.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="css/fonts/ubuntu/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="css/fonts/ubuntu-mono/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="css/icons/fontello/css/fontello.css" />
<link rel="stylesheet" type="text/css" href="css/icons/fontello/css/animation.css" />
<link id="seg_highlight" rel="stylesheet" type="text/css" href="css/segmenter_highlight.css" />
<link rel="stylesheet" type="text/css" href="css/segmenter_page.css" />
<title>Segmenter Tool — Vidjil</title>
</head>
<body>
<div id="body">
<header id="header_panel" class="panel">
<h1 id="app_title">Vidjil</h1>
<h2 id="tool_title">V(D)J designation tool</h2>
<p>This tool quickly checks the V(D)J designation of a small number of sequences with (possibly incomplete) V(D)J recombinations. To analyze complete NGS RepSeq datasets, use the <a href="http://app.vidjil.org/">full Vidjil platform</a>.
</p>
</header>
<div id="body_panel" class="flexbox">
<div id="form_panel" class="panel twopanels_left">
<form id="form_block" name="form_sequences">
<textarea autofocus id="form_sequences" name="sequences" rows="10" cols="80" placeholder="Enter up to 10 sequences in FASTA format..."></textarea>
<div id="bottom_form">
<p>or</p>
<input id="form_sequences_file" name="sequences_file" type="file" />
<input id="form_submit" type="button" value="Submit" />
<button id="btn_exportfasta" class="btn_feature">Export to FASTA</button>
</div>
</form>
<p id="copyright">Copyright Vidjil © 2016</p>
</div>
<div id="scatter_panel" class="panel twopanels_right">
<div id="scatter_container" class="vidjil_view visible">
</div>
</div>
</div>
<div id="segmenter_panel" class="panel">
<div id="segmenter_container" class="vidjil_view visible">
</div>
</div>
<form id="form"></form>
<script data-main="js/app.js" src="js/lib/require.js"></script>
<script src="js/eventListenerComp.js"></script>
<script src="segmenter_page.js"></script>
</body>
var DEFAULT_SEGMENTER_ADDRESS = 'https://dev.vidjil.org/vidjil/segmenter';
var model;
var segmenter;
var scatter;
var console;
/**
* Validates the form, and returns the data if it was successfully validated.
* Display errors if the form is invalid.
* @param {object} form - the form DOM object containing the data.
* @return {string} data - the sequences from the form if the form was successfully validated.
* @return {undefined} if the form is invalid.
*/
function validateForm(form) {
var data = form['sequences'].value;
if (!data) {
data = form['sequences_file'].files[0];
if (!data) {
data = undefined;
displayError('No sequences provided.');
}
}
return data;
}
/**
* Display the specified error message on the page.
* @param {string} error - the error message to display.
* @param {string} rawError - (optional) the raw error text.
* @param {exception} exc - (optional) the exception that caused the error.
*/
function displayError(error, rawError, exc) {
console.log({msg: error, type: 'flash', priority: 2});
if (rawError) {
console.log({msg: rawError, type: 'flash', priority: 2});
}
}
/**
* Requests the .vidjil file to the controller.
* @param {string} sequences - the sequences to send to the controller.
* @param {function} callback - the function to call upon request's successful return.
* @param {function} error - the function to call when an error occurs.
**/
function requestVidjilFile(sequences, callback, error) {
var urlController = config && config.segmenter_address
? config.segmenter_address
: DEFAULT_SEGMENTER_ADDRESS;
var dataToSend = new FormData();
dataToSend.append('sequences', sequences);
// Prepare request
var xhr = new XMLHttpRequest();
xhr.overrideMimeType("application/json");
xhr.addEventListener('readystatechange', function() {
if (this.readyState == 4 && this.status == 200) {
callback(this.responseText);
}
});
xhr.addEventListener('error', function() {
displayError('We had a problem processing your request.', this.stateText);
});
xhr.open('POST', urlController, true);
xhr.send(dataToSend);
}
/**
* Processes the resulting data from the request, and sets up the Vidjil views.
* @param {string} data - the data from the request.
*/
function processResult(data) {
console.log(data);
model.parseJsonData(data, 100);
model.loadGermline();
model.initClones();
// Do not select virtual clones
var cloneIds = [];
for (var i = 0; i < model.clones.length; i++) {
if (! model.clones[i].isVirtual()) {
cloneIds.push(i);
}
}
model.multiSelect(cloneIds);
// Delete merge button
var menuSegmenter = document.getElementsByClassName('menu-segmenter')[0];
var mergeButt = document.getElementById('merge');
menuSegmenter.removeChild(mergeButt);
}
/**
* Displays or hides the Vidjil views with a nice transition.
* @param {bool} visible - 'true' to display, 'false' to hide.
*/
function displayVidjilViews(visible) {
var views = document.getElementsByClassName('vidjil_view');
for (var i = 0; i < views.length; i++) {
var view = views[i];
if (visible) {
view.classList.add('visible');
view.classList.remove('invisible');
} else {
view.classList.add('invisible');
view.classList.remove('visible');
}
}
}
/**
* Enables or disables the display of a waiting for callback feedback.
* @param {bool} waiting - 'true' to enable, 'false' to disable.
*/
function displayWaitingForCallback(waiting) {
var views = document.getElementsByClassName('vidjil_view');
for (var i = 0; i < views.length; i++) {
var view = views[i];
// Update class depending on whether the page is waiting for response or not
if (waiting) {
view.classList.add('waitingResponse');
view.classList.remove('notWaitingResponse');
// Create loader image
var imgLoading = icon('icon-spin4 animate-spin imgAjaxLoading', '');
view.appendChild(imgLoading);
} else {
var imgLoading = view.getElementsByClassName('imgAjaxLoading');
if (imgLoading.length != 0) {
view.removeChild(imgLoading[0]);
}
view.classList.add('notWaitingResponse');
view.classList.remove('waitingResponse');
}
}
var body = document.getElementById('body');
body.style.cursor = waiting
? 'wait'
: 'auto';
}
/**
* Enables or disables the submit button.
* @param {bool} disabled - 'true' to disable, 'false' to enable.
*/
function disableSubmitButt(disabled) {
var submitButt = document.getElementById('form_submit');
submitButt.disabled = disabled;
}
/**
* Enables or disables the feature buttons.
* @param {bool} disabled - 'true' to disable, 'false' to enable.
*/
function disableFeatures(disabled) {
var featuresBtn = document.getElementsByClassName('btn_feature');
for (var i = 0; i < featuresBtn.length; i++) {
featuresBtn[i].disabled = disabled;
}
}
/**
* Prepares the button listeners.
*/
function prepareButtons() {