Skip to content

Commit

Permalink
Merge pull request #10 from nccgroup/datatables2
Browse files Browse the repository at this point in the history
Datatables 2
  • Loading branch information
neonbunny authored Aug 19, 2024
2 parents d8bc18e + 6227bdd commit 8fd9909
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 86 deletions.
102 changes: 79 additions & 23 deletions event_tracker/static/scripts/bootstrap_input.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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 = $('<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 = '<div class="input-group">' +
'<input ' + (pages === 1 ? 'disabled ' : '') + 'class="form-control rounded-0" type="number" min="1" max="' + pages + '">' +
'<span class="input-group-text rounded-0" id="basic-addon2"> of ' + pages + '</span>' +
'</div>'
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 <li> 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 = $('<li>').addClass(btnClasses.join(' '));
var clicker;

if (buttonType === 'ellipsis') {
clicker = $('<div>', {class: 'input-group'})
.append(createInputElement(settings))
.append(
$('<span>', {class: 'input-group-text rounded-0'})
.text('of ' + $(settings.nTable).DataTable().page.info().pages)[0]
)
.appendTo(li);
} else {
clicker = $('<a>', {
'href': disabled ? null : '#',
'class': 'page-link'
})
.html(content)
.appendTo(li);
}

return {
display: li,
clicker: clicker
};
}
)
})(jQuery);

