mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-21 01:28:47 +02:00
295 lines
9.5 KiB
JavaScript
295 lines
9.5 KiB
JavaScript
/*
|
|
* Copyright (C) 2013-2020 Combodo SARL
|
|
*
|
|
* This file is part of iTop.
|
|
*
|
|
* iTop is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* iTop is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
*/
|
|
|
|
;
|
|
$(function()
|
|
{
|
|
$.widget( 'itop.activity_panel',
|
|
{
|
|
// default options
|
|
options:
|
|
{
|
|
datetime_format: null,
|
|
datetimes_reformat_limit: 14, // In days
|
|
},
|
|
css_classes:
|
|
{
|
|
is_expanded: 'ibo-is-expanded',
|
|
is_opened: 'ibo-is-opened',
|
|
is_closed: 'ibo-is-closed',
|
|
is_active: 'ibo-is-active',
|
|
is_hidden: 'ibo-is-hidden',
|
|
},
|
|
js_selectors:
|
|
{
|
|
panel_size_toggler: '[data-role="ibo-activity-panel--size-toggler"]',
|
|
tab: '[data-role="ibo-activity-panel--tab"]',
|
|
tab_title: '[data-role="ibo-activity-panel--tab-title"]',
|
|
activity_tab_filter: '[data-role="ibo-activity-panel--activity-filter"]',
|
|
caselog_tab_open_all: '[data-role="ibo-activity-panel--caselog-open-all"]',
|
|
caselog_tab_close_all: '[data-role="ibo-activity-panel--caselog-close-all"]',
|
|
entry_group: '[data-role="ibo-activity-panel--entry-group"]',
|
|
entry: '[data-role="ibo-activity-entry"]',
|
|
entry_main_information: '[data-role="ibo-activity-entry--main-information"]',
|
|
entry_datetime: '[data-role="ibo-activity-entry--datetime"]',
|
|
edits_entry_long_description: '[data-role="ibo-edits-entry--long-description"]',
|
|
edits_entry_long_description_toggler: '[data-role="ibo-edits-entry--long-description-toggler"]',
|
|
},
|
|
|
|
// the constructor
|
|
_create: function()
|
|
{
|
|
this.element.addClass('ibo-activity-panel');
|
|
this._bindEvents();
|
|
this._ReformatDateTimes();
|
|
},
|
|
// events bound via _bind are removed automatically
|
|
// revert other modifications here
|
|
_destroy: function()
|
|
{
|
|
this.element.removeClass('ibo-activity-panel');
|
|
},
|
|
_bindEvents: function()
|
|
{
|
|
const me = this;
|
|
const oBodyElem = $('body');
|
|
|
|
// Click on collapse/expand toggler
|
|
this.element.find(this.js_selectors.panel_size_toggler).on('click', function(oEvent){
|
|
me._onTogglerClick(oEvent);
|
|
});
|
|
// Click on tab title
|
|
this.element.find(this.js_selectors.tab_title).on('click', function(oEvent){
|
|
me._onTabTitleClick(oEvent, $(this));
|
|
});
|
|
// Change on activity filters
|
|
this.element.find(this.js_selectors.activity_tab_filter).on('change', function(){
|
|
me._onActivityFilterChange($(this));
|
|
});
|
|
// Click on open all case log messages
|
|
this.element.find(this.js_selectors.caselog_tab_open_all).on('click', function(){
|
|
me._onCaseLogOpenAllClick($(this));
|
|
});
|
|
// Click on close all case log messages
|
|
this.element.find(this.js_selectors.caselog_tab_close_all).on('click', function(){
|
|
me._onCaseLogCloseAllClick($(this));
|
|
});
|
|
// Click on a closed case log message
|
|
this.element.find(this.js_selectors.entry_group).on('click', '.'+this.css_classes.is_closed + ' ' + this.js_selectors.entry_main_information, function(oEvent){
|
|
me._onCaseLogClosedMessageClick($(this).closest(me.js_selectors.entry));
|
|
});
|
|
// Click on an edits entry long description toggler
|
|
this.element.find(this.js_selectors.edits_entry_long_description_toggler).on('click', function(oEvent){
|
|
me._onEditsTogglerClick(oEvent, $(this).closest(me.js_selectors.entry));
|
|
});
|
|
// Mostly for outside clicks that should close elements
|
|
oBodyElem.on('click', function(oEvent){
|
|
me._onBodyClick(oEvent);
|
|
});
|
|
// Mostly for hotkeys
|
|
oBodyElem.on('keyup', function(oEvent){
|
|
me._onBodyKeyUp(oEvent);
|
|
});
|
|
},
|
|
|
|
// Events callbacks
|
|
_onTogglerClick: function(oEvent)
|
|
{
|
|
// Avoid anchor glitch
|
|
oEvent.preventDefault();
|
|
|
|
// Toggle menu
|
|
this.element.toggleClass(this.css_classes.is_expanded);
|
|
},
|
|
_onTabTitleClick: function(oEvent, oTabTitleElem)
|
|
{
|
|
// Avoid anchor glitch
|
|
oEvent.preventDefault();
|
|
|
|
const oTabElem = oTabTitleElem.closest(this.js_selectors.tab);
|
|
|
|
this.element.find(this.js_selectors.tab).removeClass(this.css_classes.is_active);
|
|
oTabElem.addClass(this.css_classes.is_active);
|
|
|
|
if(oTabElem.attr('data-tab-type') === 'caselog')
|
|
{
|
|
this._ShowCaseLogTab(oTabElem.attr('data-caselog-attribute-code'))
|
|
}
|
|
else
|
|
{
|
|
this._ShowActivityTab();
|
|
}
|
|
},
|
|
_onActivityFilterChange: function(oInputElem)
|
|
{
|
|
this._ApplyEntryFilters();
|
|
},
|
|
_onCaseLogOpenAllClick: function(oIconElem)
|
|
{
|
|
const sCaseLogAttCode = oIconElem.closest(this.js_selectors.tab).attr('data-caselog-attribute-code');
|
|
this._OpenAllMessages(sCaseLogAttCode);
|
|
},
|
|
_onCaseLogCloseAllClick: function(oIconElem)
|
|
{
|
|
const sCaseLogAttCode = oIconElem.closest(this.js_selectors.tab).attr('data-caselog-attribute-code');
|
|
this._CloseAllMessages(sCaseLogAttCode);
|
|
},
|
|
_onCaseLogClosedMessageClick: function(oEntryElem)
|
|
{
|
|
this._OpenMessage(oEntryElem);
|
|
},
|
|
_onEditsTogglerClick: function(oEvent, oEntryElem)
|
|
{
|
|
// Avoid anchor glitch
|
|
oEvent.preventDefault();
|
|
|
|
oEntryElem.toggleClass(this.css_classes.is_opened);
|
|
},
|
|
_onBodyClick: function(oEvent)
|
|
{
|
|
|
|
},
|
|
_onBodyKeyUp: function(oEvent)
|
|
{
|
|
|
|
},
|
|
|
|
// Methods
|
|
// - Helpers on dates
|
|
/**
|
|
* Reformat date times to be relative (only if they are not too far in the past)
|
|
* @private
|
|
*/
|
|
_ReformatDateTimes: function()
|
|
{
|
|
const me = this;
|
|
|
|
this.element.find(this.js_selectors.entry_datetime).each(function(){
|
|
const oEntryDateTime = moment($(this).text(), me.options.datetime_format);
|
|
const oNowDateTime = moment();
|
|
|
|
// Reformat date time only if it is not too far in the past (eg. "2 years ago" is not easy to interpret)
|
|
const fDays = moment.duration(oNowDateTime.diff(oEntryDateTime)).asDays();
|
|
if(fDays < me.options.datetimes_reformat_limit)
|
|
{
|
|
$(this).text( moment($(this).text(), me.options.datetime_format).fromNow() );
|
|
}
|
|
});
|
|
},
|
|
// - Helpers on tabs
|
|
_ShowCaseLogTab: function(sCaseLogAttCode)
|
|
{
|
|
// Show only entries from this case log
|
|
this._HideAllEntries();
|
|
this.element.find(this.js_selectors.entry+'[data-entry-caselog-attribute-code="'+sCaseLogAttCode+'"]').removeClass(this.css_classes.is_hidden);
|
|
this._UpdateEntryGroupsVisibility();
|
|
this.element.trigger('show-caselog-tab', ['caselog', sCaseLogAttCode]);
|
|
},
|
|
_ShowActivityTab: function()
|
|
{
|
|
// Show all entries but regarding the current filters
|
|
this._OpenAllMessages();
|
|
this._ShowAllEntries();
|
|
this._ApplyEntryFilters();
|
|
this.element.trigger('show-caselog-tab', 'activity');
|
|
},
|
|
// - Helpers on messages
|
|
_OpenMessage: function(oEntryElem)
|
|
{
|
|
oEntryElem.removeClass(this.css_classes.is_closed);
|
|
},
|
|
_OpenAllMessages: function(sCaseLogAttCode = null)
|
|
{
|
|
this._SwitchAllMessages('open', sCaseLogAttCode);
|
|
},
|
|
_CloseAllMessages: function(sCaseLogAttCode = null)
|
|
{
|
|
this._SwitchAllMessages('close', sCaseLogAttCode);
|
|
},
|
|
_SwitchAllMessages: function(sMode, sCaseLogAttCode = null)
|
|
{
|
|
const sExtraSelector = (sCaseLogAttCode === null) ? '' : '[data-entry-caselog-attribute-code="' + sCaseLogAttCode+'"]';
|
|
const sCallback = (sMode === 'open') ? 'removeClass' : 'addClass';
|
|
|
|
this.element.find(this.js_selectors.entry + sExtraSelector)[sCallback](this.css_classes.is_closed);
|
|
},
|
|
// - Helpers on entries
|
|
_ApplyEntryFilters: function()
|
|
{
|
|
const me = this;
|
|
|
|
this.element.find(this.js_selectors.activity_tab_filter).each(function(){
|
|
const aTargetEntryTypes = $(this).attr('data-target-entry-types').split(' ');
|
|
const sCallbackMethod = ($(this).prop('checked')) ? '_ShowEntries' : '_HideEntries';
|
|
|
|
for(let iIdx in aTargetEntryTypes)
|
|
{
|
|
me[sCallbackMethod](aTargetEntryTypes[iIdx]);
|
|
}
|
|
});
|
|
},
|
|
_ShowAllEntries: function()
|
|
{
|
|
this.element.find(this.js_selectors.entry).removeClass(this.css_classes.is_hidden);
|
|
this._UpdateEntryGroupsVisibility();
|
|
},
|
|
_HideAllEntries: function()
|
|
{
|
|
this.element.find(this.js_selectors.entry).addClass(this.css_classes.is_hidden);
|
|
this._UpdateEntryGroupsVisibility();
|
|
},
|
|
/**
|
|
* Show entries of type sEntryType but do not hide the others
|
|
*
|
|
* @param sEntryType string
|
|
* @private
|
|
*/
|
|
_ShowEntries: function(sEntryType)
|
|
{
|
|
this.element.find(this.js_selectors.entry+'[data-entry-type="'+sEntryType+'"]').removeClass(this.css_classes.is_hidden);
|
|
this._UpdateEntryGroupsVisibility();
|
|
},
|
|
/**
|
|
* Hide entries of type sEntryType but do not hide the others
|
|
*
|
|
* @param sEntryType string
|
|
* @private
|
|
*/
|
|
_HideEntries: function(sEntryType)
|
|
{
|
|
this.element.find(this.js_selectors.entry+'[data-entry-type="'+sEntryType+'"]').addClass(this.css_classes.is_hidden);
|
|
this._UpdateEntryGroupsVisibility();
|
|
},
|
|
_UpdateEntryGroupsVisibility: function()
|
|
{
|
|
const me = this;
|
|
|
|
this.element.find(this.js_selectors.entry_group).each(function(){
|
|
if($(this).find(me.js_selectors.entry + ':not(.' + me.css_classes.is_hidden + ')').length === 0)
|
|
{
|
|
$(this).addClass(me.css_classes.is_hidden);
|
|
}
|
|
else
|
|
{
|
|
$(this).removeClass(me.css_classes.is_hidden);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|