From eb9acb2d71446fe21da9d09ac51db8cdb9c0bb6e Mon Sep 17 00:00:00 2001 From: Floreal Cabanettes <floreal.cabanettes@inra.fr> Date: Tue, 20 Feb 2018 16:37:24 +0100 Subject: [PATCH] Minify css and js in production --- minify-css.sh | 18 + minify-js.sh | 24 ++ .../static/css/{style.css => dgenies.css} | 0 src/dgenies/static/css/dgenies.min.css | 1 + src/dgenies/static/js/dgenies.min.js | 2 + src/dgenies/static/js/dgenies.result.min.js | 183 ++++++++++ src/dgenies/static/js/dgenies.run.min.js | 9 + src/dgenies/static/js/dgenies.status.min.js | 1 + .../static/js/jquery.fileupload.min.js | 337 ++++++++++++++++++ src/dgenies/templates/base.html | 14 +- src/dgenies/templates/result.html | 20 +- src/dgenies/templates/run.html | 19 +- src/dgenies/templates/status.html | 4 + src/dgenies/views.py | 5 +- 14 files changed, 617 insertions(+), 20 deletions(-) create mode 100755 minify-css.sh create mode 100755 minify-js.sh rename src/dgenies/static/css/{style.css => dgenies.css} (100%) create mode 100644 src/dgenies/static/css/dgenies.min.css create mode 100644 src/dgenies/static/js/dgenies.min.js create mode 100644 src/dgenies/static/js/dgenies.result.min.js create mode 100644 src/dgenies/static/js/dgenies.run.min.js create mode 100644 src/dgenies/static/js/dgenies.status.min.js create mode 100644 src/dgenies/static/js/jquery.fileupload.min.js diff --git a/minify-css.sh b/minify-css.sh new file mode 100755 index 0000000..d4dd977 --- /dev/null +++ b/minify-css.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +if [ ! $(which index.js) ] ; then + echo """ + ERROR: minifier is not installed! + + Install it through npm: + npm install minifier + + Then, add it to the PATH: + export PATH=\$PATH:~/node_modules/minifier + """ + exit 1 +fi + +cd src/dgenies/static/css + +index.js -o dgenies.min.css dgenies.css \ No newline at end of file diff --git a/minify-js.sh b/minify-js.sh new file mode 100755 index 0000000..e19b81b --- /dev/null +++ b/minify-js.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -e + +if [ ! $(which babel.js) ] ; then + echo """ + ERROR: babel is not installed! + + Install it through npm: + npm install --save-dev babel-cli + + Then, add it to the PATH: + export PATH=\$PATH:~/node_modules/babel-cli/bin + """ + exit 1 +fi + +cd src/dgenies/static/js + +babel.js -o dgenies.min.js --compact --minified dgenies.js dgenies.prototypes.js +babel.js -o dgenies.result.min.js --compact --minified dgenies.result.js dgenies.result.controls.js dgenies.result.export.js dgenies.result.summary.js d3.boxplot.js d3.boxplot.events.js d3.boxplot.mousetip.js d3.boxplot.zoom.js +babel.js -o jquery.fileupload.min.js --compact --minified jquery.fileupload.js jquery.fileupload-process.js jquery.fileupload-validate.js +babel.js -o dgenies.run.min.js --compact --minified dgenies.run.js +babel.js -o dgenies.status.min.js --compact --minified dgenies.status.js \ No newline at end of file diff --git a/src/dgenies/static/css/style.css b/src/dgenies/static/css/dgenies.css similarity index 100% rename from src/dgenies/static/css/style.css rename to src/dgenies/static/css/dgenies.css diff --git a/src/dgenies/static/css/dgenies.min.css b/src/dgenies/static/css/dgenies.min.css new file mode 100644 index 0000000..49f56f0 --- /dev/null +++ b/src/dgenies/static/css/dgenies.min.css @@ -0,0 +1 @@ +body{font-size:14px;font-family:sans-serif;padding-top:50px}#body{max-width:850px}.navbar-brand{padding-left:45px;background:url(images/logo.svg) no-repeat 0 5px;background-size:40px 40px}#legend{width:100%;height:230px;border:none;margin-bottom:10px;margin-left:10px;margin-top:40px}label.input-checkbox-label input[type=checkbox]{position:relative;vertical-align:middle;bottom:1px}#main-bar-title{background-color:black;color:white;padding-left:10px;margin-bottom:5px}#main-bar-title h1{margin-top:0;margin-bottom:0;margin-left:10px;padding-top:10px;padding-bottom:10px}#main-bar-title h1,#main-bar-title img{display:inline-block;vertical-align:middle;width:auto}#legend .draw{width:100%;height:200px}#legend .title{width:60%;height:30px;text-align:center;font-size:12pt;font-weight:bold;font-family:sans-serif;text-decoration:underline}#legend .draw{width:60%}#draw,#sidebar{display:table-cell;vertical-align:top}#sidebar{min-width:120px;max-width:165px}#sidebar input[type=number]{width:100px}#sidebar label{font-weight:normal!important}#sidebar input[type=button],#sidebar input[type=range],#sidebar input[type=number],#sidebar label{width:100%!important}#supdraw{width:auto;height:auto;position:relative;margin-top:5px}#draw{width:850px}.mylabel{font-size:18pt;font-weight:bold;font-family:FreeSans,sans-serif;top:10pt;position:absolute}#restore-all{width:5%!important;height:5%!important;top:0;right:0;position:absolute;background:#fff url(images/reset.svg) no-repeat 6.5px 7.5px;background-size:65% 65%;cursor:pointer;border:solid 1px black;border-radius:0 15px 0 0}#restore-all:hover{background:#000 url(images/reset_hover.svg) no-repeat 6.5px 7.5px;background-size:65% 65%}#loading{position:absolute;left:calc(50% - 140px);top:calc(50% - 48px)}#loading .label{color:black;display:inline-block;padding-left:55px;padding-right:5px;margin-left:-30px;height:50px;width:180px;background:white;border:1px solid black;border-radius:25px;font-size:20pt;font-weight:bold;vertical-align:middle}.cssload-container{position:relative;display:inline-block;padding-top:-20px;vertical-align:middle}.cssload-whirlpool,.cssload-whirlpool::before,.cssload-whirlpool::after{position:absolute;top:50%;left:50%;border:1px solid rgb(204,204,204);border-left-color:rgb(0,0,0);border-radius:674px;-o-border-radius:674px;-ms-border-radius:674px;-webkit-border-radius:674px;-moz-border-radius:674px}.cssload-whirlpool{margin:-17px 0 0 -17px;height:34px;width:34px;animation:cssload-rotate 1150ms linear infinite;-o-animation:cssload-rotate 1150ms linear infinite;-ms-animation:cssload-rotate 1150ms linear infinite;-webkit-animation:cssload-rotate 1150ms linear infinite;-moz-animation:cssload-rotate 1150ms linear infinite}.cssload-whirlpool::before{content:"";margin:-16px 0 0 -16px;height:30px;width:30px;animation:cssload-rotate 1150ms linear infinite;-o-animation:cssload-rotate 1150ms linear infinite;-ms-animation:cssload-rotate 1150ms linear infinite;-webkit-animation:cssload-rotate 1150ms linear infinite;-moz-animation:cssload-rotate 1150ms linear infinite}.cssload-whirlpool::after{content:"";margin:-20px 0 0 -20px;height:38px;width:38px;animation:cssload-rotate 2300ms linear infinite;-o-animation:cssload-rotate 2300ms linear infinite;-ms-animation:cssload-rotate 2300ms linear infinite;-webkit-animation:cssload-rotate 2300ms linear infinite;-moz-animation:cssload-rotate 2300ms linear infinite}@keyframes cssload-rotate{100%{transform:rotate(360deg)}}@-o-keyframes cssload-rotate{100%{-o-transform:rotate(360deg)}}@-ms-keyframes cssload-rotate{100%{-ms-transform:rotate(360deg)}}@-webkit-keyframes cssload-rotate{100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes cssload-rotate{100%{-moz-transform:rotate(360deg)}}@media screen and (-webkit-min-device-pixel-ratio:0){Body{font-size:16px}}.form-group,.form-group input{margin-bottom:5px!important}div.submit-form fieldset{margin-bottom:10px}h2.title-launch{margin-bottom:20px}.form-group input[type=text],.form-group input[type=email]{width:300px}#body{margin-left:15px;margin-top:10px}.errors-submit ul li{background-color:#ff756b;border:solid 2px #7c0000;margin-bottom:5px;padding:3px;list-style-type:none;font-weight:bold}.errors-submit ul{padding:0;width:460px}html,body{height:100%}#main-wrapper{position:relative;padding-bottom:55px;min-height:100%}footer{position:absolute;bottom:0;height:55px;background:white}footer hr{margin-top:0}.notifyjs-corner{top:50px!important}div.top-forms{position:relative;width:810px}form#select-zone{margin-bottom:5px;margin-left:40px}div.top-forms select,div.top-forms input{height:28px}form#select-zone div.chosen-widget,form#select-zone input[type=button]{display:inline-block;vertical-align:middle}form#select-zone input[type=button]{line-height:100%}div.chosen-container{width:200px!important}a.chosen-single{height:30px!important;line-height:30px!important;font-size:11pt!important}a.chosen-single div b{background-position-y:4px!important}form#form-parameters{margin-top:20px;margin-left:15px}form#export{position:absolute;top:0;right:0}span.tip{position:absolute;z-index:2;display:none;font-size:12pt;height:auto;padding:10px;border-radius:3px;box-shadow:0 1px 2px #666;background:#ededed}table.drawtooltip td.tt-label{padding-right:5px;vertical-align:middle;font-weight:bold}#body-container{max-width:100%!important}div.navbar{background-image:linear-gradient(to bottom,#2B3044 0,#141a30 100%)}div.submit-form table td{padding-bottom:8px;vertical-align:bottom}div.submit-form table td label{padding-right:20px}div.submit-form table input#id_job,div.submit-form table input#email{width:410px}.input-group{display:inline-block}.input-group .input-group-btn,.input-group input{display:inline-block!important;position:relative!important;float:none!important}.input-group button{padding-top:0}div.input-group{padding-left:15px!important}.upload-btn-wrapper{position:relative;height:30px;width:42px;overflow:hidden;display:inline-block}button.btn-file{height:30px;width:42px}div.in-label{position:relative;display:inline-block;width:300px;height:30px;vertical-align:middle}div.progress{width:300px;height:30px;position:absolute;top:0;left:0;z-index:5!important;background:white;margin-bottom:0!important;box-shadow:none}div.progress .bar{height:100%;background:#33b234;z-index:5!important}select.select-type-input,.input-group button,.input-group input{height:30px;line-height:30px}input.show-file{padding-left:2px;padding-right:2px;width:auto;z-index:10!important;background:none!important;color:black}div.hidden-input-files{display:none}label.error{color:red}div.loading-file{display:inline-block;vertical-align:middle;width:30px;height:30px;background:url(images/loading1.gif) no-repeat 0 0;background-size:30px 30px}div.upload-success{display:inline-block;vertical-align:middle;width:30px;height:30px;background:url(images/success.svg) no-repeat 0 0;background-size:30px 30px}div.file-size{display:inline-block;vertical-align:middle;margin-left:10px}div#uploading-loading{height:30px;line-height:30px;width:200px;font-size:14pt;font-weight:bold;text-align:center;color:black}div.progress,input.show-file{width:100%!important}div.in-label{width:300px}div.submit-form table input[type=text],div.submit-form table input[type=email]{border:1px solid #A9A9A9;border-image:none}div.submit-form table input,div.submit-form button,div.submit-form select{border-radius:5px!important;-moz-border-radius:5px!important;-webkit-border-radius:5px!important;height:30px;outline:none!important}div.submit-form select:hover{border-radius:5px 5px 0 0!important;-moz-border-radius:5px 5px 0 0!important;-webkit-border-radius:5px 5px 0 0!important;outline:none!important}.beta-warning{height:30px;line-height:30px;text-align:center;color:white;background-color:#6e0000}.beta-warning a{color:white;font-weight:bold}h2.status{font-size:18pt;margin-bottom:15px;margin-top:10px}.status-body{margin-top:25px;margin-bottom:30px}.progress-status{position:relative;width:500px;height:30px;border:solid 1px black;margin-left:55px;margin-bottom:100px}.progress-status-bar .inner{background:linear-gradient(90deg,rgb(255,254,80) 0%,rgba(16,128,6,1) 100%);width:500px;height:100%}.progress-status-bar{position:absolute;width:0;height:28px;top:0;left:0;overflow:hidden}.progress-status-bar.getfiles,.progress-status-bar.getfiles-waiting{width:3.7%}.progress-status-bar.waiting{width:7%}.progress-status-bar.preparing,.progress-status-bar.prepare-scheduled,.progress-status-bar.preparing-cluster{width:10.7%}.progress-status-bar.prepared{width:20.4%}.progress-status-bar.scheduled{width:30.3%}.progress-status-bar.starting,.progress-status-bar.scheduled-cluster{width:35.2%}.progress-status-bar.started{width:40.3%}.progress-status-bar.merging{width:80.4%}.progress-status-bar.success,.progress-status-bar.fail,.progress-status-bar.no-match{width:100%}.progress-status-bar.fail .inner{background:rgb(195,16,18)}.progress-status .tick{position:absolute;top:29px;width:1px;height:10px;border:solid 1px black}.progress-status .tick p{transform:rotate(-45deg);margin-left:-70px;margin-top:35px;text-align:right;display:block;width:80px;overflow:hidden}.progress-status .tick.submitted{left:-1px}.progress-status .tick.prepared{left:20%}.progress-status .tick.scheduled{left:30%}.progress-status .tick.started{left:40%}.progress-status .tick.merging{left:80%}.progress-status .tick.success{right:-1px}h2.status,div.status-body{margin-left:55px}div#sidebar{position:relative}div#sidebar p.bottom{position:absolute;bottom:0;right:0;width:100px}div#sidebar p.bottom input#delete-job{background:#ffbba8!important}ul.nav ul.dropdown-menu{max-height:300px;overflow-y:auto} \ No newline at end of file diff --git a/src/dgenies/static/js/dgenies.min.js b/src/dgenies/static/js/dgenies.min.js new file mode 100644 index 0000000..5d0a233 --- /dev/null +++ b/src/dgenies/static/js/dgenies.min.js @@ -0,0 +1,2 @@ +dgenies={};dgenies.loading="#loading";dgenies.noise=true;dgenies.mode="webserver";dgenies.init=function(all_jobs,mode){dgenies.mode=mode;let cookies=$.cookie("results");if(mode==="webserver"){cookies=cookies!==undefined&&cookies.length>0?cookies.split("|"):[]}else{cookies=all_jobs;dgenies.save_cookies(cookies)}dgenies.update_results(cookies)};dgenies.save_cookies=function(cookies){$.cookie("results",cookies.join("|"),{path:"/"})};dgenies.update_results=function(results){let job_list_item=$("ul.nav li.result ul");job_list_item.html("");if(results.length>0){for(let i=0;i<results.length;i++){let result=results[i];job_list_item.append($("<li>").append($("<a>").attr("href",`/result/${result}`).text(result)))}}else{job_list_item.append($("<li>").append($("<a>").attr("href","/run").text("Please run a job!")))}};dgenies.notify=function(text,type="warning",delay=5000){$.notify({message:text},{type:type,placement:{from:"top",align:"center"},delay:delay,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},offset:55,newest_on_top:true})};dgenies.show_loading=function(message="Loading...",width=118){$("input,select").prop("disabled",true);d3.boxplot.all_disabled=true;$(dgenies.loading).find(".mylabel").html(message);$(dgenies.loading).find(".label").width(width);$(dgenies.loading).show();$(dgenies.loading).position({my:"center center",at:"center center",of:"#draw",collistion:"fit"})};dgenies.hide_loading=function(){$("input,select").prop("disabled",false);d3.boxplot.all_disabled=false;$(dgenies.loading).hide();dgenies.reset_loading_message()};dgenies.set_loading_message=function(message){$(dgenies.loading).find(".mylabel").html(message)};dgenies.reset_loading_message=function(){$(dgenies.loading).find(".mylabel").html("Loading...");$(dgenies.loading).find(".label").width(118)};dgenies.fill_select_zones=function(x_targets,y_contigs){let select_contig=$("select#select-contig");select_contig.find("option[value!='###NONE###']").remove();for(let i=0;i<y_contigs.length;i++){let label=y_contigs[i];let value=label;if(label.startsWith("###MIX###")){let parts=label.substr(10).split("###");label="Mix: "+parts.slice(0,3).join(", ");if(parts.length>3){label+=", ..."}}select_contig.append($("<option>",{value:value,text:label}))}select_contig.chosen({disable_search_threshold:10,search_contains:true});select_contig.trigger("chosen:updated");let select_target=$("select#select-target");select_target.find("option[value!='###NONE###']").remove();for(let i=0;i<x_targets.length;i++){let label=x_targets[i];let value=label;if(label.startsWith("###MIX###")){let parts=label.substr(10).split("###");label="Mix: "+parts.slice(0,3).join(", ");if(parts.length>3){label+=", ..."}}select_target.append($("<option>",{value:value,text:label}))}select_target.chosen({disable_search_threshold:10,search_contains:true});select_target.trigger("chosen:updated")};dgenies.numberWithCommas=function(x){return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")};dgenies.ajax=function(url,data,success,error,method="POST"){$.ajax(url,{method:method,data:data,success:success,error:error||function(){dgenies.hide_loading();dgenies.notify("An error occurred! Please contact us to report the bug","danger")}})};dgenies.post=function(url,data,success,error,async=true){dgenies.ajax({url:url,data:data,success:success,error:error,type:"POST",async:async})};dgenies.get=function(url,data,success,error){dgenies.ajax(url,data,success,error,"GET")}; +String.prototype.rsplit=function(sep,maxsplit){let split=this.split(sep);return maxsplit?[split.slice(0,-maxsplit).join(sep)].concat(split.slice(-maxsplit)):split}; diff --git a/src/dgenies/static/js/dgenies.result.min.js b/src/dgenies/static/js/dgenies.result.min.js new file mode 100644 index 0000000..25721e0 --- /dev/null +++ b/src/dgenies/static/js/dgenies.result.min.js @@ -0,0 +1,183 @@ +if(!dgenies){throw"dgenies wasn't included!"}dgenies.result={};// GLOBAL VARIABLES: +dgenies.result.id_res=null;dgenies.result.init=function(id_res){dgenies.result.id_res=id_res;dgenies.result.add_to_list();d3.boxplot.init()};dgenies.result.add_to_list=function(){console.log("pass",dgenies.result.id_res);let cookies=$.cookie("results");cookies=cookies!==undefined?cookies.split("|"):[];console.log(cookies);if(cookies.indexOf(dgenies.result.id_res)===-1){console.log("oui");cookies.splice(0,0,dgenies.result.id_res);dgenies.save_cookies(cookies);dgenies.update_results(cookies)}};dgenies.result.remove_job_from_cookie=function(job){let cookies=$.cookie("results");cookies=cookies!==undefined?cookies.split("|"):[];let index=cookies.indexOf(job);let need_update=false;if(index>-1){need_update=true;cookies.splice(index,1)}$.cookie("results",cookies.join("|"),{path:"/"});if(need_update){dgenies.update_results(cookies)}}; +if(!dgenies||!dgenies.result){throw"dgenies.result wasn't included!"}dgenies.result.controls={};dgenies.result.controls.init=function(){$("#sort-contigs").click(dgenies.result.controls.launch_sort_contigs);$("#hide-noise").click(dgenies.result.controls.launch_hide_noise);$("#summary").click(dgenies.result.controls.summary);$("#delete-job").click(dgenies.result.controls.delete_job);$("form#select-zone input.submit").click(dgenies.result.controls.select_zone);$("form#export select").change(dgenies.result.export.export)};dgenies.result.controls.summary=function(){dgenies.show_loading("Building...");window.setTimeout(()=>{dgenies.post(`/summary/${dgenies.result.id_res}`,{},function(data){dgenies.hide_loading();if(data["success"]){if(data["status"]==="done"){dgenies.result.summary.show(data["percents"])}else if(data["status"]==="waiting"){dgenies.result.controls.summary()}}else{dgenies.notify(data["message"]||"An error occurred! Please contact us to report the bug","danger")}})},0)};dgenies.result.controls.launch_sort_contigs=function(){d3.boxplot.zoom.reset_scale();window.setTimeout(()=>{dgenies.show_loading("Building...");window.setTimeout(()=>{dgenies.post(`/sort/${dgenies.result.id_res}`,{},function(data){if(data["success"]){dgenies.reset_loading_message();window.setTimeout(()=>{d3.boxplot.launch(data,true)},0)}else{dgenies.hide_loading();dgenies.notify(data["message"]||"An error occurred! Please contact us to report the bug","danger")}})},0)},0)};dgenies.result.controls.launch_reverse_contig=function(){if(d3.boxplot.query_selected!==null){d3.boxplot.zoom.reset_scale();window.setTimeout(()=>{dgenies.show_loading("Building...");window.setTimeout(()=>{dgenies.post(`/reverse-contig/${dgenies.result.id_res}`,{"contig":d3.boxplot.query_selected},function(data){if(data["success"]){dgenies.reset_loading_message();window.setTimeout(()=>{d3.boxplot.launch(data,true)},0)}else{dgenies.hide_loading();dgenies.notify(data["message"]||"An error occurred! Please contact us to report the bug","danger")}})},0)},0)}else{dgenies.notify("Error: no query selected. Please contact us to report the bug","danger")}};dgenies.result.controls.launch_hide_noise=function(){d3.boxplot.zoom.reset_scale();window.setTimeout(()=>{dgenies.show_loading("Building...");window.setTimeout(()=>{dgenies.post(`/freenoise/${dgenies.result.id_res}`,{noise:dgenies.noise?0:1},function(data){if(data["success"]){dgenies.noise=!dgenies.noise;dgenies.reset_loading_message();window.setTimeout(()=>{d3.boxplot.launch(data,true,true)},0)}else{dgenies.hide_loading();dgenies.notify(data["message"]||"An error occurred! Please contact us to report the bug","danger")}})},0)},0)};dgenies.result.controls.select_zone=function(){let contig_select=$("#select-contig").find(":selected");let target_select=$("#select-target").find(":selected");if(contig_select.val()!=="###NONE###"&&target_select.val()!=="###NONE###"){d3.boxplot.select_zone(null,null,target_select.val(),contig_select.val(),true)}else{dgenies.notify("Please select zones into zoom!","danger",2000)}};dgenies.result.controls.do_delete_job=function(){dgenies.post(`/delete/${dgenies.result.id_res}`,{},function(data){if(data["success"]){dgenies.notify("Your job has been deleted!","success",1500);window.setTimeout(()=>{dgenies.result.remove_job_from_cookie(dgenies.result.id_res);window.location="/"},1500)}else{dgenies.notify("error"in data?data["error"]:"An error has occurred. Please contact the support","danger")}})};dgenies.result.controls.delete_job=function(){let dialog=$("<div>").attr("id","dialog-confirm").attr("title","Delete job?");let icon=$("<span>").attr("class","ui-icon ui-icon-help").css("float","left").css("margin","12px 12px 20px 0");let body=$("<p>");body.append(icon);body.append("Confirm deletion of this job? This operation is definitive.");dialog.append(body);dialog.dialog({resizable:false,height:"auto",width:500,modal:true,buttons:{"Yes":function(){$(this).dialog("close");dgenies.result.controls.do_delete_job()},"No":function(){$(this).dialog("close")}}})}; +if(!dgenies||!dgenies.result){throw"dgenies.result wasn't included!"}dgenies.result.export={};dgenies.result.export.get_svg=function(){return"<svg width='5000px' height='5000px' viewBox='0 0 100 100'>"+$("#draw-in").find(">svg").html()+"</svg>"};dgenies.result.export.save_file=function(blob,format){dgenies.hide_loading();saveAs(blob,`map_${d3.boxplot.name_y}_to_${d3.boxplot.name_x}.${format}`)};dgenies.result.export.export_png=function(){dgenies.show_loading("Building picture...",210);window.setTimeout(()=>{let export_div=$("div#export-pict");export_div.html("").append($("<canvas>"));canvg(export_div.find("canvas")[0],dgenies.result.export.get_svg());let canvas=export_div.find("canvas")[0];canvas.toBlob(function(blob){dgenies.result.export.save_file(blob,"png");export_div.html("")},"image/png")},0)};dgenies.result.export.export_svg=function(){dgenies.show_loading("Building picture...",180);window.setTimeout(()=>{let transform=d3.boxplot.container.attr("transform");let after=function(){let blob=new Blob([dgenies.result.export.get_svg()],{type:"image/svg+xml"});d3.boxplot.zoom.restore_scale(transform);dgenies.result.export.save_file(blob,"svg")};d3.boxplot.zoom.reset_scale(true,after)},0)};dgenies.result.export.export_paf=function(){let export_div=$("div#export-pict");export_div.html("");export_div.append($("<a>").attr("href",`/paf/${dgenies.result.id_res}`).attr("download",`map_${d3.boxplot.name_y}_to_${d3.boxplot.name_x}.paf`).attr("id","my-download").text("download"));dgenies.hide_loading();document.getElementById("my-download").click()};dgenies.result.export.dl_fasta=function(gzip=false){let export_div=$("div#export-pict");export_div.html("");export_div.append($("<a>").attr("href",`/fasta-query/${dgenies.result.id_res}`).attr("download",d3.boxplot.name_y+(gzip?".fasta.gz":".fasta")).attr("id","my-download").text("download"));dgenies.hide_loading();document.getElementById("my-download").click()};dgenies.result.export.export_fasta=function(compress=false){dgenies.show_loading("Building file...",180);dgenies.post("/get-fasta-query/"+dgenies.result.id_res,{gzip:compress},function(data,success){if(data["status"]===0){window.setTimeout(()=>{dgenies.result.export.export_fasta()},10000)}else if(data["status"]===2){dgenies.result.export.dl_fasta(data["gzip"])}else if(data["status"]===1){dgenies.hide_loading();dgenies.notify("We are building your Fasta file. You will receive by mail a link to download it soon!","info")}else{dgenies.hide_loading();dgenies.notify("An error has occurred. Please contact us to report the bug","danger")}})};dgenies.result.export.ask_export_fasta=function(){let dialog=$("<div>").attr("id","dialog-confirm").attr("title","Gzip?");let icon=$("<span>").attr("class","ui-icon ui-icon-help").css("float","left").css("margin","12px 12px 20px 0");let body=$("<p>");body.append(icon);body.append("Compression is recommanded on slow connections. Download Gzip file?");dialog.append(body);dialog.dialog({resizable:false,height:"auto",width:500,modal:true,buttons:{"Use default":function(){$(this).dialog("close");dgenies.result.export.export_fasta(false)},"Use Gzip":function(){$(this).dialog("close");dgenies.result.export.export_fasta(true)},Cancel:function(){$(this).dialog("close")}}})};dgenies.result.export.export_association_table=function(){let export_div=$("div#export-pict");export_div.html("");export_div.append($("<a>").attr("href",`/qt-assoc/${dgenies.result.id_res}`).attr("download",d3.boxplot.name_y+"_"+d3.boxplot.name_x+"_assoc.tsv").attr("id","my-download").text("download"));dgenies.hide_loading();document.getElementById("my-download").click()};dgenies.result.export.export_no_association_file=function(to){window.setTimeout(()=>{dgenies.show_loading("Building file...",180);let on=to==="query"?"target":"query";dgenies.post("/no-assoc/"+dgenies.result.id_res,{"to":to},function(data,success){dgenies.hide_loading();if(!data["empty"]){let blob=new Blob([data["file_content"]],{type:"text/plain"});saveAs(blob,`no_${to}_matches_${d3.boxplot.name_y}_to_${d3.boxplot.name_x}.txt`)}else{dgenies.notify(`No contigs in ${to} have None match with any ${on}!`,"success")}})},0)};dgenies.result.export.export_query_as_reference_fasta_webserver=function(){dgenies.post(`/build-query-as-reference/${dgenies.result.id_res}`,{},function(data,success){if(data["success"]){dgenies.notify("You will receive a mail soon with the link to download your Fasta file","success")}else{dgenies.notify(`An error has occurred. Please contact the support`,"danger")}})};dgenies.result.export.export_query_as_reference_fasta_standalone=function(){dgenies.show_loading("Building file...",180);window.setTimeout(()=>{dgenies.post(`/build-query-as-reference/${dgenies.result.id_res}`,{},function(data,success){if(data["success"]){let export_div=$("div#export-pict");export_div.html("");export_div.append($("<a>").attr("href",`/get-query-as-reference/${dgenies.result.id_res}`).attr("download",`as_reference_${d3.boxplot.name_y}.fasta`).attr("id","my-download").text("download"));document.getElementById("my-download").click();dgenies.hide_loading()}else{dgenies.notify(`An error has occurred. Please contact the support`,"danger")}})},0)};dgenies.result.export.export=function(){let select=$("form#export select");let selection=parseInt(select.val());window.setTimeout(()=>{if(selection>0){let async=false;if(selection===1){dgenies.result.export.export_svg();async=true}else if(selection===2){dgenies.result.export.export_png();async=true}else if(selection===3)dgenies.result.export.export_paf();else if(selection===4){dgenies.result.export.ask_export_fasta();async=true}else if(selection===5){dgenies.result.export.export_association_table()}else if(selection===6){dgenies.result.export.export_no_association_file("query");async=true}else if(selection===7){dgenies.result.export.export_no_association_file("target");async=true}else if(selection===8){if(dgenies.mode==="webserver"){dgenies.result.export.export_query_as_reference_fasta_webserver()}else{dgenies.result.export.export_query_as_reference_fasta_standalone();async=true}}else dgenies.notify("Not supported yet!","danger",2000);if(!async)dgenies.hide_loading();select.val("0")}},0)}; +if(!dgenies||!dgenies.result){throw"dgenies.result wasn't included!"}dgenies.result.summary={};dgenies.result.summary.show=function(percents){console.log(percents);let svgcontainer=d3.select("#draw-stats").html("").append("svg:svg").attr("width","500px").attr("height","220px");let container=svgcontainer.append("svg:g");let percents_order=["-1","0","1","2","3"];let x=0;let percent_value=0;for(let i in percents_order){let percent=percents_order[i];let label="";switch(percent){case"-1":label="No match";break;case"0":label="< 25 %";break;case"1":label="< 50 %";break;case"2":label="< 75 %";break;case"3":label="> 75 %";break;}console.log(percent);x+=percent_value;percent_value=percent in percents?percents[percent]:0;container.append("rect").attr("x",x+"%").attr("y",0).attr("width",percent_value+"%").attr("height","50px").attr("stroke","none").attr("fill",d3.boxplot.color_idy[d3.boxplot.color_idy_theme][percent]);container.append("rect").attr("x",5).attr("y",70+i*30).attr("width","10px").attr("height","10px").attr("fill",d3.boxplot.color_idy[d3.boxplot.color_idy_theme][percent]).style("stroke","#000").style("stroke-width","1px");container.append("text").attr("x",30).attr("y",82+i*30).attr("font-family","sans-serif").attr("font-size","12pt").text(label+":");container.append("text").attr("x",110).attr("y",82+i*30).attr("font-family","sans-serif").attr("font-size","12pt").text(percent_value.toFixed(2)+" %")}container.append("rect").attr("x",0).attr("y",0).attr("width","100%").attr("height","50px").style("stroke","#000").style("fill","none").style("stroke-width","1px");$("#modal-stats").dialog({title:"Summary of identity",width:"550px",buttons:[{text:"Export PNG",click:dgenies.result.summary.export_png},{text:"Export SVG",click:dgenies.result.summary.export_svg},{text:"Close",click:function(){$(this).dialog("close")}}]})};dgenies.result.summary.get_svg=function(){return $("#draw-stats").html()};dgenies.result.summary.save_file=function(blob,format){saveAs(blob,`summary_${d3.boxplot.name_y}_to_${d3.boxplot.name_x}.${format}`)};dgenies.result.summary.export_svg=function(){let blob=new Blob([dgenies.result.summary.get_svg()],{type:"image/svg+xml"});dgenies.result.summary.save_file(blob,"svg")};dgenies.result.summary.export_png=function(){let export_div=$("div#export-pict");export_div.html("").append($("<canvas>"));canvg(export_div.find("canvas")[0],dgenies.result.summary.get_svg());let canvas=export_div.find("canvas")[0];canvas.toBlob(function(blob){dgenies.result.summary.save_file(blob,"png");export_div.html("")},"image/png")}; +if(!d3){throw"d3 wasn't included!"}d3.boxplot={};//GLOBAL VARIABLES: +d3.boxplot.svgcontainer=null;d3.boxplot.container=null;d3.boxplot.svgsupercontainer=null;d3.boxplot.name_x=null;d3.boxplot.name_y=null;d3.boxplot.lines=null;d3.boxplot.x_len=null;d3.boxplot.y_len=null;d3.boxplot.x_zones=null;d3.boxplot.y_zones=null;d3.boxplot.zoom_enabled=true;d3.boxplot.all_disabled=false;d3.boxplot.min_idy=0;d3.boxplot.max_idy=0;d3.boxplot.zone_selected=false;d3.boxplot.query_selected=null;//For translations: +d3.boxplot.translate_start=null;d3.boxplot.posX=null;d3.boxplot.posY=null;d3.boxplot.old_translate=null;//Graphical parameters: +d3.boxplot.scale=1000;d3.boxplot.content_lines_width=d3.boxplot.scale/400;d3.boxplot.break_lines_width=d3.boxplot.scale/1500;d3.boxplot.color_idy_theme="default";d3.boxplot.color_idy_themes=["default","colorblind","black&white"];d3.boxplot.color_idy={"default":{"3":"#094b09","2":"#2ebd40","1":"#d5670b","0":"#ffd84b","-1":"#fff"},"colorblind":{"3":"#000","2":"#006DDB","1":"#DB6E00","0":"#FFB677","-1":"#fff"},"black&white":{"3":"#000","2":"#626262","1":"#9c9c9c","0":"#DDDCDC","-1":"#fff"}};d3.boxplot.limit_idy=null;d3.boxplot.min_idy_draw=0;d3.boxplot.min_size=0;d3.boxplot.linecap="round";d3.boxplot.background_axis="#f4f4f4";d3.boxplot.break_lines_color="#7c7c7c";d3.boxplot.break_lines_dash="3, 3";d3.boxplot.break_lines_show=true;d3.boxplot.zoom_scale_lines=1;// Zoom scale used for lines width +d3.boxplot.tick_width=0.5;d3.boxplot.color_mixes="#969696";//Filter sizes: +d3.boxplot.min_sizes=[0,0.01,0.02,0.03,0.05,1,2];d3.boxplot.init=function(id_res=null,from_file=false){if(id_res===null){id_res=dgenies.result.id_res}$("#form-parameters")[0].reset();$("form#select-zone")[0].reset();if(!from_file){dgenies.post("/get_graph",{"id":id_res},function(data){if(data["success"]){d3.boxplot.launch(data)}else{$("#supdraw").html($("<p>").html("This job does not exist!").css("margin-top","15px"));dgenies.result.remove_job_from_cookie(dgenies.result.id_res)}})}else{dgenies.get(id_res,{},function(data){d3.boxplot.launch(data)})}};d3.boxplot.launch=function(res,update=false,noise_change=false){dgenies.fill_select_zones(res["x_order"],res["y_order"]);if(res["sorted"]){$("input#sort-contigs").val("Undo sort");$("#export").find("select option[value=4]").show();$("#export").find("select option[value=8]").show()}else{$("input#sort-contigs").val("Sort contigs");$("#export").find("select option[value=4]").hide();$("#export").find("select option[value=8]").hide()}d3.boxplot.name_x=res["name_x"];d3.boxplot.name_y=res["name_y"];if(d3.boxplot.name_x===d3.boxplot.name_y){$("input#sort-contigs").hide()}else{$("input#sort-contigs").show()}d3.boxplot.lines=res["lines"];d3.boxplot.x_len=res["x_len"];d3.boxplot.y_len=res["y_len"];d3.boxplot.min_idy=res["min_idy"];d3.boxplot.max_idy=res["max_idy"];d3.boxplot.limit_idy=res["limit_idy"];if(!noise_change){dgenies.noise=true}$("#hide-noise").val(dgenies.noise?"Hide noise":"Show noise");d3.boxplot.draw(res["x_contigs"],res["x_order"],res["y_contigs"],res["y_order"]);if(!update){$("div#draw").resizable({aspectRatio:true});d3.boxplot.events.init();dgenies.result.controls.init()}if(res["sampled"]){let max_nb_lines=dgenies.numberWithCommas(res["max_nb_lines"].toString());dgenies.notify(`<div style="text-align: center"><b>There are too much matches.\nOnly the ${max_nb_lines} best matches are displayed</b></div>`)}d3.boxplot.mousetip.init()};d3.boxplot.select_target=function(x){for(let zone in d3.boxplot.x_zones){if(d3.boxplot.x_zones[zone][0]<x&&x<=d3.boxplot.x_zones[zone][1]){return zone}}return null};d3.boxplot.select_query=function(y){for(let zone in d3.boxplot.y_zones){if(d3.boxplot.y_zones[zone][0]<y&&y<=d3.boxplot.y_zones[zone][1]){return zone}}return null};d3.boxplot.select_zone=function(x=null,y=null,x_zone=null,y_zone=null,force=false){d3.boxplot.mousetip.hide();dgenies.show_loading();window.setTimeout(()=>{if(!d3.boxplot.zone_selected||force){if(x_zone===null){//Search zone for X axis: +x_zone=d3.boxplot.select_target(x)}if(y_zone===null){//Search zone for Y axis: +y_zone=d3.boxplot.select_query(y)}d3.boxplot.zone_selected=[x_zone,y_zone];//Compute X and Y scales to zoom into zone: +let x_len_zone=d3.boxplot.x_zones[x_zone][1]-d3.boxplot.x_zones[x_zone][0];let y_len_zone=d3.boxplot.y_zones[y_zone][1]-d3.boxplot.y_zones[y_zone][0];let scale_x=d3.boxplot.scale/x_len_zone;let scale_y=d3.boxplot.scale/y_len_zone;// +// let lines_s = []; +// +// let my_x_zone = [d3.boxplot.x_zones[x_zone][0] / d3.boxplot.scale * d3.boxplot.x_len, d3.boxplot.x_zones[x_zone][1] / d3.boxplot.scale * d3.boxplot.x_len]; +// let my_y_zone = [d3.boxplot.y_zones[y_zone][0] / d3.boxplot.scale * d3.boxplot.y_len, d3.boxplot.y_zones[y_zone][1] / d3.boxplot.scale * d3.boxplot.y_len]; +// +// for (let l in d3.boxplot.lines) { +// let line = d3.boxplot.lines[l].slice(0); +// if (((line[0] >= my_x_zone[0] && line[0] < my_x_zone[1]) || (line[1] >= my_x_zone[0] && line[1] < my_x_zone[1])) +// && ((line[2] >= my_y_zone[0] && line[2] < my_y_zone[1]) || +// (line[3] >= my_y_zone[0] && line[3] < my_y_zone[1]))) { +// //console.log(line); +// line[0] -= my_x_zone[0]; +// line[1] -= my_x_zone[0]; +// line[2] -= my_y_zone[0]; +// line[3] -= my_y_zone[0]; +// if (line[1] < 0) +// console.log("WARN!!!", line[0]); +// //console.log(line); +// lines_s.push(line); +// } +// } +// +// d3.selectAll("line.content-lines").remove(); +// d3.boxplot.draw_lines(lines_s, my_x_zone[1] - my_x_zone[0], my_y_zone[1] - my_y_zone[0]); +//Zoom in: +d3.boxplot.container.attr("transform","scale("+scale_x+","+scale_y+")"+"translate(-"+d3.boxplot.x_zones[x_zone][0]+",-"+(d3.boxplot.scale-d3.boxplot.y_zones[y_zone][1])+")");// Correct lines stroke width to be not impacted by the zoom: +d3.selectAll(".content-lines").attr("stroke-width",d3.boxplot.content_lines_width/Math.min(scale_x,scale_y));d3.boxplot.zoom_scale_lines=Math.min(scale_x,scale_y);d3.selectAll("line.break-lines").style("visibility","hidden");//Update left and bottom axis: +let y_max=d3.boxplot.y_zones[y_zone][1]/d3.boxplot.scale*d3.boxplot.y_len;let y_min=d3.boxplot.y_zones[y_zone][0]/d3.boxplot.scale*d3.boxplot.y_len;d3.boxplot.draw_left_axis(y_max-y_min,0);let x_max=d3.boxplot.x_zones[x_zone][1]/d3.boxplot.scale*d3.boxplot.x_len;let x_min=d3.boxplot.x_zones[x_zone][0]/d3.boxplot.scale*d3.boxplot.x_len;d3.boxplot.draw_bottom_axis(x_max-x_min,0);//Update top and right axis: +let pseudo_x_zones={};pseudo_x_zones[x_zone]=[0,d3.boxplot.x_len];d3.boxplot.draw_top_axis(pseudo_x_zones);let pseudo_y_zones={};pseudo_y_zones[y_zone]=[0,d3.boxplot.y_len];d3.boxplot.draw_right_axis(pseudo_y_zones);d3.boxplot.zoom_enabled=false}$("#restore-all").show();dgenies.hide_loading()},0)};d3.boxplot.draw_left_axis=function(y_max,y_min=0){let axis_length=500;$("svg.left-axis").remove();//Remove previous axis (if any) +let svg_left=d3.boxplot.svgsupercontainer.append("svg:svg").attr("class","axis left-axis").attr("width",5).attr("height",90).attr("x",0).attr("y",5).attr("viewBox","0 0 20 "+axis_length).attr("preserveAspectRatio","none");let container_left=svg_left.append("g").attr("width",axis_length).attr("height",20).attr("transform","translate(0,"+axis_length+")rotate(-90)");let y_size=y_max-y_min;for(let i=1;i<10;i++){let y=axis_length/10*i;let y_t=y_min+y_size/10*i;if(y_t>=0&&y_t<=d3.boxplot.y_len){let y_lab="";if(y_t>1000000){y_lab=(Math.round(y_t/100000)/10).toString()+" M"}else if(y_t>1000){y_lab=(Math.round(y_t/100)/10).toString()+" K"}else{y_lab=Math.round(y_t).toString()}container_left.append("line").attr("x1",y).attr("y1",15).attr("x2",y).attr("y2",20).attr("stroke-width",d3.boxplot.tick_width).attr("stroke","black");container_left.append("text").attr("x",y).attr("y",12).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6.5pt").text(y_lab)}}};d3.boxplot.draw_bottom_axis=function(x_max,x_min=0){let axis_length=500;$("svg.bottom-axis").remove();//Remove previous axis (if any) +let svg_bottom=d3.boxplot.svgsupercontainer.append("svg:svg").attr("class","axis bottom-axis").attr("width",90).attr("height",5).attr("x",5).attr("y",95).attr("viewBox","0 0 "+axis_length+" 20").attr("preserveAspectRatio","none");let x_size=x_max-x_min;for(let i=1;i<10;i++){let x=axis_length/10*i;let x_t=x_min+x_size/10*i;if(x_t>=0&&x_t<=d3.boxplot.x_len){let x_lab="";if(x_t>=1000000){x_lab=(Math.round(x_t/100000)/10).toString()+" M"}else if(x_t>=1000){x_lab=(Math.round(x_t/100)/10).toString()+" K"}else{x_lab=Math.round(x_t).toString()}svg_bottom.append("line").attr("x1",x).attr("y1",0).attr("x2",x).attr("y2",5).attr("stroke-width",d3.boxplot.tick_width).attr("stroke","black");svg_bottom.append("text").attr("x",x).attr("y",15).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6.5pt").text(x_lab)}}};d3.boxplot.zoom_left_axis=function(){let transform=d3.boxplot.container.attr("transform");if(transform===null){transform="translate(0,0)scale(1)"}let tr_regex=/translate\(([^,]+),([^)]+)\)/;let translate=parseFloat(transform.match(tr_regex)[2]);let sc_regex=/scale\(([^,)]+)(,([^)]+))?\)/;let scale=parseFloat(transform.match(sc_regex)[3]!==undefined?transform.match(sc_regex)[3]:transform.match(sc_regex)[1]);let max_y=d3.boxplot.y_len+translate/d3.boxplot.scale*d3.boxplot.y_len/scale;let min_y=max_y-d3.boxplot.y_len/scale;d3.boxplot.draw_left_axis(max_y,min_y)};d3.boxplot.zoom_bottom_axis=function(){let transform=d3.boxplot.container.attr("transform");if(transform===null){transform="translate(0,0)scale(1)"}let tr_regex=/translate\(([^,]+),([^)]+)\)/;let translate=parseFloat(transform.match(tr_regex)[1]);let sc_regex=/scale\(([^,)]+)(,([^)]+))?\)/;let scale=parseFloat(transform.match(sc_regex)[1]);let min_x=-translate/d3.boxplot.scale*d3.boxplot.x_len/scale;let max_x=(d3.boxplot.x_len-translate/d3.boxplot.scale*d3.boxplot.x_len)/scale;d3.boxplot.draw_bottom_axis(max_x,min_x)};d3.boxplot.draw_top_axis=function(x_zones=d3.boxplot.x_zones){$("svg.top-axis").remove();//Remove previous axis (if any) +let transform=d3.boxplot.container.attr("transform");if(transform===null){transform="translate(0,0)scale(1)"}let tr_regex=/translate\(([^,]+),([^)]+)\)/;let translate=parseFloat(transform.match(tr_regex)[1]);let sc_regex=/scale\(([^,)]+)(,([^)]+))?\)/;let scale=parseFloat(transform.match(sc_regex)[1]);let axis_length=500;let svg_top=d3.boxplot.svgsupercontainer.append("svg:svg").attr("class","top-axis axis").attr("width",90).attr("height",5).attr("x",5).attr("y",0).attr("viewBox","0 0 "+axis_length+" 20").attr("preserveAspectRatio","none");svg_top.append("text").attr("x",axis_length/2).attr("y",7.5).attr("font-size","6pt").attr("font-family","sans-serif").attr("font-style","italic").attr("text-anchor","middle").text(d3.boxplot.name_x);let nb_zone=0;for(let zone in x_zones){let x_pos_1=Math.min(Math.max(x_zones[zone][0]*scale+translate,0),d3.boxplot.scale);let x_pos_2=Math.min(Math.max(x_zones[zone][1]*scale+translate,0),d3.boxplot.scale);let z_len=x_pos_2/d3.boxplot.scale*axis_length-x_pos_1/d3.boxplot.scale*axis_length;if(!zone.startsWith("###MIX###")){//z_middle = (x_zones[zone][1] + x_zones[zone][0]) / 2 +let text_container=svg_top.append("svg:svg").attr("x",x_pos_1/d3.boxplot.scale*axis_length).attr("y",0).attr("width",z_len).attr("height","100%");let text=text_container.append("text").attr("x",z_len/2).attr("y",17).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6pt").text(zone);let zone_txt=zone;let i=4;while(text.node().getComputedTextLength()>z_len&&zone_txt.length>=5){text.remove();zone_txt=zone.slice(0,-i)+"...";text=text_container.append("text").attr("x",z_len/2).attr("y",17).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6pt").text(zone_txt);i++}if(text.node().getComputedTextLength()>z_len){text.remove()}}if(zone.startsWith("###MIX###")){svg_top.append("rect").attr("x",x_pos_1/d3.boxplot.scale*axis_length).attr("y",12).attr("width",z_len).attr("height",8).attr("fill",d3.boxplot.color_mixes).attr("stroke",d3.boxplot.color_mixes)}else if(nb_zone>0){//Draw zone separator at left of zone (except for first zone) +svg_top.append("line").attr("x1",x_pos_1/d3.boxplot.scale*axis_length).attr("x2",x_pos_1/d3.boxplot.scale*axis_length).attr("y1",12).attr("y2",20).attr("stroke","black").attr("stroke-width",d3.boxplot.tick_width)}nb_zone++}};d3.boxplot.draw_right_axis=function(y_zones=d3.boxplot.y_zones){$("svg.right-axis").remove();//Remove previous axis (if any) +let transform=d3.boxplot.container.attr("transform");if(transform===null){transform="translate(0,0)scale(1)"}let tr_regex=/translate\(([^,]+),([^)]+)\)/;let translate=parseFloat(transform.match(tr_regex)[2]);let sc_regex=/scale\(([^,)]+)(,([^)]+))?\)/;let scale=parseFloat(transform.match(sc_regex)[3]!==undefined?transform.match(sc_regex)[3]:transform.match(sc_regex)[1]);let axis_length=500;let svg_right=d3.boxplot.svgsupercontainer.append("svg:svg").attr("class","right-axis").attr("width",5).attr("height",90).attr("x",95).attr("y",5).attr("viewBox","0 0 20 "+axis_length).attr("preserveAspectRatio","none");let container_right=svg_right.append("g").attr("width",axis_length).attr("height",20).attr("transform","translate(20)rotate(90)");container_right.append("text").attr("x",axis_length/2).attr("y",7.5).attr("font-size","6pt").attr("font-family","sans-serif").attr("font-style","italic").attr("text-anchor","middle").text(d3.boxplot.name_y);let nb_zone=Object.keys(y_zones).length-1;for(let zone in y_zones){let y_pos_2=Math.min(Math.max((d3.boxplot.scale-y_zones[zone][0])*scale+translate,0),d3.boxplot.scale);let y_pos_1=Math.min(Math.max((d3.boxplot.scale-y_zones[zone][1])*scale+translate,0),d3.boxplot.scale);let z_len=y_pos_2/d3.boxplot.scale*axis_length-y_pos_1/d3.boxplot.scale*axis_length;if(!zone.startsWith("###MIX###")){//z_middle = (x_zones[zone][1] + x_zones[zone][0]) / 2 +let text_container=container_right.append("svg:svg").attr("x",y_pos_1/d3.boxplot.scale*axis_length).attr("y",0).attr("width",z_len).attr("height","100%");let text=text_container.append("text").attr("x",z_len/2).attr("y",17).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6pt").text(zone);let zone_txt=zone;let i=4;while(text.node().getComputedTextLength()>z_len&&zone_txt.length>=5){text.remove();zone_txt=zone.slice(0,-i)+"...";text=text_container.append("text").attr("x",z_len/2).attr("y",17).attr("text-anchor","middle").attr("font-family","sans-serif").attr("font-size","6pt").text(zone_txt);i++}if(text.node().getComputedTextLength()>z_len){text.remove()}}if(zone.startsWith("###MIX###")){container_right.append("rect").attr("x",y_pos_1/d3.boxplot.scale*axis_length).attr("y",12).attr("width",z_len).attr("height",8).attr("fill",d3.boxplot.color_mixes).attr("stroke","None")}else if(nb_zone>0){//Draw zone separator at left of zone (except for first zone) +container_right.append("line").attr("x1",y_pos_1/d3.boxplot.scale*axis_length).attr("x2",y_pos_1/d3.boxplot.scale*axis_length).attr("y1",12).attr("y2",20).attr("stroke","black").attr("stroke-width",d3.boxplot.tick_width).attr("class","whereis")}nb_zone--}};d3.boxplot.draw_axis_bckgd=function(){// Top: +let svg_top=d3.boxplot.svgsupercontainer.append("svg:svg").attr("width",100).attr("height",5).attr("x",0).attr("y",0).attr("viewBox","0 0 100 5").attr("preserveAspectRatio","none");svg_top.append("polygon").attr("points","5,0 95,0 100,5 0,5").attr("stroke","none").style("fill",d3.boxplot.background_axis);// Right: +let svg_right=d3.boxplot.svgsupercontainer.append("svg:svg").attr("width",5).attr("height",100).attr("x",95).attr("y",0).attr("viewBox","0 0 5 100").attr("preserveAspectRatio","none");svg_right.append("polygon").attr("points","0,0 5,5 5,95 0,100").attr("stroke","none").style("fill",d3.boxplot.background_axis);// Bottom: +let svg_bottom=d3.boxplot.svgsupercontainer.append("svg:svg").attr("width",100).attr("height",5).attr("x",0).attr("y",95).attr("viewBox","0 0 100 5").attr("preserveAspectRatio","none");svg_bottom.append("polygon").attr("points","0,0 100,0 95,5 5,5").attr("stroke","none").style("fill",d3.boxplot.background_axis);//Left: +let svg_left=d3.boxplot.svgsupercontainer.append("svg:svg").attr("width",5).attr("height",100).attr("x",0).attr("y",0).attr("viewBox","0 0 5 100").attr("preserveAspectRatio","none");svg_left.append("polygon").attr("points","5,0 5,100 0,95 0,5").attr("stroke",d3.boxplot.background_axis).attr("stroke-width","0px").style("fill",d3.boxplot.background_axis)};d3.boxplot._sort_color_idy=function(a,b){return parseFloat(b)-parseFloat(a)};d3.boxplot.draw_legend=function(){d3.select("#legend .draw").html("");//Empty legend +let color_idy=d3.boxplot.color_idy[d3.boxplot.color_idy_theme];let color_idy_len=Object.keys(color_idy).length;let color_idy_order=["3","2","1","0"];let color_idy_labels=[d3.boxplot.limit_idy[2].toString(),d3.boxplot.limit_idy[1].toString(),d3.boxplot.limit_idy[0].toString(),"0"];let svgcontainer=d3.select("#legend .draw").append("svg:svg").attr("width","100%").attr("height","99%");let draw=$("#legend").find(".draw");let draw_w=draw.width();let draw_h=draw.height();let container=svgcontainer.append("g");for(let i=0;i<color_idy_order.length;i++){let color_idy_idx=color_idy_order[i];container.append("rect").attr("x","50%").attr("y",i*(100/color_idy_len)+"%").attr("width","50%").attr("height",100/color_idy_len+"%").attr("stroke","none").attr("fill",color_idy[color_idy_idx]);container.append("text").attr("x","45%").attr("y",i*(100/color_idy_len)+100/color_idy_len-1+"%").attr("text-anchor","end").attr("font-family","sans-serif").attr("font-size","10pt").text(color_idy_labels[i])}container.append("text").attr("x","45%").attr("y",10).attr("text-anchor","end").attr("font-family","sans-serif").attr("font-size","10pt").text("1");container.append("text").attr("x",0).attr("y","50%").attr("text-anchor","middle").attr("transform","translate(-"+(draw_w-15)+","+draw_h/2+")rotate(-90)").attr("font-family","sans-serif").attr("font-size","11.5pt").attr("font-weight","bold").text("Identity")};d3.boxplot._get_line_len=function(line){let x1=line[0]/d3.boxplot.x_len*d3.boxplot.scale;let x2=line[1]/d3.boxplot.x_len*d3.boxplot.scale;let y1=d3.boxplot.scale-line[2]/d3.boxplot.y_len*d3.boxplot.scale;let y2=d3.boxplot.scale-line[3]/d3.boxplot.y_len*d3.boxplot.scale;return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2))};d3.boxplot._sort_lines=function(l1,l2){return d3.boxplot._get_line_len(l2)-d3.boxplot._get_line_len(l1)};d3.boxplot._sort_lines_by_idy=function(l1,l2){return l1[4]-l2[4]};d3.boxplot.__lineFunction=function(d,min_size=0,max_size=null,x_len,y_len){d=d.sort(d3.boxplot._sort_lines_by_idy);let path=[];for(let i=0;i<d.length;i++){let d_i=d[i];let x1=d_i[0]/x_len*d3.boxplot.scale;let x2=d_i[1]/x_len*d3.boxplot.scale;let y1=d3.boxplot.scale-d_i[2]/y_len*d3.boxplot.scale;let y2=d3.boxplot.scale-d_i[3]/y_len*d3.boxplot.scale;let idy=d_i[4];let len=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));if(len>min_size&&(max_size===null||len<max_size)&&Math.abs(idy)>=d3.boxplot.min_idy_draw){path.push(`M${x1} ${y1} L${x2} ${y2}`)}}return path.join(" ")};d3.boxplot.__draw_idy_lines=function(idy,lines,x_len,y_len){let min_sizes=d3.boxplot.min_sizes;for(let i=0;i<min_sizes.length;i++){let min_size=min_sizes[i];let max_size=i+1<min_sizes.length?min_sizes[i+1]:null;if(lines[idy].length>0){d3.boxplot.container.append("path").attr("d",d3.boxplot.__lineFunction(lines[idy],min_size,max_size,x_len,y_len)).attr("class","content-lines s_"+min_size.toString().replace(".","_")+" idy_"+idy).attr("stroke-width",d3.boxplot.content_lines_width+"px").attr("stroke",d3.boxplot.color_idy[d3.boxplot.color_idy_theme][idy]).attr("stroke-linecap",d3.boxplot.linecap)}}};d3.boxplot.switch_color_theme=function(){if(!d3.boxplot.all_disabled){let current_theme=d3.boxplot.color_idy_theme;let idx=d3.boxplot.color_idy_themes.indexOf(current_theme);if(idx<d3.boxplot.color_idy_themes.length-1){idx++}else{idx=0}d3.boxplot.change_color_theme(d3.boxplot.color_idy_themes[idx])}};d3.boxplot.change_color_theme=function(theme){if(d3.boxplot.color_idy_themes.indexOf(theme)===-1){throw"Theme not valid!"}for(let idy=0;idy<4;idy++){d3.boxplot.color_idy_theme=theme;d3.boxplot.container.selectAll("path.idy_"+idy.toString()).attr("stroke",d3.boxplot.color_idy[d3.boxplot.color_idy_theme][idy])}d3.boxplot.draw_legend()};d3.boxplot.draw_lines=function(lines=d3.boxplot.lines,x_len=d3.boxplot.x_len,y_len=d3.boxplot.y_len){// let tmp_max = d3.boxplot.max_idy - d3.boxplot.min_idy; +// +// let nb_lines = 0; +// for (let i = 0; i < lines.length; i++) { +// nb_lines++; +// if (nb_lines > 50000) { +// break; +// } +// let line = lines[i]; +// let x1 = line[0] / x_len * d3.boxplot.scale; +// let x2 = line[1] / x_len * d3.boxplot.scale; +// let y1 = d3.boxplot.scale - (line[2] / y_len * d3.boxplot.scale); +// let y2 = d3.boxplot.scale - (line[3] / y_len * d3.boxplot.scale); +// let line_len = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); +// let color = "#000"; +// for (let part in color_idy) { +// if (line[4] >= part) { +// color = color_idy[part]; +// } +// } +// d3.boxplot.container.append("line") +// .attr("x1", x1) +// .attr("y1", y1) +// .attr("x2", x2) +// .attr("y2", y2) +// .attr("class", "content-lines") +// .attr("stroke-width", d3.boxplot.scale / 400) +// .attr("stroke", line_len >= 1 ? color : "black"); +// } +//Remove old lines (if any): +$("path.content-lines").remove();//lines = lines.sort(d3.boxplot._sort_lines); +for(let i=0;i<4;i++){d3.boxplot.__draw_idy_lines(i.toString(),lines,x_len,y_len)}d3.boxplot.events.filter_size(d3.boxplot.min_size)};d3.boxplot.draw=function(x_contigs,x_order,y_contigs,y_order){let width=850;let height=850;$("div#draw").width(width).height(height);let draw=$("#draw");draw.empty();draw.append($("<div>").attr("id","restore-all").css("display","none").attr("title","Unzoom"));let draw_in=draw.append($("<div>").attr("id","draw-in"));d3.boxplot.svgsupercontainer=d3.select("#draw-in").append("svg:svg").attr("width","100%").attr("height","100%").attr("viewBox","0 0 100 100").attr("preserveAspectRatio","none");let drawcontainer=d3.boxplot.svgsupercontainer.append("svg:g").attr("class","drawcontainer");drawcontainer.append("rect").attr("x",0).attr("y",0).attr("width","100%").attr("height","100%").attr("stroke","none").attr("fill","white");d3.boxplot.svgcontainer=drawcontainer.append("svg:svg").attr("class","svgcontainer").attr("width",90).attr("height",90).attr("x",5).attr("y",5).attr("viewBox","0 0 "+d3.boxplot.scale+" "+d3.boxplot.scale).attr("preserveAspectRatio","none");d3.boxplot.container=d3.boxplot.svgcontainer.append("svg:g").attr("class","container");d3.boxplot.container.append("rect").attr("x",0).attr("y",0).attr("width","100%").attr("height","100%").attr("stroke","none").attr("fill","white");//X axis: +d3.boxplot.x_zones={};let sum=0;for(let i=0;i<x_order.length-1;i++){let x_id=x_order[i];let x_contig_len=x_contigs[x_id]/d3.boxplot.x_len*d3.boxplot.scale;d3.boxplot.x_zones[x_id]=[sum,sum+x_contig_len];sum+=x_contig_len;d3.boxplot.container.append("line").attr("x1",sum).attr("y1",d3.boxplot.scale).attr("x2",sum).attr("y2",0).attr("class","break-lines").attr("stroke-width",d3.boxplot.break_lines_width).attr("stroke",d3.boxplot.break_lines_color).style("stroke-dasharray",d3.boxplot.break_lines_dash)}d3.boxplot.x_zones[x_order[x_order.length-1]]=[sum,d3.boxplot.scale];//Y axis: +d3.boxplot.y_zones={};sum=0;for(let i=0;i<y_order.length-1;i++){let y_id=y_order[i];let y_contig_len=y_contigs[y_id]/d3.boxplot.y_len*d3.boxplot.scale;d3.boxplot.y_zones[y_id]=[sum,sum+y_contig_len];sum+=y_contig_len;d3.boxplot.container.append("line").attr("x1",0).attr("y1",d3.boxplot.scale-sum).attr("x2",d3.boxplot.scale).attr("y2",d3.boxplot.scale-sum).attr("class","break-lines").attr("stroke-width",d3.boxplot.break_lines_width).attr("stroke",d3.boxplot.break_lines_color).style("stroke-dasharray",d3.boxplot.break_lines_dash)}d3.boxplot.y_zones[y_order[y_order.length-1]]=[sum,d3.boxplot.scale];if(!d3.boxplot.break_lines_show){d3.selectAll("line.break-lines").style("visibility","hidden")}d3.boxplot.draw_axis_bckgd();d3.boxplot.draw_left_axis(d3.boxplot.y_len);d3.boxplot.draw_bottom_axis(d3.boxplot.x_len);d3.boxplot.draw_top_axis(d3.boxplot.x_zones);d3.boxplot.draw_right_axis(d3.boxplot.y_zones);window.setTimeout(()=>{//Data: +d3.boxplot.draw_lines();$("#restore-all").click(function(){if(d3.boxplot.zoom.reset_scale(false,null,false)){$(this).hide()}});$(document).on("keyup",function(e){if(e.keyCode===27){if(d3.boxplot.zoom.reset_scale(false,null,false)){$("#restore-all").hide()}}});d3.boxplot.draw_legend();dgenies.hide_loading()},0);d3.boxplot.zoom.init();d3.boxplot.events.init_context_menu()}; +if(!d3||!d3.boxplot){throw"d3.boxplot wasn't included!"}d3.boxplot.events={};d3.boxplot.events.init=function(){$("input#filter_size").change(function(){d3.boxplot.events.filter_size(d3.boxplot.min_sizes[this.value])});$("input#stroke-linecap").change(function(){d3.boxplot.events.stroke_linecap(!this.checked)});$("input#stroke-width").change(function(){d3.boxplot.events.stroke_width(this.value)});$("input#filter_identity").change(function(){d3.boxplot.events.filter_identity(this.value)});$("input#chroms-limits").change(function(){d3.boxplot.events.set_break_lines_visibility(this.value)});$("div#legend div.draw").on("click",d3.boxplot.switch_color_theme)};d3.boxplot.events.init_context_menu=function(){d3.boxplot.svgcontainer.on("mousedown",function(){let event=d3.event;let rect=$("g.container")[0].getBoundingClientRect();let posY=rect.top+window.scrollY,height_c=rect.height;let y=d3.boxplot.scale-(event.pageY-posY)/height_c*d3.boxplot.scale;d3.boxplot.query_selected=d3.boxplot.select_query(y)});let menu=new BootstrapMenu("svg.svgcontainer",{actions:[{name:"Export SVG",onClick:dgenies.result.export.export_svg},{name:"Export PNG",onClick:dgenies.result.export.export_png},{name:"Reverse query",isShown:function(){return d3.boxplot.name_x!==d3.boxplot.name_y},onClick:dgenies.result.controls.launch_reverse_contig}]})};d3.boxplot.events.set_break_lines_visibility=function(value){if(value==="0"){d3.boxplot.break_lines_show=false;d3.boxplot.break_lines_dash="3, 3"}else if(value==="1"){d3.boxplot.break_lines_show=true;d3.boxplot.break_lines_width=d3.boxplot.scale/2000;d3.boxplot.break_lines_color="#bfbfbf";d3.boxplot.break_lines_dash="3, 3"}else if(value==="2"){d3.boxplot.break_lines_show=true;d3.boxplot.break_lines_width=d3.boxplot.scale/1500;d3.boxplot.break_lines_color="#7c7c7c";d3.boxplot.break_lines_dash="3, 3"}else if(value==="3"){d3.boxplot.break_lines_show=true;d3.boxplot.break_lines_width=d3.boxplot.scale/1000;d3.boxplot.break_lines_color="#424242";d3.boxplot.break_lines_dash="3, 3"}else if(value==="4"){d3.boxplot.break_lines_show=true;d3.boxplot.break_lines_width=d3.boxplot.scale/800;d3.boxplot.break_lines_color="#2b2b2b";d3.boxplot.break_lines_dash="3, 3"}else if(value==="5"){d3.boxplot.break_lines_show=true;d3.boxplot.break_lines_width=d3.boxplot.scale/600;d3.boxplot.break_lines_color="#000000";d3.boxplot.break_lines_dash="none"}if(d3.boxplot.break_lines_show){d3.selectAll("line.break-lines").style("visibility","visible");d3.selectAll("line.break-lines").attr("stroke-width",d3.boxplot.break_lines_width/d3.boxplot.zoom_scale_lines);d3.selectAll("line.break-lines").attr("stroke",d3.boxplot.break_lines_color);d3.selectAll("line.break-lines").style("stroke-dasharray",d3.boxplot.break_lines_dash)}else{d3.selectAll("line.break-lines").style("visibility","hidden")}};d3.boxplot.events.filter_size=function(min_size){for(let i=0;i<d3.boxplot.min_sizes.length;i++){let size=d3.boxplot.min_sizes[i];if(size<min_size){$("path.content-lines.s_"+size.toString().replace(".","_")).hide()}else{$("path.content-lines.s_"+size.toString().replace(".","_")).show()}}d3.boxplot.min_size=min_size};d3.boxplot.events.filter_identity=function(min_idy){d3.boxplot.min_idy_draw=min_idy;dgenies.show_loading();window.setTimeout(()=>{d3.boxplot.draw_lines();d3.selectAll("path.content-lines").attr("stroke-width",d3.boxplot.content_lines_width/d3.boxplot.zoom_scale_lines);d3.boxplot.events.filter_size(d3.boxplot.min_size);dgenies.hide_loading()},0)};d3.boxplot.events.stroke_linecap=function(rounded){d3.boxplot.linecap=rounded?"round":"butt";$("path").attr("stroke-linecap",d3.boxplot.linecap)};d3.boxplot.events.stroke_width=function(width){let stroke_width=d3.boxplot.scale/600;if(width==="1"){stroke_width=d3.boxplot.scale/400}else if(width==="2"){stroke_width=d3.boxplot.scale/200}else if(width==="3"){stroke_width=d3.boxplot.scale/100}d3.boxplot.content_lines_width=stroke_width;d3.selectAll("path.content-lines").attr("stroke-width",stroke_width/d3.boxplot.zoom_scale_lines)}; +if(!d3||!d3.boxplot){throw"d3.boxplot wasn't included!"}d3.boxplot.mousetip={};$.fn.mousetip=function(my_tip,relative_to=null,x=20,y=20){let $this=$(this);let tip=relative_to===null?$(my_tip,this):$(my_tip,relative_to);let hidden=true;$this.hover(function(e){if(!e.ctrlKey){tip.show();hidden=false}},function(){hidden=true;tip.hide().removeAttr("style")}).mousemove(function(e){tip.hide();if(!e.ctrlKey&&!d3.boxplot.zone_selected){window.setTimeout(()=>{let rect=relative_to===null?this.getBoundingClientRect():$(relative_to)[0].getBoundingClientRect();let posX=rect.left+window.scrollX,posY=rect.top+window.scrollY,m_x=e.pageX-rect.left-window.scrollX,m_y=e.pageY-rect.top-window.scrollY;let mouseX=m_x+x;let mouseY=m_y+y;let rect_g=$("g.container")[0].getBoundingClientRect();let posX_g=rect_g.left+window.scrollX,posY_g=rect_g.top+window.scrollY,width_c=rect_g.width,height_c=rect_g.height;let x_g=(e.pageX-posX_g)/width_c*d3.boxplot.scale,y_g=d3.boxplot.scale-(e.pageY-posY_g)/height_c*d3.boxplot.scale;let x_zone="unknown";for(let zone in d3.boxplot.x_zones){if(d3.boxplot.x_zones[zone][0]<x_g&&x_g<=d3.boxplot.x_zones[zone][1]){x_zone=d3.boxplot.mousetip.get_label(zone);break}}let y_zone="unknown";for(let zone in d3.boxplot.y_zones){if(d3.boxplot.y_zones[zone][0]<y_g&&y_g<=d3.boxplot.y_zones[zone][1]){y_zone=d3.boxplot.mousetip.get_label(zone);break}}tip.html(`<table class="drawtooltip"> + <tr> + <td class="tt-label">Query:</td><td>${y_zone}</td> + </tr> + <tr> + <td class="tt-label">Target:</td><td>${x_zone}</td> + </tr> + </table>`);if(!hidden){tip.show().css({top:mouseY,left:mouseX})}},0)}})};d3.boxplot.mousetip.init=function(){$("#draw").append($("<span>").attr("class","tip"));$("g.container").mousetip(".tip","#draw")};d3.boxplot.mousetip.hide=function(){$(".tip","#draw").hide()};d3.boxplot.mousetip.get_label=function(label){if(label.startsWith("###MIX###")){let parts=label.substr(10).split("###");label="Mix: "+parts.slice(0,3).join(", ");if(parts.length>3){label+=", ..."}}return label}; +if(!d3||!d3.boxplot){throw"d3.boxplot wasn't included!"}d3.boxplot.zoom={};d3.boxplot.zoom.init=function(){d3.boxplot.svgcontainer.on("click",d3.boxplot.zoom.click);d3.select(".drawcontainer").on("mousedown",d3.boxplot.zoom.mousedown).on("mouseup",d3.boxplot.zoom.mouseup).on("mousemove",d3.boxplot.zoom.translate);d3.boxplot.svgcontainer.on("wheel",d3.boxplot.zoom.zoom)};// d3.boxplot.zoom.zoom = function () { +// console.log(d3.event); +// if (d3.event.ctrlKey) { +// d3.event.preventDefault(); +// let rect = $("g.container")[0].getBoundingClientRect(); +// let posX = rect.left, +// posY = rect.top, +// width_c = rect.width, +// height_c = rect.height; +// let cursor_x = (d3.event.pageX - posX) / width_c * d3.boxplot.x_len, +// cursor_y = (d3.event.pageY - posY) / height_c * d3.boxplot.y_len; +// console.log(cursor_x, cursor_y); +// let zoom_f = 1.2; +// let old_transform = d3.boxplot.container.attr("transform") +// if (old_transform !== null) { +// let search_tr = old_transform.match(/translate\(([-\de.]+),([-\de.]+)\)/); +// let search_sc = old_transform.match(/scale\(([-\de.]+)(,[-\de.]+)?\)/); +// old_transform = { +// "scale": parseFloat(search_sc[1]), +// "translate": [parseFloat(search_tr[1]), parseFloat(search_tr[2])] +// } +// } +// else { +// old_transform = { +// "scale": 1, +// "translate": [0, 0] +// } +// } +// console.log(old_transform); +// +// //Cursor localisation on picture with old zoom: +// let cursor_old = [(cursor_x - old_transform["translate"][0]), (cursor_y - old_transform["translate"][1])]; //x0,y0 bleu (visible) +// console.log([(cursor_x - old_transform["translate"][0]), (cursor_y - old_transform["translate"][1])]); +// console.log("c_old", cursor_old); +// let new_scale, +// cursor_new; +// if (d3.event.deltaY < 0) { +// new_scale = old_transform["scale"] * zoom_f; +// cursor_new = [cursor_old[0] * zoom_f, cursor_old[1] * zoom_f]; +// } +// else { +// new_scale = old_transform["scale"] / zoom_f; +// if (new_scale < 1) { +// new_scale = 1; +// zoom_f = old_transform["scale"] / new_scale; +// } +// cursor_new = [cursor_old[0] / zoom_f, cursor_old[1] / zoom_f]; +// } +// +// let new_transform = vsprintf("translate(%f,%f) scale(%f)", +// [old_transform["translate"][0] - (cursor_new[0] - cursor_old[0]), +// old_transform["translate"][1] - (cursor_new[1] - cursor_old[1]), +// new_scale]); +// d3.boxplot.container.attr("transform", new_transform); +// +// //Correct lines stroke width to be not impacted by the zoom: +// d3.selectAll("line.content-lines").attr("stroke-width", (d3.boxplot.x_len / 400) / new_scale); +// } +// }; +d3.boxplot.zoom.click=function(){if(!d3.event.ctrlKey&&!d3.boxplot.all_disabled){let event=d3.event;let rect=$("g.container")[0].getBoundingClientRect();let posX=rect.left+window.scrollX,posY=rect.top+window.scrollY,width_c=rect.width,height_c=rect.height;let x=(event.pageX-posX)/width_c*d3.boxplot.scale,y=d3.boxplot.scale-(event.pageY-posY)/height_c*d3.boxplot.scale;d3.boxplot.select_zone(x,y)}};d3.boxplot.zoom.mousedown=function(){if(d3.boxplot.zoom_enabled){d3.boxplot.mousetip.hide();let rect=$("g.container")[0].getBoundingClientRect();let posX=rect.left+window.scrollX,posY=rect.top+window.scrollY,width_c=rect.width,height_c=rect.height;let cursor_x=(d3.event.pageX-posX)/width_c*d3.boxplot.scale,cursor_y=(d3.event.pageY-posY)/height_c*d3.boxplot.scale;d3.boxplot.translate_start=[cursor_x,cursor_y];d3.boxplot.posX=posX;d3.boxplot.posY=posY;let old_transform=d3.boxplot.container.attr("transform");d3.boxplot.old_translate=[0,0];if(old_transform!==null){let search_tr=old_transform.match(/translate\(([-\d.]+),\s*([-\d.]+)\)/);d3.boxplot.old_translate=[parseFloat(search_tr[1]),parseFloat(search_tr[2])]}}};d3.boxplot.zoom.mouseup=function(){d3.boxplot.translate_start=null};d3.boxplot.zoom.translate=function(){let rect=$("g.container")[0].getBoundingClientRect();let posX=d3.boxplot.posX,posY=d3.boxplot.posY,width_c=rect.width,height_c=rect.height;let cursor_x=(d3.event.pageX-posX)/width_c*d3.boxplot.scale,cursor_y=(d3.event.pageY-posY)/height_c*d3.boxplot.scale;if(d3.boxplot.translate_start!==null&&d3.event.ctrlKey){let old_transform=d3.boxplot.container.attr("transform");//let scale = 1; +let scale_x=1;let scale_y=1;if(old_transform){let scale=old_transform.match(/scale\(([-\d.]+)(,\s*([-\d.]+))?\)/);scale_x=scale[1];scale_y=scale[1];if(scale[3]!==undefined)scale_y=scale[3]}let translate=[d3.boxplot.old_translate[0]+(cursor_x-d3.boxplot.translate_start[0])*scale_x,d3.boxplot.old_translate[1]+(cursor_y-d3.boxplot.translate_start[1])*scale_y];let min_tr=[d3.boxplot.scale-0.2*d3.boxplot.scale,d3.boxplot.scale-0.2*d3.boxplot.scale];let max_tr=[-d3.boxplot.scale*scale_x+200,-d3.boxplot.scale*scale_x+200];if(translate[0]<max_tr[0]){translate[0]=max_tr[0]}else if(translate[0]>min_tr[0]){translate[0]=min_tr[0]}if(translate[1]<max_tr[1]){translate[1]=max_tr[1]}else if(translate[1]>min_tr[1]){translate[1]=min_tr[1]}let new_transform=`translate(${translate[0]}, ${translate[1]}) scale(${scale_x}, ${scale_y})`;d3.boxplot.container.attr("transform",new_transform);//Update axis: +d3.boxplot.draw_top_axis();d3.boxplot.draw_right_axis();d3.boxplot.zoom_bottom_axis();d3.boxplot.zoom_left_axis()}};d3.boxplot.zoom.zoom=function(){if(d3.event.ctrlKey){d3.event.preventDefault();d3.boxplot.mousetip.hide();if(d3.boxplot.zoom_enabled){let zoom_f=1.2;let old_transform=d3.boxplot.container.attr("transform");if(old_transform!==null){let search_tr=old_transform.match(/translate\(([-\de.]+),\s*([-\de.]+)\)/);let search_sc=old_transform.match(/scale\(([-\de.]+)(,\s*[-\de.]+)?\)/);old_transform={"scale":parseFloat(search_sc[1]),"translate":[parseFloat(search_tr[1]),parseFloat(search_tr[2])]}}else{old_transform={"scale":1,"translate":[0,0]}}let new_scale;if(d3.event.deltaY<0){new_scale=old_transform["scale"]*zoom_f}else{new_scale=old_transform["scale"]/zoom_f;if(new_scale<1){new_scale=1}}let new_transform=`translate(${old_transform["translate"][0]},${old_transform["translate"][1]}) + scale(${new_scale})`;d3.boxplot.container.attr("transform",new_transform);d3.boxplot.zoom_scale_lines=new_scale;//Correct lines stroke width to be not impacted by the zoom: +d3.selectAll("path.content-lines").attr("stroke-width",d3.boxplot.content_lines_width/new_scale);d3.selectAll("line.break-lines").attr("stroke-width",d3.boxplot.break_lines_width/new_scale);//Update axis: +d3.boxplot.draw_top_axis();d3.boxplot.draw_right_axis();d3.boxplot.zoom_bottom_axis();d3.boxplot.zoom_left_axis()}}};d3.boxplot.zoom.restore_scale=function(transform){if(d3.boxplot.zone_selected){d3.boxplot.select_zone(null,null,d3.boxplot.zone_selected[0],d3.boxplot.zone_selected[1],true)}else{let scale_x=1;let scale_y=1;if(transform!==null){let search_sc=transform.match(/scale\(([-\de.]+)(,\s*[-\de.]+)?\)/);scale_x=search_sc[1];scale_y=search_sc[2]}else{transform="translate(0,0)scale(1,1)"}if(scale_y===undefined){scale_y=1000000}d3.boxplot.container.attr("transform",transform);d3.selectAll("path.content-lines").attr("stroke-width",d3.boxplot.content_lines_width/Math.min(scale_x,scale_y));if(d3.boxplot.break_lines_show){d3.selectAll("line.break-lines").style("visibility","visible");d3.selectAll("line.break-lines").attr("stroke-width",d3.boxplot.break_lines_width)}}};d3.boxplot.zoom.reset_scale=function(temp=false,after=null,force=true){if(!d3.boxplot.all_disabled||force){dgenies.show_loading();window.setTimeout(()=>{//Reset scale: +d3.boxplot.container.attr("transform","scale(1,1)translate(0,0)");d3.boxplot.zoom_scale_lines=1;//Restore lines stroke width: +d3.selectAll("path.content-lines").attr("stroke-width",d3.boxplot.content_lines_width);if(d3.boxplot.break_lines_show){d3.selectAll("line.break-lines").style("visibility","visible");d3.selectAll("line.break-lines").attr("stroke-width",d3.boxplot.break_lines_width)}//Update left and bottom axis: +d3.boxplot.draw_left_axis(d3.boxplot.y_len);d3.boxplot.draw_bottom_axis(d3.boxplot.x_len);//Update top and right axis: +d3.boxplot.draw_top_axis();d3.boxplot.draw_right_axis();if(!temp)d3.boxplot.zone_selected=false;dgenies.hide_loading();//Re-enable zoom: +d3.boxplot.zoom_enabled=true;if(after!==null){after()}},0);return true}return false;// +// //Restore axis: +// d3.boxplot.draw_left_axis(d3.boxplot.y_len); +// d3.boxplot.draw_bottom_axis(d3.boxplot.x_len); +// d3.boxplot.draw_top_axis(d3.boxplot.x_zones); +// d3.boxplot.draw_right_axis(d3.boxplot.y_zones); +// +// d3.selectAll("line.content-lines").remove(); +// d3.boxplot.draw_lines(d3.boxplot.lines, d3.boxplot.x_len, d3.boxplot.y_len); +// dgenies.show_loading(); +// window.setTimeout(() => { +// d3.select("g.container").html(d3.boxplot.full_pict); +// dgenies.hide_loading(); +// }, 0); +}; diff --git a/src/dgenies/static/js/dgenies.run.min.js b/src/dgenies/static/js/dgenies.run.min.js new file mode 100644 index 0000000..4f135be --- /dev/null +++ b/src/dgenies/static/js/dgenies.run.min.js @@ -0,0 +1,9 @@ +if(!dgenies){throw"dgenies wasn't included!"}dgenies.run={};// Init global variables: +dgenies.run.s_id=null;dgenies.run.allowed_ext=[];dgenies.run.max_upload_file_size=-1;dgenies.run.files=[undefined,undefined];dgenies.run.allow_upload=false;dgenies.run.ping_interval=null;dgenies.run.target_example="";dgenies.run.query_example="";dgenies.run.init=function(s_id,allowed_ext,max_upload_file_size=1073741824,target_example="",query_example=""){dgenies.run.s_id=s_id;dgenies.run.allowed_ext=allowed_ext;dgenies.run.max_upload_file_size=max_upload_file_size;dgenies.run.target_example=target_example;dgenies.run.query_example=query_example;dgenies.run.restore_form();dgenies.run.set_events();dgenies.run.init_fileuploads()};dgenies.run.restore_form=function(){dgenies.run.change_fasta_type("query",$("select.query").find(":selected").text().toLowerCase(),true);dgenies.run.change_fasta_type("target",$("select.target").find(":selected").text().toLowerCase(),true)};dgenies.run.upload_next=function(){let next=dgenies.run.files.pop();while(next===undefined&&dgenies.run.files.length>0){next=dgenies.run.files.pop()}if(next!==undefined){next.submit();return true}dgenies.run.do_submit();return false};dgenies.run.__upload_server_error=function(fasta,data){dgenies.notify("message"in data?data["message"]:`An error has occured when uploading <b>${fasta}</b> file. Please contact us to report the bug!`,"danger");dgenies.run.enable_form()};dgenies.run.allowed_file=function(filename){return filename.indexOf(".")!==-1&&(dgenies.run.allowed_ext.indexOf(filename.rsplit(".",1)[1].toLowerCase())!==-1||dgenies.run.allowed_ext.indexOf(filename.rsplit(".",2).splice(1).join(".").toLowerCase())!==-1)};dgenies.run.init_fileuploads=function(){$("input.file-query").fileupload({dataType:"json",formData:{"s_id":dgenies.run.s_id},add:function(e,data){let filename=data.files[0].name;if(dgenies.run.allowed_file(filename))dgenies.run.files[0]=data;else{$("input.file-query").trigger("change");// The value is null after fired +dgenies.notify(`File <b>${filename}</b> is not supported!`,"danger",3000)}},progressall:function(e,data){var progress=parseInt(data.loaded/data.total*100,10);$("#progress-query").find(".bar").css("width",progress+"%")},success:function(data,success){if(data["success"]!=="OK"){dgenies.run.__upload_server_error("query",data)}else if("error"in data["files"][0]){dgenies.run.add_error("Query file: "+data["files"][0]["error"],"error");dgenies.run.enable_form()}else{$("input#query").val(data["files"][0]["name"]);dgenies.run.hide_loading("query");dgenies.run.show_success("query");dgenies.run.upload_next()}},error:function(data,success){dgenies.run.__upload_server_error("query",data)}});$("input.file-target").fileupload({dataType:"json",formData:{"s_id":dgenies.run.s_id},add:function(e,data){let filename=data.files[0].name;if(dgenies.run.allowed_file(filename))dgenies.run.files[1]=data;else{$("input.file-target").trigger("change");// The value is null after fired +dgenies.notify(`File <b>${filename}</b> is not supported!`,"danger",3000)}},progressall:function(e,data){var progress=parseInt(data.loaded/data.total*100,10);$("#progress-target").find(".bar").css("width",progress+"%")},success:function(data,success){if(data["success"]!=="OK"){dgenies.run.__upload_server_error("target",data)}else if("error"in data["files"][0]){dgenies.run.add_error("Target file: "+data["files"][0]["error"],"error");dgenies.run.enable_form()}else{$("input#target").val(data["files"][0]["name"]);dgenies.run.hide_loading("target");dgenies.run.show_success("target");dgenies.run.upload_next()}},error:function(data,success){dgenies.run.__upload_server_error("target",data)}});//Trigger events on hidden file inputs: +$("button#button-query").click(function(){$("input.file-query").trigger("click")});$("button#button-target").click(function(){$("input.file-target").trigger("click")})};dgenies.run.get_file_size_str=function(size){if(size<1000){return size+" O"}else if(size<1000000){return Math.round(size/1024)+" Ko"}else if(size<1000000000){return Math.round(size/1048576)+" Mo"}return Math.round(size/1073741824)+" Go"};dgenies.run.fill_examples=function(){$("select.target").val("1").trigger("change");$("input#target").val("example://"+dgenies.run.target_example);if(dgenies.run.query_example!==""){$("select.query").val("1").trigger("change");$("input#query").val("example://"+dgenies.run.query_example)}};dgenies.run.set_events=function(){let max_file_size_txt=dgenies.run.get_file_size_str(dgenies.run.max_upload_file_size);$("input.file-query").change(function(){let file_size_query=$("div.file-size.query");if(this.files.length>0){if(this.files[0].size<=dgenies.run.max_upload_file_size){file_size_query.html(dgenies.run.get_file_size_str(this.files[0].size));dgenies.run.set_filename(this.files[0].name,"query")}else{$(this).val("");dgenies.run.set_filename("","query");dgenies.notify(`File exceed the size limit (${max_file_size_txt})`,"danger",2000);file_size_query.html("")}}else{dgenies.run.set_filename("","query");file_size_query.html("")}});$("input.file-target").change(function(){let file_size_target=$("div.file-size.target");if(this.files.length>0){if(this.files[0].size<=dgenies.run.max_upload_file_size){file_size_target.html(dgenies.run.get_file_size_str(this.files[0].size));dgenies.run.set_filename(this.files[0].name,"target")}else{$(this).val("");dgenies.run.set_filename("","target");dgenies.notify(`File exceed the size limit (${max_file_size_txt})`,"danger",2000);file_size_target.html("")}}else{dgenies.run.set_filename("","target");file_size_target.html("")}});$("button#submit").click(function(){dgenies.run.submit()});$("select.query").change(function(){dgenies.run.change_fasta_type("query",$("select.query").find(":selected").text().toLowerCase())});$("select.target").change(function(){dgenies.run.change_fasta_type("target",$("select.target").find(":selected").text().toLowerCase())});$("button#example").click(function(){dgenies.run.fill_examples()})};dgenies.run.change_fasta_type=function(fasta,type,keep_url=false){let button=$("button#button-"+fasta);let input=$("input#"+fasta);let container=$("div."+fasta+"-label");$("input.file-"+fasta).val("");if(type==="local"){button.show();input.prop("readonly",true);input.val("");container.width(300)}else{button.hide();input.prop("readonly",false);if(!keep_url)input.val("");container.width(348)}$("div.file-size."+fasta).html("")};dgenies.run.set_filename=function(name,fasta){$("input#"+fasta).val(name)};dgenies.run.disable_form=function(){$("input, select, button").prop("disabled",true)};dgenies.run.enable_form=function(){$(".progress").find(".bar").css("width","0%");$("input, select, button").prop("disabled",false);$("div#uploading-loading").hide();$("button#submit").show();dgenies.run.hide_loading("query");dgenies.run.hide_loading("target");dgenies.run.hide_success("query");dgenies.run.hide_success("target");dgenies.run.files=[undefined,undefined];dgenies.run.restore_form()};dgenies.run.do_submit=function(){$("div#uploading-loading").html("Submitting form...");dgenies.post("/launch_analysis",{"id_job":$("input#id_job").val(),"email":dgenies.mode==="webserver"?$("input#email").val():"","query":$("input#query").val(),"query_type":$("select.query").find(":selected").text().toLowerCase(),"target":$("input#target").val(),"target_type":$("select.target").find(":selected").text().toLowerCase(),"s_id":dgenies.run.s_id},function(data,status){if(data["success"]){window.location=data["redirect"]}else{if(dgenies.run.ping_interval!==null){clearInterval(dgenies.run.ping_interval);dgenies.run.ping_interval=null}if("errors"in data){for(let i=0;i<data["errors"].length;i++){dgenies.notify(data["errors"][i],"danger",3000)}}else{dgenies.notify("An error has occurred. Please contact the support","danger",3000)}dgenies.run.enable_form()}})};dgenies.run.add_error=function(error){$("div.errors-submit ul.flashes").append($("<li>").append(error))};dgenies.run.valid_form=function(){let has_errors=false;// Check name: +if($("input#id_job").val().length===0){$("label.id-job").addClass("error");dgenies.run.add_error("Name of your job is required!");has_errors=true}// Check mail: +if(dgenies.mode==="webserver"){let email=$("input#email").val();let mail_re=/^.+@.+\..+$/;if(email.match(mail_re)===null){$("label.email").addClass("error");if(email==="")dgenies.run.add_error("Email is required!");else dgenies.run.add_error("Email is not correct!");has_errors=true}}//Check input target: +if($("input#target").val().length===0){$("label.file-target").addClass("error");dgenies.run.add_error("Target fasta is required!");has_errors=true}// Returns +return!has_errors};dgenies.run.show_loading=function(fasta){$(".loading-file."+fasta).show()};dgenies.run.hide_loading=function(fasta){$(".loading-file."+fasta).hide()};dgenies.run.show_success=function(fasta){$(".upload-success."+fasta).show()};dgenies.run.hide_success=function(fasta){$(".upload-success."+fasta).hide()};dgenies.run.reset_errors=function(){$("label").removeClass("error");$("div.errors-submit ul.flashes").find("li").remove()};dgenies.run.ask_for_upload=function(){console.log("Ask for upload...");dgenies.post("/ask-upload",{"s_id":dgenies.run.s_id},function(data,status){if(data["success"]){let allow_upload=data["allowed"];if(allow_upload){$("div#uploading-loading").html("Uploading files...");dgenies.run.ping_interval=window.setInterval(dgenies.run.ping_upload,15000);dgenies.run.upload_next()}else{window.setTimeout(dgenies.run.ask_for_upload,15000)}}else{dgenies.notify("message"in data?data["message"]:"An error has occurred. Please contact the support","danger",3000)}},undefined,false)};dgenies.run.ping_upload=function(){dgenies.post("/ping-upload",{"s_id":dgenies.run.s_id},function(data,status){})};dgenies.run.check_url=function(url){return url.startsWith("http://")||url.startsWith("https://")||url.startsWith("ftp://")||url.startsWith("example://")};dgenies.run.start_uploads=function(){let query_type=parseInt($("select.query").val());let has_uploads=false;let query_val=$("input#query").val();if(query_type===0&&query_val.length>0){$("button#button-query").hide();dgenies.run.show_loading("query");has_uploads=true}else{dgenies.run.files[0]=undefined;if(query_val!==""&&!dgenies.run.check_url(query_val)){dgenies.run.add_error("Query file: invalid URL","error");dgenies.run.enable_form();return false}}let target_type=parseInt($("select.target").val());let target_val=$("input#target").val();if(target_type===0&&target_val.length>0){$("button#button-target").hide();dgenies.run.show_loading("target");has_uploads=true}else{dgenies.run.files[1]=undefined;if(target_val!==""&&!dgenies.run.check_url(target_val)){dgenies.run.add_error("Target file: invalid URL","error");dgenies.run.enable_form();return false}}if(has_uploads){$("div#uploading-loading").html("Asking for upload...");dgenies.run.ask_for_upload()}else{dgenies.run.upload_next()}};dgenies.run.show_global_loading=function(){$("button#submit").hide();$("button#example").hide();$("div#uploading-loading").show()};dgenies.run.submit=function(){dgenies.run.reset_errors();if(dgenies.run.valid_form()){dgenies.run.disable_form();dgenies.run.show_global_loading();dgenies.run.start_uploads()}}; diff --git a/src/dgenies/static/js/dgenies.status.min.js b/src/dgenies/static/js/dgenies.status.min.js new file mode 100644 index 0000000..0a891c0 --- /dev/null +++ b/src/dgenies/static/js/dgenies.status.min.js @@ -0,0 +1 @@ +if(!dgenies){throw"dgenies wasn't included!"}dgenies.status={};dgenies.status.mode="webserver";dgenies.status.init=function(status,mode){dgenies.status.mode=mode;if(status!=="success"&&status!=="done"&&status!=="no-match"&&status!=="fail"){dgenies.status.autoreload()}};dgenies.status.autoreload=function(){let get_p=new URLSearchParams(window.location.search);let refresh=get_p.get("refresh")!==null?parseInt(get_p.get("refresh")):1;let count=get_p.get("count")!==null?parseInt(get_p.get("count")):1;if(refresh<30){if(refresh%5===0){if(count>3){refresh+=1;count=1}else{count+=1}}else{refresh+=1}}setTimeout(function(){if(dgenies.status.mode==="webserver"){window.location.replace(`?refresh=${refresh}&count=${count}`)}else{window.location.replace(`?refresh=1&count=1`)}},refresh*1000)}; diff --git a/src/dgenies/static/js/jquery.fileupload.min.js b/src/dgenies/static/js/jquery.fileupload.min.js new file mode 100644 index 0000000..bc99b8d --- /dev/null +++ b/src/dgenies/static/js/jquery.fileupload.min.js @@ -0,0 +1,337 @@ +/* + * jQuery File Upload Plugin + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + *//* jshint nomen:false *//* global define, require, window, document, location, Blob, FormData */;(function(factory){'use strict';if(typeof define==='function'&&define.amd){// Register as an anonymous AMD module: +define(['jquery','jquery-ui/ui/widget'],factory)}else if(typeof exports==='object'){// Node/CommonJS: +factory(require('jquery'),require('./vendor/jquery.ui.widget'))}else{// Browser globals: +factory(window.jQuery)}})(function($){'use strict';// Detect file input support, based on +// http://viljamis.com/blog/2012/file-upload-support-on-mobile/ +$.support.fileInput=!(new RegExp(// Handle devices which give false positives for the feature detection: +'(Android (1\\.[0156]|2\\.[01]))'+'|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)'+'|(w(eb)?OSBrowser)|(webOS)'+'|(Kindle/(1\\.0|2\\.[05]|3\\.0))').test(window.navigator.userAgent)||// Feature detection for all other devices: +$('<input type="file">').prop('disabled'));// The FileReader API is not actually used, but works as feature detection, +// as some Safari versions (5?) support XHR file uploads via the FormData API, +// but not non-multipart XHR file uploads. +// window.XMLHttpRequestUpload is not available on IE10, so we check for +// window.ProgressEvent instead to detect XHR2 file upload capability: +$.support.xhrFileUpload=!!(window.ProgressEvent&&window.FileReader);$.support.xhrFormDataFileUpload=!!window.FormData;// Detect support for Blob slicing (required for chunked uploads): +$.support.blobSlice=window.Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice);// Helper function to create drag handlers for dragover/dragenter/dragleave: +function getDragHandler(type){var isDragOver=type==='dragover';return function(e){e.dataTransfer=e.originalEvent&&e.originalEvent.dataTransfer;var dataTransfer=e.dataTransfer;if(dataTransfer&&$.inArray('Files',dataTransfer.types)!==-1&&this._trigger(type,$.Event(type,{delegatedEvent:e}))!==false){e.preventDefault();if(isDragOver){dataTransfer.dropEffect='copy'}}}}// The fileupload widget listens for change events on file input fields defined +// via fileInput setting and paste or drop events of the given dropZone. +// In addition to the default jQuery Widget methods, the fileupload widget +// exposes the "add" and "send" methods, to add or directly send files using +// the fileupload API. +// By default, files added via file input selection, paste, drag & drop or +// "add" method are uploaded immediately, but it is possible to override +// the "add" callback option to queue file uploads. +$.widget('blueimp.fileupload',{options:{// The drop target element(s), by the default the complete document. +// Set to null to disable drag & drop support: +dropZone:$(document),// The paste target element(s), by the default undefined. +// Set to a DOM node or jQuery object to enable file pasting: +pasteZone:undefined,// The file input field(s), that are listened to for change events. +// If undefined, it is set to the file input fields inside +// of the widget element on plugin initialization. +// Set to null to disable the change listener. +fileInput:undefined,// By default, the file input field is replaced with a clone after +// each input field change event. This is required for iframe transport +// queues and allows change events to be fired for the same file +// selection, but can be disabled by setting the following option to false: +replaceFileInput:true,// The parameter name for the file form data (the request argument name). +// If undefined or empty, the name property of the file input field is +// used, or "files[]" if the file input name property is also empty, +// can be a string or an array of strings: +paramName:undefined,// By default, each file of a selection is uploaded using an individual +// request for XHR type uploads. Set to false to upload file +// selections in one request each: +singleFileUploads:true,// To limit the number of files uploaded with one XHR request, +// set the following option to an integer greater than 0: +limitMultiFileUploads:undefined,// The following option limits the number of files uploaded with one +// XHR request to keep the request size under or equal to the defined +// limit in bytes: +limitMultiFileUploadSize:undefined,// Multipart file uploads add a number of bytes to each uploaded file, +// therefore the following option adds an overhead for each file used +// in the limitMultiFileUploadSize configuration: +limitMultiFileUploadSizeOverhead:512,// Set the following option to true to issue all file upload requests +// in a sequential order: +sequentialUploads:false,// To limit the number of concurrent uploads, +// set the following option to an integer greater than 0: +limitConcurrentUploads:undefined,// Set the following option to true to force iframe transport uploads: +forceIframeTransport:false,// Set the following option to the location of a redirect url on the +// origin server, for cross-domain iframe transport uploads: +redirect:undefined,// The parameter name for the redirect url, sent as part of the form +// data and set to 'redirect' if this option is empty: +redirectParamName:undefined,// Set the following option to the location of a postMessage window, +// to enable postMessage transport uploads: +postMessage:undefined,// By default, XHR file uploads are sent as multipart/form-data. +// The iframe transport is always using multipart/form-data. +// Set to false to enable non-multipart XHR uploads: +multipart:true,// To upload large files in smaller chunks, set the following option +// to a preferred maximum chunk size. If set to 0, null or undefined, +// or the browser does not support the required Blob API, files will +// be uploaded as a whole. +maxChunkSize:undefined,// When a non-multipart upload or a chunked multipart upload has been +// aborted, this option can be used to resume the upload by setting +// it to the size of the already uploaded bytes. This option is most +// useful when modifying the options object inside of the "add" or +// "send" callbacks, as the options are cloned for each file upload. +uploadedBytes:undefined,// By default, failed (abort or error) file uploads are removed from the +// global progress calculation. Set the following option to false to +// prevent recalculating the global progress data: +recalculateProgress:true,// Interval in milliseconds to calculate and trigger progress events: +progressInterval:100,// Interval in milliseconds to calculate progress bitrate: +bitrateInterval:500,// By default, uploads are started automatically when adding files: +autoUpload:true,// Error and info messages: +messages:{uploadedBytes:'Uploaded bytes exceed file size'},// Translation function, gets the message key to be translated +// and an object with context specific data as arguments: +i18n:function(message,context){message=this.messages[message]||message.toString();if(context){$.each(context,function(key,value){message=message.replace('{'+key+'}',value)})}return message},// Additional form data to be sent along with the file uploads can be set +// using this option, which accepts an array of objects with name and +// value properties, a function returning such an array, a FormData +// object (for XHR file uploads), or a simple object. +// The form of the first fileInput is given as parameter to the function: +formData:function(form){return form.serializeArray()},// The add callback is invoked as soon as files are added to the fileupload +// widget (via file input selection, drag & drop, paste or add API call). +// If the singleFileUploads option is enabled, this callback will be +// called once for each file in the selection for XHR file uploads, else +// once for each file selection. +// +// The upload starts when the submit method is invoked on the data parameter. +// The data object contains a files property holding the added files +// and allows you to override plugin options as well as define ajax settings. +// +// Listeners for this callback can also be bound the following way: +// .bind('fileuploadadd', func); +// +// data.submit() returns a Promise object and allows to attach additional +// handlers using jQuery's Deferred callbacks: +// data.submit().done(func).fail(func).always(func); +add:function(e,data){if(e.isDefaultPrevented()){return false}if(data.autoUpload||data.autoUpload!==false&&$(this).fileupload('option','autoUpload')){data.process().done(function(){data.submit()})}},// Other callbacks: +// Callback for the submit event of each file upload: +// submit: function (e, data) {}, // .bind('fileuploadsubmit', func); +// Callback for the start of each file upload request: +// send: function (e, data) {}, // .bind('fileuploadsend', func); +// Callback for successful uploads: +// done: function (e, data) {}, // .bind('fileuploaddone', func); +// Callback for failed (abort or error) uploads: +// fail: function (e, data) {}, // .bind('fileuploadfail', func); +// Callback for completed (success, abort or error) requests: +// always: function (e, data) {}, // .bind('fileuploadalways', func); +// Callback for upload progress events: +// progress: function (e, data) {}, // .bind('fileuploadprogress', func); +// Callback for global upload progress events: +// progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); +// Callback for uploads start, equivalent to the global ajaxStart event: +// start: function (e) {}, // .bind('fileuploadstart', func); +// Callback for uploads stop, equivalent to the global ajaxStop event: +// stop: function (e) {}, // .bind('fileuploadstop', func); +// Callback for change events of the fileInput(s): +// change: function (e, data) {}, // .bind('fileuploadchange', func); +// Callback for paste events to the pasteZone(s): +// paste: function (e, data) {}, // .bind('fileuploadpaste', func); +// Callback for drop events of the dropZone(s): +// drop: function (e, data) {}, // .bind('fileuploaddrop', func); +// Callback for dragover events of the dropZone(s): +// dragover: function (e) {}, // .bind('fileuploaddragover', func); +// Callback for the start of each chunk upload request: +// chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func); +// Callback for successful chunk uploads: +// chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func); +// Callback for failed (abort or error) chunk uploads: +// chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func); +// Callback for completed (success, abort or error) chunk upload requests: +// chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func); +// The plugin options are used as settings object for the ajax calls. +// The following are jQuery ajax settings required for the file uploads: +processData:false,contentType:false,cache:false,timeout:0},// A list of options that require reinitializing event listeners and/or +// special initialization code: +_specialOptions:['fileInput','dropZone','pasteZone','multipart','forceIframeTransport'],_blobSlice:$.support.blobSlice&&function(){var slice=this.slice||this.webkitSlice||this.mozSlice;return slice.apply(this,arguments)},_BitrateTimer:function(){this.timestamp=Date.now?Date.now():new Date().getTime();this.loaded=0;this.bitrate=0;this.getBitrate=function(now,loaded,interval){var timeDiff=now-this.timestamp;if(!this.bitrate||!interval||timeDiff>interval){this.bitrate=(loaded-this.loaded)*(1000/timeDiff)*8;this.loaded=loaded;this.timestamp=now}return this.bitrate}},_isXHRUpload:function(options){return!options.forceIframeTransport&&(!options.multipart&&$.support.xhrFileUpload||$.support.xhrFormDataFileUpload)},_getFormData:function(options){var formData;if($.type(options.formData)==='function'){return options.formData(options.form)}if($.isArray(options.formData)){return options.formData}if($.type(options.formData)==='object'){formData=[];$.each(options.formData,function(name,value){formData.push({name:name,value:value})});return formData}return[]},_getTotal:function(files){var total=0;$.each(files,function(index,file){total+=file.size||1});return total},_initProgressObject:function(obj){var progress={loaded:0,total:0,bitrate:0};if(obj._progress){$.extend(obj._progress,progress)}else{obj._progress=progress}},_initResponseObject:function(obj){var prop;if(obj._response){for(prop in obj._response){if(obj._response.hasOwnProperty(prop)){delete obj._response[prop]}}}else{obj._response={}}},_onProgress:function(e,data){if(e.lengthComputable){var now=Date.now?Date.now():new Date().getTime(),loaded;if(data._time&&data.progressInterval&&now-data._time<data.progressInterval&&e.loaded!==e.total){return}data._time=now;loaded=Math.floor(e.loaded/e.total*(data.chunkSize||data._progress.total))+(data.uploadedBytes||0);// Add the difference from the previously loaded state +// to the global loaded counter: +this._progress.loaded+=loaded-data._progress.loaded;this._progress.bitrate=this._bitrateTimer.getBitrate(now,this._progress.loaded,data.bitrateInterval);data._progress.loaded=data.loaded=loaded;data._progress.bitrate=data.bitrate=data._bitrateTimer.getBitrate(now,loaded,data.bitrateInterval);// Trigger a custom progress event with a total data property set +// to the file size(s) of the current upload and a loaded data +// property calculated accordingly: +this._trigger('progress',$.Event('progress',{delegatedEvent:e}),data);// Trigger a global progress event for all current file uploads, +// including ajax calls queued for sequential file uploads: +this._trigger('progressall',$.Event('progressall',{delegatedEvent:e}),this._progress)}},_initProgressListener:function(options){var that=this,xhr=options.xhr?options.xhr():$.ajaxSettings.xhr();// Accesss to the native XHR object is required to add event listeners +// for the upload progress event: +if(xhr.upload){$(xhr.upload).bind('progress',function(e){var oe=e.originalEvent;// Make sure the progress event properties get copied over: +e.lengthComputable=oe.lengthComputable;e.loaded=oe.loaded;e.total=oe.total;that._onProgress(e,options)});options.xhr=function(){return xhr}}},_isInstanceOf:function(type,obj){// Cross-frame instanceof check +return Object.prototype.toString.call(obj)==='[object '+type+']'},_initXHRData:function(options){var that=this,formData,file=options.files[0],// Ignore non-multipart setting if not supported: +multipart=options.multipart||!$.support.xhrFileUpload,paramName=$.type(options.paramName)==='array'?options.paramName[0]:options.paramName;options.headers=$.extend({},options.headers);if(options.contentRange){options.headers['Content-Range']=options.contentRange}if(!multipart||options.blob||!this._isInstanceOf('File',file)){options.headers['Content-Disposition']='attachment; filename="'+encodeURI(file.name)+'"'}if(!multipart){options.contentType=file.type||'application/octet-stream';options.data=options.blob||file}else if($.support.xhrFormDataFileUpload){if(options.postMessage){// window.postMessage does not allow sending FormData +// objects, so we just add the File/Blob objects to +// the formData array and let the postMessage window +// create the FormData object out of this array: +formData=this._getFormData(options);if(options.blob){formData.push({name:paramName,value:options.blob})}else{$.each(options.files,function(index,file){formData.push({name:$.type(options.paramName)==='array'&&options.paramName[index]||paramName,value:file})})}}else{if(that._isInstanceOf('FormData',options.formData)){formData=options.formData}else{formData=new FormData;$.each(this._getFormData(options),function(index,field){formData.append(field.name,field.value)})}if(options.blob){formData.append(paramName,options.blob,file.name)}else{$.each(options.files,function(index,file){// This check allows the tests to run with +// dummy objects: +if(that._isInstanceOf('File',file)||that._isInstanceOf('Blob',file)){formData.append($.type(options.paramName)==='array'&&options.paramName[index]||paramName,file,file.uploadName||file.name)}})}}options.data=formData}// Blob reference is not needed anymore, free memory: +options.blob=null},_initIframeSettings:function(options){var targetHost=$('<a></a>').prop('href',options.url).prop('host');// Setting the dataType to iframe enables the iframe transport: +options.dataType='iframe '+(options.dataType||'');// The iframe transport accepts a serialized array as form data: +options.formData=this._getFormData(options);// Add redirect url to form data on cross-domain uploads: +if(options.redirect&&targetHost&&targetHost!==location.host){options.formData.push({name:options.redirectParamName||'redirect',value:options.redirect})}},_initDataSettings:function(options){if(this._isXHRUpload(options)){if(!this._chunkedUpload(options,true)){if(!options.data){this._initXHRData(options)}this._initProgressListener(options)}if(options.postMessage){// Setting the dataType to postmessage enables the +// postMessage transport: +options.dataType='postmessage '+(options.dataType||'')}}else{this._initIframeSettings(options)}},_getParamName:function(options){var fileInput=$(options.fileInput),paramName=options.paramName;if(!paramName){paramName=[];fileInput.each(function(){var input=$(this),name=input.prop('name')||'files[]',i=(input.prop('files')||[1]).length;while(i){paramName.push(name);i-=1}});if(!paramName.length){paramName=[fileInput.prop('name')||'files[]']}}else if(!$.isArray(paramName)){paramName=[paramName]}return paramName},_initFormSettings:function(options){// Retrieve missing options from the input field and the +// associated form, if available: +if(!options.form||!options.form.length){options.form=$(options.fileInput.prop('form'));// If the given file input doesn't have an associated form, +// use the default widget file input's form: +if(!options.form.length){options.form=$(this.options.fileInput.prop('form'))}}options.paramName=this._getParamName(options);if(!options.url){options.url=options.form.prop('action')||location.href}// The HTTP request method must be "POST" or "PUT": +options.type=(options.type||$.type(options.form.prop('method'))==='string'&&options.form.prop('method')||'').toUpperCase();if(options.type!=='POST'&&options.type!=='PUT'&&options.type!=='PATCH'){options.type='POST'}if(!options.formAcceptCharset){options.formAcceptCharset=options.form.attr('accept-charset')}},_getAJAXSettings:function(data){var options=$.extend({},this.options,data);this._initFormSettings(options);this._initDataSettings(options);return options},// jQuery 1.6 doesn't provide .state(), +// while jQuery 1.8+ removed .isRejected() and .isResolved(): +_getDeferredState:function(deferred){if(deferred.state){return deferred.state()}if(deferred.isResolved()){return'resolved'}if(deferred.isRejected()){return'rejected'}return'pending'},// Maps jqXHR callbacks to the equivalent +// methods of the given Promise object: +_enhancePromise:function(promise){promise.success=promise.done;promise.error=promise.fail;promise.complete=promise.always;return promise},// Creates and returns a Promise object enhanced with +// the jqXHR methods abort, success, error and complete: +_getXHRPromise:function(resolveOrReject,context,args){var dfd=$.Deferred(),promise=dfd.promise();context=context||this.options.context||promise;if(resolveOrReject===true){dfd.resolveWith(context,args)}else if(resolveOrReject===false){dfd.rejectWith(context,args)}promise.abort=dfd.promise;return this._enhancePromise(promise)},// Adds convenience methods to the data callback argument: +_addConvenienceMethods:function(e,data){var that=this,getPromise=function(args){return $.Deferred().resolveWith(that,args).promise()};data.process=function(resolveFunc,rejectFunc){if(resolveFunc||rejectFunc){data._processQueue=this._processQueue=(this._processQueue||getPromise([this])).then(function(){if(data.errorThrown){return $.Deferred().rejectWith(that,[data]).promise()}return getPromise(arguments)}).then(resolveFunc,rejectFunc)}return this._processQueue||getPromise([this])};data.submit=function(){if(this.state()!=='pending'){data.jqXHR=this.jqXHR=that._trigger('submit',$.Event('submit',{delegatedEvent:e}),this)!==false&&that._onSend(e,this)}return this.jqXHR||that._getXHRPromise()};data.abort=function(){if(this.jqXHR){return this.jqXHR.abort()}this.errorThrown='abort';that._trigger('fail',null,this);return that._getXHRPromise(false)};data.state=function(){if(this.jqXHR){return that._getDeferredState(this.jqXHR)}if(this._processQueue){return that._getDeferredState(this._processQueue)}};data.processing=function(){return!this.jqXHR&&this._processQueue&&that._getDeferredState(this._processQueue)==='pending'};data.progress=function(){return this._progress};data.response=function(){return this._response}},// Parses the Range header from the server response +// and returns the uploaded bytes: +_getUploadedBytes:function(jqXHR){var range=jqXHR.getResponseHeader('Range'),parts=range&&range.split('-'),upperBytesPos=parts&&parts.length>1&&parseInt(parts[1],10);return upperBytesPos&&upperBytesPos+1},// Uploads a file in multiple, sequential requests +// by splitting the file up in multiple blob chunks. +// If the second parameter is true, only tests if the file +// should be uploaded in chunks, but does not invoke any +// upload requests: +_chunkedUpload:function(options,testOnly){options.uploadedBytes=options.uploadedBytes||0;var that=this,file=options.files[0],fs=file.size,ub=options.uploadedBytes,mcs=options.maxChunkSize||fs,slice=this._blobSlice,dfd=$.Deferred(),promise=dfd.promise(),jqXHR,upload;if(!(this._isXHRUpload(options)&&slice&&(ub||($.type(mcs)==='function'?mcs(options):mcs)<fs))||options.data){return false}if(testOnly){return true}if(ub>=fs){file.error=options.i18n('uploadedBytes');return this._getXHRPromise(false,options.context,[null,'error',file.error])}// The chunk upload method: +upload=function(){// Clone the options object for each chunk upload: +var o=$.extend({},options),currentLoaded=o._progress.loaded;o.blob=slice.call(file,ub,ub+($.type(mcs)==='function'?mcs(o):mcs),file.type);// Store the current chunk size, as the blob itself +// will be dereferenced after data processing: +o.chunkSize=o.blob.size;// Expose the chunk bytes position range: +o.contentRange='bytes '+ub+'-'+(ub+o.chunkSize-1)+'/'+fs;// Process the upload data (the blob and potential form data): +that._initXHRData(o);// Add progress listeners for this chunk upload: +that._initProgressListener(o);jqXHR=(that._trigger('chunksend',null,o)!==false&&$.ajax(o)||that._getXHRPromise(false,o.context)).done(function(result,textStatus,jqXHR){ub=that._getUploadedBytes(jqXHR)||ub+o.chunkSize;// Create a progress event if no final progress event +// with loaded equaling total has been triggered +// for this chunk: +if(currentLoaded+o.chunkSize-o._progress.loaded){that._onProgress($.Event('progress',{lengthComputable:true,loaded:ub-o.uploadedBytes,total:ub-o.uploadedBytes}),o)}options.uploadedBytes=o.uploadedBytes=ub;o.result=result;o.textStatus=textStatus;o.jqXHR=jqXHR;that._trigger('chunkdone',null,o);that._trigger('chunkalways',null,o);if(ub<fs){// File upload not yet complete, +// continue with the next chunk: +upload()}else{dfd.resolveWith(o.context,[result,textStatus,jqXHR])}}).fail(function(jqXHR,textStatus,errorThrown){o.jqXHR=jqXHR;o.textStatus=textStatus;o.errorThrown=errorThrown;that._trigger('chunkfail',null,o);that._trigger('chunkalways',null,o);dfd.rejectWith(o.context,[jqXHR,textStatus,errorThrown])})};this._enhancePromise(promise);promise.abort=function(){return jqXHR.abort()};upload();return promise},_beforeSend:function(e,data){if(this._active===0){// the start callback is triggered when an upload starts +// and no other uploads are currently running, +// equivalent to the global ajaxStart event: +this._trigger('start');// Set timer for global bitrate progress calculation: +this._bitrateTimer=new this._BitrateTimer;// Reset the global progress values: +this._progress.loaded=this._progress.total=0;this._progress.bitrate=0}// Make sure the container objects for the .response() and +// .progress() methods on the data object are available +// and reset to their initial state: +this._initResponseObject(data);this._initProgressObject(data);data._progress.loaded=data.loaded=data.uploadedBytes||0;data._progress.total=data.total=this._getTotal(data.files)||1;data._progress.bitrate=data.bitrate=0;this._active+=1;// Initialize the global progress values: +this._progress.loaded+=data.loaded;this._progress.total+=data.total},_onDone:function(result,textStatus,jqXHR,options){var total=options._progress.total,response=options._response;if(options._progress.loaded<total){// Create a progress event if no final progress event +// with loaded equaling total has been triggered: +this._onProgress($.Event('progress',{lengthComputable:true,loaded:total,total:total}),options)}response.result=options.result=result;response.textStatus=options.textStatus=textStatus;response.jqXHR=options.jqXHR=jqXHR;this._trigger('done',null,options)},_onFail:function(jqXHR,textStatus,errorThrown,options){var response=options._response;if(options.recalculateProgress){// Remove the failed (error or abort) file upload from +// the global progress calculation: +this._progress.loaded-=options._progress.loaded;this._progress.total-=options._progress.total}response.jqXHR=options.jqXHR=jqXHR;response.textStatus=options.textStatus=textStatus;response.errorThrown=options.errorThrown=errorThrown;this._trigger('fail',null,options)},_onAlways:function(jqXHRorResult,textStatus,jqXHRorError,options){// jqXHRorResult, textStatus and jqXHRorError are added to the +// options object via done and fail callbacks +this._trigger('always',null,options)},_onSend:function(e,data){if(!data.submit){this._addConvenienceMethods(e,data)}var that=this,jqXHR,aborted,slot,pipe,options=that._getAJAXSettings(data),send=function(){that._sending+=1;// Set timer for bitrate progress calculation: +options._bitrateTimer=new that._BitrateTimer;jqXHR=jqXHR||((aborted||that._trigger('send',$.Event('send',{delegatedEvent:e}),options)===false)&&that._getXHRPromise(false,options.context,aborted)||that._chunkedUpload(options)||$.ajax(options)).done(function(result,textStatus,jqXHR){that._onDone(result,textStatus,jqXHR,options)}).fail(function(jqXHR,textStatus,errorThrown){that._onFail(jqXHR,textStatus,errorThrown,options)}).always(function(jqXHRorResult,textStatus,jqXHRorError){that._onAlways(jqXHRorResult,textStatus,jqXHRorError,options);that._sending-=1;that._active-=1;if(options.limitConcurrentUploads&&options.limitConcurrentUploads>that._sending){// Start the next queued upload, +// that has not been aborted: +var nextSlot=that._slots.shift();while(nextSlot){if(that._getDeferredState(nextSlot)==='pending'){nextSlot.resolve();break}nextSlot=that._slots.shift()}}if(that._active===0){// The stop callback is triggered when all uploads have +// been completed, equivalent to the global ajaxStop event: +that._trigger('stop')}});return jqXHR};this._beforeSend(e,options);if(this.options.sequentialUploads||this.options.limitConcurrentUploads&&this.options.limitConcurrentUploads<=this._sending){if(this.options.limitConcurrentUploads>1){slot=$.Deferred();this._slots.push(slot);pipe=slot.then(send)}else{this._sequence=this._sequence.then(send,send);pipe=this._sequence}// Return the piped Promise object, enhanced with an abort method, +// which is delegated to the jqXHR object of the current upload, +// and jqXHR callbacks mapped to the equivalent Promise methods: +pipe.abort=function(){aborted=[undefined,'abort','abort'];if(!jqXHR){if(slot){slot.rejectWith(options.context,aborted)}return send()}return jqXHR.abort()};return this._enhancePromise(pipe)}return send()},_onAdd:function(e,data){var that=this,result=true,options=$.extend({},this.options,data),files=data.files,filesLength=files.length,limit=options.limitMultiFileUploads,limitSize=options.limitMultiFileUploadSize,overhead=options.limitMultiFileUploadSizeOverhead,batchSize=0,paramName=this._getParamName(options),paramNameSet,paramNameSlice,fileSet,i,j=0;if(!filesLength){return false}if(limitSize&&files[0].size===undefined){limitSize=undefined}if(!(options.singleFileUploads||limit||limitSize)||!this._isXHRUpload(options)){fileSet=[files];paramNameSet=[paramName]}else if(!(options.singleFileUploads||limitSize)&&limit){fileSet=[];paramNameSet=[];for(i=0;i<filesLength;i+=limit){fileSet.push(files.slice(i,i+limit));paramNameSlice=paramName.slice(i,i+limit);if(!paramNameSlice.length){paramNameSlice=paramName}paramNameSet.push(paramNameSlice)}}else if(!options.singleFileUploads&&limitSize){fileSet=[];paramNameSet=[];for(i=0;i<filesLength;i=i+1){batchSize+=files[i].size+overhead;if(i+1===filesLength||batchSize+files[i+1].size+overhead>limitSize||limit&&i+1-j>=limit){fileSet.push(files.slice(j,i+1));paramNameSlice=paramName.slice(j,i+1);if(!paramNameSlice.length){paramNameSlice=paramName}paramNameSet.push(paramNameSlice);j=i+1;batchSize=0}}}else{paramNameSet=paramName}data.originalFiles=files;$.each(fileSet||files,function(index,element){var newData=$.extend({},data);newData.files=fileSet?element:[element];newData.paramName=paramNameSet[index];that._initResponseObject(newData);that._initProgressObject(newData);that._addConvenienceMethods(e,newData);result=that._trigger('add',$.Event('add',{delegatedEvent:e}),newData);return result});return result},_replaceFileInput:function(data){var input=data.fileInput,inputClone=input.clone(true),restoreFocus=input.is(document.activeElement);// Add a reference for the new cloned file input to the data argument: +data.fileInputClone=inputClone;$('<form></form>').append(inputClone)[0].reset();// Detaching allows to insert the fileInput on another form +// without loosing the file input value: +input.after(inputClone).detach();// If the fileInput had focus before it was detached, +// restore focus to the inputClone. +if(restoreFocus){inputClone.focus()}// Avoid memory leaks with the detached file input: +$.cleanData(input.unbind('remove'));// Replace the original file input element in the fileInput +// elements set with the clone, which has been copied including +// event handlers: +this.options.fileInput=this.options.fileInput.map(function(i,el){if(el===input[0]){return inputClone[0]}return el});// If the widget has been initialized on the file input itself, +// override this.element with the file input clone: +if(input[0]===this.element[0]){this.element=inputClone}},_handleFileTreeEntry:function(entry,path){var that=this,dfd=$.Deferred(),entries=[],dirReader,errorHandler=function(e){if(e&&!e.entry){e.entry=entry}// Since $.when returns immediately if one +// Deferred is rejected, we use resolve instead. +// This allows valid files and invalid items +// to be returned together in one set: +dfd.resolve([e])},successHandler=function(entries){that._handleFileTreeEntries(entries,path+entry.name+'/').done(function(files){dfd.resolve(files)}).fail(errorHandler)},readEntries=function(){dirReader.readEntries(function(results){if(!results.length){successHandler(entries)}else{entries=entries.concat(results);readEntries()}},errorHandler)};path=path||'';if(entry.isFile){if(entry._file){// Workaround for Chrome bug #149735 +entry._file.relativePath=path;dfd.resolve(entry._file)}else{entry.file(function(file){file.relativePath=path;dfd.resolve(file)},errorHandler)}}else if(entry.isDirectory){dirReader=entry.createReader();readEntries()}else{// Return an empy list for file system items +// other than files or directories: +dfd.resolve([])}return dfd.promise()},_handleFileTreeEntries:function(entries,path){var that=this;return $.when.apply($,$.map(entries,function(entry){return that._handleFileTreeEntry(entry,path)})).then(function(){return Array.prototype.concat.apply([],arguments)})},_getDroppedFiles:function(dataTransfer){dataTransfer=dataTransfer||{};var items=dataTransfer.items;if(items&&items.length&&(items[0].webkitGetAsEntry||items[0].getAsEntry)){return this._handleFileTreeEntries($.map(items,function(item){var entry;if(item.webkitGetAsEntry){entry=item.webkitGetAsEntry();if(entry){// Workaround for Chrome bug #149735: +entry._file=item.getAsFile()}return entry}return item.getAsEntry()}))}return $.Deferred().resolve($.makeArray(dataTransfer.files)).promise()},_getSingleFileInputFiles:function(fileInput){fileInput=$(fileInput);var entries=fileInput.prop('webkitEntries')||fileInput.prop('entries'),files,value;if(entries&&entries.length){return this._handleFileTreeEntries(entries)}files=$.makeArray(fileInput.prop('files'));if(!files.length){value=fileInput.prop('value');if(!value){return $.Deferred().resolve([]).promise()}// If the files property is not available, the browser does not +// support the File API and we add a pseudo File object with +// the input value as name with path information removed: +files=[{name:value.replace(/^.*\\/,'')}]}else if(files[0].name===undefined&&files[0].fileName){// File normalization for Safari 4 and Firefox 3: +$.each(files,function(index,file){file.name=file.fileName;file.size=file.fileSize})}return $.Deferred().resolve(files).promise()},_getFileInputFiles:function(fileInput){if(!(fileInput instanceof $)||fileInput.length===1){return this._getSingleFileInputFiles(fileInput)}return $.when.apply($,$.map(fileInput,this._getSingleFileInputFiles)).then(function(){return Array.prototype.concat.apply([],arguments)})},_onChange:function(e){var that=this,data={fileInput:$(e.target),form:$(e.target.form)};this._getFileInputFiles(data.fileInput).always(function(files){data.files=files;if(that.options.replaceFileInput){that._replaceFileInput(data)}if(that._trigger('change',$.Event('change',{delegatedEvent:e}),data)!==false){that._onAdd(e,data)}})},_onPaste:function(e){var items=e.originalEvent&&e.originalEvent.clipboardData&&e.originalEvent.clipboardData.items,data={files:[]};if(items&&items.length){$.each(items,function(index,item){var file=item.getAsFile&&item.getAsFile();if(file){data.files.push(file)}});if(this._trigger('paste',$.Event('paste',{delegatedEvent:e}),data)!==false){this._onAdd(e,data)}}},_onDrop:function(e){e.dataTransfer=e.originalEvent&&e.originalEvent.dataTransfer;var that=this,dataTransfer=e.dataTransfer,data={};if(dataTransfer&&dataTransfer.files&&dataTransfer.files.length){e.preventDefault();this._getDroppedFiles(dataTransfer).always(function(files){data.files=files;if(that._trigger('drop',$.Event('drop',{delegatedEvent:e}),data)!==false){that._onAdd(e,data)}})}},_onDragOver:getDragHandler('dragover'),_onDragEnter:getDragHandler('dragenter'),_onDragLeave:getDragHandler('dragleave'),_initEventHandlers:function(){if(this._isXHRUpload(this.options)){this._on(this.options.dropZone,{dragover:this._onDragOver,drop:this._onDrop,// event.preventDefault() on dragenter is required for IE10+: +dragenter:this._onDragEnter,// dragleave is not required, but added for completeness: +dragleave:this._onDragLeave});this._on(this.options.pasteZone,{paste:this._onPaste})}if($.support.fileInput){this._on(this.options.fileInput,{change:this._onChange})}},_destroyEventHandlers:function(){this._off(this.options.dropZone,'dragenter dragleave dragover drop');this._off(this.options.pasteZone,'paste');this._off(this.options.fileInput,'change')},_destroy:function(){this._destroyEventHandlers()},_setOption:function(key,value){var reinit=$.inArray(key,this._specialOptions)!==-1;if(reinit){this._destroyEventHandlers()}this._super(key,value);if(reinit){this._initSpecialOptions();this._initEventHandlers()}},_initSpecialOptions:function(){var options=this.options;if(options.fileInput===undefined){options.fileInput=this.element.is('input[type="file"]')?this.element:this.element.find('input[type="file"]')}else if(!(options.fileInput instanceof $)){options.fileInput=$(options.fileInput)}if(!(options.dropZone instanceof $)){options.dropZone=$(options.dropZone)}if(!(options.pasteZone instanceof $)){options.pasteZone=$(options.pasteZone)}},_getRegExp:function(str){var parts=str.split('/'),modifiers=parts.pop();parts.shift();return new RegExp(parts.join('/'),modifiers)},_isRegExpOption:function(key,value){return key!=='url'&&$.type(value)==='string'&&/^\/.*\/[igm]{0,3}$/.test(value)},_initDataAttributes:function(){var that=this,options=this.options,data=this.element.data();// Initialize options set via HTML5 data-attributes: +$.each(this.element[0].attributes,function(index,attr){var key=attr.name.toLowerCase(),value;if(/^data-/.test(key)){// Convert hyphen-ated key to camelCase: +key=key.slice(5).replace(/-[a-z]/g,function(str){return str.charAt(1).toUpperCase()});value=data[key];if(that._isRegExpOption(key,value)){value=that._getRegExp(value)}options[key]=value}})},_create:function(){this._initDataAttributes();this._initSpecialOptions();this._slots=[];this._sequence=this._getXHRPromise(true);this._sending=this._active=0;this._initProgressObject(this);this._initEventHandlers()},// This method is exposed to the widget API and allows to query +// the number of active uploads: +active:function(){return this._active},// This method is exposed to the widget API and allows to query +// the widget upload progress. +// It returns an object with loaded, total and bitrate properties +// for the running uploads: +progress:function(){return this._progress},// This method is exposed to the widget API and allows adding files +// using the fileupload API. The data parameter accepts an object which +// must have a files property and can contain additional options: +// .fileupload('add', {files: filesList}); +add:function(data){var that=this;if(!data||this.options.disabled){return}if(data.fileInput&&!data.files){this._getFileInputFiles(data.fileInput).always(function(files){data.files=files;that._onAdd(null,data)})}else{data.files=$.makeArray(data.files);this._onAdd(null,data)}},// This method is exposed to the widget API and allows sending files +// using the fileupload API. The data parameter accepts an object which +// must have a files or fileInput property and can contain additional options: +// .fileupload('send', {files: filesList}); +// The method returns a Promise object for the file upload call. +send:function(data){if(data&&!this.options.disabled){if(data.fileInput&&!data.files){var that=this,dfd=$.Deferred(),promise=dfd.promise(),jqXHR,aborted;promise.abort=function(){aborted=true;if(jqXHR){return jqXHR.abort()}dfd.reject(null,'abort','abort');return promise};this._getFileInputFiles(data.fileInput).always(function(files){if(aborted){return}if(!files.length){dfd.reject();return}data.files=files;jqXHR=that._onSend(null,data);jqXHR.then(function(result,textStatus,jqXHR){dfd.resolve(result,textStatus,jqXHR)},function(jqXHR,textStatus,errorThrown){dfd.reject(jqXHR,textStatus,errorThrown)})});return this._enhancePromise(promise)}data.files=$.makeArray(data.files);if(data.files.length){return this._onSend(null,data)}}return this._getXHRPromise(false,data&&data.context)}})}); +/* + * jQuery File Upload Processing Plugin + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2012, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + *//* jshint nomen:false *//* global define, require, window */;(function(factory){'use strict';if(typeof define==='function'&&define.amd){// Register as an anonymous AMD module: +define(['jquery','./jquery.fileupload'],factory)}else if(typeof exports==='object'){// Node/CommonJS: +factory(require('jquery'),require('./jquery.fileupload'))}else{// Browser globals: +factory(window.jQuery)}})(function($){'use strict';var originalAdd=$.blueimp.fileupload.prototype.options.add;// The File Upload Processing plugin extends the fileupload widget +// with file processing functionality: +$.widget('blueimp.fileupload',$.blueimp.fileupload,{options:{// The list of processing actions: +processQueue:[/* + { + action: 'log', + type: 'debug' + } + */],add:function(e,data){var $this=$(this);data.process(function(){return $this.fileupload('process',data)});originalAdd.call(this,e,data)}},processActions:{/* + log: function (data, options) { + console[options.type]( + 'Processing "' + data.files[data.index].name + '"' + ); + } + */},_processFile:function(data,originalData){var that=this,dfd=$.Deferred().resolveWith(that,[data]),chain=dfd.promise();this._trigger('process',null,data);$.each(data.processQueue,function(i,settings){var func=function(data){if(originalData.errorThrown){return $.Deferred().rejectWith(that,[originalData]).promise()}return that.processActions[settings.action].call(that,data,settings)};chain=chain.then(func,settings.always&&func)});chain.done(function(){that._trigger('processdone',null,data);that._trigger('processalways',null,data)}).fail(function(){that._trigger('processfail',null,data);that._trigger('processalways',null,data)});return chain},// Replaces the settings of each processQueue item that +// are strings starting with an "@", using the remaining +// substring as key for the option map, +// e.g. "@autoUpload" is replaced with options.autoUpload: +_transformProcessQueue:function(options){var processQueue=[];$.each(options.processQueue,function(){var settings={},action=this.action,prefix=this.prefix===true?action:this.prefix;$.each(this,function(key,value){if($.type(value)==='string'&&value.charAt(0)==='@'){settings[key]=options[value.slice(1)||(prefix?prefix+key.charAt(0).toUpperCase()+key.slice(1):key)]}else{settings[key]=value}});processQueue.push(settings)});options.processQueue=processQueue},// Returns the number of files currently in the processsing queue: +processing:function(){return this._processing},// Processes the files given as files property of the data parameter, +// returns a Promise object that allows to bind callbacks: +process:function(data){var that=this,options=$.extend({},this.options,data);if(options.processQueue&&options.processQueue.length){this._transformProcessQueue(options);if(this._processing===0){this._trigger('processstart')}$.each(data.files,function(index){var opts=index?$.extend({},options):options,func=function(){if(data.errorThrown){return $.Deferred().rejectWith(that,[data]).promise()}return that._processFile(opts,data)};opts.index=index;that._processing+=1;that._processingQueue=that._processingQueue.then(func,func).always(function(){that._processing-=1;if(that._processing===0){that._trigger('processstop')}})})}return this._processingQueue},_create:function(){this._super();this._processing=0;this._processingQueue=$.Deferred().resolveWith(this).promise()}})}); +/* + * jQuery File Upload Validation Plugin + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + *//* global define, require, window */;(function(factory){'use strict';if(typeof define==='function'&&define.amd){// Register as an anonymous AMD module: +define(['jquery','./jquery.fileupload-process'],factory)}else if(typeof exports==='object'){// Node/CommonJS: +factory(require('jquery'),require('./jquery.fileupload-process'))}else{// Browser globals: +factory(window.jQuery)}})(function($){'use strict';// Append to the default processQueue: +$.blueimp.fileupload.prototype.options.processQueue.push({action:'validate',// Always trigger this action, +// even if the previous action was rejected: +always:true,// Options taken from the global options map: +acceptFileTypes:'@',maxFileSize:'@',minFileSize:'@',maxNumberOfFiles:'@',disabled:'@disableValidation'});// The File Upload Validation plugin extends the fileupload widget +// with file validation functionality: +$.widget('blueimp.fileupload',$.blueimp.fileupload,{options:{/* + // The regular expression for allowed file types, matches + // against either file type or file name: + acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, + // The maximum allowed file size in bytes: + maxFileSize: 10000000, // 10 MB + // The minimum allowed file size in bytes: + minFileSize: undefined, // No minimal file size + // The limit of files to be uploaded: + maxNumberOfFiles: 10, + */// Function returning the current number of files, +// has to be overriden for maxNumberOfFiles validation: +getNumberOfFiles:$.noop,// Error and info messages: +messages:{maxNumberOfFiles:'Maximum number of files exceeded',acceptFileTypes:'File type not allowed',maxFileSize:'File is too large',minFileSize:'File is too small'}},processActions:{validate:function(data,options){if(options.disabled){return data}var dfd=$.Deferred(),settings=this.options,file=data.files[data.index],fileSize;if(options.minFileSize||options.maxFileSize){fileSize=file.size}if($.type(options.maxNumberOfFiles)==='number'&&(settings.getNumberOfFiles()||0)+data.files.length>options.maxNumberOfFiles){file.error=settings.i18n('maxNumberOfFiles')}else if(options.acceptFileTypes&&!(options.acceptFileTypes.test(file.type)||options.acceptFileTypes.test(file.name))){file.error=settings.i18n('acceptFileTypes')}else if(fileSize>options.maxFileSize){file.error=settings.i18n('maxFileSize')}else if($.type(fileSize)==='number'&&fileSize<options.minFileSize){file.error=settings.i18n('minFileSize')}else{delete file.error}if(file.error||data.files.error){data.files.error=true;dfd.rejectWith(this,[data])}else{dfd.resolveWith(this,[data])}return dfd.promise()}}})}); diff --git a/src/dgenies/templates/base.html b/src/dgenies/templates/base.html index 7426d40..743cce4 100644 --- a/src/dgenies/templates/base.html +++ b/src/dgenies/templates/base.html @@ -10,14 +10,22 @@ <script src="{{ url_for('static', filename='js/bootstrap-notify.min.js') }}" type="text/JavaScript"></script> <script src="{{ url_for('static', filename='js/jquery-ui.min.js') }}" type="text/JavaScript"></script> <script src="{{ url_for('static', filename='js/jquery.cookie-1.4.1.min.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.prototypes.js') }}" type="text/JavaScript"></script> + {% if debug %} + <script src="{{ url_for('static', filename='js/dgenies.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/dgenies.prototypes.js') }}" type="text/JavaScript"></script> + {% else %} + <script src="{{ url_for('static', filename='js/dgenies.min.js') }}" type="text/JavaScript"></script> + {% endif %} {% endblock %} <link rel="stylesheet" href="{{ url_for('static', filename='css/animate.css') }}" type="text/css"> <link rel="stylesheet" href="{{ url_for('static', filename='css/jquery-ui.min.css') }}" type="text/css"> <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css"> <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}" type="text/css"> - <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css"> + {% if debug %} + <link rel="stylesheet" href="{{ url_for('static', filename='css/dgenies.css') }}" type="text/css"> + {% else %} + <link rel="stylesheet" href="{{ url_for('static', filename='css/dgenies.min.css') }}" type="text/css"> + {% endif %} <link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}"> </head> <body role="document" onload="{% block onload %}dgenies.init({{ all_jobs}}, '{{ mode }}');{% endblock %}"> diff --git a/src/dgenies/templates/result.html b/src/dgenies/templates/result.html index 2adf647..9e4bfe2 100644 --- a/src/dgenies/templates/result.html +++ b/src/dgenies/templates/result.html @@ -4,15 +4,19 @@ <script src="{{ url_for('static', filename='js/chosen.jquery.min.js') }}" type="text/JavaScript"></script> <script src="{{ url_for('static', filename='js/FileSaver.min.js') }}" type="text/JavaScript"></script> <script src="{{ url_for('static', filename='js/canvg.min.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.result.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.result.controls.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.result.export.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/dgenies.result.summary.js') }}" type="text/JavaScript"></script> <script src="{{ url_for('static', filename='js/d3.min.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/d3.boxplot.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/d3.boxplot.zoom.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/d3.boxplot.events.js') }}" type="text/JavaScript"></script> - <script src="{{ url_for('static', filename='js/d3.boxplot.mousetip.js') }}" type="text/JavaScript"></script> + {% if debug %} + <script src="{{ url_for('static', filename='js/dgenies.result.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/dgenies.result.controls.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/dgenies.result.export.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/dgenies.result.summary.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/d3.boxplot.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/d3.boxplot.zoom.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/d3.boxplot.events.js') }}" type="text/JavaScript"></script> + <script src="{{ url_for('static', filename='js/d3.boxplot.mousetip.js') }}" type="text/JavaScript"></script> + {% else %} + <script src="{{ url_for('static', filename='js/dgenies.result.min.js') }}" type="text/JavaScript"></script> + {% endif %} <script src="{{ url_for('static', filename='js/BootstrapMenu.min.js') }}" type="text/JavaScript"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/chosen.min.css') }}" type="text/css"> {% endblock %} diff --git a/src/dgenies/templates/run.html b/src/dgenies/templates/run.html index a06c93b..0fe0dbc 100644 --- a/src/dgenies/templates/run.html +++ b/src/dgenies/templates/run.html @@ -1,13 +1,18 @@ {% extends 'base.html' %} {% block scripts %} {{ super() }} - <!-- The basic File Upload plugin --> - <script src="{{ url_for('static', filename='js/jquery.fileupload.js') }}"></script> - <!-- The File Upload processing plugin --> - <script src="{{ url_for('static', filename='js/jquery.fileupload-process.js') }}"></script> - <!-- The File Upload validation plugin --> - <script src="{{ url_for('static', filename='js/jquery.fileupload-validate.js') }}"></script> - <script src="{{ url_for('static', filename='js/dgenies.run.js') }}" type="text/JavaScript"></script> + {% if debug %} + <!-- The basic File Upload plugin --> + <script src="{{ url_for('static', filename='js/jquery.fileupload.js') }}"></script> + <!-- The File Upload processing plugin --> + <script src="{{ url_for('static', filename='js/jquery.fileupload-process.js') }}"></script> + <!-- The File Upload validation plugin --> + <script src="{{ url_for('static', filename='js/jquery.fileupload-validate.js') }}"></script> + <script src="{{ url_for('static', filename='js/dgenies.run.js') }}" type="text/JavaScript"></script> + {% else %} + <script src="{{ url_for('static', filename='js/jquery.fileupload.min.js') }}"></script> + <script src="{{ url_for('static', filename='js/dgenies.run.min.js') }}" type="text/JavaScript"></script> + {% endif %} {% endblock %} {% block onload %} {{ super() }} diff --git a/src/dgenies/templates/status.html b/src/dgenies/templates/status.html index 10ea38f..7768744 100644 --- a/src/dgenies/templates/status.html +++ b/src/dgenies/templates/status.html @@ -1,7 +1,11 @@ {% extends 'base.html' %} {% block scripts %} {{ super() }} + {% if debug %} <script src="{{ url_for('static', filename='js/dgenies.status.js') }}" type="text/JavaScript"></script> + {% else %} + <script src="{{ url_for('static', filename='js/dgenies.status.min.js') }}" type="text/JavaScript"></script> + {% endif %} {% endblock %} {% block onload %} {{ super() }} diff --git a/src/dgenies/views.py b/src/dgenies/views.py index 9c1432d..b3fe1fc 100644 --- a/src/dgenies/views.py +++ b/src/dgenies/views.py @@ -1,4 +1,4 @@ -from dgenies import app, app_title, app_folder, config_reader, mailer, APP_DATA, MODE +from dgenies import app, app_title, app_folder, config_reader, mailer, APP_DATA, MODE, DEBUG import os import time @@ -25,7 +25,8 @@ def global_templates_variables(): return { "title": app_title, "mode": MODE, - "all_jobs": Functions.get_list_all_jobs(MODE) + "all_jobs": Functions.get_list_all_jobs(MODE), + "debug": DEBUG } -- GitLab