diff --git a/event_tracker/static/scripts/bootstrap_input.js b/event_tracker/static/scripts/bootstrap_input.js index 4ca21cd..01a103d 100644 --- a/event_tracker/static/scripts/bootstrap_input.js +++ b/event_tracker/static/scripts/bootstrap_input.js @@ -1,6 +1,8 @@ /** * Plug-in offers the same functionality as `default` pagination type - * (see `pagingType` option) but with input field for jumping pages, for use with bootstrap theme. + * (see `pagingType` option) but with an input field for jumping pages, for use with bootstrap theme. + * A combination of Dist-DataTables-Bootstrap5/js/dataTables.bootstrap5.js and + * Plugins/pagination/input.js * * @example * $(document).ready(function() { @@ -10,35 +12,89 @@ * } ); */ -$.fn.DataTable.ext.pager.bootstrap_input = function (page, pages) { - return ['first', 'previous', 'input', 'next', 'last']; -}; +(function ($) { + /** + * Add bootstrap themed input field (based on input.js) with addition UX tweaks of disabling for single + * page tables and reacting to the enter key on text input. + */ + function createInputElement(settings) { + const pageInfo = $(settings.nTable).DataTable().page.info(); + const $input = $('', { + class: 'form-control rounded-0 text-end', + type: 'number', + min: 1, + max: pageInfo.pages, + }).val(pageInfo.page + 1); + if (pageInfo.pages === 1) { + $input.prop("disabled", true) + } -main_pageButtonFunc = $.fn.DataTable.ext.renderer.pageButton.bootstrap + var changeHandler = function (e) { + if (e.target.value === '' || e.target.value.match(/[^0-9]/)) { + /* Nothing entered or non-numeric character */ + e.target.value = e.target.value.replace(/[^\d]/g, ''); // don't even allow anything but digits + return; + } -$.fn.DataTable.ext.renderer.pageButton = $.extend(true, $.fn.DataTable.ext.renderer.pageButton, - { - bootstrap: function (settings, host, idx, buttons, page, pages) { - main_pageButtonFunc(settings, host, idx, buttons, page, pages); + const page = Number(e.target.value - 1); + $(settings.nTable).DataTable().page(page).draw(false); + }; - pages = Math.max(pages, 1); + $input.on("change", changeHandler) + $input.on('keyup', function (e) { + if (e.key === 'Enter' || e.keyCode === 13) { + changeHandler(e); + } + }); - let input_html = '
' + - '' + - ' of ' + pages + '' + - '
' + return $input; + } - let input_section = $(host).find("[data-dt-idx='input']"); - input_section.closest("li").prop("onclick", null).off("click"); - input_section.closest("li").prop("onkeypress", null).off("keypress"); - input_section.replaceWith(input_html); + // Use "ellipsis" as a placeholder for where we want the input fields placing + $.fn.DataTable.ext.pager.bootstrap_input = function() { + return ['first', 'previous', 'ellipsis', 'next', 'last']; + }; - const api = new DataTable.Api(settings); + /** + * Render the pagination buttons as a series of
  • tags (as per dataTables.bootstrap5.js) but deviate when + * we are asked to render the ellipsis. + */ + $.fn.DataTable.ext.renderer.pagingButton.bootstrap = function (settings, buttonType, content, active, disabled) { + var btnClasses = ['dt-paging-button', 'page-item']; - $(host).find("ul.pagination input").val(page + 1).on('change', function (e) { - api.page(Number($(e.target).val()) - 1).draw('page'); - }); + if (active) { + btnClasses.push('active'); } + + if (disabled) { + btnClasses.push('disabled'); + } + + var li = $('
  • ').addClass(btnClasses.join(' ')); + var clicker; + + if (buttonType === 'ellipsis') { + clicker = $('
    ', {class: 'input-group'}) + .append(createInputElement(settings)) + .append( + $('', {class: 'input-group-text rounded-0'}) + .text('of ' + $(settings.nTable).DataTable().page.info().pages)[0] + ) + .appendTo(li); + } else { + clicker = $('', { + 'href': disabled ? null : '#', + 'class': 'page-link' + }) + .html(content) + .appendTo(li); + } + + return { + display: li, + clicker: clicker + }; } -) +})(jQuery); + diff --git a/event_tracker/templates/base/external-libs/datatables-basic.html b/event_tracker/templates/base/external-libs/datatables-basic.html index 91ba243..a9ffac6 100644 --- a/event_tracker/templates/base/external-libs/datatables-basic.html +++ b/event_tracker/templates/base/external-libs/datatables-basic.html @@ -1,6 +1,23 @@ {# use https://www.srihash.org/ for integrity if not on https://cdnjs.com/ #} - - + + {% include "base/external-libs/momentjs.html" %} - \ No newline at end of file + + + \ No newline at end of file diff --git a/event_tracker/templates/base/external-libs/datatables-pdfexport.html b/event_tracker/templates/base/external-libs/datatables-pdfexport.html index d888323..6f84bf5 100644 --- a/event_tracker/templates/base/external-libs/datatables-pdfexport.html +++ b/event_tracker/templates/base/external-libs/datatables-pdfexport.html @@ -1,9 +1,26 @@ {# use https://www.srihash.org/ for integrity if not on https://cdnjs.com/ #} - - + + {% include "base/external-libs/momentjs.html" %} - + + + \ No newline at end of file diff --git a/event_tracker/templates/cobalt_strike_monitor/archive_list.html b/event_tracker/templates/cobalt_strike_monitor/archive_list.html index 5fa021f..e66596c 100644 --- a/event_tracker/templates/cobalt_strike_monitor/archive_list.html +++ b/event_tracker/templates/cobalt_strike_monitor/archive_list.html @@ -33,6 +33,11 @@ div.dataTables_wrapper div.dataTables_info { padding-top: 0; } + + div:has(+.dt-layout-table) { + padding-top: 0.5em; + padding-bottom: 1em; + } {% endblock head %} @@ -98,16 +103,17 @@ }, { text: 'Export PDF', - action: function (e, dt, node, config) { + action: function (e, dt, node, config, cb) { let outer_dt = dt; let outer_config = config; let orig_len = dt.page.len(); + let outer_cb = cb; - doExport = function (e, _dt, node, _config) { + doExport = function (e, _dt, node, _config, cb) { // Deregister the event handler dt.off('draw', doExport); // Trigger the print action - $.fn.dataTable.ext.buttons.pdfHtml5.action.call(outer_dt.button(), e, outer_dt, node, outer_config); + $.fn.dataTable.ext.buttons.pdfHtml5.action.call(outer_dt.button(), e, outer_dt, node, outer_config, outer_cb); // Redraw the table at the original page size dt.page.len(orig_len).draw(); } @@ -146,17 +152,14 @@ stripNewlines: false } }, - ], - dom: "<'row'<'col-sm-12 col-md-12'Bf>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-12 col-md-4 d-flex justify-content-start align-items-center'i><'col-sm-12 col-md-4 d-flex justify-content-center align-items-center'l><'col-sm-12 col-md-4 d-flex justify-content-end align-items-center'p>>", + ], fixedHeader: { header: true, headerOffset: $('.navbar').outerHeight() }, order: [[0, 'desc']], columns: [ - null, + { searchBuilderType: "moment-{% datetime_format_moment %}" }, { orderable: false }, { orderable: false }, null, diff --git a/event_tracker/templates/event_tracker/credential_list.html b/event_tracker/templates/event_tracker/credential_list.html index 019b857..c1c5004 100644 --- a/event_tracker/templates/event_tracker/credential_list.html +++ b/event_tracker/templates/event_tracker/credential_list.html @@ -13,6 +13,9 @@ {% block head %} {% include "base/external-libs/jquery.html" %} {% include "base/external-libs/datatables-basic.html" %} + + + {% endblock head %} {% block body %} {% block bootstrap5_content %}
    -
    -
    + +
    {% if object_list %} @@ -179,11 +186,17 @@ $('[data-toggle="tooltip"]').tooltip(); $.fn.dataTable.moment('{% datetime_format_moment %}'); $('.table').DataTable({ + pagingType: "bootstrap_input", searching: true, paging: true, processing: true, serverSide: true, ajax: "{% url 'event_tracker:credential-list-json' 1 %}", + layout: { + topStart: { + features: [$("#page-controls").detach()] + }, + }, fixedHeader: { header: true, headerOffset: $('.navbar').outerHeight() diff --git a/event_tracker/templates/event_tracker/event_list.html b/event_tracker/templates/event_tracker/event_list.html index c54679d..9a9be0c 100644 --- a/event_tracker/templates/event_tracker/event_list.html +++ b/event_tracker/templates/event_tracker/event_list.html @@ -19,11 +19,7 @@ {% endblock head %} @@ -79,8 +74,7 @@ {% block bootstrap5_content %}
    -
    -
    +
    {% if perms.event_tracker.add_event %} Add event {% endif %} @@ -122,13 +116,9 @@
    {% endif %}
    -
    -
    -
    - {{ dateformat }} - +
    @@ -353,6 +343,11 @@ } } }, + layout: { + topStart: { + features: [$("#page-controls").detach()] + }, + }, fixedHeader: { header: true, headerOffset: $('.navbar').outerHeight() @@ -360,7 +355,7 @@ order: [[1, 'desc']], columns: [ {orderable: false}, - null, + { searchBuilderType: "moment-{% datetime_format_moment %}" }, null, null, {orderable: false}, @@ -375,16 +370,17 @@ buttons: [ { text: 'Export PDF', - action: function (e, dt, node, config) { + action: function (e, dt, node, config, cb) { let outer_dt = dt; let outer_config = config; let orig_len = dt.page.len(); + let outer_cb = cb; - doExport = function (e, _dt, node, _config) { + doExport = function (e, _dt, node, _config, cb) { // Deregister the event handler dt.off('draw', doExport); // Trigger the print action - $.fn.dataTable.ext.buttons.pdfHtml5.action.call(outer_dt.button(), e, outer_dt, node, outer_config); + $.fn.dataTable.ext.buttons.pdfHtml5.action.call(outer_dt.button(), e, outer_dt, node, outer_config, outer_cb); // Redraw the table at the original page size dt.page.len(orig_len).draw(); } @@ -428,10 +424,6 @@ } ] }) - $(".dataTables_filter").detach().appendTo('#table-filter'); - - var table = $('table').DataTable(); - table.button('.dt-searchBuilder').container().appendTo( '#table-filter' ); $('#pdf-export').on('click', function() {$('.table').DataTable().buttons('.buttons-pdf').trigger()}) }); diff --git a/event_tracker/templates/event_tracker/eventstream_list.html b/event_tracker/templates/event_tracker/eventstream_list.html index 6c00a35..6f967b9 100644 --- a/event_tracker/templates/event_tracker/eventstream_list.html +++ b/event_tracker/templates/event_tracker/eventstream_list.html @@ -42,16 +42,21 @@ .table-striped-columns th::after { content: ':'; } + + div:has(+.dt-layout-table) { + padding-top: 0.5em; + padding-bottom: 1em; + } {% endblock head %} {% block body %} {% block bootstrap5_content %}
    -
    +
    {% if perms.event_tracker.add_eventstream %} -
    +
    Upload EventStream