Fix timestamps not sorting in datatables

Timestamps retrieved from the API were always converted to a browser
local format. The format specified for moment.js added in
5160eff294 did not work because of this.

Additionally, the format specified used `dd` which looks for two letter
days, such as "Mo", "Tu", "We", etc. Furthermore, `mm` is used for
minutes, not months.

Because the locale formatted datetime can vary a lot, it is not easy to
get this into moment.js to enable the sorting of datetimes in the
datatables. In other words, there is no conversion from an
`Intl.DateTimeFormat` specifier string to moment.js. Adding many
`$.fn.dataTable.moment(format);` with different `format`s is not useful.

I have fixed this rewriting how the timestamps from the API are added
to the tables. It still uses the locale of the browser, because not
everyone wants to use ISO 8601, but no longer requires moment.js (which
has been removed).

Two data attributes are added to the `td`s of the timestamps:
- `data-order`
- `data-sort`

The values of these are the timestamps as returned by the server, which
are very easily sorted (as they are just UNIX timestamps). Then, when
creating the cell in the table, it will be converted to what the locale
of the browser specified (this has not changed).
This commit is contained in:
Tom Udding 2022-12-24 17:33:49 +01:00
parent 55d57c552d
commit 240b2c63f6
No known key found for this signature in database
GPG Key ID: F1377C292CA6E5CD
13 changed files with 1883 additions and 1964 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,70 +0,0 @@
/**
* This plug-in for DataTables represents the ultimate option in extensibility
* for sorting date / time strings correctly. It uses
* [Moment.js](http://momentjs.com) to create automatic type detection and
* sorting plug-ins for DataTables based on a given format. This way, DataTables
* will automatically detect your temporal information and sort it correctly.
*
* For usage instructions, please see the DataTables blog
* post that [introduces it](//datatables.net/blog/2014-12-18).
*
* @name Ultimate Date / Time sorting
* @summary Sort date and time in any format using Moment.js
* @author [Allan Jardine](//datatables.net)
* @depends DataTables 1.10+, Moment.js 1.7+
*
* @example
* $.fn.dataTable.moment( 'HH:mm MMM D, YY' );
* $.fn.dataTable.moment( 'dddd, MMMM Do, YYYY' );
*
* $('#example').DataTable();
*/
(function (factory) {
if (typeof define === "function" && define.amd) {
define(["jquery", "moment", "datatables.net"], factory);
} else {
factory(jQuery, moment);
}
}(function ($, moment) {
function strip (d) {
if ( typeof d === 'string' ) {
// Strip HTML tags and newline characters if possible
d = d.replace(/(<.*?>)|(\r?\n|\r)/g, '');
// Strip out surrounding white space
d = d.trim();
}
return d;
}
$.fn.dataTable.moment = function ( format, locale, reverseEmpties ) {
var types = $.fn.dataTable.ext.type;
// Add type detection
types.detect.unshift( function ( d ) {
d = strip(d);
// Null and empty values are acceptable
if ( d === '' || d === null ) {
return 'moment-'+format;
}
return moment( d, format, locale, true ).isValid() ?
'moment-'+format :
null;
} );
// Add sorting method - use an integer for the sorting
types.order[ 'moment-'+format+'-pre' ] = function ( d ) {
d = strip(d);
return !moment(d, format, locale, true).isValid() ?
(reverseEmpties ? -Infinity : Infinity) :
parseInt( moment( d, format, locale, true ).format( 'x' ), 10 );
};
};
}));

View File

@ -274,11 +274,10 @@ $(document).ready(function() {
}); });
}) })
// Jquery Datatables, enable responsive plugin and date sort plugin // Jquery Datatables, enable responsive plugin
$.extend($.fn.dataTable.defaults, { $.extend($.fn.dataTable.defaults, {
responsive: true responsive: true
}); });
$.fn.dataTable.moment('dd:mm:YYYY');
// tag boxes // tag boxes
$('.tag-box .tag-add').click(function(){ $('.tag-box .tag-add').click(function(){

View File

@ -1,3 +1,13 @@
const LOCALE = undefined;
const DATETIME_FORMAT = {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
};
$(document).ready(function() { $(document).ready(function() {
// Parse seconds ago to date // Parse seconds ago to date
// Get "now" timestamp // Get "now" timestamp
@ -7,14 +17,7 @@ $(document).ready(function() {
if (typeof started_s_ago != 'NaN') { if (typeof started_s_ago != 'NaN') {
var started_date = new Date((ts_now - started_s_ago) * 1000); var started_date = new Date((ts_now - started_s_ago) * 1000);
if (started_date instanceof Date && !isNaN(started_date)) { if (started_date instanceof Date && !isNaN(started_date)) {
var started_local_date = started_date.toLocaleDateString(undefined, { var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
$(this).text(started_local_date); $(this).text(started_local_date);
} else { } else {
$(this).text('-'); $(this).text('-');
@ -25,14 +28,7 @@ $(document).ready(function() {
$('.parse_date').each(function(i, parse_date) { $('.parse_date').each(function(i, parse_date) {
var started_date = new Date(Date.parse($(this).text())); var started_date = new Date(Date.parse($(this).text()));
if (typeof started_date != 'NaN') { if (typeof started_date != 'NaN') {
var started_local_date = started_date.toLocaleDateString(undefined, { var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
$(this).text(started_local_date); $(this).text(started_local_date);
} }
}); });
@ -75,6 +71,13 @@ jQuery(function($){
var table_name = $(this).data('table'); var table_name = $(this).data('table');
$('#' + table_name).DataTable().ajax.reload(); $('#' + table_name).DataTable().ajax.reload();
}); });
function createSortableDate(td, cellData) {
$(td).attr({
"data-order": cellData,
"data-sort": cellData
});
$(td).html(convertTimestampToLocalFormat(cellData));
}
function draw_autodiscover_logs() { function draw_autodiscover_logs() {
// just recalc width if instance already exists // just recalc width if instance already exists
if ($.fn.DataTable.isDataTable('#autodiscover_log') ) { if ($.fn.DataTable.isDataTable('#autodiscover_log') ) {
@ -100,9 +103,8 @@ jQuery(function($){
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
responsivePriority: 1, responsivePriority: 1,
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -157,9 +159,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -200,9 +201,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -247,9 +247,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -306,9 +305,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -393,9 +391,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -481,9 +478,9 @@ jQuery(function($){
title: lang.login_time, title: lang.login_time,
data: 'datetime', data: 'datetime',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data.replace(/-/g, "/")); cellData = Math.floor((new Date(data.replace(/-/g, "/"))).getTime() / 1000);
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); createSortableDate(td, cellData)
} }
} }
] ]
@ -513,9 +510,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -551,9 +547,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -594,9 +589,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -637,9 +631,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -740,9 +733,8 @@ jQuery(function($){
title: lang.time, title: lang.time,
data: 'time', data: 'time',
defaultContent: '', defaultContent: '',
render: function(data, type){ createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); createSortableDate(td, cellData)
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
} }
}, },
{ {
@ -1531,3 +1523,8 @@ function parseGithubMarkdownLinks(inputText) {
return replacedText; return replacedText;
} }
function convertTimestampToLocalFormat(timestamp) {
var date = new Date(timestamp ? timestamp * 1000 : 0);
return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
}