Commit fbb7234f authored by lcottret's avatar lcottret
parents 999c527a b00ffc5c
......@@ -7,56 +7,48 @@
$rh_sets->{"set2"} = ["id2,id3,id4"];
$rh_sets->{"set3"} = ["id1,id2,id5,id6"];
$rh_sets->{"set4"} = ["id3,id1"];
&CreateJsonVenn($rh_sets,
"/home/lcottret/workspaces/workspaceBBRIC/bbric-bioinfo/orthomcl/site/data/examples/venn/",
"../../../../web/js/ext/jquery-min.js",
"../../../../web/js/ext/jvenn-min.js" );
&CreateJsonVenn($rh_sets, $outdir, $title);
Prerequisite : General, JSON, File::Path, the jvenn libray installed
Function : creates a json for jvenn from a set of ids
Returns : nothing
Args : 1. a hashref containing arrays of strings containing the ids separated by commas
2. a directory path to save the json and the js file
3. the path of jquery.js (relative to the directory path set above)
4. the path of jvenn.min.js (relative to the directory path set above)
Access : public
TODO :
Globals :
2. a directory path to save the json and venn.html
3. a title for the html page
Globals : none
=cut
sub CreateJsonVenn
{
my ($rh_sets, $outdir, $jquery_lib, $jvenn_lib) = @_;
my %h_param = (
'series' => [],
'displayStat' => 'true'
);
my ($rh_sets, $outdir, $title) = @_;
my @a_series = ();
foreach my $name (keys %{$rh_sets})
{
my $rh_serie = {};
$rh_serie->{"name"} = $name;
my $ra_set = $rh_sets->{$name};
$rh_serie->{"data"} = $ra_set;
push(@{$h_param{'series'}}, $rh_serie);
push(@a_series, $rh_serie);
}
my $json = to_json(\%h_param);
my $json_series = to_json(\@a_series, {pretty => 1});
if (!-d $outdir)
{
make_path($outdir);
}
# creates the js file
my $js_file = "$outdir/series.js";
my $fh_output = &GetStreamOut($js_file);
print $fh_output "\$(document).ready(function(){\$('#jvenn-container').jvenn(" . $json . ");});";
my $json_file = "$outdir/series.json";
my $fh_output = &GetStreamOut($json_file);
print $fh_output "$json_series";
$fh_output->close();
......@@ -68,6 +60,7 @@ sub CreateJsonVenn
while (my $line = <$fh_html_template>)
{
$line =~ s/%ROOT_URL%/$root_url/g;
$line =~ s/%TITLE%/$title/g;
print $fh_html_out $line;
}
$fh_html_out->close;
......
/**
* Bootstrap Multiselect v0.9.8 (https://github.com/davidstutz/bootstrap-multiselect)
*
* Copyright 2012 - 2014 David Stutz
*
* Dual licensed under the BSD-3-Clause and the Apache License, Version 2.0.
*/
!function($) {
"use strict";// jshint ;_;
if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
ko.bindingHandlers.multiselect = {
after: ['options', 'value', 'selectedOptions'],
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var config = ko.toJS(valueAccessor());
$element.multiselect(config);
if (allBindings.has('options')) {
var options = allBindings.get('options');
if (ko.isObservable(options)) {
ko.computed({
read: function() {
options();
setTimeout(function() {
var ms = $element.data('multiselect');
if (ms)
ms.updateOriginalOptions();//Not sure how beneficial this is.
$element.multiselect('rebuild');
}, 1);
},
disposeWhenNodeIsRemoved: element
});
}
}
//value and selectedOptions are two-way, so these will be triggered even by our own actions.
//It needs some way to tell if they are triggered because of us or because of outside change.
//It doesn't loop but it's a waste of processing.
if (allBindings.has('value')) {
var value = allBindings.get('value');
if (ko.isObservable(value)) {
ko.computed({
read: function() {
value();
setTimeout(function() {
$element.multiselect('refresh');
}, 1);
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
}
}
//Switched from arrayChange subscription to general subscription using 'refresh'.
//Not sure performance is any better using 'select' and 'deselect'.
if (allBindings.has('selectedOptions')) {
var selectedOptions = allBindings.get('selectedOptions');
if (ko.isObservable(selectedOptions)) {
ko.computed({
read: function() {
selectedOptions();
setTimeout(function() {
$element.multiselect('refresh');
}, 1);
},
disposeWhenNodeIsRemoved: element
}).extend({ rateLimit: 100, notifyWhenChangesStop: true });
}
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$element.multiselect('destroy');
});
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var config = ko.toJS(valueAccessor());
$element.multiselect('setOptions', config);
$element.multiselect('rebuild');
}
};
}
function forEach(array, callback) {
for (var index = 0; index < array.length; ++index) {
callback(array[index], index);
}
}
/**
* Constructor to create a new multiselect using the given select.
*
* @param {jQuery} select
* @param {Object} options
* @returns {Multiselect}
*/
function Multiselect(select, options) {
this.$select = $(select);
this.options = this.mergeOptions($.extend({}, options, this.$select.data()));
// Initialization.
// We have to clone to create a new reference.
this.originalOptions = this.$select.clone()[0].options;
this.query = '';
this.searchTimeout = null;
this.lastToggledInput = null
this.options.multiple = this.$select.attr('multiple') === "multiple";
this.options.onChange = $.proxy(this.options.onChange, this);
this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
// Build select all if enabled.
this.buildContainer();
this.buildButton();
this.buildDropdown();
this.buildSelectAll();
this.buildDropdownOptions();
this.buildFilter();
this.updateButtonText();
this.updateSelectAll();
if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
this.disable();
}
this.$select.hide().after(this.$container);
};
Multiselect.prototype = {
defaults: {
/**
* Default text function will either print 'None selected' in case no
* option is selected or a list of the selected options up to a length
* of 3 selected options.
*
* @param {jQuery} options
* @param {jQuery} select
* @returns {String}
*/
buttonText: function(options, select) {
if (options.length === 0) {
return this.nonSelectedText;
}
else if (options.length == $('option', $(select)).length) {
return this.allSelectedText;
}
else if (options.length > this.numberDisplayed) {
return options.length + ' ' + this.nSelectedText;
}
else {
var selected = '';
options.each(function() {
var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
selected += label + ', ';
});
return selected.substr(0, selected.length - 2);
}
},
/**
* Updates the title of the button similar to the buttonText function.
*
* @param {jQuery} options
* @param {jQuery} select
* @returns {@exp;selected@call;substr}
*/
buttonTitle: function(options, select) {
if (options.length === 0) {
return this.nonSelectedText;
}
else {
var selected = '';
options.each(function () {
selected += $(this).text() + ', ';
});
return selected.substr(0, selected.length - 2);
}
},
/**
* Create a label.
*
* @param {jQuery} element
* @returns {String}
*/
optionLabel: function(element){
return $(element).attr('label') || $(element).text();
},
/**
* Triggered on change of the multiselect.
*
* Not triggered when selecting/deselecting options manually.
*
* @param {jQuery} option
* @param {Boolean} checked
*/
onChange : function(option, checked) {
},
/**
* Triggered when the dropdown is shown.
*
* @param {jQuery} event
*/
onDropdownShow: function(event) {
},
/**
* Triggered when the dropdown is hidden.
*
* @param {jQuery} event
*/
onDropdownHide: function(event) {
},
/**
* Triggered after the dropdown is shown.
*
* @param {jQuery} event
*/
onDropdownShown: function(event) {
},
/**
* Triggered after the dropdown is hidden.
*
* @param {jQuery} event
*/
onDropdownHidden: function(event) {
},
/**
* Triggered on select all.
*/
onSelectAll: function() {
},
buttonClass: 'btn btn-default',
inheritClass: false,
buttonWidth: 'auto',
buttonContainer: '<div class="btn-group" />',
dropRight: false,
selectedClass: 'active',
// Maximum height of the dropdown menu.
// If maximum height is exceeded a scrollbar will be displayed.
maxHeight: false,
checkboxName: false,
includeSelectAllOption: false,
includeSelectAllIfMoreThan: 0,
selectAllText: ' Select all',
selectAllValue: 'multiselect-all',
selectAllName: false,
enableFiltering: false,
enableCaseInsensitiveFiltering: false,
enableClickableOptGroups: false,
filterPlaceholder: 'Search',
// possible options: 'text', 'value', 'both'
filterBehavior: 'text',
includeFilterClearBtn: true,
preventInputChangeEvent: false,
nonSelectedText: 'None selected',
nSelectedText: 'selected',
allSelectedText: 'All selected',
numberDisplayed: 3,
disableIfEmpty: false,
templates: {
button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',
ul: '<ul class="multiselect-container dropdown-menu"></ul>',
filter: '<li class="multiselect-item filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>',
filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>',
li: '<li><a tabindex="0"><label></label></a></li>',
divider: '<li class="multiselect-item divider"></li>',
liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>'
}
},
constructor: Multiselect,
/**
* Builds the container of the multiselect.
*/
buildContainer: function() {
this.$container = $(this.options.buttonContainer);
this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
},
/**
* Builds the button of the multiselect.
*/
buildButton: function() {
this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
if (this.$select.attr('class') && this.options.inheritClass) {
this.$button.addClass(this.$select.attr('class'));
}
// Adopt active state.
if (this.$select.prop('disabled')) {
this.disable();
}
else {
this.enable();
}
// Manually add button width if set.
if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
this.$button.css({
'width' : this.options.buttonWidth,
'overflow' : 'hidden',
'text-overflow' : 'ellipsis'
});
this.$container.css({
'width': this.options.buttonWidth
});
}
// Keep the tab index from the select.
var tabindex = this.$select.attr('tabindex');
if (tabindex) {
this.$button.attr('tabindex', tabindex);
}
this.$container.prepend(this.$button);
},
/**
* Builds the ul representing the dropdown menu.
*/
buildDropdown: function() {
// Build ul.
this.$ul = $(this.options.templates.ul);
if (this.options.dropRight) {
this.$ul.addClass('pull-right');
}
// Set max height of dropdown menu to activate auto scrollbar.
if (this.options.maxHeight) {
// TODO: Add a class for this option to move the css declarations.
this.$ul.css({
'max-height': this.options.maxHeight + 'px',
'overflow-y': 'auto',
'overflow-x': 'hidden'
});
}
this.$container.append(this.$ul);
},
/**
* Build the dropdown options and binds all nessecary events.
*
* Uses createDivider and createOptionValue to create the necessary options.
*/
buildDropdownOptions: function() {
this.$select.children().each($.proxy(function(index, element) {
var $element = $(element);
// Support optgroups and options without a group simultaneously.
var tag = $element.prop('tagName')
.toLowerCase();
if ($element.prop('value') === this.options.selectAllValue) {
return;
}
if (tag === 'optgroup') {
this.createOptgroup(element);
}
else if (tag === 'option') {
if ($element.data('role') === 'divider') {
this.createDivider();
}
else {
this.createOptionValue(element);
}
}
// Other illegal tags will be ignored.
}, this));
// Bind the change event on the dropdown elements.
$('li input', this.$ul).on('change', $.proxy(function(event) {
var $target = $(event.target);
var checked = $target.prop('checked') || false;
var isSelectAllOption = $target.val() === this.options.selectAllValue;
// Apply or unapply the configured selected class.
if (this.options.selectedClass) {
if (checked) {
$target.closest('li')
.addClass(this.options.selectedClass);
}
else {
$target.closest('li')
.removeClass(this.options.selectedClass);
}
}
// Get the corresponding option.
var value = $target.val();
var $option = this.getOptionByValue(value);
var $optionsNotThis = $('option', this.$select).not($option);
var $checkboxesNotThis = $('input', this.$container).not($target);
if (isSelectAllOption) {
if (checked) {
this.selectAll();
}
else {
this.deselectAll();
}
}
if(!isSelectAllOption){
if (checked) {
$option.prop('selected', true);
if (this.options.multiple) {
// Simply select additional option.
$option.prop('selected', true);
}
else {
// Unselect all other options and corresponding checkboxes.
if (this.options.selectedClass) {
$($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);
}
$($checkboxesNotThis).prop('checked', false);
$optionsNotThis.prop('selected', false);
// It's a single selection, so close.
this.$button.click();
}
if (this.options.selectedClass === "active") {
$optionsNotThis.closest("a").css("outline", "");
}
}
else {
// Unselect option.
$option.prop('selected', false);
}
}
this.$select.change();
this.updateButtonText();
this.updateSelectAll();
this.options.onChange($option, checked);
if(this.options.preventInputChangeEvent) {
return false;
}
}, this));
$('li a', this.$ul).on('mousedown', function(e) {
if (e.shiftKey) {
// Prevent selecting text by Shift+click
return false;
}
});
$('li a', this.$ul).on('touchstart click', $.proxy(function(event) {
event.stopPropagation();
var $target = $(event.target);
if (event.shiftKey && this.options.multiple) {
if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
event.preventDefault();
$target = $target.find("input");
$target.prop("checked", !$target.prop("checked"));
}
var checked = $target.prop('checked') || false;
if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
var from = $target.closest("li").index();
var to = this.lastToggledInput.closest("li").index();
if (from > to) { // Swap the indices
var tmp = to;
to = from;
from = tmp;
}
// Make sure we grab all elements since slice excludes the last index
++to;
// Change the checkboxes and underlying options
var range = this.$ul.find("li").slice(from, to).find("input");
range.prop('checked', checked);
if (this.options.selectedClass) {
range.closest('li')
.toggleClass(this.options.selectedClass, checked);
}
for (var i = 0, j = range.length; i < j; i++) {
var $checkbox = $(range[i]);
var $option = this.getOptionByValue($checkbox.val());
$option.prop('selected', checked);
}
}
// Trigger the select "change" event
$target.trigger("change");
}
// Remembers last clicked option
if($target.is("input") && !$target.closest("li").is(".multiselect-item")){
this.lastToggledInput = $target;
}
$target.blur();
}, this));
// Keyboard support.
this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) {
if ($('input[type="text"]', this.$container).is(':focus')) {
return;
}
if (event.keyCode === 9 && this.$container.hasClass('open')) {
this.$button.click();
}
else {
var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");
if (!$items.length) {
return;
}
var index = $items.index($items.filter(':focus'));
// Navigation up.
if (event.keyCode === 38 && index > 0) {
index--;
}
// Navigate down.
else if (event.keyCode === 40 && index < $items.length - 1) {
index++;
}
else if (!~index) {
index = 0;
}
var $current = $items.eq(index);
$current.focus();
if (event.keyCode === 32 || event.keyCode === 13) {
var $checkbox = $current.find('input');
$checkbox.prop("checked", !$checkbox.prop("checked"));
$checkbox.change();
}
event.stopPropagation();
event.preventDefault();
}
}, this));
if(this.options.enableClickableOptGroups && this.options.multiple) {
$('li.multiselect-group', this.$ul).on('click', $.proxy(function(event) {
event.stopPropagation();
var group = $(event.target).parent();
// Search all option in optgroup
var $options = group.nextUntil('li.multiselect-group');
var $visibleOptions = $options.filter(":visible");
// check or uncheck items
var allChecked = true;
var optionInputs = $visibleOptions.find('input');
optionInputs.each(function() {
allChecked = allChecked && $(this).prop('checked');
});
optionInputs.prop('checked', !allChecked).trigger('change');
}, this));
}
},
/**
* Create an option using the given select option.
*
* @param {jQuery} element
*/
createOptionValue: function(element) {
var $element = $(element);
if ($element.is(':selected')) {
$element.prop('selected', true);
}
// Support the label attribute on options.
var label = this.options.optionLabel(element);
var value = $element.val();
var inputType = this.options.multiple ? "checkbox" : "radio";
var $li = $(this.options.templates.li);
var $label = $('label', $li);
$label.addClass(inputType);
var $checkbox = $('<input/>').attr('type', inputType);
if (this.options.checkboxName) {
$checkbox.attr('name', this.options.checkboxName);
}
$label.append($checkbox);