Files
kimai/assets/js/plugins/KimaiToolbar.js
Kevin Papst d661c8b54e fix closing search dropdown (#1142)
* using a different library for javascript selects, fixing the closing search dropdown
* fix closing dropdown for daterangepicker
* added missing search button for mobile on customer page
* fix meta fields with same names than existing columns
2019-09-25 18:34:25 +02:00

233 lines
8.4 KiB
JavaScript

/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/*!
* [KIMAI] KimaiToolbar: some event listener to handle the toolbar/data-table filter, toolbar and navigation
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiToolbar extends KimaiPlugin {
constructor(formSelector, formSubmitActionClass) {
super();
this.formSelector = formSelector;
this.actionClass = formSubmitActionClass;
}
getId() {
return 'toolbar';
}
init() {
const formSelector = this.getSelector();
const self = this;
const EVENT = self.getContainer().getPlugin('event');
this._registerPagination(formSelector, EVENT);
this._registerSortableTables(formSelector, EVENT);
this._registerAlternativeSubmitActions(formSelector, this.actionClass);
this._registerSearchButtons(formSelector);
jQuery('body')
// prevent that the dropdown closes, when a form input is changed - eg. a select option was clicked
.on('click', formSelector + ' .dropdown-menu', function (event) {
event.stopPropagation();
})
// prevent that a click into the search field will close the dropdown
.on('click', '.select2-search__field', function (event) {
event.stopPropagation();
})
// prevent that the dropdown closes when a optgroup header is clicked
.on('click', '.select2-results__group', function (event) {
event.stopPropagation();
})
// prevent that a click into a daterangepicker will close the dropdown
.on('click', '.daterangepicker', function (event) {
event.stopPropagation();
})
// prevent that clicks in the dropdown elements, but outside of elements will close the dropdown (eg border besides the search field)
.on('click', '.select2-container', function (event) {
event.stopPropagation();
})
;
// Reset the page if filter values are changed, otherwise we might end up with a limited set of data,
// which does not support the given page - and it would be just wrong to stay in the same page
jQuery(formSelector +' input').change(function (event) {
switch (event.target.id) {
case 'order':
case 'orderBy':
case 'page':
break;
default:
jQuery(formSelector + ' input#page').val(1);
break;
}
self.triggerChange();
});
// when user selected a new customer or project, reset the pagination back to 1
// and then find out if the results should be reloaded
jQuery(formSelector + ' select').change(function (event) {
let reload = true;
switch (event.target.id) {
case 'customer':
if (jQuery(formSelector + ' select#project').length > 0) {
reload = false;
}
break;
case 'project':
if (jQuery(formSelector + ' select#activity').length > 0) {
reload = false;
}
break;
}
jQuery(formSelector + ' input#page').val(1);
if (reload) {
self.triggerChange();
}
});
// close all open selectpicker upon choosing any dropdown option
jQuery(formSelector + ' select.selectpicker').on('change', function(event) {
jQuery('.bootstrap-select.open').removeClass('open');
});
}
/**
* The search toggle button is not part of this component, but it is directly connected to it.
* @private
*/
_registerSearchButtons(formSelector) {
jQuery('body')
// only for mobile experience currently: show the search form field
.on('click', '.btn-search.search-toggle', function (event) {
event.preventDefault();
event.stopPropagation();
jQuery(formSelector).parent('section').toggleClass('search-open');
jQuery(formSelector).toggleClass('hidden-xs');
jQuery(formSelector + ' input#searchTerm').dropdown('toggle');
jQuery(formSelector + ' input#searchTerm').focus();
})
// hide the search form field
.on('click', formSelector + ' a.search-cancel', function (event) {
event.preventDefault();
event.stopPropagation();
jQuery(formSelector).parent('section').toggleClass('search-open');
jQuery(formSelector + ' input#searchTerm').dropdown('toggle');
jQuery(formSelector).toggleClass('hidden-xs');
})
;
}
/**
* Some actions utilize the filter from the search form and submit it to another URL.
* @private
*/
_registerAlternativeSubmitActions(toolbarSelector, actionBtnClass) {
document.addEventListener('click', function(event) {
let target = event.target;
while (target !== null && !target.matches('body')) {
if (target.classList.contains(actionBtnClass)) {
const form = document.querySelector(toolbarSelector);
if (form === null) {
return;
}
const prevAction = form.action;
const prevMethod = form.method;
form.target = '_blank';
form.action = target.href;
if (target.dataset.method !== undefined) {
form.method = target.dataset.method;
}
form.submit();
form.target = '';
form.action = prevAction;
form.method = prevMethod;
event.preventDefault();
event.stopPropagation();
}
target = target.parentNode;
}
});
}
/**
* Sortable datatables use hidden fields in the toolbar filter/search form
* @private
*/
_registerSortableTables(formSelector, EVENT) {
jQuery('body').on('click', 'th.sortable', function(event){
var $header = jQuery(event.target);
var order = 'DESC';
var orderBy = $header.data('order');
if ($header.hasClass('sorting_desc')) {
order = 'ASC';
}
jQuery(formSelector + ' input#orderBy').val(orderBy);
jQuery(formSelector + ' input#order').val(order);
// triggers the page reset - see below
jQuery(formSelector + ' input#order').trigger('change');
// triggers the datatable reload - search for the event name
EVENT.trigger('filter-change');
});
}
/**
* This catches all clicks on the pagination and prevents the default action, as we want to reload the page via JS
* @private
*/
_registerPagination(formSelector, EVENT) {
jQuery('body').on('click', 'div.navigation ul.pagination li a', function(event) {
let pager = jQuery(formSelector + " input#page");
if (pager.length === 0) {
return;
}
event.preventDefault();
event.stopPropagation();
let urlParts = jQuery(this).attr('href').split('/');
let page = urlParts[urlParts.length-1];
pager.val(page);
pager.trigger('change');
EVENT.trigger('pagination-change');
return false;
});
}
hide() {
const toggle = jQuery(this.getSelector() + ' #searchTerm.dropdown-toggle');
if (toggle.parent().hasClass('open')) {
toggle.dropdown('toggle');
}
}
/**
* Triggers an event, that everyone can listen for.
*/
triggerChange() {
this.getContainer().getPlugin('event').trigger('toolbar-change');
}
/**
* Returns the CSS selector to target the toolbar form.
*
* @returns {string}
*/
getSelector() {
return this.formSelector;
}
}