// Default DataTables initialisation settings var collapsedGroups = {}; $.extend(true, $.fn.dataTable.defaults, { 'paginate': false, 'deferRender': true, 'language': IsJsonString(__t('datatables_localization')) ? JSON.parse(__t('datatables_localization')) : {}, 'scrollY': false, 'scrollX': true, 'colReorder': true, 'stateSave': true, 'stateDuration': 0, 'stateSaveParams': function(settings, data) { data.search.search = ""; data.columns.forEach(column => { column.search.search = ""; }); }, 'stateSaveCallback': function(settings, data) { var settingKey = 'datatables_state_' + settings.sTableId; if ($.isEmptyObject(data)) { // state.clear() was called (resetting table layout) Grocy.FrontendHelpers.DeleteUserSetting(settingKey, true); } else { // Don't save when the state data hasn't actually changed if (Grocy.UserSettings[settingKey] !== undefined) { var data1 = JSON.parse(Grocy.UserSettings[settingKey]); delete data1.time; delete data1.childRows; var data2 = Object.assign({}, data); // Clone `data` without reference delete data2.time; delete data2.childRows; if (JSON.stringify(data1) == JSON.stringify(data2)) { return; } } Grocy.FrontendHelpers.SaveUserSetting(settingKey, JSON.stringify(data)); } }, 'stateLoadCallback': function(settings, data) { var settingKey = 'datatables_state_' + settings.sTableId; if (Grocy.UserSettings[settingKey] == undefined) { return null; } else { return JSON.parse(Grocy.UserSettings[settingKey]); } }, 'preDrawCallback': function(settings) { // Currently it is not possible to save the state of rowGroup via saveState events var api = new $.fn.dataTable.Api(settings); if (typeof api.rowGroup === "function") { var settingKey = 'datatables_rowGroup_' + settings.sTableId; if (Grocy.UserSettings[settingKey] !== undefined) { var rowGroup = JSON.parse(Grocy.UserSettings[settingKey]); // Check if there way changed. the draw event is called often therefore we have to check if it's really necessary if (rowGroup.enable !== api.rowGroup().enabled() || ("dataSrc" in rowGroup && rowGroup.dataSrc !== api.rowGroup().dataSrc())) { api.rowGroup().enable(rowGroup.enable); if ("dataSrc" in rowGroup) { api.rowGroup().dataSrc(rowGroup.dataSrc); // Apply fixed order for group column api.order.fixed({ pre: [rowGroup.dataSrc, 'asc'] }); } else { // Remove fixed order api.order.fixed({}); } } } } }, 'columnDefs': [ { type: 'chinese-string', targets: '_all' } ], 'rowGroup': { enable: false, startRender: function(rows, group) { var collapsed = !!collapsedGroups[group]; var toggleClass = collapsed ? "fa-caret-right" : "fa-caret-down"; rows.nodes().each(function(row) { row.style.display = collapsed ? "none" : ""; }); return $("") .append('' + group + ' ') .attr("data-name", group) .toggleClass("collapsed", collapsed); } } }); $(document).on("click", "tr.dtrg-group", function() { var name = $(this).data('name'); collapsedGroups[name] = !collapsedGroups[name]; $("table").DataTable().draw(); }); $.fn.dataTable.ext.type.order["custom-sort-pre"] = function(data) { // Workaround for https://github.com/DataTables/ColReorder/issues/85 // // Custom sorting can normally be provided by a "data-order" attribute on the element, // however this causes issues when reordering such a column... // // This here is for a custom column type "custom-sort", // the custom order value needs to be provided in the first child () of the return (Number.parseFloat($(data).get(0).innerText)); }; $('.table').on('column-sizing.dt', function(e, settings) { var dtScrollWidth = $('.dataTables_scroll').width(); var tableWidth = $('.table').width() + 100; // Some extra padding, otherwise the scrollbar maybe only appears after a column is already completely out of the viewport if (dtScrollWidth < tableWidth) { $('.dataTables_scrollBody').addClass("no-force-overflow-visible"); $('.dataTables_scrollBody').removeClass("force-overflow-visible"); } else { $('.dataTables_scrollBody').removeClass("no-force-overflow-visible"); $('.dataTables_scrollBody').addClass("force-overflow-visible"); } }); $(document).on("show.bs.dropdown", "td .dropdown", function(e) { if ($('.dataTables_scrollBody').hasClass("no-force-overflow-visible")) { $('.dataTables_scrollBody').addClass("force-overflow-visible"); } }); $(document).on("hide.bs.dropdown", "td .dropdown", function(e) { if ($('.dataTables_scrollBody').hasClass("no-force-overflow-visible")) { $('.dataTables_scrollBody').removeClass("force-overflow-visible"); } }); $(".change-table-columns-visibility-button").on("click", function(e) { e.preventDefault(); var dataTableSelector = $(e.currentTarget).attr("data-table-selector"); var dataTable = $(dataTableSelector).DataTable(); var columnCheckBoxesHtml = ""; var rowGroupRadioBoxesHtml = ""; var rowGroupDefined = typeof dataTable.rowGroup === "function"; if (rowGroupDefined) { var rowGroupChecked = (dataTable.rowGroup().enabled()) ? "" : "checked"; rowGroupRadioBoxesHtml = ' \
\ \ \
'; } dataTable.columns().every(function() { var index = this.index(); var indexForGrouping = index; var headerCell = $(this.header()); var title = headerCell.text(); var visible = this.visible(); if (!title || title.trim().length == 0 || title.startsWith("Hidden") || headerCell.hasClass("d-none")) { return; } var shadowColumnIndex = headerCell.attr("data-shadow-rowgroup-column"); if (shadowColumnIndex) { indexForGrouping = shadowColumnIndex; } var checked = "checked"; if (!visible) { checked = ""; } columnCheckBoxesHtml += ' \
\ \ \
'; if (rowGroupDefined && headerCell.hasClass("allow-grouping")) { var rowGroupChecked = ""; if (dataTable.rowGroup().enabled() && dataTable.rowGroup().dataSrc() == index) { rowGroupChecked = "checked"; } rowGroupRadioBoxesHtml += ' \
\ \ \
'; } }); var message = '\
\
' + __t('Table options') + '
\
\
' + __t('Hide/view columns') + '
\
\ ' + columnCheckBoxesHtml + ' \
\
'; if (rowGroupDefined) { message += ' \
\
' + __t('Group by') + '
\
\ ' + rowGroupRadioBoxesHtml + ' \
\
'; } bootbox.dialog({ message: message, size: 'small', backdrop: true, closeButton: false, buttons: { reset: { label: __t('Reset'), className: 'btn-outline-danger float-left responsive-button', callback: function() { bootbox.confirm({ message: __t("Are you sure you want to reset the table options?"), closeButton: false, buttons: { cancel: { label: 'No', className: 'btn-danger' }, confirm: { label: 'Yes', className: 'btn-success' } }, callback: function(result) { if (result) { var dataTable = $(dataTableSelector).DataTable(); var tableId = dataTable.settings()[0].sTableId; // Delete rowgroup settings Grocy.FrontendHelpers.DeleteUserSetting('datatables_rowGroup_' + tableId); // Delete state settings dataTable.state.clear(); } $(".modal").last().modal("hide"); } }); } }, ok: { label: __t('OK'), className: 'btn-primary responsive-button', callback: function() { $(".modal").last().modal("hide"); } } } }); }); $(document).on("click", ".change-table-columns-visibility-toggle", function() { var dataTableSelector = $(this).attr("data-table-selector"); var columnIndex = $(this).attr("data-column-index"); var dataTable = $(dataTableSelector).DataTable(); dataTable.columns(columnIndex).visible(this.checked); }); $(document).on("click", ".change-table-columns-rowgroup-toggle", function() { var dataTableSelector = $(this).attr("data-table-selector"); var columnIndex = $(this).attr("data-column-index"); var dataTable = $(dataTableSelector).DataTable(); var rowGroup; if (columnIndex == -1) { rowGroup = { enable: false }; dataTable.rowGroup().enable(false); // Remove fixed order dataTable.order.fixed({}); } else { rowGroup = { enable: true, dataSrc: columnIndex } dataTable.rowGroup().enable(true); dataTable.rowGroup().dataSrc(columnIndex); // Apply fixed order for group column dataTable.order.fixed({ pre: [columnIndex, 'asc'] }); } var settingKey = 'datatables_rowGroup_' + dataTable.settings()[0].sTableId; Grocy.FrontendHelpers.SaveUserSetting(settingKey, JSON.stringify(rowGroup)); dataTable.draw(); });