Commit 963833b3 authored by Mathieu Giraud's avatar Mathieu Giraud

Merge branch 'feature-w/multi_upload' into 'dev'

Feature cs/multi-upload : generic forms for batch creating sets and uploading samples

Closes #3073, #3017, #1362, #2963, #2976, #3046, #3045, #3044, #3016, #3006, #2997, #2979, #2977, #2746, #2896, and #2948

See merge request !167
parents 31a1667a 3bcea7b6
Pipeline #19866 passed with stages
in 41 seconds
......@@ -15,6 +15,9 @@
@tagColor6 : #d33682;
@tagColor7 : #859900;
@patientTokenColor : #adffae;
@runTokenColor : #ffadad;
@genericTokenColor : #adccff;
html{
height: 100%;
......@@ -1022,22 +1025,33 @@ a.tag-link {
/* ----------------- */
.data-container, .info-container{
.modal {
z-index:3;
border:solid;
position: fixed;
top: 50px;
left: 20px + @width_left_container;
font-size: 13px;
padding: 10px;
background: @background;
display:none;
max-width: -moz-calc(~"100%" - @width_left_container + 60px);
max-width: -webkit-calc(~"100%" - @width_left_container + 60px);
max-width: calc(~"100%" - @width_left_container + 60px);
height: -moz-calc(~"100%" - 215px);
height: -webkit-calc(~"100%" - 215px);
height: calc(~"100%" - 215px);
&.data-container, &.info-container{
top: 50px;
left: 20px + @width_left_container;
max-width: -moz-calc(~"100%" - @width_left_container + 60px);
max-width: -webkit-calc(~"100%" - @width_left_container + 60px);
max-width: calc(~"100%" - @width_left_container + 60px);
height: -moz-calc(~"100%" - 215px);
height: -webkit-calc(~"100%" - 215px);
height: calc(~"100%" - 215px);
}
&.jstree-container {
padding-top: 30px;
top: 10%;
left: 25%;
width: 50%;
height: 70%;
}
}
.data-msg, .info-msg{
......@@ -1607,10 +1621,12 @@ h3 .uid {
}
.db_footer{
display: inline-block;
display: block;
position: absolute;
bottom: 5px;
left:0px;
width: 100%;
background: white;
}
.db_block_left {
......@@ -1869,12 +1885,10 @@ h3 .uid {
.right {
float: right;
clear: both;
}
.left {
float: left;
clear: both;
}
select>option:hover {
......@@ -2201,9 +2215,15 @@ label.highlight_label {
white-space: pre-line;
}
#jstree {
max-height: 300px;
.jstree {
height: 90%;
width: 100%;
overflow-y: auto;
overflow-x: auto;
}
.jstree_button {
float: right;
}
.jstree-anchor {
......@@ -2231,77 +2251,243 @@ label.highlight_label {
min-width: @width_axisBox;
}
/* atwho css */
.set_token {
border-radius: 5px;
padding: 3px;
margin: 3px;
color: #000;
font-size: 85%;
display: inline-block;
background-color: #eee;
//float: left;
}
.atwho-view {
position:absolute;
top: 0;
left: 0;
display: none;
margin-top: 18px;
background: white;
color: black;
border: 1px solid #DDD;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0,0,0,0.1);
min-width: 120px;
z-index: 11110 !important;
.run_token {
background-color: @runTokenColor;
}
.atwho-view .atwho-header {
padding: 5px;
margin: 5px;
cursor: pointer;
border-bottom: solid 1px #eaeff1;
color: #6f8092;
font-size: 11px;
font-weight: bold;
.generic_token {
background-color: @genericTokenColor;
}
.atwho-view .atwho-header .small {
color: #6f8092;
float: right;
padding-top: 2px;
margin-right: -5px;
font-size: 12px;
font-weight: normal;
.patient_token {
background-color: @patientTokenColor;
}
.atwho-view .atwho-header:hover {
cursor: default;
.token_container {
display: inline-block;
}
.atwho-view .cur {
background: #3366FF;
color: white;
.token_input, .token_input:focus {
border: 0;
box-shadow: none;
width: 100px;
height: 25px;
}
.atwho-view .cur small {
color: white;
fieldset {
//display: inline-block;
//float: left;
}
.atwho-view strong {
color: #3366FF;
.file_fieldset {
clear: right;
width: -moz-available;
}
.atwho-view .cur strong {
color: white;
font:bold;
form {
label {
display: inline-block;
text-align: right;
}
div.field_div {
float: left;
display: inline-block;
}
.form_label {
line-height: 33px;
width: 70px;
}
}
.atwho-view ul {
/* width: 100px; */
list-style:none;
padding:0;
margin:auto;
max-height: 200px;
overflow-y: auto;
.error {
font-weight: bold;
color: red;
}
.atwho-view ul li {
display: block;
padding: 5px 10px;
border-bottom: 1px solid #DDD;
.icon-cancel {
cursor: pointer;
/* border-top: 1px solid #C8C8C8; */
}
.atwho-view small {
font-size: smaller;
color: #777;
font-weight: normal;
.inline {
display: inline-block;
}
.hidden {
display: none;
}
#fieldset_container {
:not(.set_token) {
> .icon-cancel {
float: right;
}
}
}
.buttons_add_elements {
margin: 1em 0;
}
/* atwho css */
.atwho-view {
position:absolute;
top: 0;
left: 0;
display: none;
margin-top: 18px;
background: white;
color: black;
border: 1px solid #DDD;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0,0,0,0.1);
min-width: 120px;
z-index: 11110 !important;
.atwho-header {
padding: 5px;
margin: 5px;
cursor: pointer;
border-bottom: solid 1px #eaeff1;
color: #6f8092;
font-size: 11px;
font-weight: bold;
.small {
color: #6f8092;
float: right;
padding-top: 2px;
margin-right: -5px;
font-size: 12px;
font-weight: normal;
}
&:hover {
cursor: default;
}
}
.cur {
background: #3366FF;
color: white;
small {
color: white;
}
strong {
color: white;
font:bold;
}
&.patient_li, &.generic_li, &.run_li {
& strong {
color: black;
font: bold;
}
}
}
strong {
color: #3366FF;
}
ul {
/* width: 100px; */
list-style:none;
padding:0;
margin:auto;
max-height: 200px;
overflow-y: auto;
li {
display: block;
padding: 5px 10px;
border-bottom: 1px solid #DDD;
cursor: pointer;
/* border-top: 1px solid #C8C8C8; */
&.patient_li:before {
font-size: 80%;
content: 'patient';
}
&.run_li:before {
font-size: 80%;
content: 'run';
}
&.generic_li:before {
font-size: 80%;
content: 'set';
}
& span.autocomplete_li {
display: none;
}
}
}
small {
font-size: smaller;
color: #777;
font-weight: normal;
}
}
// taken and modified from the W3 schools webpage https://www.w3schools.com/bootstrap/bootstrap_forms_inputs.asp
.form-control {
padding: 3px 6px;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
transition-property: border-color, box-shadow;
transition-duration: 0.15s, 0.15s;
transition-timing-function: ease-in-out, ease-in-out;
transition-delay: 0s, 0s;
display: inline-block;
min-width: 200px;
vertical-align: middle;
margin: 0;
height: 25px;
&:invalid {
border: 1px solid red;
-webkit-box-shadow: inset 0 1px 1px rgba(255,0,0,.075);
box-shadow: inset 0 1px 1px rgba(255,0,0,.075);
}
&[type="file"], &.jstree_field {
border: 0px;
border-radius: unset;
box-shadow: unset;
cursor: pointer;
width: 234px;
}
&.date {
min-width: 60px;
width: 60px;
}
}
[hidden] {
display: none !important;
}
......@@ -39,7 +39,8 @@ function loadAfterConf() {
require(["../germline"],
function() {
require(["../generic_axis"],
require(["../generic_axis",
"../closeable"],
function() {
require(["../compare",
"../menu",
......@@ -69,8 +70,10 @@ function loadAfterConf() {
"../url",
"../autocomplete",
"../tips",
"../tokeniser",
// Speed test
"../speed_test",
"../form_builder",
"../../test/QUnit/testFiles/data_test",
], function(){
if (typeof main == "undefined"){
......
......@@ -124,26 +124,77 @@ VidjilAutoComplete.prototype = {
this.initCache(at);
this.dataUrls[at] = this.datasource.db_address + 'sample_set/auto_complete'
var callbacks = self.getDefaultCallbacks()
callbacks.matcher = function(flag, subtext) {
var regex = /([:0-9a-z_\[\]\(\)\-]+\s*)*/ig;
var match = subtext.match(regex);
if (match) {
var filtered = match.filter(function(word) {
return word.length > 0
});
if (filtered.length) {
return filtered[0];
}
return match[0];
}
return null;
}
callbacks.beforeSave = function(data) {
if (data.length == 1 && data[0] == VidjilAutoComplete.defaultLoadingData[0]) {
return data;
}
var res = $.map(data, function(i) {
return {
id: i.id,
name: i.name,
search: i.name
search: i.name,
set_type: i.type
};
});
return res;
};
callbacks.matcher = function(flag, subtext) {
var regex = new RegExp("[\\s\\S]+");
var match = regex.exec(subtext);
if (match) {
return match[0];
// code modified from atwho source
callbacks.highlighter = function(li, query) {
var mapper = {'p': 'patient',
'r': 'run',
's': 'generic'}
var set_type = li.charAt(5)
// encapsulate the string_id's set_type token (:p, :r, :s) within a span
li = li.replace(li.substr(4,2),
function(str) {
return '<span class="autocomplete_li ' + mapper[set_type] + '">' + str + '</span><span class="set_token '+ mapper[set_type] + '_token">';
});
li = li.replace('<li>', '<li class="' + mapper[set_type] + '_li">');
li = li.replace('</li>', '</span></li>');
var regexp;
if (!query) {
return li;
}
return null;
regexp = new RegExp(">([\\(\\)\\[\\]A-Za-z0-9\\-\\s]*)+(" + query.replace(/([\+\[\]\(\)\-])/g, function(str, s) { return "\\" + s; }) + ")([\\(\\)\\[\\]A-Za-z0-9\\s\\-]*)<", 'ig');
return li.replace(regexp, function(str, $1, $2, $3) {
return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
});
};
callbacks.beforeInsert = function(value, li) {
new Tokeniser().tokenise(value); // Tokeniser is a Singleton
return "";
};
callbacks.sorter = function(query, items) {
return items.sort(function(a, b){
if(a.id < b.id) {
return 1;
} else if (a.id == b.id) {
return 0
}
return -1;
});
};
$input.atwho({
......
function Closeable() {
}
Closeable.prototype = {
createCloseButton: function() {
var x = document.createElement('i');
x.className = "icon-cancel";
x.onclick = function() {
var elem = this.parentNode;
$(elem).slideUp({
'duration': 150,
'complete': function() {
elem.parentNode.removeChild(elem);
}
});
}
return x;
}
}
......@@ -49,7 +49,7 @@ function Com(default_console) {
}
}
this.data_id = "data-container"; //TODO
this.data_id = "modal data-container"; //TODO
this.DEBUG = 0
......@@ -199,7 +199,7 @@ Com.prototype = {
this.div_dataBox = document.createElement("div");
this.div_dataBox.className = "data-container";
this.div_dataBox.className = "modal data-container";
var closedataBox = document.createElement("span");
closedataBox.className = "closeButton" ;
......
This diff is collapsed.
This diff is collapsed.
......@@ -130,3 +130,69 @@ db.ajax_indicator_stop();
db.loadNotifications();
setTimeout(worker, NOTIFICATION_PERIOD);
})();
// This function was taken from https://gist.github.com/Rad1calDreamer/46407ccdef492511e80e
$.fn.serializeObject = function(){
var self = this,
json = {},
push_counters = {},
patterns = {
"validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
"key": /[a-zA-Z0-9_]+|(?=\[\])/g,
"push": /^$/,
"fixed": /^\d+$/,
"named": /^[a-zA-Z0-9_]+$/
};
this.build = function(base, key, value){
base[key] = value;
return base;
};
this.push_counter = function(key){
if(push_counters[key] === undefined){
push_counters[key] = 0;
}
return push_counters[key]++;
};
$.each($(this).serializeArray(), function(){
// skip invalid keys
if(!patterns.validate.test(this.name)){
return;
}
var k,
keys = this.name.match(patterns.key),
merge = this.value,
reverse_key = this.name;
while((k = keys.pop()) !== undefined){
// adjust reverse_key
reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');
// push
if(k.match(patterns.push)){
merge = self.build([], self.push_counter(reverse_key), merge);
}
// fixed
else if(k.match(patterns.fixed)){
merge = self.build([], k, merge);
}
// named
else if(k.match(patterns.named)){
merge = self.build({}, k, merge);
}
}
json = $.extend(true, json, merge);
});
return json;
};
......@@ -80,7 +80,7 @@ Model.prototype = {
//build infoBox
this.infoBox = document.createElement("div");
this.infoBox.className = "info-container";
this.infoBox.className = "modal info-container";
var closeinfoBox = document.createElement("span");
closeinfoBox.className = "closeButton" ;
......
/* This file is part of Vidjil <http://www.vidjil.org>,
* High-throughput Analysis of V(D)J Immune Repertoire.
* Copyright (C) 2013-2017 by Bonsai bioinformatics
* at CRIStAL (UMR CNRS 9189, Université Lille) and Inria Lille
* Contributors:
* Marc Duez <marc.duez@vidjil.org>
* The Vidjil Team <contact@vidjil.org>
*
* "Vidjil" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "Vidjil" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "Vidjil". If not, see <http://www.gnu.org/licenses/>
*/
function Tokeniser(target, form_input) {
if (typeof Tokeniser.instance === 'object') {
if (typeof target !== "undefined") {
Tokeniser.instance.target = target;
}
if (typeof form_input !== "undefined") {
Tokeniser.instance.form_input = form_input
}
return Tokeniser.instance;
}
Closeable.call(this);
this.target = target;
this.form_input = form_input
Tokeniser.instance = this;
return this;
}
Tokeniser.prototype = Object.create(Closeable.prototype);
Tokeniser.prototype.tokenise = function(text) {
var token = this.createToken(text);