mirror of https://github.com/MISP/MISP
786 lines
27 KiB
JavaScript
786 lines
27 KiB
JavaScript
var max_displayed_char_timeline = 64;
|
|
var imgSize = '80';
|
|
var eventTimeline;
|
|
var items_timeline;
|
|
var items_backup;
|
|
var use_local_timezone = true;
|
|
var mapping_text_to_id = new Map();
|
|
var user_manipulation = $('#event_timeline').data('user-manipulation');
|
|
var extended_text = $('#event_timeline').data('extended') == 1 ? "extended:1/" : "";
|
|
var container_timeline = document.getElementById('event_timeline');
|
|
var hardThreshold = 1000;
|
|
var softThreshold = 200;
|
|
var timeline_disabled = false;
|
|
var default_editable = {
|
|
add: false, // add new items by double tapping
|
|
updateTime: true, // drag items horizontally
|
|
remove: true
|
|
};
|
|
var relationship_type_mapping = {
|
|
'followed-by': 'after',
|
|
'preceding-by': 'before',
|
|
}
|
|
var shortcut_text_timeline = "<b>ALT+Mouse_Wheel</b> Zoom IN/OUT"
|
|
+ "\n<b>CTRL</b> Multi select"
|
|
var options = {
|
|
template: function (item, element, data) {
|
|
switch(item.group) {
|
|
case "attribute":
|
|
return build_attr_template(item);
|
|
|
|
case "object":
|
|
return build_object_template(item);
|
|
|
|
case "object_attribute":
|
|
console.log('Error: Group not valid');
|
|
break;
|
|
|
|
default:
|
|
if (item.className == "sighting_positive" || item.className == "sighting_negative") {
|
|
return build_sighting_template(item);
|
|
} else {
|
|
console.log(item)
|
|
console.log('Error: Unkown group');
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
moment: function(date) {
|
|
if (use_local_timezone) {
|
|
return vis.moment(date);
|
|
} else {
|
|
return vis.moment(date).utc();
|
|
}
|
|
},
|
|
verticalScroll: true,
|
|
zoomKey: 'altKey',
|
|
maxHeight: 400,
|
|
minHeight: 400,
|
|
multiselect: true,
|
|
editable: user_manipulation ? default_editable : false,
|
|
tooltipOnItemUpdateTime: true,
|
|
onRemove: function(item, callback) { // clear timestamps
|
|
update_seen(item, 'first', null, false, function() {
|
|
update_seen(item, 'last', null, false, function() { reflect_change(true); });
|
|
});
|
|
eventTimeline.setSelection([]);
|
|
$('.timelineSelectionTooltip').remove()
|
|
},
|
|
onMove: function(item, callback) {
|
|
var newStart = moment(item.start.toISOString());
|
|
var newEnd = (item.end !== undefined && item.end !== null) ? moment(item.end.toISOString()) : null;
|
|
var fsChanged = item.first_seen !== null ? !item.first_seen.isSame(newStart) : true;
|
|
var lsChanged = item.last_seen !== null ? !item.last_seen.isSame(newEnd) && item.seen_enabled : false;
|
|
if (fsChanged) {
|
|
if (item.first_seen === null) {
|
|
if (!lsChanged) {
|
|
update_seen(item, 'first', newStart, true, undefined);
|
|
} else {
|
|
update_seen(
|
|
item,
|
|
'first',
|
|
newStart,
|
|
false,
|
|
function() {
|
|
update_seen(
|
|
item,
|
|
'last',
|
|
newEnd,
|
|
true,
|
|
function() {
|
|
reflect_change(true);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
}
|
|
} else {
|
|
update_seen(item, 'first', newStart, !lsChanged, function() {
|
|
if (lsChanged) {
|
|
update_seen(item, 'last', newEnd, true, undefined);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if (lsChanged && !fsChanged) {
|
|
update_seen(item, 'last', newEnd, true, undefined);
|
|
}
|
|
}
|
|
};
|
|
|
|
function isDefined(element) {
|
|
return element !== undefined && element !== null;
|
|
}
|
|
|
|
function generate_timeline_tooltip(itemID, target) {
|
|
var item = items_timeline.get(itemID);
|
|
if (
|
|
item.first_seen === undefined
|
|
|| item.first_seen === null
|
|
|| item.first_seen_overwrite
|
|
) { // do not generate if first_seen not set
|
|
return;
|
|
}
|
|
var closest = $(target.closest(".vis-selected.vis-editable"));
|
|
var btn_type = item.last_seen !== null ? 'collapse-btn' : 'expand-btn';
|
|
var fct_type = item.last_seen !== null ? 'collapseItem' : 'expandItem';
|
|
var btn = $('<div class="timelineSelectionTooltip vis-expand-action '+btn_type+'" data-itemid="'+item.id+'"></div>')
|
|
if (item.last_seen !== null) {
|
|
btn.click(collapseItem);
|
|
} else {
|
|
btn.click(expandItem);
|
|
}
|
|
closest.append(btn);
|
|
}
|
|
|
|
/* UTIL */
|
|
function collapseItem() {
|
|
var itemID = $(this).data('itemid');
|
|
var item = items_timeline.get(itemID);
|
|
update_seen(item, 'last', null, true, undefined);
|
|
}
|
|
function expandItem() {
|
|
var itemID = $(this).data('itemid');
|
|
var item = items_timeline.get(itemID);
|
|
var newEnd = get_next_step(item.first_seen);
|
|
update_seen(item, 'last', newEnd, true, undefined);
|
|
}
|
|
|
|
function get_next_step(mom) {
|
|
var scale = adapt_scale(eventTimeline.timeAxis.step.scale);
|
|
var momAhead = mom.clone();
|
|
momAhead.add(1, scale);
|
|
return momAhead;
|
|
}
|
|
|
|
function adapt_scale(scale) {
|
|
first_letter = scale.charAt(0);
|
|
if (first_letter !== 'm' && first_letter !== 'w') {
|
|
return first_letter;
|
|
} else {
|
|
switch (scale) {
|
|
case 'millisecond':
|
|
return 'ms';
|
|
case 'minute':
|
|
return 'm';
|
|
case 'month':
|
|
return 'M';
|
|
case 'week':
|
|
return 'w';
|
|
case 'weekday':
|
|
return 'd';
|
|
default:
|
|
return scale;
|
|
}
|
|
}
|
|
}
|
|
|
|
function build_attr_template(attr) {
|
|
var span = $('<span data-itemID="'+attr.id+'">');
|
|
if (!attr.seen_enabled) {
|
|
span.addClass('timestamp-attr');
|
|
}
|
|
if (attr.attribute_type == 'attachment' && attr.is_image) {
|
|
var $img = $('<img/>')
|
|
.addClass('screenshot img-rounded')
|
|
.attr('alt', attr.content)
|
|
.attr('title', attr.content)
|
|
.attr('loading', 'lazy')
|
|
.attr('src', '/attributes/viewPicture/' + attr.orig_id + '/1')
|
|
.attr('width', imgSize)
|
|
.attr('height', imgSize);
|
|
span.append($img)
|
|
} else {
|
|
span.text(attr.content);
|
|
}
|
|
span.data('seen_enabled', attr.seen_enabled);
|
|
var html = span[0].outerHTML;
|
|
return html;
|
|
}
|
|
|
|
function build_object_template(obj) {
|
|
var table = $('<table>');
|
|
table.data('seen_enabled', obj.seen_enabled);
|
|
if (!obj.seen_enabled) {
|
|
table.addClass('timestamp-obj');
|
|
}
|
|
var $imgContainer = $('<div/>');
|
|
for (var attr of obj.Attribute) {
|
|
if (attr.attribute_type == 'attachment' && attr.is_image) {
|
|
var $img = $('<img/>')
|
|
.addClass('screenshot img-rounded')
|
|
.attr('alt', attr.content)
|
|
.attr('title', attr.content)
|
|
.attr('loading', 'lazy')
|
|
.attr('src', '/attributes/viewPicture/' + attr.id + '/1')
|
|
.attr('width', imgSize)
|
|
.attr('height', imgSize)
|
|
.attr('style', $imgContainer.length > 0 ? 'margin-left: 5px' : '');
|
|
$imgContainer.append($img)
|
|
}
|
|
}
|
|
var bolt_html = obj.overwrite_enabled ? " <i class=\"fa fa-bolt\" style=\"color: yellow; font-size: large;\" title=\"The Object is overwritten by its attributes\">" : "";
|
|
table.append($('<tr class="timeline-objectName"><th>'+obj.content+bolt_html+'</th><th></th></tr>'));
|
|
if ($imgContainer.length > 0) {
|
|
table.append($('<tr/>').append('<td colspan="2"/>').append($imgContainer));
|
|
}
|
|
for (var attr of obj.Attribute) {
|
|
var overwritten = obj.overwrite_enabled && (attr.contentType == "first-seen" || attr.contentType == "last-seen") ? " <i class=\"fa fa-bolt\" style=\"color: yellow;\" title=\"Overwrite object "+attr.contentType+"\"></i>" : "";
|
|
table.append(
|
|
$('<tr>').append(
|
|
$('<td class="timeline-objectAttrType">' + attr.contentType + '</td>'
|
|
+'<td class="timeline-objectAttrVal">' + attr.content+overwritten + '</td>'
|
|
)
|
|
)
|
|
)
|
|
}
|
|
var html = table[0].outerHTML;
|
|
return html;
|
|
}
|
|
|
|
function build_sighting_template(attr){
|
|
var span = $('<span data-itemID="'+attr.id+'">');
|
|
span.text(attr.content);
|
|
var html = span[0].outerHTML;
|
|
return html;
|
|
}
|
|
|
|
function contain_seen_attribute(obj) {
|
|
if (obj['Attribute'] === undefined) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < obj['Attribute'].length; i++) {
|
|
var attribute = obj['Attribute'][i];
|
|
if (attribute['contentType'] == 'first-seen' || attribute['contentType'] == 'last-seen') {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function reflect_change(onIndex, itemType, itemId, item) {
|
|
if (onIndex) {
|
|
updateIndex(scope_id, 'event'); // MISP function
|
|
} else { // reflect change on item only
|
|
quick_fetch_seens(itemType, item.orig_id, function(firstSeen, lastSeen) {
|
|
var updatedItem = items_timeline.get(itemId);
|
|
updatedItem.first_seen = firstSeen;
|
|
updatedItem.last_seen = lastSeen;
|
|
updatedItem.first_seen_overwrite = false;
|
|
updatedItem.last_seen_overwrite = false;
|
|
if (user_manipulation) {
|
|
var e = $.extend({}, default_editable);
|
|
e.remove = true;
|
|
updatedItem.editable = e;
|
|
}
|
|
set_spanned_time(updatedItem);
|
|
items_timeline.remove(updatedItem.id);
|
|
items_timeline.add(updatedItem);
|
|
});
|
|
}
|
|
}
|
|
|
|
function quick_fetch_seens(itemType, itemId, callback) {
|
|
var url = baseurl + "/" + itemType + "/" + "fetchViewValue" + "/" + itemId + "/";
|
|
var dfs = $.ajax({
|
|
dataType: "html",
|
|
cache: false,
|
|
success: function(data, textStatus) {
|
|
return data;
|
|
},
|
|
url: url+"first_seen"
|
|
});
|
|
var dls = $.ajax({
|
|
dataType: "html",
|
|
cache: false,
|
|
success: function(data, textStatus) {
|
|
return data;
|
|
},
|
|
url: url+"last_seen"
|
|
});
|
|
|
|
$.when( dfs, dls).done(function(a1, a2) {
|
|
firstSeen = a1[0].replace(' ', '');
|
|
firstSeen = firstSeen == '' ? null : firstSeen;
|
|
lastSeen = a2[0].replace(' ', '');
|
|
lastSeen = lastSeen == '' ? null : lastSeen;
|
|
callback(firstSeen, lastSeen);
|
|
});
|
|
}
|
|
|
|
function update_seen(item, seenType, value, reflect, callback) {
|
|
var itemType = item.group + 's';
|
|
var momentISO = value !== null ? value.toISOString() : null;
|
|
fetch_form_and_submit(itemType, item, seenType, momentISO, reflect, callback);
|
|
}
|
|
|
|
function fetch_form_and_submit(itemType, item, seenType, value, reflect, callback) {
|
|
var url = baseurl + "/" + itemType + "/fetchEditForm/" + item.orig_id + "/" + seenType+"_seen";
|
|
$.ajax({
|
|
beforeSend: function (XMLHttpRequest) {
|
|
$(".loadingTimeline").show();
|
|
},
|
|
dataType:"html",
|
|
cache: false,
|
|
success: function (data, textStatus) {
|
|
var form = $(data);
|
|
$(container_timeline).append(form);
|
|
form.css({display: 'none'});
|
|
var field = form.find('input[name*="' + seenType + '_seen"]');
|
|
field.val(value);
|
|
// submit the form
|
|
$.ajax({
|
|
data: form.serialize(),
|
|
cache: false,
|
|
success:function (data, textStatus) {
|
|
if (reflect) {
|
|
if (contain_seen_attribute(item)) {
|
|
reflect_change(true, itemType, item.id, item);
|
|
} else {
|
|
reflect_change(true, itemType, item.id, item);
|
|
}
|
|
}
|
|
form.remove()
|
|
},
|
|
error:function() {
|
|
console.log('fail', 'Request failed for an unknown reason.');
|
|
},
|
|
complete: function () {
|
|
$(".loadingTimeline").hide();
|
|
if (callback !== undefined) {
|
|
callback();
|
|
}
|
|
},
|
|
type:"post",
|
|
url: form.attr('action')
|
|
});
|
|
},
|
|
error: function() {
|
|
console.log('Feature not supported.');
|
|
},
|
|
url: url,
|
|
});
|
|
}
|
|
|
|
function timestampToMoment(timestamp) {
|
|
var factor = 1000;
|
|
var d = moment(timestamp*factor);
|
|
return d;
|
|
}
|
|
|
|
function set_spanned_time(item) {
|
|
var timestamp = item.timestamp;
|
|
var fs = item.first_seen == null ? null : moment(item.first_seen);
|
|
var ls = item.last_seen == null ? null : moment(item.last_seen);
|
|
item.first_seen = fs;
|
|
item.last_seen = ls;
|
|
|
|
item.seen_enabled = false;
|
|
item.overwrite_enabled = false;
|
|
if (fs===null && ls===null) {
|
|
item.start = timestampToMoment(timestamp);
|
|
item.type = 'box';
|
|
|
|
} else if (fs===null && ls!==null) {
|
|
item.start = timestampToMoment(timestamp);
|
|
item.type = 'box';
|
|
|
|
} else if (ls===null && fs!==null) {
|
|
item.start = fs;
|
|
item.seen_enabled = true;
|
|
delete item.end;
|
|
item.type = 'box';
|
|
|
|
} else { // fs and ls are defined
|
|
item.start = fs;
|
|
item.end = ls;
|
|
item.seen_enabled = true;
|
|
if (fs == ls) {
|
|
item.type = 'box';
|
|
} else {
|
|
item.type = 'range';
|
|
}
|
|
}
|
|
|
|
if (item.first_seen_overwrite === true || item.last_seen_overwrite === true) {
|
|
if (user_manipulation) {
|
|
var e = $.extend({}, default_editable);
|
|
e.remove = false;
|
|
item.editable = e;
|
|
}
|
|
item.overwrite_enabled = true;
|
|
}
|
|
}
|
|
|
|
function map_scope(val) {
|
|
switch(val) {
|
|
case 'First seen/Last seen':
|
|
return 'seen';
|
|
case 'Object relationship':
|
|
return 'relationship';
|
|
case 'Sightings':
|
|
return 'sightings';
|
|
default:
|
|
return 'seen';
|
|
}
|
|
}
|
|
|
|
function timelinePopupCallback(state) {
|
|
if (eventTimeline === undefined) {
|
|
return;
|
|
}
|
|
reload_timeline();
|
|
}
|
|
|
|
function adjust_text_length(elem) {
|
|
var maxChar = $('#slider_timeline_display_max_char_num').val();
|
|
maxChar = maxChar === undefined ? 64 : maxChar;
|
|
elem.content = elem.content.substring(0, maxChar) + (elem.content.length < maxChar ? "" : "[...]");
|
|
}
|
|
|
|
function update_badge() {
|
|
if (use_local_timezone) {
|
|
$("#timeline-display-badge").text("Timezone: " + ": " + moment().format('Z'));
|
|
} else {
|
|
$("#timeline-display-badge").text("Timezone: " + ": " + moment().utc().format('Z (z)'));
|
|
}
|
|
}
|
|
|
|
function reload_timeline() {
|
|
update_badge();
|
|
var selectedScope = map_scope($('#select_timeline_scope').val());
|
|
var payload = {scope: selectedScope};
|
|
$.ajax({
|
|
url: baseurl + "/events/"+"getEventTimeline"+"/"+scope_id+"/"+extended_text+"event.json",
|
|
dataType: 'json',
|
|
type: 'post',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify( payload ),
|
|
processData: false,
|
|
beforeSend: function (XMLHttpRequest) {
|
|
$(".loadingTimeline").show();
|
|
},
|
|
success: function( data, textStatus, jQxhr ){
|
|
items_timeline.clear();
|
|
mapping_text_to_id = new Map();
|
|
var itemIds = {};
|
|
for (var item of data.items) {
|
|
item.className = item.group;
|
|
item.orig_id = item.id;
|
|
item.id = item.uuid;
|
|
set_spanned_time(item);
|
|
if (item.group == 'object') {
|
|
for (var attr of item.Attribute) {
|
|
if (selectedScope == 'sightings') {
|
|
var k = attr.contentType+': '+attr.content+' ('+item.orig_id.split('-')[0]+')'
|
|
if (!mapping_text_to_id.get(k)) {
|
|
mapping_text_to_id.set(k, item.id);
|
|
}
|
|
} else {
|
|
mapping_text_to_id.set(attr.contentType+': '+attr.content+' ('+item.orig_id+')', item.id);
|
|
}
|
|
adjust_text_length(attr);
|
|
}
|
|
} else {
|
|
if (selectedScope == 'sightings') {
|
|
var k = item.content+' ('+item.orig_id.split('-')[0]+')'
|
|
if (!mapping_text_to_id.get(k)) {
|
|
mapping_text_to_id.set(k, item.id);
|
|
}
|
|
} else {
|
|
mapping_text_to_id.set(item.content+' ('+item.orig_id+')', item.id);
|
|
}
|
|
adjust_text_length(item);
|
|
}
|
|
if (selectedScope == 'sightings') {
|
|
itemIds[item.attribute_id] = item.content;
|
|
item.group = item.attribute_id;
|
|
item.content = '';
|
|
}
|
|
}
|
|
handle_not_seen_enabled($('#checkbox_timeline_display_hide_not_seen_enabled').prop('checked'), false)
|
|
if (selectedScope == 'sightings') {
|
|
var groups = Object.keys(itemIds).map(function(id) {
|
|
return {id: id, content: itemIds[id]}
|
|
})
|
|
eventTimeline.setGroups(groups);
|
|
eventTimeline.setOptions({selectable: false});
|
|
} else {
|
|
eventTimeline.setOptions({selectable: true});
|
|
eventTimeline.setGroups(null);
|
|
}
|
|
items_timeline.add(data.items);
|
|
eventTimeline.fit()
|
|
},
|
|
error: function( jqXhr, textStatus, errorThrown ){
|
|
console.log( errorThrown );
|
|
},
|
|
complete: function() {
|
|
$(".loadingTimeline").hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
function enable_timeline() {
|
|
if (eventTimeline !== undefined) {
|
|
return;
|
|
}
|
|
|
|
init_popover();
|
|
|
|
var chosen_options_timeline = {
|
|
max_shown_results: 20,
|
|
inherit_select_classes: true
|
|
};
|
|
var payload = {scope: map_scope($('#select_timeline_scope').val())};
|
|
$.ajax({
|
|
url: baseurl + "/events/"+"getEventTimeline"+"/"+scope_id+"/"+extended_text+"event.json",
|
|
dataType: 'json',
|
|
type: 'post',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify( payload ),
|
|
processData: false,
|
|
beforeSend: function (XMLHttpRequest) {
|
|
$(".loadingTimeline").show();
|
|
},
|
|
success: function( data, textStatus, jQxhr ){
|
|
if (data.items.length > hardThreshold) {
|
|
$('#eventtimeline_div').html('<div class="alert alert-danger" style="margin: 10px;">Timeline: Too much data to show</div>');
|
|
timeline_disabled = true;
|
|
return;
|
|
} else if (data.items.length > softThreshold) {
|
|
var res = confirm('You are about to draw a lot ('+data.items.length+') of items in the timeline. Do you wish to continue?');
|
|
if (!res) {
|
|
$('#eventtimeline_div').html('<div class="alert alert-danger" style="margin: 10px;">Timeline: Too much data to show</div>');
|
|
timeline_disabled = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (var item of data.items) {
|
|
item.className = item.group;
|
|
item.orig_id = item.id;
|
|
item.id = item.uuid;
|
|
set_spanned_time(item);
|
|
if (item.group == 'object') {
|
|
for (var attr of item.Attribute) {
|
|
mapping_text_to_id.set(attr.contentType+': '+attr.content+' ('+item.orig_id+')', item.id);
|
|
adjust_text_length(attr);
|
|
}
|
|
} else {
|
|
mapping_text_to_id.set(item.content+' ('+item.orig_id+')', item.id);
|
|
adjust_text_length(item);
|
|
}
|
|
}
|
|
items_timeline = new vis.DataSet(data.items);
|
|
eventTimeline = new vis.Timeline(container_timeline, items_timeline, options);
|
|
update_badge();
|
|
|
|
eventTimeline.on('select', handle_selection);
|
|
|
|
eventTimeline.on('doubleClick', handle_doubleClick);
|
|
|
|
items_timeline.on('update', function(eventname, data) {
|
|
handle_selection({
|
|
event: { target: $('span[data-itemID="'+data.items[0]+'"]')},
|
|
items: data.items
|
|
});
|
|
});
|
|
|
|
var $selectTypeahead = $('#timeline-typeahead');
|
|
Array.from(mapping_text_to_id.keys()).forEach(function(element) {
|
|
var value = mapping_text_to_id[element];
|
|
var $option = $('<option></option>');
|
|
$option.text(element);
|
|
$option.attr('value', value);
|
|
$selectTypeahead.append($option);
|
|
});
|
|
$selectTypeahead.css('display', '').chosen(chosen_options_timeline).on('change', function(evt, params) {
|
|
var value = params.selected;
|
|
var id = mapping_text_to_id.get(value);
|
|
eventTimeline.focus(id);
|
|
$("#timeline-typeahead").blur();
|
|
});
|
|
$('.timeline-help').popover({
|
|
container: 'body',
|
|
title: 'Shortcuts',
|
|
content: shortcut_text_timeline,
|
|
placement: 'left',
|
|
trigger: 'hover',
|
|
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content preWarp"></div></div>',
|
|
html: true,
|
|
});
|
|
},
|
|
error: function( jqXhr, textStatus, errorThrown ){
|
|
console.log( errorThrown );
|
|
},
|
|
complete: function() {
|
|
$(".loadingTimeline").hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
function handle_selection(data) {
|
|
var event = data.event;
|
|
var target = event.target;
|
|
var items = data.items;
|
|
|
|
if (items.length == 0) {
|
|
$('.timelineSelectionTooltip').remove()
|
|
} else {
|
|
for (var itemID of items) {
|
|
generate_timeline_tooltip(itemID, target);
|
|
}
|
|
}
|
|
}
|
|
|
|
function edit_item(id, callback) {
|
|
var item = items_timeline.get(id);
|
|
var group = item.group;
|
|
if (group == 'attribute') {
|
|
simplePopup(baseurl+'/attributes/edit/'+item.orig_id);
|
|
} else if (group == 'object') {
|
|
window.location = baseurl+'/objects/edit/'+item.orig_id;
|
|
}
|
|
}
|
|
|
|
function handle_doubleClick(data) {
|
|
// should be replaced by keyboard shortcut: SHIFT+E ?
|
|
//edit_item(data.item);
|
|
}
|
|
|
|
function handle_not_seen_enabled(hide, include_hidden) {
|
|
include_hidden = include_hidden !== undefined ? include_hidden : true;
|
|
if (hide) {
|
|
var hidden = items_timeline.get({
|
|
filter: function(item) {
|
|
return !item.seen_enabled;
|
|
}
|
|
});
|
|
var hidden_ids = [];
|
|
items_timeline.forEach(function(item) {
|
|
hidden_ids.push(item.id);
|
|
});
|
|
items_timeline.remove(hidden)
|
|
items_backup = hidden;
|
|
} else if (include_hidden) {
|
|
if (items_backup !== undefined) {
|
|
items_timeline.add(items_backup);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setVisibleWindow() {
|
|
var startDate = $('#checkbox_timeline_display_daterange_start').val()
|
|
var endDate = $('#checkbox_timeline_display_daterange_end').val()
|
|
var currentWindow = eventTimeline.getWindow()
|
|
startDate = startDate === '' ? currentWindow.start : startDate
|
|
endDate = endDate === '' ? currentWindow.end : endDate
|
|
eventTimeline.setWindow(startDate, endDate);
|
|
}
|
|
|
|
$('#fullscreen-btn-timeline').click(function() {
|
|
var timeline_div = $('#eventtimeline_div');
|
|
var fullscreen_enabled = !timeline_div.data('fullscreen');
|
|
timeline_div.data('fullscreen', fullscreen_enabled);
|
|
var height_val = fullscreen_enabled == true ? "calc(100vh - 42px - 42px - 10px)" : "400px";
|
|
|
|
timeline_div.css("max-height", height_val);
|
|
setTimeout(function() { // timeline takes time to be drawn
|
|
timeline_div[0].scrollIntoView({
|
|
behavior: "smooth",
|
|
});
|
|
}, 1);
|
|
eventTimeline.setOptions({maxHeight: height_val});
|
|
});
|
|
|
|
// init_scope_menu
|
|
var menu_scope_timeline, menu_display_timeline;
|
|
function init_popover() {
|
|
if (timeline_disabled) return;
|
|
menu_scope_timeline = new ContextualMenu({
|
|
trigger_container: document.getElementById("timeline-scope"),
|
|
bootstrap_popover: true,
|
|
style: "z-index: 1",
|
|
container: document.getElementById("eventtimeline_div")
|
|
});
|
|
menu_scope_timeline.add_select({
|
|
id: "select_timeline_scope",
|
|
label: "Scope",
|
|
tooltip: "The time scope represented by the timeline",
|
|
event: function(value) {
|
|
if (value == "First seen/Last seen" || value == "Sightings") {
|
|
reload_timeline();
|
|
}
|
|
},
|
|
options: ["First seen/Last seen", "Sightings"],
|
|
default: "First seen/Last seen"
|
|
});
|
|
|
|
menu_display_timeline = new ContextualMenu({
|
|
trigger_container: document.getElementById("timeline-display"),
|
|
bootstrap_popover: true,
|
|
style: "z-index: 1",
|
|
container: document.getElementById("eventtimeline_div")
|
|
});
|
|
menu_display_timeline.add_slider({
|
|
id: 'slider_timeline_display_max_char_num',
|
|
label: "Characters to show",
|
|
title: "Maximum number of characters to display in the label",
|
|
min: 8,
|
|
max: 2048,
|
|
value: max_displayed_char_timeline,
|
|
step: 8,
|
|
applyButton: true,
|
|
event: function(value) {
|
|
$("#slider_timeline__display_max_char_num").parent().find("span").text(value);
|
|
},
|
|
eventApply: function(value) {
|
|
reload_timeline();
|
|
}
|
|
});
|
|
menu_display_timeline.add_checkbox({
|
|
id: 'checkbox_timeline_display_hide_not_seen_enabled',
|
|
label: "Hide first seen not set",
|
|
title: "Hide items that do not have first seen set",
|
|
event: function(value) {
|
|
handle_not_seen_enabled(value)
|
|
}
|
|
});
|
|
menu_display_timeline.add_checkbox({
|
|
id: 'checkbox_timeline_display_gmt',
|
|
label: "Display with current timezone",
|
|
title: "Set the dates relative to the browser timezone. Otherwise, keep dates in GMT",
|
|
event: function(value) {
|
|
use_local_timezone = value;
|
|
reload_timeline()
|
|
},
|
|
checked: true
|
|
});
|
|
menu_display_timeline.add_datepicker({
|
|
id: 'checkbox_timeline_display_daterange_start',
|
|
label: "Start date",
|
|
title: "Start date of the window",
|
|
event: function(value) {
|
|
setVisibleWindow()
|
|
},
|
|
});
|
|
menu_display_timeline.add_datepicker({
|
|
id: 'checkbox_timeline_display_daterange_end',
|
|
label: "End date",
|
|
title: "End date of the window",
|
|
event: function(value) {
|
|
setVisibleWindow()
|
|
},
|
|
});
|
|
menu_display_timeline.add_button({
|
|
id: 'checkbox_timeline_display_fit',
|
|
type: "primary",
|
|
label: "Fit all visible items",
|
|
title: "Fit all visible items in the window",
|
|
event: function(value) {
|
|
eventTimeline.fit()
|
|
}
|
|
});
|
|
}
|