23 changes: 20 additions & 3 deletions event_tracker/templates/base/external-libs/datatables-basic.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
{# use https://www.srihash.org/ for integrity if not on https://cdnjs.com/ #}
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-1.13.4/b-2.3.6/date-1.4.1/fh-3.3.2/sb-1.4.2/datatables.min.css" integrity="sha512-kEW8Az2EL66Lst08m47S56qupKJRycFZJ+QC0lrM/kNUVfROSXXI4hywUPoyqPWcimn4vxeJGqLmiVh5JRBgIw==" crossorigin="anonymous">
<script src="https://cdn.datatables.net/v/bs5/dt-1.13.4/b-2.3.6/date-1.4.1/fh-3.3.2/sb-1.4.2/datatables.min.js" integrity="sha512-RkrDRwehVbBYvstGSalr8yPKbcLA2TThjnrtVXEvxWSk7PP3bDoxBcDVtbz3AKea98UzpqhBLnP6+ThdD+mIxw==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-2.1.4/b-3.1.1/date-1.5.3/fh-4.0.1/sb-1.8.0/datatables.min.css" integrity="sha384-NkgQmT2leS1PF3E0GY/HMojHV3Mv96eC9tatSiT7VgqyJjdS9eYkHqf5rVcS2flU" crossorigin="anonymous">
<script src="https://cdn.datatables.net/v/bs5/dt-2.1.4/b-3.1.1/date-1.5.3/fh-4.0.1/sb-1.8.0/datatables.min.js" integrity="sha384-R+CZHUf1UzZxEsbywkUnsMtBgx0SoiGKM8wOACZq3sCrK2Tg+2WzcpCGZp7pZy7u" crossorigin="anonymous"></script>

{% include "base/external-libs/momentjs.html" %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables-plugins/1.13.4/sorting/datetime-moment.min.js" integrity="sha512-cln13IRvnKJQmByR8cXOb9NMF0BzbIQbQb29vbX6mQYKsO1uyRYlGB2jWtGRgXaCq3JWqLqDZNOJ9kHzYH+dkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables-plugins/2.0.8/sorting/datetime-moment.min.js" integrity="sha512-cln13IRvnKJQmByR8cXOb9NMF0BzbIQbQb29vbX6mQYKsO1uyRYlGB2jWtGRgXaCq3JWqLqDZNOJ9kHzYH+dkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<script nonce="{{request.csp_nonce}}">
DataTable.datetime("{% datetime_format_moment %}")
DataTable.defaults.column.orderSequence = ['asc', 'desc']; // Remove neutral column sorting as an option - it breaks the server side query string parsing and feels clunky
DataTable.defaults.layout = {
topStart: null,
topEnd: {
features: ['search', 'buttons']
},
bottom: {
rowClass: 'mt-2',
features: ['info', 'pageLength', 'paging']
},
bottomStart: null,
bottomEnd: null
}
</script>
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
{# use https://www.srihash.org/ for integrity if not on https://cdnjs.com/ #}
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-1.13.4/b-2.3.6/b-html5-2.3.6/date-1.4.1/fh-3.3.2/sb-1.4.2/datatables.min.css" integrity="sha512-TAISwwR6lNl66WfQHcyCx62vIoRYqzaOZ1L0Mr97C3sUOYgYHeHL2kFdZd4UsJ69o73JW7e4FHaMdO0Js6ykHQ==" crossorigin="anonymous">
<script src="https://cdn.datatables.net/v/bs5/dt-1.13.4/b-2.3.6/b-html5-2.3.6/date-1.4.1/fh-3.3.2/sb-1.4.2/datatables.min.js" integrity="sha512-5anoVukc27KB1IlOytOHd0MawHJN4EC+XUWwEP1ub9Qy2u3+KW/2yCE42mP3fGDwvJWDs5Ur8y7+P+u11+/gqQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/v/bs5/dt-2.1.4/b-3.1.1/b-html5-3.1.1/date-1.5.3/fh-4.0.1/sb-1.8.0/datatables.min.css" integrity="sha384-byq5ukAC/9bM4DYloC9DXyDbEDwy0qD1FOQcLWNOMYHoBiW+ZgUOMkKQ0Trgffko" crossorigin="anonymous">
<script src="https://cdn.datatables.net/v/bs5/dt-2.1.4/b-3.1.1/b-html5-3.1.1/date-1.5.3/fh-4.0.1/sb-1.8.0/datatables.min.js" integrity="sha384-PY3/gZOyFRGQ4i6UqwA4QGhCYOsN83rNljQd62TwzlxUnCRyRdAmf9SF8lak6bGQ" crossorigin="anonymous"></script>

{% include "base/external-libs/momentjs.html" %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables-plugins/1.13.4/sorting/datetime-moment.min.js" integrity="sha512-cln13IRvnKJQmByR8cXOb9NMF0BzbIQbQb29vbX6mQYKsO1uyRYlGB2jWtGRgXaCq3JWqLqDZNOJ9kHzYH+dkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables-plugins/2.0.8/sorting/datetime-moment.min.js" integrity="sha512-cln13IRvnKJQmByR8cXOb9NMF0BzbIQbQb29vbX6mQYKsO1uyRYlGB2jWtGRgXaCq3JWqLqDZNOJ9kHzYH+dkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<script nonce="{{request.csp_nonce}}">
DataTable.datetime("{% datetime_format_moment %}")
DataTable.defaults.column.orderSequence = ['asc', 'desc']; // Remove neutral column sorting as an option - it breaks the server side query string parsing and feels clunky
DataTable.defaults.layout = {
topStart: null,
topEnd: {
features: ['search', 'buttons']
},
bottom: {
rowClass: 'mt-2',
features: ['info', 'pageLength', 'paging']
},
bottomStart: null,
bottomEnd: null
}
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js" integrity="sha512-a9NgEEK7tsCvABL7KqtUTQjl69z7091EVPpw5KxPlZ93T141ffe1woLtbXTX+r2/8TtTvRX/v4zTL2UlMUPgwg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.min.js" integrity="sha512-P0bOMePRS378NwmPDVPU455C/TuxDS+8QwJozdc7PGgN8kLqR4ems0U/3DeJkmiE31749vYWHvBOtR+37qDCZQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
19 changes: 11 additions & 8 deletions event_tracker/templates/cobalt_strike_monitor/archive_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
</style>
{% endblock head %}

Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 16 additions & 3 deletions event_tracker/templates/event_tracker/credential_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,28 @@
{% block head %}
{% include "base/external-libs/jquery.html" %}
{% include "base/external-libs/datatables-basic.html" %}

<script src="{% static "/scripts/bootstrap_input.js" %}"></script>

<style nonce="{{request.csp_nonce}}">
.copyToClipboard { text-decoration: none; cursor: copy; color: var(--bs-body-color) }
.copyToClipboard i { opacity: 25%; color: var(--bs-secondary-color) }
.copyToClipboard:hover { text-decoration: none; cursor: copy}
.copyToClipboard:hover i { opacity: 100% !important }
.fa-check { color: var(--bs-success) }
.fa-xmark { color: var(--bs-danger) }
div:has(> .dt-search) { padding-right: 0}
div:has(+.dt-layout-table) {
padding-top: 0.5em;
padding-bottom: 1em;
}
</style>
{% endblock head %}

{% block body %}
{% block bootstrap5_content %}
<div class="container-fluid">
<div class="py-4 row">
<div class="col-md-12">
<div id="page-controls">
{% if perms.event_tracker.add_credential %}
<div class="btn-group" role="group" aria-label="Creation">
<a href="{% url 'event_tracker:credential-add' 1 %}" class="btn btn-success"><i class="fa-solid fa-book-medical"></i> Add Credential</a>
Expand Down Expand Up @@ -104,7 +111,7 @@
<a href="{% url 'event_tracker:credential-stats' 1 %}" class="btn btn-outline-secondary"><i class="fa-solid fa-calculator"></i> Stats</a>
{% endif %}
</div>
</div>

<div class="row">
<div class="col-md-12">
{% if object_list %}
Expand Down Expand Up @@ -179,11 +186,17 @@ <h5 class="modal-title">Are you sure?</h5>
$('[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()
Expand Down
Loading

0 comments on commit 8fd9909

Please sign in to comment.