/** * map info dialog */ define([ 'jquery', 'app/init', 'app/util', 'app/render', 'app/counter', 'bootbox', 'app/map/util' ], ($, Init, Util, Render, Counter, bootbox, MapUtil) => { 'use strict'; let config = { // global dialog dialogNavigationClass: 'pf-dialog-navigation-list', // class for dialog navigation bar // map info dialog/tabs dialogMapInfoSummaryId: 'pf-map-info-dialog-summary', // id for map "summary" container dialogMapInfoUsersId: 'pf-map-info-dialog-users', // id for map "user" container dialogMapInfoLogsId: 'pf-map-info-dialog-logs', // id for map "logs" container dialogMapInfoRefreshId: 'pf-map-info-dialog-refresh', // id for map "refresh" container // dialog containers mapInfoId: 'pf-map-info', // id for map info mapInfoSystemsId: 'pf-map-info-systems', // id for map info systems box mapInfoConnectionsId: 'pf-map-info-connections', // id for map info connections box mapInfoUsersId: 'pf-map-info-users', // id for map info users box mapInfoLogsId: 'pf-map-info-logs', // id for map info logs box mapInfoLifetimeCounterClass: 'pf-map-info-lifetime-counter', // class for map lifetime counter systemInfoPlanetsClass: 'pf-system-info-planets', // class for "planets" information element // dataTable tableId: 'pf-info-table-', // Table id prefix tableToolsClass: 'pf-table-tools', // class for table "tools" section (e.g. Buttons) tableCellImageClass: 'pf-table-image-cell', // class for table "image" cells tableCellImageSmallClass: 'pf-table-image-small-cell', // class for table "small image" cells tableCellActionClass: 'pf-table-action-cell', // class for table "action" cells tableCellLinkClass: 'pf-table-link-cell', // class for table "links" cells tableCellCounterClass: 'pf-table-counter-cell', // class for table "counter" cells tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells tableCellActionIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content) tableCellUnknownDataClass: 'pf-table-unknown-cell', // class for table "unknown" cells textActionIconClass: 'pf-module-icon-button', // class for text action textActionIconCopyClass: 'pf-module-icon-button-copy', // class for text action "copy" loadingOptions: { // config for loading overlay icon: { size: 'fa-2x' } } }; /** * get icon that marks a table cell as clickable * @returns {string} */ let getIconForInformationWindow = () => { return ''; }; /** * get icon for socked status * @param type * @returns {string} */ let getIconForDockedStatus = (type) => { let icon = type === 'station' ? 'fa-home' : type === 'structure' ? 'fa-industry' : ''; return icon.length ? '' : ''; }; /** * get label for "unknown" label * @returns {string} */ let getLabelForUnknownData = () => { return 'unknown'; }; /** * loads the map info data into an element * @param mapData */ $.fn.initMapInfoData = function(mapData){ let mapElement = $(this).empty(); mapElement.showLoadingAnimation(config.loadingOptions); // get some more config values from this map. Which are not part of "mapData" let mapDataOrigin = Util.getCurrentMapData(mapData.config.id); let countSystems = mapData.data.systems.length; let countConnections = mapData.data.connections.length; // map type let mapTypes = MapUtil.getMapTypes(); let mapType = mapTypes.find(data => data.id === mapData.config.type.id); // check max map limits (e.g. max systems per map) ------------------------------------------------------------ let percentageSystems = (100 / mapType.defaultConfig.max_systems) * countSystems; let maxSystemsClass = (percentageSystems < 90) ? 'txt-color-success' : (percentageSystems < 100) ? 'txt-color-warning' : 'txt-color-danger'; // build content ---------------------------------------------------------------------------------------------- let dlElementLeft = $('
', { class: 'dl-horizontal', css: {'float': 'left'} }).append( $('
').text('Icon') ).append( $('
').append( $('', { class: ['fas', 'fa-fw', mapData.config.icon].join(' ') }) ) ).append( $('
').text('Name') ).append( $('
').text(mapData.config.name) ).append( $('
').text('Type') ).append( $('
', { class: mapType.class }).text(mapType.name) ).append( $('
').text('Link') ).append( $('
', { class: [config.textActionIconClass, config.textActionIconCopyClass].join(' ') }).append( $('', { title: 'copy to clipboard', }).text(MapUtil.getMapDeeplinkUrl(mapData.config.id) + ' ') ).append( $('', { class: ['fas', 'fa-fw', 'fa-copy'].join(' ') }) ) ); mapElement.append(dlElementLeft); let dlElementRight = $('
', { class: 'dl-horizontal', css: {'float': 'right'} }).append( $('
').text('Systems') ).append( $('
', { class: ['txt-color', maxSystemsClass].join(' ') }).text(countSystems + ' / ' + mapType.defaultConfig.max_systems) ).append( $('
').text('Connections') ).append( $('
').text(countConnections) ).append( $('
').text('Lifetime') ).append( $('
', { class: config.mapInfoLifetimeCounterClass, text: mapData.config.created }) ).append( $('
').text('Created') ).append( $('
').text(Util.getObjVal(mapDataOrigin, 'config.created.character.name')) ); mapElement.append(dlElementRight); // init map lifetime counter Counter.initTimestampCounter($('.' + config.mapInfoLifetimeCounterClass)); mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){ let mapUrl = $(this).find('span').text().trim(); Util.copyToClipboard(mapUrl).then(payload => { if(payload.data){ Util.showNotify({title: 'Copied to clipboard', text: mapUrl, type: 'success'}); } }); }); mapElement.hideLoadingAnimation(); mapElement.initTooltips({container: '.modal'}); }; /** * loads system info table into an element * @param mapData */ $.fn.initSystemInfoTable = function(mapData){ let tableApi = Util.getDataTableInstance(config.tableId, mapData.config.id, '', 'systems'); if(tableApi){ tableApi.clear(); tableApi.rows.add(mapData.data.systems); tableApi.draw(); }else{ let systemsElement = $(this); let systemTable = $('', { id: Util.getTableId(config.tableId, 'systems', mapData.config.id), class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ') }); systemsElement.append(systemTable); systemsElement.showLoadingAnimation(config.loadingOptions); let systemsDataTable = systemTable.DataTable({ pageLength: 20, paging: true, lengthMenu: [[5, 10, 20, 50, -1], [5, 10, 20, 50, 'All']], ordering: true, order: [15, 'desc'], hover: false, data: mapData.data.systems, columnDefs: [], language: { emptyTable: 'Map is empty', zeroRecords: 'No systems found', lengthMenu: 'Show _MENU_ systems', info: 'Showing _START_ to _END_ of _TOTAL_ systems' }, columns: [ { name: 'type', title: 'type', width: 25, className: ['min-screen-l'].join(' '), data: 'type', render: { _: (cellData, type, rowData, meta) => { return MapUtil.getSystemTypeInfo(cellData.id, 'name'); } } },{ name: 'security', title: '', width: 1, data: 'security', render: { display: (cellData, type, rowData, meta) => { let securityClass = Util.getSecurityClassForSystem(cellData); return '' + cellData + ''; } } },{ name: 'trueSec', title: 'sec', width: 18, className: ['text-center', 'min-screen-l'].join(' '), searchable: false, data: 'trueSec', render: { display: (cellData, type, rowData, meta) => { let systemTrueSecClass = Util.getTrueSecClassForSystem(cellData); return '' + cellData.toFixed(1) + ''; } } },{ name: 'shattered', title: '', width: 10, className: ['text-center', 'min-screen-l'].join(' '), searchable: false, data: 'shattered', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData){ value = ''; } return value; } } },{ name: 'name', title: 'system', data: 'name', className: [config.tableCellLinkClass].join(' '), createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // select system $(cell).on('click', function(e){ Util.triggerMenuAction(Util.getMapModule().getActiveMap(), 'SelectSystem', {systemId: rowData.id}); }); } },{ name: 'alias', title: 'alias', data: 'alias', render: { _: (cellData, type, rowData, meta) => { return (cellData === rowData.name) ? '' : cellData; } } },{ name: 'region', title: 'region', data: 'region.name', className: 'min-screen-l', },{ name: 'sovereignty', title: 'sov.', width: 30, className: 'text-center', data: 'sovereignty.alliance.ticker', defaultContent: '', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData){ value = '<' + cellData + '>'; } return value; } } },{ name: 'planets', title: '', width: 10, className: ['text-right', config.systemInfoPlanetsClass, Util.config.helpDefaultClass, Util.config.popoverTriggerClass].join(' '), searchable: false, orderSequence: ['desc', 'asc'], data: 'planets', render: { _: (cellData, type, rowData, meta) => { return cellData.length; } } },{ name: 'status', title: '', width: 10, className: 'text-center', searchable: false, data: 'status.id', render: { display: (cellData, type, rowData, meta) => { let value = ''; let systemStatusClass = Util.getStatusInfoForSystem(cellData, 'class'); if(systemStatusClass !== ''){ value = ''; } return value; } } },{ name: 'effect', title: '', width: 10, className: 'text-center', searchable: false, data: 'effect', defaultContent: '', render: { display: (cellData, type, rowData, meta) => { let value = ''; let systemEffectClass = MapUtil.getEffectInfoForSystem(cellData, 'class'); if(systemEffectClass !== ''){ value = ''; } return value; } } },{ name: 'statics', title: 'statics', width: 30, searchable: false, data: 'statics', render: { _: (cellData, type, rowData, meta) => { let statics = []; if(Array.isArray(cellData)) { for (let wormholeName of cellData) { let wormholeData = Object.assign({}, Init.wormholes[wormholeName]); statics.push('' + wormholeData.security + ''); } } return statics.join('  '); } } },{ name: 'position', title: '', width: 8, className: 'text-center', searchable: false, data: 'currentUser', defaultContent: false, render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData === true){ value = ''; } return value; } } },{ name: 'userCount', title: '', width: 12, className: 'text-center', searchable: false, data: 'userCount', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData > 0){ value = cellData; } return value; } } },{ name: 'locked', title: '', width: 10, className: 'text-center', searchable: false, data: 'locked', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData === 1){ value = ''; } return value; } } },{ name: 'updated', title: 'updated', width: 80, searchable: false, className: ['text-right', config.tableCellCounterClass].join(' '), data: 'updated.updated', defaultContent: '', },{ name: 'action', title: '', orderable: false, searchable: false, width: 10, className: ['text-center', config.tableCellActionClass].join(' '), data: null, defaultContent: '', createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ let tempTableElement = this; let confirmationSettings = { placement: 'left', title: '---', template: Util.getConfirmationTemplate(null, { size: 'small', noTitle: true }), onConfirm: function(e, target){ let deleteRowElement = $(target).parents('tr'); let activeMap = Util.getMapModule().getActiveMap(); let systemElement = $('#' + MapUtil.getSystemId(mapData.config.id, rowData.id) ); if(systemElement.length){ // trigger system delete event activeMap.trigger('pf:deleteSystems', [{ systems: [systemElement[0]], callback: function(deletedSystems){ // callback function after ajax "delete" success // check if system was deleted if(deletedSystems.length === 1){ // remove table row tempTableElement.DataTable().rows(deleteRowElement).remove().draw(); Util.showNotify({title: 'System deleted', text: rowData.name, type: 'success'}); // refresh connection table (connections might have changed) -------------- let connectionsElement = $('#' + config.mapInfoConnectionsId); let mapDataNew = activeMap.getMapDataFromClient(['hasId']); connectionsElement.initConnectionInfoTable(mapDataNew); }else{ // error Util.showNotify({title: 'Failed to delete system', text: rowData.name, type: 'error'}); } } }]); } } }; // init confirmation dialog $(cell).confirmation(confirmationSettings); } } ], initComplete: function(settings){ systemsElement.hideLoadingAnimation(); systemsElement.initTooltips({container: '.modal'}); Counter.initTableCounter(this, ['updated:name']); } }); } }; /** * loads connection info table into an element * @param mapData */ $.fn.initConnectionInfoTable = function(mapData){ let tableApi = Util.getDataTableInstance(config.tableId, mapData.config.id, '', 'connections'); if(tableApi){ tableApi.clear(); tableApi.rows.add(mapData.data.connections); tableApi.draw(); }else{ let connectionsElement = $(this); let connectionTable = $('
', { id: Util.getTableId(config.tableId, 'connections', mapData.config.id), class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ') }); connectionsElement.append(connectionTable); connectionsElement.showLoadingAnimation(config.loadingOptions); // connections table ------------------------------------------------------------------------------------------ let connectionDataTable = connectionTable.dataTable({ pageLength: 20, paging: true, lengthMenu: [[5, 10, 20, 50, -1], [5, 10, 20, 50, 'All']], ordering: true, order: [ 6, 'desc' ], autoWidth: false, hover: false, data: mapData.data.connections, columnDefs: [], language: { emptyTable: 'No connections', zeroRecords: 'No connections found', lengthMenu: 'Show _MENU_ connections', info: 'Showing _START_ to _END_ of _TOTAL_ connections' }, columns: [ { name: 'scope', title: 'scope', width: 50, orderable: true, data: 'scope', render: { display: (cellData, type, rowData, meta) => { return MapUtil.getScopeInfoForConnection(cellData, 'label'); } } },{ name: 'sourceName', title: 'source system', data: 'sourceName', className: [config.tableCellLinkClass].join(' '), createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // select system $(cell).on('click', function(e){ Util.triggerMenuAction(Util.getMapModule().getActiveMap(), 'SelectSystem', {systemId: rowData.source}); }); } },{ name: 'sourceBubble', title: '', width: 10, data: 'endpoints.source', className: 'text-right', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData.types.includes('bubble')){ value = ''; } return value; } } },{ name: 'connection', title: 'connection', width: 80, className: 'text-center', orderable: false, searchable: false, data: 'type', render: { display: (cellData, type, rowData, meta) => { let connectionClasses = MapUtil.getConnectionFakeClassesByTypes(cellData); connectionClasses = connectionClasses.join(' '); return '
'; } } },{ name: 'targetBubble', title: '', width: 10, data: 'endpoints.target', className: 'text-left', render: { display: (cellData, type, rowData, meta) => { let value = ''; if(cellData.types.includes('bubble')){ value = ''; } return value; } } },{ name: 'targetName', title: 'target system', data: 'targetName', className: [config.tableCellLinkClass].join(' '), createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // select system $(cell).on('click', function(e){ Util.triggerMenuAction(Util.getMapModule().getActiveMap(), 'SelectSystem', {systemId: rowData.target}); }); } },{ name: 'updated', title: 'updated', width: 80, searchable: false, className: ['text-right', config.tableCellCounterClass].join(' '), data: 'updated', createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ if(rowData.scope.scope_sort === 'wh'){ // highlight cell let diff = new Date().getTime() - cellData * 1000; let dateDiff = new Date(diff); if(dateDiff.getUTCDate() > 1){ $(cell).addClass('txt-color txt-color-warning'); } } } },{ name: 'action', title: '', orderable: false, searchable: false, width: 10, className: ['text-center', config.tableCellActionClass].join(' '), data: null, defaultContent: '', createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ let tempTableElement = this; let confirmationSettings = { placement: 'left', title: '---', template: Util.getConfirmationTemplate(null, { size: 'small', noTitle: true }), onConfirm: function(e, target){ let deleteRowElement = $(target).parents('tr'); let connection = $().getConnectionById(mapData.config.id, rowData.id); MapUtil.deleteConnections([connection], () => { // callback function after ajax "delete" success // remove table row tempTableElement.DataTable().rows(deleteRowElement).remove().draw(); }); } }; // init confirmation dialog $(cell).confirmation(confirmationSettings); } } ], initComplete: function(settings){ connectionsElement.hideLoadingAnimation(); connectionsElement.initTooltips({container: '.modal'}); Counter.initTableCounter(this, ['updated:name']); } }); } }; /** * loads user info table into an element * @param mapData */ $.fn.initUsersInfoTable = function(mapData){ let usersElement = $(this).empty(); let userTable = $('
', { class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ') }); usersElement.append(userTable); usersElement.showLoadingAnimation(config.loadingOptions); // users table ------------------------------------------------------------------------------------------------ // prepare users data for dataTables let currentMapUserData = Util.getCurrentMapUserData( mapData.config.id ); let usersData = []; if( currentMapUserData && currentMapUserData.data && currentMapUserData.data.systems ){ for(let i = 0; i < currentMapUserData.data.systems.length; i++){ let tempSystemUserData = currentMapUserData.data.systems[i]; for(let j = 0; j < tempSystemUserData.user.length; j++){ usersData.push( tempSystemUserData.user[j] ); } } } let userDataTable = userTable.dataTable({ pageLength: 20, paging: true, lengthMenu: [[5, 10, 20, 50, -1], [5, 10, 20, 50, 'All']], ordering: true, order: [[ 3, 'asc' ]], hover: false, data: usersData, language: { emptyTable: 'No active pilots', zeroRecords: 'No active pilots found', lengthMenu: 'Show _MENU_ pilots', info: 'Showing _START_ to _END_ of _TOTAL_ pilots' }, columnDefs: [ { targets: 0, title: '', width: 26, orderable: false, searchable: false, className: [Util.config.helpDefaultClass, 'text-center', config.tableCellImageClass].join(' '), data: 'log.ship', defaultContent: '', render: { _: function(data, type, row, meta){ let value = data; if(data && type === 'display'){ value = ''; } return value; } } },{ targets: 1, title: 'ship name', width: 100, orderable: true, searchable: true, data: 'log.ship', defaultContent: getLabelForUnknownData(), render: { _: function(data, type, row){ let value = data; if(data){ value = data.name; if(type === 'display'){ value = '
' + data.name + '
'; } } return value; } } },{ targets: 2, title: '', width: 26, orderable: false, searchable: false, className: [config.tableCellImageClass].join(' '), data: 'id', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value = ''; } return value; } } },{ targets: 3, title: 'pilot', orderable: true, searchable: true, className: [config.tableCellActionClass].join(' '), data: 'name', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value += ' ' + getIconForInformationWindow(); } return value; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // open character information window (ingame) $(cell).on('click', { tableApi: this.api(), rowIndex: rowIndex }, function(e){ let rowData = e.data.tableApi.row(e.data.rowIndex).data(); Util.openIngameWindow(rowData.id); }); } },{ targets: 4, title: '', width: 26, orderable: false, searchable: false, className: [config.tableCellImageClass, config.tableCellImageSmallClass, 'min-screen-l'].join(' '), data: 'corporation', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value = ''; } return value; } } },{ targets: 5, title: 'corporation', orderable: true, searchable: true, className: [config.tableCellActionClass, 'min-screen-l'].join(' '), data: 'corporation', render: { _: function(data, type, row, meta){ let value = data.name; if(type === 'display'){ value += ' ' + getIconForInformationWindow(); } return value; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // open corporation information window (ingame) $(cell).on('click', { tableApi: this.api() }, function(e){ let cellData = e.data.tableApi.cell(this).data(); Util.openIngameWindow(cellData.id); }); } },{ targets: 6, title: 'system', orderable: true, searchable: true, data: 'log.system', defaultContent: getLabelForUnknownData(), render: { _: function(data, type, row, meta){ let value = data; if(data && type === 'display'){ value = data.name; } return value; } } },{ targets: 7, title: 'docked', orderable: true, searchable: true, className: [config.tableCellActionClass].join(' '), data: 'log', defaultContent: getLabelForUnknownData(), render: { _: function(data, type, row, meta){ let value = data; if(data){ if(data.station && data.station.id > 0){ value = data.station.name + ' ' + getIconForDockedStatus('station'); }else if(data.structure && data.structure.id > 0){ value = data.structure.name + ' ' + getIconForDockedStatus('structure'); }else{ value = ''; } } return value; } } },{ targets: 8, title: 'role', width: 30, orderable: true, searchable: true, className: ['text-right', 'min-screen-l'].join(' '), data: 'role', render: { _: function(data, type, row, meta){ let value = data.label; if(type === 'display'){ value = Util.getLabelByRole(data).prop('outerHTML'); } return value; } } } ], initComplete: function(settings){ usersElement.hideLoadingAnimation(); usersElement.initTooltips({container: '.modal'}); } }); }; /** * set global dialog observer (all tabs/tables) * @param mapInfoDialog * @param mapData */ let setDialogObserver = (mapInfoDialog, mapData) => { // planets popover -------------------------------------------------------------------------------------------- mapInfoDialog.hoverIntent({ over: function(e){ let cellElement = $(this); let tableApi = Util.getDataTableInstance(config.tableId, mapData.config.id, '', 'systems'); let rowData = tableApi.row(cellElement.parents('tr')).data(); cellElement.addSystemPlanetsTooltip(rowData.planets, { trigger: 'manual', placement: 'left', show: true }); }, out: function(e){ $(this).destroyPopover(); }, selector: 'td.' + config.systemInfoPlanetsClass }); }; /** * loads logs table into an element * @param mapData */ $.fn.initLogsInfoTable = function(mapData){ let logsElement = $(this).empty(); /** * ajax load function for log fdata * @param requestData * @param context */ let getLogsData = (requestData, context) => { context.logsElement.showLoadingAnimation(config.loadingOptions); $.ajax({ type: 'POST', url: Init.path.getMapLogData, data: requestData, dataType: 'json', context: context }).done(function(data){ this.callback(data, context); }).fail(function(jqXHR, status, error){ let reason = status + ' ' + error; Util.showNotify({title: jqXHR.status + ': loadLogs', text: reason, type: 'warning'}); }).always(function(){ this.logsElement.hideLoadingAnimation(); }); }; /** * callback function after ajax response with log data * @param responseData * @param context */ let updateTableDataCallback = (responseData, context) => { let newLogCount = responseData.data.length; if(newLogCount > 0){ let pageInfoOld = context.tableApi.page.info(); // add new rows context.tableApi.rows.add(responseData.data).draw(); let newPageIndex = 0; if(pageInfoOld.recordsDisplay === 0){ Util.showNotify({title: 'New logs loaded', text: newLogCount + ' most recent logs added', type: 'success'}); }else{ // get new pageInfo (new max page count) let pageInfoNew = context.tableApi.page.info(); newPageIndex = Math.max(0, pageInfoNew.pages - 1); Util.showNotify({title: 'More logs loaded', text: newLogCount + ' older logs added', type: 'info'}); } // get to last page (pageIndex starts at zero) -> check if last page > 0 context.tableApi.page(newPageIndex).draw(false); }else{ Util.showNotify({title: 'No logs found', text: 'No more entries', type: 'warning'}); } }; // init logs table -------------------------------------------------------------------------------------------- let logTable = $('
', { class: ['compact', 'stripe', 'order-column', 'row-border', 'pf-table-fixed'].join(' ') }); logsElement.append(logTable); let serverDate = Util.getServerTime(); let serverHours = serverDate.setHours(0,0,0,0); let logDataTable = logTable.DataTable({ pageLength: 25, paging: true, lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]], pagingType: 'full_numbers', ordering: false, autoWidth: false, searching: true, hover: false, data: [], language: { emptyTable: 'No logs available', zeroRecords: 'No logs found', lengthMenu: 'Show _MENU_ rows', info: 'Showing _START_ to _END_ of _TOTAL_ rows' }, columnDefs: [ { targets: 0, title: ' ', width: 12, data: 'context.tag', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ let className = 'txt-color-' + data; value = ''; } return value; } } },{ targets: 1, name: 'timestamp', title: '', width: 100, className: ['text-right'].join(' '), data: 'datetime', render: { _: function(data, type, row, meta){ let value = ''; let logDateString; if(typeof data === 'string' && data.length){ // NEW: > v1.5.5 e.g: '2019-12-09T22:07:01.382455+00:00' logDateString = data; }else if(data && data.date){ // OLD: <= v1.5.5 object data.date: '2019-12-09 14:50:46.608484' logDateString = data.date; } if(logDateString){ logDateString = logDateString .substring(0, 19) .replace(/-/g, '/') .replace(/T/g, ' '); let logDate = new Date(logDateString); value = Util.convertDateToString(logDate, true); // check whether log is new (today) -> if(logDate.setHours(0,0,0,0) === serverHours){ // replace dd/mm/YYYY value = 'today' + value.substring(10); } } return value; } } },{ targets: 2, title: 'level', width: 40, data: 'level_name' },{ targets: 3, title: 'channel', className: [config.tableCellEllipsisClass].join(' '), width: 40, data: 'channel' },{ targets: 4, title: 'message', width: 115, data: 'message', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ let className = 'txt-color-'; if(Util.getObjVal(row, 'context.tag')){ className += row.context.tag; } value = '' + value + ''; } return value; } } },{ targets: 5, title: '', width: 26, searchable: false, className: [config.tableCellImageClass].join(' '), data: 'context.data.character.id' , render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value = ''; } return value; } } },{ targets: 6, title: 'pilot', width: 110, className: [config.tableCellActionClass].join(' '), data: 'context.data.character.name', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value += ' ' + getIconForInformationWindow(); } return value; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // open character information window (ingame) $(cell).on('click', { tableApi: this.api(), rowIndex: rowIndex }, function(e){ let rowData = e.data.tableApi.row(e.data.rowIndex).data(); Util.openIngameWindow(rowData.context.data.character.id); }); } },{ targets: 7, title: 'context', className: [config.tableCellEllipsisClass].join(' '), data: 'context.data.formatted' },{ targets: 8, title: '', width: 12, className: [config.tableCellActionClass].join(' '), data: 'context.data', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display'){ value = ''; } return value; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ // unset formatted string (to much content) $(cell).on('mouseenter', function(e){ let cell = $(this); if(!cell.data('bs.popover')){ if(cellData.formatted){ // clone data before delete() values cellData = Object.assign({}, cellData); delete(cellData.formatted); } let jsonHighlighted = Render.highlightJson(cellData); let content = '
' + jsonHighlighted + '
'; // open popover with raw log data cell.popover({ placement: 'left', html: true, trigger: 'hover', content: content, container: 'body', title: 'Raw data', delay: { show: 180, hide: 0 } }); cell.popover('show'); } }); } } ], initComplete: function(settings){ let tableApi = this.api(); // empty table is ready -> load logs getLogsData({ mapId: mapData.config.id }, { tableApi: tableApi, callback: updateTableDataCallback, logsElement: logsElement }); }, drawCallback: function(settings){ let tableApi = this.api(); // en/disable "load more" button ---------------------------------------------------------------------- let tableInfo = tableApi.page.info(); let isLastPage = (tableInfo.pages === 0 || tableInfo.page === tableInfo.pages - 1); tableApi.button(0).enable(isLastPage); // adjust "timestamp" column width -------------------------------------------------------------------- let timestampColumn = tableApi.column('timestamp:name').header(); let timestampColumnCells = tableApi.cells(undefined, 'timestamp:name', {page: 'current', order:'current'}); let hasOldLogs = timestampColumnCells.render('display').reduce((hasOldLogs, cellValue) => { return (hasOldLogs === false && !cellValue.startsWith('today')) ? true : hasOldLogs; }, false); if(hasOldLogs){ $(timestampColumn).css({width: '100px'}); }else{ $(timestampColumn).css({width: '80px'}); } } }); // ------------------------------------------------------------------------------------------------------------ // add dataTable buttons (extension) logsElement.append($('
', { class: config.tableToolsClass })); let buttons = new $.fn.dataTable.Buttons(logDataTable, { buttons: [ { className: 'btn btn-sm btn-default', text: ' load more', enabled: false, action: function(e, dt, node, config ){ let pageInfo = dt.page.info(); getLogsData({ mapId: mapData.config.id, limit: pageInfo.length, offset: pageInfo.recordsTotal }, { tableApi: dt, callback: updateTableDataCallback, logsElement: logsElement }); } } ] } ); logDataTable.buttons().container().appendTo($(this).find('.' + config.tableToolsClass)); }; /** * shows the map information modal dialog * @param options */ $.fn.showMapInfoDialog = function(options){ let activeMap = Util.getMapModule().getActiveMap(); let mapData = activeMap ? activeMap.getMapDataFromClient(['hasId']) : false; if(mapData !== false){ // "log" tab -> get "Origin", not all config options are set in mapData let mapDataOrigin = Util.getCurrentMapData(mapData.config.id); requirejs(['text!templates/dialog/map_info.html', 'mustache'], (template, Mustache) => { let data = { dialogSummaryContainerId: config.dialogMapInfoSummaryId, dialogUsersContainerId: config.dialogMapInfoUsersId, dialogLogsContainerId: config.dialogMapInfoLogsId, dialogRefreshContainerId: config.dialogMapInfoRefreshId, dialogNavigationClass: config.dialogNavigationClass, mapInfoId: config.mapInfoId, mapInfoSystemsId: config.mapInfoSystemsId, mapInfoConnectionsId: config.mapInfoConnectionsId, mapInfoUsersId: config.mapInfoUsersId, mapInfoLogsId: config.mapInfoLogsId, logHistoryEnabled: Boolean(Util.getObjVal(mapDataOrigin, 'config.logging.history')), // default open tab ---------- openTabInformation: options.tab === 'information', openTabActivity: options.tab === 'activity', openTabLog: options.tab === 'log' }; let content = Mustache.render(template, data); let mapInfoDialog = bootbox.dialog({ title: 'Map information', message: content, size: 'large', buttons: { success: { label: 'close', className: 'btn-primary', callback: function(){ $(mapInfoDialog).modal('hide'); } } } }); mapInfoDialog.on('shown.bs.modal', function(e){ let mapInfoDialog = $(this); let mapElement = $('#' + config.mapInfoId); let systemsElement = $('#' + config.mapInfoSystemsId); let connectionsElement = $('#' + config.mapInfoConnectionsId); let usersElement = $('#' + config.mapInfoUsersId); // set refresh button observer $('#' + config.dialogMapInfoRefreshId).on('click', function(e){ let menuAction = $(this).attr('data-action'); if(menuAction === 'refresh'){ // get new map data let mapData = activeMap.getMapDataFromClient(['hasId']); // find active tab let activeTabLink = $(this).parents('.navbar').find('.navbar-header.pull-left li.active a'); if(activeTabLink.attr('href') === '#' + config.dialogMapInfoLogsId){ $('#' + config.mapInfoLogsId).initLogsInfoTable(mapDataOrigin); } mapElement.initMapInfoData(mapData); systemsElement.initSystemInfoTable(mapData); connectionsElement.initConnectionInfoTable(mapData); usersElement.initUsersInfoTable(mapData); } }); // load map data mapElement.initMapInfoData(mapData); // load system table systemsElement.initSystemInfoTable(mapData); // load connection table connectionsElement.initConnectionInfoTable(mapData); // load users table usersElement.initUsersInfoTable(mapData); // set global dialog observer setDialogObserver(mapInfoDialog, mapData); }); // events for tab change mapInfoDialog.find('.navbar a').on('shown.bs.tab', function(e){ if($(e.target).attr('href') === '#' + config.dialogMapInfoLogsId){ // "log" tab let mapDataOrigin = Util.getCurrentMapData(mapData.config.id); $('#' + config.mapInfoLogsId).initLogsInfoTable(mapDataOrigin); } }); }); }else{ // no active map found (e.g. not loaded yet, or no map exists) Util.showNotify({ title: 'Map data not found', text: 'No map initialized at this point', type: 'warning'} ); } }; });