diff --git a/src/resources/assets/css/common.css b/src/resources/assets/css/common.css index 9c79cc1fc8..b42d7b55b3 100644 --- a/src/resources/assets/css/common.css +++ b/src/resources/assets/css/common.css @@ -61,9 +61,50 @@ form .select2.select2-container { } /*Table - List View*/ +.dataTables_wrapper { + position: relative; + isolation: isolate; +} + .dataTables_wrapper div.row .col-sm-12 { position: relative; } + +.dataTables_wrapper .table-responsive { + position: relative; +} + +.dataTables_wrapper table.dataTable { + position: relative; + z-index: 1; +} + +/* Ensure any processing indicator within or related to table wrapper covers full area */ +.dataTables_wrapper, +div[id$="_wrapper"] { + position: relative !important; +} + +.dataTables_wrapper > .dataTables_processing, +.dataTables_wrapper > .dt-processing, +.dataTables_wrapper .dataTables_processing, +.dataTables_wrapper .dt-processing, +div[id$="_wrapper"] > .dataTables_processing, +div[id$="_wrapper"] > .dt-processing, +div[id$="_wrapper"] .dataTables_processing, +div[id$="_wrapper"] .dt-processing { + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 60px !important; + width: 100% !important; + height: calc(100% - 60px) !important; + transform: none !important; + margin: 0 !important; + z-index: 1000 !important; + inset: unset !important; +} .navbar-filters { min-height: 25px; border-radius: 0; @@ -629,42 +670,59 @@ table.dataTable tr th:first-child, table.dataTable tr td:first-child, table.data padding-left: 0.6rem; } +/* Processing indicator - global styles */ .dataTables_processing, .dt-processing { + position: absolute !important; background: rgba(255, 255, 255, 0.8) !important; - color: transparent !important; /* Hide any text */ border: none !important; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1) !important; - border-radius: 5px !important; - width: 100% !important; - height: 100% !important; - position: absolute !important; - top: 0 !important; - left: 0 !important; - transform: none !important; - margin: 0 !important; + box-shadow: none !important; + border-radius: 0 !important; padding: 0 !important; - z-index: 999 !important; + z-index: 1000 !important; display: flex !important; justify-content: center !important; align-items: center !important; + overflow: hidden !important; + /* Aggressive text hiding */ + font-size: 0 !important; + line-height: 0 !important; + color: transparent !important; + text-indent: -9999px !important; + white-space: nowrap !important; + text-shadow: none !important; + text-decoration: none !important; } +/* Hide ALL text content and children */ +.dataTables_processing *:not(img), +.dt-processing *:not(img), +.dataTables_processing::before, +.dataTables_processing::after, +.dt-processing::before, +.dt-processing::after { + display: none !important; + visibility: hidden !important; + opacity: 0 !important; + font-size: 0 !important; + color: transparent !important; + text-indent: -9999px !important; +} + +/* Show only spinner image */ .dataTables_processing img, .dt-processing img { display: block !important; - width: 30px !important; - height: 30px !important; + width: 40px !important; + height: 40px !important; opacity: 1 !important; visibility: visible !important; margin: 0 auto !important; + position: relative !important; + z-index: 1001 !important; } -.dataTables_processing > *:not(img), -.dt-processing > *:not(img) { - display: none !important; -} - +/* Hide when not active */ .dataTables_processing:not([style*="block"]), .dt-processing:not([style*="block"]) { display: none !important; @@ -812,10 +870,6 @@ div.dt-scroll-body { margin-bottom: 0; } -.dt-buttons { - margin-bottom: 8px; -} - /* Adjust table headers */ .dataTable thead th { font-size: 0.70em; @@ -823,7 +877,7 @@ div.dt-scroll-body { } /* Make export and column visibility buttons smaller */ -.dataTables_wrapper .dt-buttons .btn { +.dt-container .dt-buttons .btn-group .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; } diff --git a/src/resources/views/crud/components/datatable/datatable_logic.blade.php b/src/resources/views/crud/components/datatable/datatable_logic.blade.php index 314cf7a8c1..52219ef39d 100644 --- a/src/resources/views/crud/components/datatable/datatable_logic.blade.php +++ b/src/resources/views/crud/components/datatable/datatable_logic.blade.php @@ -305,10 +305,23 @@ functionsToRunOnDataTablesDrawEvent: [], "colvis": "{{ trans('backpack::crud.export.column_visibility') }}" }, }, - dom: - "<'row hidden'<'col-sm-6'i><'col-sm-6 d-print-none'f>>" + - "<'table-content row'<'col-sm-12'tr>>" + - "<'table-footer row mt-2 d-print-none align-items-center '<'col-sm-12 col-md-4'l><'col-sm-0 col-md-4 text-center'B><'col-sm-12 col-md-4 'p>>", + layout: { + topStart: null, + topEnd: null, + bottomEnd: null, + bottomStart: null, + bottom: [ + 'pageLength', + { + buttons: config.exportButtons ? window.crud.exportButtonsConfig : [] + }, + { + paging: { + firstLast: false, + } + } + ] + }, buttons: [] }; @@ -406,7 +419,7 @@ functionsToRunOnDataTablesDrawEvent: [], // Configure export buttons if present if (config.exportButtons) { - dataTableConfig.buttons = window.crud.exportButtonsConfig; + dataTableConfig.layout.bottom.buttons = window.crud.exportButtonsConfig; } @@ -429,6 +442,33 @@ functionsToRunOnDataTablesDrawEvent: [], }; } + // Add initComplete callback to fix processing indicator positioning + dataTableConfig.initComplete = function(settings, json) { + // Move processing indicator into table wrapper if it exists outside + const tableWrapper = document.querySelector('#' + tableId + '_wrapper'); + const processingIndicator = document.querySelector('.dataTables_processing, .dt-processing'); + + if (tableWrapper && processingIndicator && !tableWrapper.contains(processingIndicator)) { + // Move the processing indicator into the wrapper + tableWrapper.appendChild(processingIndicator); + + // Ensure proper positioning + processingIndicator.style.position = 'absolute'; + processingIndicator.style.top = '0'; + processingIndicator.style.left = '0'; + processingIndicator.style.right = '0'; + processingIndicator.style.bottom = '0'; + processingIndicator.style.width = 'auto'; + processingIndicator.style.height = 'auto'; + processingIndicator.style.zIndex = '1000'; + } + + // Call any existing initComplete function + if (typeof window.crud.initCompleteCallback === 'function') { + window.crud.initCompleteCallback.call(this, settings, json); + } + }; + // Store the dataTableConfig in the config object for future reference config.dataTableConfig = dataTableConfig; @@ -526,8 +566,6 @@ function setupTableUI(tableId, config) { } }); window.dispatchEvent(event); - // move the bottom buttons before pagination - $(`#bottom_buttons_${tableId}`).insertBefore($(`#${tableId}_wrapper .row:last-child`)); } // Function to set up table event handlers @@ -629,6 +667,55 @@ function setupTableEvents(tableId, config) { } }).dataTable(); + $(`#${tableId}`).on('processing.dt', function(e, settings, processing) { + if (processing) { + setTimeout(function() { + const tableWrapper = document.querySelector('#' + tableId + '_wrapper'); + const processingIndicator = document.querySelector('.dataTables_processing, .dt-processing'); + + if (tableWrapper && processingIndicator) { + if (!tableWrapper.contains(processingIndicator)) { + tableWrapper.appendChild(processingIndicator); + } + + processingIndicator.style.cssText = ` + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 60px !important; + width: 100% !important; + height: calc(100% - 60px) !important; + z-index: 1000 !important; + transform: none !important; + margin: 0 !important; + padding: 0 !important; + display: flex !important; + justify-content: center !important; + align-items: center !important; + background: rgba(255, 255, 255, 0.8) !important; + font-size: 0 !important; + color: transparent !important; + text-indent: -9999px !important; + overflow: hidden !important; + `; + + tableWrapper.style.position = 'relative'; + + const allChildren = processingIndicator.querySelectorAll('*:not(img)'); + allChildren.forEach(child => { + child.style.cssText = 'display: none !important; visibility: hidden !important; opacity: 0 !important;'; + }); + + const images = processingIndicator.querySelectorAll('img'); + images.forEach(img => { + img.style.cssText = 'display: block !important; visibility: visible !important; opacity: 1 !important; width: 40px !important; height: 40px !important; margin: 0 auto !important;'; + }); + } + }, 10); + } + }); + // when datatables-colvis (column visibility) is toggled $(`#${tableId}`).on('column-visibility.dt', function(event) { if (table.responsive) { diff --git a/src/resources/views/crud/inc/export_buttons.blade.php b/src/resources/views/crud/inc/export_buttons.blade.php index 3a44c8d770..f074b76193 100644 --- a/src/resources/views/crud/inc/export_buttons.blade.php +++ b/src/resources/views/crud/inc/export_buttons.blade.php @@ -55,6 +55,7 @@ { extend: 'collection', text: ' {{ trans('backpack::crud.export.export') }}', + className: 'buttons-collection dropdown-toggle', dropup: true, buttons: [ { @@ -159,6 +160,7 @@ ,{ extend: 'colvis', text: ' {{ trans('backpack::crud.export.column_visibility') }}', + className: 'buttons-collection dropdown-toggle', columns: function ( idx, data, node ) { return $(node).attr('data-can-be-visible-in-table') == 'true'; }, @@ -173,14 +175,12 @@ var table = window.crud.tables[tableId]; if (!table || !table.buttons) return; - table.buttons().each(function(button) { if (button.node.className.indexOf('buttons-columnVisibility') == -1 && button.node.nodeName=='BUTTON') { - button.node.className = button.node.className + " btn-sm"; + button.node.className = button.node.className.replace('btn-secondary', 'btn-sm'); } }); - - $(`#${tableId}_wrapper .dt-buttons`).appendTo($('.datatable_button_stack')); + $('.dt-buttons').addClass('d-xs-block') .addClass('d-sm-inline-block') .addClass('d-md-inline-block')