Grocy.Api = {};
Grocy.Api.Get = function(apiFunction, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/' + apiFunction);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText), {
recordsTotal: xhr.getResponseHeader('x-rowcount-total'),
recordsFiltered: xhr.getResponseHeader('x-rowcount-filtered'),
});
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('GET', url, true);
xhr.send();
return xhr;
};
Grocy.Api.Post = function(apiFunction, jsonData, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/' + apiFunction);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify(jsonData));
return xhr;
};
Grocy.Api.Put = function(apiFunction, jsonData, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/' + apiFunction);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('PUT', url, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify(jsonData));
return xhr;
};
Grocy.Api.Delete = function(apiFunction, jsonData, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/' + apiFunction);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('DELETE', url, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send(JSON.stringify(jsonData));
return xhr;
};
Grocy.Api.UploadFile = function(file, group, fileName, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/files/' + group + '/' + btoa(fileName));
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('PUT', url, true);
xhr.setRequestHeader('Content-type', 'application/octet-stream');
xhr.send(file);
return xhr;
};
Grocy.Api.DeleteFile = function(fileName, group, success, error) {
var xhr = new XMLHttpRequest();
var url = U('/api/files/' + group + '/' + btoa(fileName));
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 204) {
if (success) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
} else {
success({});
}
}
} else {
if (error) {
error(xhr);
}
}
}
};
xhr.open('DELETE', url, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.send();
return xhr;
};
U = function(relativePath) {
return Grocy.BaseUrl.replace(/\/$/, '') + relativePath;
}
Grocy.Translator = new Translator(Grocy.LocalizationStrings);
Grocy.TranslatorQu = new Translator(Grocy.LocalizationStringsQu);
__t = function(text, ...placeholderValues) {
if (Grocy.Mode === "dev") {
var text2 = text;
if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(text2)) {
Grocy.Api.Post('system/log-missing-localization', {
"text": text2
});
}
}
return Grocy.Translator.__(text, ...placeholderValues)
}
__n = function(number, singularForm, pluralForm, isQu = false) {
if (Grocy.Mode === "dev") {
var singularForm2 = singularForm;
if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(singularForm2)) {
Grocy.Api.Post('system/log-missing-localization', {
"text": singularForm2
});
}
}
if (isQu) {
return Grocy.TranslatorQu.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number))
} else {
return Grocy.Translator.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number))
}
}
if (!Grocy.ActiveNav.isEmpty()) {
var menuItem = $('#sidebarResponsive').find("[data-nav-for-page='" + Grocy.ActiveNav + "']");
menuItem.addClass('active-page');
if (menuItem.length) {
var parentMenuSelector = menuItem.data("sub-menu-of");
if (typeof parentMenuSelector !== "undefined") {
$(parentMenuSelector).collapse("show");
$(parentMenuSelector).prev(".nav-link-collapse").addClass("active-page");
$(parentMenuSelector).on("shown.bs.collapse", function(e) {
if (!menuItem.isVisibleInViewport(75)) {
menuItem[0].scrollIntoView();
}
})
} else {
if (!menuItem.isVisibleInViewport(75)) {
menuItem[0].scrollIntoView();
}
}
}
}
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === "class") {
var attributeValue = $(mutation.target).prop(mutation.attributeName);
if (attributeValue.contains("sidenav-toggled")) {
window.localStorage.setItem("sidebar_state", "collapsed");
} else {
window.localStorage.setItem("sidebar_state", "expanded");
}
}
});
});
observer.observe(document.body, {
attributes: true
});
if (window.localStorage.getItem("sidebar_state") === "collapsed") {
$("#sidenavToggler").click();
}
RefreshContextualTimeago = function(rootSelector = "#page-content") {
$(rootSelector + " time.timeago").each(function() {
var element = $(this);
if (!element.hasAttr("datetime")) {
element.text("")
return
}
var timestamp = element.attr("datetime");
if (timestamp.isEmpty() || timestamp.length < 10) {
element.text("")
return
}
var isNever = timestamp && timestamp.substring(0, 10) == "2999-12-31";
var isToday = timestamp && timestamp.substring(0, 10) == moment().format("YYYY-MM-DD");
var isDateWithoutTime = element.hasClass("timeago-date-only");
if (isNever) {
element.prev().text(__t("Never"));
element.text("");
} else if (isToday) {
element.text(__t("Today"));
} else {
element.text(moment(timestamp).fromNow());
}
if (isDateWithoutTime) {
element.prev().text(element.prev().text().substring(0, 10));
}
});
}
RefreshContextualTimeago();
toastr.options = {
toastClass: 'alert',
closeButton: true,
timeOut: 20000,
extendedTimeOut: 5000
};
window.FontAwesomeConfig = {
searchPseudoElements: true
}
Grocy.FrontendHelpers = {};
Grocy.FrontendHelpers.ValidateForm = function(formId) {
var form = document.getElementById(formId);
if (form === null || form === undefined) {
return;
}
if (form.checkValidity() === true) {
$(form).find(':submit').removeClass('disabled');
$(form).find('.keep-disabled').addClass('disabled');
} else {
$(form).find(':submit').addClass('disabled');
}
$(form).addClass('was-validated');
}
Grocy.FrontendHelpers.BeginUiBusy = function(formId = null) {
$("body").addClass("cursor-busy");
if (formId !== null) {
$("#" + formId + " :input").attr("disabled", true);
}
}
Grocy.FrontendHelpers.EndUiBusy = function(formId = null) {
$("body").removeClass("cursor-busy");
if (formId !== null) {
$("#" + formId + " :input").attr("disabled", false);
}
}
Grocy.FrontendHelpers.ShowGenericError = function(message, exception) {
toastr.error(__t(message) + '
' + __t('Click to show technical details'), '', {
onclick: function() {
bootbox.alert({
title: __t('Error details'),
message: '
' + JSON.stringify(exception, null, 4) + '',
closeButton: false
});
}
});
console.error(exception);
}
Grocy.FrontendHelpers.SaveUserSetting = function(settingsKey, value) {
if (Grocy.UserSettings[settingsKey] == value) {
return;
}
Grocy.UserSettings[settingsKey] = value;
jsonData = {};
jsonData.value = value;
Grocy.Api.Put('user/settings/' + settingsKey, jsonData,
function(result) {
// Nothing to do...
},
function(xhr) {
console.error(xhr);
}
);
}
Grocy.FrontendHelpers.DeleteUserSetting = function(settingsKey, reloadPageOnSuccess = false) {
delete Grocy.UserSettings[settingsKey];
Grocy.Api.Delete('user/settings/' + settingsKey, {},
function(result) {
if (reloadPageOnSuccess) {
location.reload();
}
},
function(xhr) {
if (!xhr.statusText.isEmpty()) {
Grocy.FrontendHelpers.ShowGenericError('Error while deleting, please retry', xhr.response)
}
}
);
}
Grocy.FrontendHelpers.RunWebhook = function(webhook, data, repetitions = 1) {
Object.assign(data, webhook.extra_data);
var hasAlreadyFailed = false;
for (i = 0; i < repetitions; i++) {
$.post(webhook.hook, data).fail(function(req, status, errorThrown) {
if (!hasAlreadyFailed) {
hasAlreadyFailed = true;
Grocy.FrontendHelpers.ShowGenericError(__t("Error while executing WebHook", {
"status": status,
"errorThrown": errorThrown
}));
}
});
}
}
$(document).on("keyup paste change", "input, textarea", function() {
$(this).closest("form").addClass("is-dirty");
});
$(document).on("click", "select", function() {
$(this).closest("form").addClass("is-dirty");
});
// Auto saving user setting controls
$(document).on("change", ".user-setting-control", function() {
var element = $(this);
var settingKey = element.attr("data-setting-key");
if (!element[0].checkValidity()) {
return;
}
var inputType = "unknown";
if (typeof element.attr("type") !== typeof undefined && element.attr("type") !== false) {
inputType = element.attr("type").toLowerCase();
}
if (inputType === "checkbox") {
value = element.is(":checked");
} else {
var value = element.val();
}
Grocy.FrontendHelpers.SaveUserSetting(settingKey, value);
});
// Show file name Bootstrap custom file input
$('input.custom-file-input').on('change', function() {
$(this).next('.custom-file-label').html(GetFileNameFromPath($(this).val()));
});
// Translation of "Browse"-button of Bootstrap custom file input
if ($(".custom-file-label").length > 0) {
$("