MISP/app/webroot/js/contextual_menu.js

434 lines
16 KiB
JavaScript

class ContextualMenu {
constructor(options) {
this.options = options;
this.trigger_container = options.trigger_container;
this.container = options.container;
this.bootstrap_popover = options.bootstrap_popover;
this.right_click = options.right_click;
this.has_been_shown_once = false;
this.items = {};
this.__is_shown = false;
this.__globalCounter = 0;
if (this.bootstrap_popover) {
if (typeof $.fn.popover != 'function') { // boostrap loaded
console.log("Boostrap not loaded or does not support popover");
this.menu = this.__create_menu_div();
} else {
this.menu = this.__create_menu_div_bootstrap_popover();
}
} else {
this.menu = this.__create_menu_div();
}
}
/* Addition */
add_button(options) {
this.__create_divider_if_needed('btn');
var btn = this.__create_button(options);
this.items[btn.id] = btn;
}
add_checkbox(options) {
this.__create_divider_if_needed('checkbox');
var checkbox = this.__create_checkbox(options);
this.items[checkbox.id] = checkbox;
}
add_input(options) {
this.__create_divider_if_needed('input');
var input = this.__create_input(options);
this.items[input.id] = input;
}
add_slider(options) {
this.__create_divider_if_needed('slider');
var slider = this.__create_slider(options);
this.items[slider.id] = slider;
}
add_select(options) {
this.__create_divider_if_needed('select');
var select = this.__create_select(options);
this.items[select.id] = select;
}
add_select_button(options) {
this.__create_divider_if_needed('select_button');
var select_button = this.__create_select_button(options);
this.items[select_button.id] = select_button;
}
add_fileinput(options) {
this.__create_divider_if_needed('fileinput');
var fileinput = this.__create_fileinput(options);
this.items[fileinput.id] = fileinput;
}
add_action_table(options) {
this.__create_divider_if_needed('action_table');
var action_table = this.__create_action_table(options);
this.items[action_table.id] = action_table;
}
add_datepicker(options) {
this.__create_divider_if_needed('checkbox');
var checkbox = this.__create_datepicker(options);
this.items[checkbox.id] = checkbox;
}
create_divider(height) {
var divider = document.createElement('li');
divider.classList.add("contextual-menu-divider");
if (height !== undefined) {
divider.style.height = height+"px";
divider.style.marginTop = "15px";
divider.style.marginBottom = "15px";
}
this.menu.appendChild(divider);
this.previous_context = undefined; // do not draw another line
}
/* Manipulation */
add_options(id, values) {
var select = this.items[id];
var selected_value = select.value;
select.innerHTML = ""; // ensure uniqueness
this.__add_options_to_select(select, values);
select.value = selected_value;
}
/* Private */
__get_uniq_index() {
this.__globalCounter++;
return this.__globalCounter-1;
}
__toggleMenu(x, y, hide) {
var that = this;
if(this.__is_shown || hide) {
this.menu.style.visibility = 'hidden';
} else {
this.menu.style.left = x+'px';
this.menu.style.top = y+'px';
this.menu.style.visibility = 'visible';
}
this.__is_shown = !this.__is_shown;
}
__create_menu_div() {
var div = document.createElement('div');
div.classList.add("contextual-menu");
div.classList.add("contextual-menu-styling");
this.container.appendChild(div);
// register on click for the trigger_container
var that = this;
if (this.right_click) {
this.trigger_container.addEventListener('contextmenu', function(evt) {
evt.preventDefault();
var offsetX = $(that.trigger_container).offset().left;
var offsetY = $(that.trigger_container).offset().top-40;
that.__toggleMenu(evt.pageX-offsetX, evt.pageY-offsetY);
});
// hide the contextual menu on any click
document.getElementsByTagName("BODY")[0].addEventListener("click", function(evt) {
that.__toggleMenu(evt.pageX, evt.pageY, true);
});
} else {
this.trigger_container.addEventListener("click", function(evt) {
var offsetX = 0;
var offsetY = 1;
that.__toggleMenu(evt.pageX+offsetX, evt.pageY+offsetY);
});
}
return div;
}
__create_menu_div_bootstrap_popover() {
var div = document.createElement('div');
div.classList.add("contextual-menu");
div.style.display = 'none';
this.container.appendChild(div);
var that = this;
this.trigger_container.tabIndex = 0; // required for the popover focus feature
var additional_styling = this.options.style === undefined ? "" : this.options.style;
$(this.trigger_container).popover({
container: 'body',
html: true,
placement: "bottom",
content: function () { var html=$(that.menu); html.css('display', 'inline-block'); return html;}, // return contextual menu html
trigger: "manual",
template: '<div class="popover" id="popover-contextual-menu-'+this.trigger_container.id+'" role="tooltip" style="'+additional_styling+'"><div class="arrow"></div></h3><div class="popover-content"></div></div>'
})
// Overwrite the default popover behavior: hidding cause the popover to be detached from the DOM, making impossible to fetch input values in the form
$(this.trigger_container).click (function(e) {
$(this).popover('toggle');
// if (that.has_been_shown_once) {
// $('#popover-contextual-menu-'+this.id).toggle();
// } else {
// that.has_been_shown_once = true;
// $(this).popover('show');
// }
});
return div;
}
__create_divider_if_needed(context) {
if (this.previous_context === undefined) {
this.previous_context = context;
} else if (this.previous_context != context) {
this.create_divider();
this.previous_context = context;
}
return;
}
__create_button(options) {
var btn = document.createElement('button');
btn.classList.add("btn-dropdown", "btn", "btn-"+options.type);
btn.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
if(options.tooltip !== undefined) {
btn.title = options.tooltip;
}
var span = document.createElement('span');
span.classList.add("fa", "fa-"+options.icon);
btn.innerHTML = span.outerHTML + options.label;
if(options.event !== undefined) {
btn.addEventListener("click", function(evt) {
options.event();
});
}
this.menu.appendChild(btn);
return btn;
}
__create_input(options) {
var input = document.createElement("input");
input.classList.add("form-group");
input.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
if(options.tooltip !== undefined) {
input.title = options.tooltip;
}
if(options.placeholder !== undefined) {
input.placeholder = options.placeholder;
}
if(options.event !== undefined) {
input.addEventListener("change", function(evt) {
options.event(evt.target.value);
});
}
this.menu.appendChild(input);
if (options.typeahead !== undefined) {
var typeaheadOption = options.typeahead;
$('#'+input.id).typeahead(typeaheadOption);
}
return input;
}
__create_fileinput(options) {
var div = document.createElement('div');
var label = document.createElement('label');
label.innerHTML = options.label+":";
var input = document.createElement("input");
input.classList.add("form-group");
input.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
if(options.tooltip !== undefined) {
input.title = options.tooltip;
}
input.type = "file";
input.accept = ".json";
var file_status = document.createElement('span');
file_status.id = input.id + "_status";
input.dataset.relatedStatusId = file_status.id;
if(options.event !== undefined) {
input.addEventListener("change", function(evtInput) {
var file = this.files[0];
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evtReader) {
document.getElementById(evtInput.target.dataset.relatedStatusId).innerHTML = "File loaded";
var content = evtReader.target.result;
evtInput.target.value = '';
options.event(content);
};
reader.onerror = function (evtReader) {
document.getElementById(evtInput.target.dataset.relatedStatusId).innerHTML = "Error while reading the file";
};
reader.onprogress = function (evtReader) {
if (evtReader.lengthComputable) {
var loaded = (evtReader.loaded / evtReader.total)*100;
if (loaded < 100) {
document.getElementById(evtInput.target.dataset.relatedStatusId).innerHTML = "Reading file: "+loaded.toFixed(2)+"%";
}
}
};
}
});
}
div.appendChild(label);
div.appendChild(input);
div.appendChild(file_status);
this.menu.appendChild(div);
return input;
}
__create_slider(options) {
var div = document.createElement('div');
var label = document.createElement('label');
label.innerHTML = options.label+":";
if(options.tooltip !== undefined) {
label.title = options.tooltip;
}
var slider = document.createElement('input');
slider.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
slider.type = "range";
slider.min = options.min;
slider.max = options.max;
slider.value = options.value;
slider.step = options.step;
var slider_val = options.value == undefined ? 0 : options.value;
slider.value = slider_val;
var span = document.createElement('span');
span.innerHTML = slider_val;
span.id = slider.id + "_span";
if(options.event !== undefined) {
slider.addEventListener('input', function(evt) {
span.innerHTML = evt.target.value; // Update associated span
options.event(evt.target.value);
});
}
$(slider).on('reflectOnSpan', function(evt) {
span.innerHTML = evt.target.value; // Update associated span
});
div.appendChild(label);
div.appendChild(span);
if (options.applyButton !== undefined) {
var button = document.createElement('button');
button.innerHTML = "Apply";
button.classList.add("btn");
button.addEventListener("click", function(evt) { options.eventApply(slider.value); });
div.appendChild(button);
}
div.appendChild(slider);
this.menu.appendChild(div);
return slider;
}
__create_checkbox(options) {
var checkbox = document.createElement('input');
var label = document.createElement('label');
checkbox.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
checkbox.type = "checkbox";
checkbox.checked = options.checked;
if(options.tooltip !== undefined) {
label.title = options.tooltip;
}
label.appendChild(checkbox);
label.appendChild(document.createTextNode(options.label));
if(options.event !== undefined) {
label.addEventListener("change", function(evt) { options.event(evt.target.checked); });
}
this.menu.appendChild(label);
return checkbox;
}
__create_select(select_options) {
var select = document.createElement('select');
var label = document.createElement('label');
label.innerHTML = select_options.label+":";
label.title = select_options.tooltip;
select.id = select_options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : select_options.id;
this.__add_options_to_select(select, select_options.options);
if(select_options.default !== undefined) {
select.value = select_options.default;
}
this.menu.appendChild(label);
this.menu.appendChild(select);
if(select_options.event !== undefined) {
select.addEventListener("change", function(evt) { select_options.event(evt.target.value); });
}
return select;
}
__create_select_button(options) {
var div = document.createElement('div');
div.style = "width: inherit;";
var select = document.createElement('select');
var label = document.createElement('label');
var button = document.createElement('button');
button.classList.add("btn-dropdown", "btn", "btn-default");
button.style = "padding: 4px 12px; line-height: 20px; margin-left: 7px;";
button.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id+"_btn";
button.innerHTML = options.textButton !== undefined ? options.textButton : "";
label.innerHTML = options.label+":";
label.title = options.tooltip;
select.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id+"_select";
button.dataset.correspondingId = select.id;
this.__add_options_to_select(select, options.options);
if(options.default !== undefined) {
select.value = options.default;
}
div.appendChild(select);
div.appendChild(button);
this.menu.appendChild(label);
this.menu.appendChild(div);
if(options.event !== undefined) {
button.addEventListener("click", function(evt) {
var corresponding_select_id = evt.target.dataset.correspondingId;
var selected_value = $('#'+corresponding_select_id).val();
options.event(selected_value);
});
}
return button;
}
__add_options_to_select(select, options) {
for(var value of options) {
var option = document.createElement('option');
if (typeof value === 'object') {
option.value = value.value;
option.innerHTML = value.text;
} else {
option.value = value;
option.innerHTML = value;
}
select.appendChild(option);
}
}
__create_action_table(options) {
var action_table = new ActionTable(options);
return action_table;
}
__create_datepicker(options) {
var div = document.createElement('div');
div.style = "width: inherit;";
var datepicker = document.createElement('input');
datepicker.classList.add("datepicker");
var label = document.createElement('label');
label.innerHTML = options.label+":";
label.title = options.tooltip;
datepicker.id = options.id === undefined ? 'contextualMenu_'+this.__get_uniq_index() : options.id;
datepicker.type = "text";
if(options.tooltip !== undefined) {
label.title = options.tooltip;
}
div.appendChild(label);
div.appendChild(datepicker);
this.menu.appendChild(div);
$("#" + datepicker.id).datepicker({
format: 'yyyy-mm-dd',
}).on('changeDate', function(evt) {
options.event(evt.target.checked);
});
return datepicker;
}
}