added tags for timesheets (#604)
This commit is contained in:
@@ -18,7 +18,7 @@ export default class KimaiAPI extends KimaiPlugin {
|
||||
return 'api';
|
||||
}
|
||||
|
||||
get(url, callback) {
|
||||
get(url, data, callback) {
|
||||
jQuery.ajax({
|
||||
url: url,
|
||||
headers: {
|
||||
@@ -26,6 +26,7 @@ export default class KimaiAPI extends KimaiPlugin {
|
||||
'Content-Type':'application/json'
|
||||
},
|
||||
method: 'GET',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: callback
|
||||
});
|
||||
@@ -45,4 +46,18 @@ export default class KimaiAPI extends KimaiPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
delete(url, callbackSuccess, callbackError) {
|
||||
jQuery.ajax({
|
||||
url: url,
|
||||
headers: {
|
||||
'X-AUTH-SESSION': true,
|
||||
'Content-Type':'application/json'
|
||||
},
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
success: callbackSuccess,
|
||||
error: callbackError
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,15 +5,19 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* [KIMAI] KimaiAPILink
|
||||
*
|
||||
* allows to assign the given selector to any element, which then is used as click-handler
|
||||
* calling an API method and trigger the event from data-event attribute afterwards
|
||||
*/
|
||||
|
||||
import KimaiClickHandlerReducedInTableRow from "./KimaiClickHandlerReducedInTableRow";
|
||||
|
||||
/**
|
||||
* Needs to be initialized with a class name.
|
||||
*
|
||||
* A link like <a href=# class=remoteLink> can be activated with:
|
||||
* new KimaiAPILink('remoteLink')
|
||||
*
|
||||
* Allows to assign the given selector to any element, which then is used as click-handler
|
||||
* calling an API method and trigger the event from data-event attribute afterwards.
|
||||
*
|
||||
* @param selector
|
||||
*/
|
||||
export default class KimaiAPILink extends KimaiClickHandlerReducedInTableRow {
|
||||
|
||||
constructor(selector) {
|
||||
@@ -26,7 +30,7 @@ export default class KimaiAPILink extends KimaiClickHandlerReducedInTableRow {
|
||||
document.addEventListener('click', function(event) {
|
||||
let target = event.target;
|
||||
while (!target.matches('body')) {
|
||||
if (target.matches(self.selector)) {
|
||||
if (target.classList.contains(self.selector)) {
|
||||
const attributes = target.dataset;
|
||||
|
||||
let url = attributes['href'];
|
||||
@@ -34,28 +38,12 @@ export default class KimaiAPILink extends KimaiClickHandlerReducedInTableRow {
|
||||
url = target.getAttribute('href');
|
||||
}
|
||||
|
||||
const method = attributes['method'];
|
||||
const eventName = attributes['event'];
|
||||
const api = self.getContainer().getPlugin('api');
|
||||
const eventing = self.getContainer().getPlugin('event');
|
||||
const alert = self.getContainer().getPlugin('alert');
|
||||
|
||||
if (method === 'PATCH') {
|
||||
api.patch(url, function(result) {
|
||||
eventing.trigger(eventName);
|
||||
if (attributes.msgSuccess) {
|
||||
alert.success(attributes.msgSuccess);
|
||||
}
|
||||
}, function(xhr, err) {
|
||||
let message = 'action.update.error';
|
||||
if (attributes.msgError) {
|
||||
message = attributes.msgError;
|
||||
}
|
||||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||||
err = xhr.responseJSON.message;
|
||||
}
|
||||
alert.error(message, err);
|
||||
if (attributes.question !== undefined) {
|
||||
self.getContainer().getPlugin('alert').question(attributes.question, function() {
|
||||
self._callApi(url, attributes);
|
||||
});
|
||||
} else {
|
||||
self._callApi(url, attributes);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
@@ -67,4 +55,35 @@ export default class KimaiAPILink extends KimaiClickHandlerReducedInTableRow {
|
||||
});
|
||||
}
|
||||
|
||||
_callApi(url, attributes)
|
||||
{
|
||||
const method = attributes['method'];
|
||||
const eventName = attributes['event'];
|
||||
const api = this.getContainer().getPlugin('api');
|
||||
const eventing = this.getContainer().getPlugin('event');
|
||||
const alert = this.getContainer().getPlugin('alert');
|
||||
const successHandle = function(result) {
|
||||
eventing.trigger(eventName);
|
||||
if (attributes.msgSuccess) {
|
||||
alert.success(attributes.msgSuccess);
|
||||
}
|
||||
};
|
||||
const errorHandle = function(xhr, err) {
|
||||
let message = 'action.update.error';
|
||||
if (attributes.msgError) {
|
||||
message = attributes.msgError;
|
||||
}
|
||||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||||
err = xhr.responseJSON.message;
|
||||
}
|
||||
alert.error(message, err);
|
||||
};
|
||||
|
||||
if (method === 'PATCH') {
|
||||
api.patch(url, successHandle, errorHandle);
|
||||
} else if (method === 'DELETE') {
|
||||
api.delete(url, successHandle, errorHandle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
|
||||
const self = this;
|
||||
const apiService = this.getContainer().getPlugin('api');
|
||||
|
||||
apiService.get(this.attributes['api'], function(result) {
|
||||
apiService.get(this.attributes['api'], {}, function(result) {
|
||||
self.setEntries(result);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ export default class KimaiAjaxModalForm extends KimaiClickHandlerReducedInTableR
|
||||
|
||||
// activate new loaded widgets
|
||||
self.getContainer().getPlugin('date-time-picker').activateDateTimePicker(formIdentifier);
|
||||
self.getContainer().getPlugin('autocomplete').activateAutocomplete(formIdentifier + " .js-autocomplete");
|
||||
|
||||
// activate selectpicker if beta test is active
|
||||
jQuery('.selectpicker').selectpicker('refresh');
|
||||
}
|
||||
|
||||
@@ -51,4 +51,30 @@ export default class KimaiAlert extends KimaiPlugin {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback receives a value and needs to decide what should happen with it
|
||||
*
|
||||
* @param message
|
||||
* @param callback
|
||||
*/
|
||||
question(message, callback) {
|
||||
const translation = this.getContainer().getTranslation();
|
||||
|
||||
if (translation.has(message)) {
|
||||
message = translation.get(message);
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: message,
|
||||
type: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: translation.get('confirm'),
|
||||
cancelButtonText: translation.get('cancel')
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
callback(result.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
93
assets/js/plugins/KimaiAutocomplete.js
Normal file
93
assets/js/plugins/KimaiAutocomplete.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import jQuery from 'jquery';
|
||||
import KimaiPlugin from "../KimaiPlugin";
|
||||
|
||||
/**
|
||||
* Supporting auto-complete fields via API.
|
||||
* Currently used for timesheet tagging in toolbar and edit dialogs.
|
||||
*/
|
||||
export default class KimaiAutocomplete extends KimaiPlugin {
|
||||
|
||||
constructor(selector) {
|
||||
super();
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.activateAutocomplete(this.selector);
|
||||
}
|
||||
|
||||
getId() {
|
||||
return 'autocomplete';
|
||||
}
|
||||
|
||||
splitTagList(val) {
|
||||
return val.split(/,\s*/);
|
||||
}
|
||||
|
||||
extractLastTag(term) {
|
||||
return this.splitTagList(term).pop();
|
||||
}
|
||||
|
||||
activateAutocomplete(selector)
|
||||
{
|
||||
const apiUrl = jQuery(selector).attr('data-autocomplete-url');
|
||||
const self = this;
|
||||
|
||||
jQuery(selector)
|
||||
// don't navigate away from the field on tab when selecting an item
|
||||
.on("keydown", function (event) {
|
||||
if (event.keyCode === jQuery.ui.keyCode.TAB &&
|
||||
jQuery(this).autocomplete("instance").menu.active) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
.autocomplete({
|
||||
source: function (request, response) {
|
||||
const lastEntry = self.extractLastTag(request.term);
|
||||
self.getContainer().getPlugin('api').get(apiUrl, {'name': lastEntry}, function(data){
|
||||
response(data);
|
||||
});
|
||||
},
|
||||
search: function () {
|
||||
// custom minLength
|
||||
var term = self.extractLastTag(this.value);
|
||||
if (term.length < 2) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
focus: function () {
|
||||
// prevent value inserted on focus
|
||||
return false;
|
||||
},
|
||||
select: function (event, ui) {
|
||||
var terms = self.splitTagList(this.value);
|
||||
|
||||
// remove the current input
|
||||
terms.pop();
|
||||
|
||||
// check if selected tag is already in list
|
||||
if (!terms.includes(ui.item.value)) {
|
||||
// add the selected item
|
||||
terms.push(ui.item.value);
|
||||
}
|
||||
// add placeholder to get the comma-and-space at the end
|
||||
terms.push("");
|
||||
|
||||
this.value = terms.join(", ");
|
||||
|
||||
$(this).trigger('change');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export default class KimaiDatePicker extends KimaiPlugin {
|
||||
locale: {
|
||||
format: localeFormat,
|
||||
firstDay: 1,
|
||||
applyLabel: translator.get('apply'),
|
||||
applyLabel: translator.get('confirm'),
|
||||
cancelLabel: translator.get('cancel'),
|
||||
customRangeLabel: translator.get('customRange'),
|
||||
daysOfWeek: moment.weekdaysShort(),
|
||||
|
||||
@@ -53,7 +53,7 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
|
||||
separator: separator,
|
||||
format: localeFormat,
|
||||
firstDay: 1,
|
||||
applyLabel: translator.get('apply'),
|
||||
applyLabel: translator.get('confirm'),
|
||||
cancelLabel: translator.get('cancel'),
|
||||
customRangeLabel: translator.get('customRange'),
|
||||
daysOfWeek: moment.weekdaysShort(),
|
||||
|
||||
@@ -43,7 +43,7 @@ export default class KimaiDateTimePicker extends KimaiPlugin {
|
||||
locale: {
|
||||
format: localeFormat,
|
||||
firstDay: 1,
|
||||
applyLabel: translator.get('apply'),
|
||||
applyLabel: translator.get('confirm'),
|
||||
cancelLabel: translator.get('cancel'),
|
||||
customRangeLabel: translator.get('customRange'),
|
||||
daysOfWeek: moment.weekdaysShort(),
|
||||
|
||||
@@ -74,7 +74,7 @@ export default class KimaiRecentActivities extends KimaiPlugin {
|
||||
const self = this;
|
||||
const apiService = this.getContainer().getPlugin('api');
|
||||
|
||||
apiService.get(this.attributes['api'], function(result) {
|
||||
apiService.get(this.attributes['api'], {}, function(result) {
|
||||
self.setEntries(result);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user