/** * System intel module */ define([ 'jquery', 'app/init', 'app/util', 'module/base', 'bootbox', 'app/counter' ], ($, Init, Util, BaseModule, bootbox, Counter) => { 'use strict'; let SystemIntelModule = class SystemIntelModule extends BaseModule { constructor(config = {}) { super(Object.assign({}, new.target.defaultConfig, config)); } /** * get status icon for structure * @param statusData * @returns {string} */ getIconForStatusData(statusData){ return ''; } /** * get icon that marks a table cell as clickable * @returns {string} */ getIconForInformationWindow(){ return ''; } /** * get a dataTableApi instance from global cache * @param mapId * @param systemId * @param tableType * @returns {*} */ getDataTableInstance(mapId, systemId, tableType){ return BaseModule.Util.getDataTableInstance(this._config.intelTableId, mapId, systemId, tableType); } /** * get dataTable id * @param {...string} parts e.g. 'tableType', 'mapId', 'systemId' * @returns {string} */ getTableId(...parts){ return BaseModule.Util.getTableId(this._config.intelTableId, ...parts); } /** * get dataTable row id * @param tableType * @param id * @returns {string} */ getRowId(tableType, id){ return BaseModule.Util.getTableRowId(this._config.intelTableRowIdPrefix, tableType, id); } /** * get DOM id by id * @param tableApi * @param id * @returns {*} */ getRowById(tableApi, id){ return tableApi.rows().ids().toArray().find(rowId => rowId === this.getRowId(BaseModule.Util.getObjVal(this.getTableMetaData(tableApi), 'type'), id)); } /** * get custom "metaData" from dataTables API * @param tableApi * @returns {*} */ getTableMetaData(tableApi){ return tableApi ? tableApi.init().pfMeta : null; } /** * vormat roman numeric string to int * -> e.g. 'VII' => 7 * @param str * @returns {number} */ romanToInt(str){ let charToTnt = char => { switch (char) { case 'I': return 1; case 'V': return 5; case 'X': return 10; case 'L': return 50; case 'C': return 100; case 'D': return 500; case 'M': return 1000; default: return -1; } }; if(str == null) return -1; let num = charToTnt(str.charAt(0)); let pre, curr; for(let i = 1; i < str.length; i++){ curr = charToTnt(str.charAt(i)); pre = charToTnt(str.charAt(i - 1)); if(curr <= pre){ num += curr; }else{ num = num - pre * 2 + curr; } } return num; } /** * render module * @param mapId * @param systemData * @returns {HTMLElement} */ render(mapId, systemData){ this._systemData = systemData; let showStationTable = ['H', 'L', '0.0', 'C12'].includes(Util.getObjVal(this._systemData, 'security')); this._bodyEl = Object.assign(document.createElement('div'), { className: this._config.bodyClassName }); this.moduleElement.append(this._bodyEl); $(this.moduleElement).showLoadingAnimation(); this.initStructureTable(); if(showStationTable){ this.initStationTable(); } this.setModuleObserver(); return this.moduleElement; } /** * init 'Structure' table */ initStructureTable(){ let module = this; let corporationId = Util.getCurrentUserInfo('corporationId'); let structureTableEl = document.createElement('table'); structureTableEl.id = module.getTableId('structure', module._systemData.mapId, module._systemData.id); structureTableEl.classList.add('compact', 'stripe', 'order-column', 'row-border', 'pf-table-fixed', module._config.systemStructuresTableClass); this._bodyEl.append(structureTableEl); let structureDataTableOptions = { pfMeta: { type: 'structures' }, order: [[10, 'desc' ], [0, 'asc' ]], rowId: rowData => module.getRowId('structures', rowData.id), select: { style: 'os', selector: 'td:not(.' + module._config.tableCellActionClass + ')' }, language: { emptyTable: 'No structures recorded', info: '_START_ to _END_ of _MAX_', infoEmpty: '' }, columnDefs: [ { targets: 0, name: 'status', title: '', width: 2, className: ['text-center', 'all'].join(' '), data: 'status', render: { display: data => module.getIconForStatusData(data), sort: data => data.id }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ $(cell).find('i').tooltip(); } },{ targets: 1, name: 'structureImage', title: '', width: 24, orderable: false, className: [module._config.tableCellImageClass, 'text-center', 'all'].join(' '), data: 'structure.id', defaultContent: '', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display' && value){ value = ''; } return value; } } },{ targets: 2, name: 'structureType', title: 'type', width: 30, className: [module._config.tableCellEllipsisClass, 'all'].join(' '), data: 'structure.name', defaultContent: '', },{ targets: 3, name: 'name', title: 'name', width: 60, className: [module._config.tableCellEllipsisClass, 'all'].join(' '), data: 'name' },{ targets: 4, name: 'ownerImage', title: '', width: 24, orderable: false, className: [module._config.tableCellImageClass, 'text-center', 'all'].join(' '), data: 'owner.id', defaultContent: '', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display' && value){ value = ''; value += ''; value += ''; } return value; } } },{ targets: 5, name: 'ownerName', title: 'owner', width: 50, className: [module._config.tableCellEllipsisClass, 'all'].join(' '), data: 'owner.name', defaultContent: '', },{ targets: 6, name: 'note', title: 'note', className: [module._config.tableCellEllipsisClass, 'all', Util.config.popoverTriggerClass, module._config.tableCellPopoverClass].join(' '), data: 'description' },{ targets: 7, name: 'updated', title: 'updated', width: 60, className: ['text-right', module._config.tableCellCounterClass, 'not-screen-l'].join(' '), data: 'updated.updated' },{ targets: 8, name: 'edit', title: '', orderable: false, width: 10, className: ['text-center', module._config.tableCellActionClass, module._config.moduleHeadlineIconClass, 'all'].join(' '), data: null, render: { display: data => { let icon = ''; if(data.rowGroupData.id !== corporationId){ icon = ''; } return icon; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ let tableApi = this.api(); if($(cell).is(':empty')){ $(cell).removeClass(module._config.tableCellActionClass + ' ' + module._config.moduleHeadlineIconClass); }else{ $(cell).on('click', function(e){ let rowData = null; let bulkData = null; // check if multiple rows are selected + current row is one of them -> bulk edit let rowsSelected = tableApi.rows({selected: true}); if(rowsSelected.count() && tableApi.row(rowIndex, {selected: true}).count()){ bulkData = [...new Set(rowsSelected.data().toArray().map(rowData => ({id: rowData.id})))]; }else{ // get current row data (important!) // -> "rowData" param is not current state, values are "on createCell()" state rowData = tableApi.row( $(cell).parents('tr')).data(); } module.showStructureDialog(tableApi, rowData, bulkData); }); } } },{ targets: 9, name: 'delete', title: '', orderable: false, width: 10, className: ['text-center', module._config.tableCellActionClass, 'all'].join(' '), data: null, render: { display: data => { let icon = ''; if(data.rowGroupData.id !== corporationId){ icon = ''; } return icon; } }, createdCell: function(cell, cellData, rowData, rowIndex, colIndex){ let tableApi = this.api(); if($(cell).find('.fa-ban').length){ $(cell).removeClass(module._config.tableCellActionClass + ' ' + module._config.moduleHeadlineIconClass); $(cell).find('i').tooltip(); }else{ let confirmationSettings = { title: '---', template: Util.getConfirmationTemplate(null, { size: 'small', noTitle: true }), onConfirm : function(e, target){ // get current row data (important!) // -> "rowData" param is not current state, values are "on createCell()" state rowData = tableApi.row( $(cell).parents('tr')).data(); // let deleteRowElement = $(cell).parents('tr'); // tableApi.rows(deleteRowElement).remove().draw(); $(module.moduleElement).showLoadingAnimation(); Util.request('DELETE', 'Structure', rowData.id, {}, { tableApi: tableApi }, () => $(module.moduleElement).hideLoadingAnimation() ).then( payload => module.callbackDeleteStructures(payload.context, payload.data), Util.handleAjaxErrorResponse ); } }; // init confirmation dialog $(cell).confirmation(confirmationSettings); } } },{ targets: 10, name: 'rowGroupData', className: 'never', // never show this column. see: https://datatables.net/extensions/responsive/classes data: 'rowGroupData', visible: false, render: { sort: function(data){ return data.name; } } } ], initComplete: function(settings){ // table data is load in updateModule() method // -> no need to trigger additional ajax call here for data // -> in case table update failed -> each if this initComplete() function finished before table updated // e.g. return now promise in getModule() function Counter.initTableCounter(this, ['updated:name'], 'd'); } }; this._tableApiStructure = $(structureTableEl).DataTable($.extend(true, {}, module.getDataTableDefaults(module), structureDataTableOptions)); // "Responsive" Datatables Plugin new $.fn.dataTable.Responsive(this._tableApiStructure); this._tableApiStructure.on('responsive-resize', function(e, tableApi, columns){ // rowGroup length changes as well -> trigger draw() updates rowGroup length (see drawCallback()) tableApi.draw(); }); // "Select" Datatables Plugin this._tableApiStructure.select(); this._tableApiStructure.on('user-select', function(e, tableApi, type, cell, originalEvent){ let rowData = tableApi.row(cell.index().row).data(); if(Util.getObjVal(rowData, 'rowGroupData.id') !== corporationId){ e.preventDefault(); } }); // "Buttons" Datatables Plugin let buttons = new $.fn.dataTable.Buttons(this._tableApiStructure, { dom: { container: { tag: 'h5', className: 'pull-right' }, button: { tag: 'i', className: ['fas', 'fa-fw', module._config.moduleHeadlineIconClass].join(' '), }, buttonLiner: { tag: null } }, name: 'tableTools', buttons: [ { name: 'add', className: 'fa-plus', titleAttr: 'add', attr: { 'data-toggle': 'tooltip', 'data-html': true }, action: function(e, tableApi, node, config){ module.showStructureDialog(tableApi); } }, { name: 'selectToggle', className: ['fa-check-double'].join(' '), titleAttr: 'select all', attr: { 'data-toggle': 'tooltip', 'data-html': true }, action: function(e, tableApi, node, config){ let indexes = tableApi.rows().eq(0).filter(rowIdx => { return Util.getObjVal(tableApi.cell(rowIdx, 'rowGroupData:name').data(), 'id') === corporationId; }); let rowCountAll = tableApi.rows(indexes).count(); let rowCountSelected = tableApi.rows({selected: true}).count(); if(rowCountSelected && (rowCountSelected >= rowCountAll)){ tableApi.rows().deselect(); node.removeClass('active'); }else{ tableApi.rows(indexes).select(); node.addClass('active'); } } }, { name: 'dScan', className: 'fa-paste', titleAttr: 'D-Scan reader', attr: { 'data-toggle': 'tooltip', 'data-html': true }, action: function(e, tableApi, node, config){ module.showDscanReaderDialog(tableApi); } }, { name: 'refresh', className: 'fa-sync', titleAttr: 'refresh', attr: { 'data-toggle': 'tooltip', 'data-html': true }, action: function(e, tableApi, node, config){ $(module.moduleElement).showLoadingAnimation(); Util.request('GET', 'System', module._systemData.id, {mapId: module._systemData.mapId}, { tableApi: tableApi, removeMissing: true }, context => $(module.moduleElement).hideLoadingAnimation() ).then(payload => module.callbackUpdateTableRows(payload.context, Util.getObjVal(payload.data, 'structures'))); } } ] }); this._tableApiStructure.buttons().container().appendTo(module.moduleElement.querySelector('.' + module._config.headClassName)); } /** * init 'Station' table */ initStationTable(){ let module = this; this._bodyEl.append(module.newHeaderElement(module._config.headlineSub)); let stationTableEl = document.createElement('table'); stationTableEl.id = module.getTableId('station', module._systemData.mapId, module._systemData.id); stationTableEl.classList.add('compact', 'stripe', 'order-column', 'row-border', 'pf-table-fixed', module._config.systemStationsTableClass); this._bodyEl.append(stationTableEl); let stationDataTableOptions = { pfMeta: { type: 'stations' }, order: [[1, 'asc' ], [8, 'asc' ]], rowId: rowData => module.getRowId('stations', rowData.id), language: { emptyTable: 'No stations found', info: '_START_ to _END_ of _MAX_', infoEmpty: '' }, columnDefs: [ { targets: 0, name: 'stationImage', title: '', width: 24, orderable: false, className: [module._config.tableCellImageClass, 'text-center', 'all'].join(' '), data: 'type.id', defaultContent: '', render: { _: function(data, type, row, meta){ let value = data; if(type === 'display' && value){ value = ''; } return value; } } },{ targets: 1, name: 'count', title: '', width: 5, className: ['text-center', 'all'].join(' '), data: 'name', render: { _: function(cellData, type, rowData, meta){ let value = ''; if(cellData){ // "grouped" regex not supported by FF // let matches = /^(?[a-z0-9\s\-]+) (?[MDCLXVI]+) .*$/i.exec(cellData); // let count = Util.getObjVal(matches, 'groups.count'); let matches = /^([a-z0-9\s\-]+) ([MDCLXVI]+) .*$/i.exec(cellData); let count = Util.getObjVal(matches, '2'); if(type === 'display'){ value = count || 0; }else{ value = module.romanToInt(count) || ''; } } return value; } } },{ targets: 2, name: 'name', title: 'station', className: [module._config.tableCellEllipsisClass, 'all'].join(' '), data: 'name', render: { _: function(cellData, type, rowData, meta){ let value = cellData; if(cellData){ // "grouped" regex not supported by FF // let matches = /^(?[a-z0-9\s\-]+) (?[MDCLXVI]+) (?