- New "bulk" update dialog for "structures", closed #869

This commit is contained in:
Mark Friedrich
2019-11-02 11:15:11 +01:00
parent 1fd1306228
commit 925894774e
17 changed files with 444 additions and 671 deletions

View File

@@ -134,11 +134,12 @@ class StructureModel extends AbstractPathfinderModel {
if($corporationId){
if($corporationId !== $oldCorporationId){
// make sure there is already corporation data available for new corporationId
// -> $ttl = 0 is important! Otherwise "bulk" update for structures could fail
/**
* @var CorporationModel $corporation
*/
$corporation = $this->rel('corporationId');
$corporation->getById($corporationId);
$corporation->getById($corporationId, 0);
if($corporation->dry()){
$corporationId = null;
}
@@ -234,7 +235,7 @@ class StructureModel extends AbstractPathfinderModel {
* @param int $systemId
*/
public function getByName(CorporationModel $corporation, string $name, int $systemId){
if( !$corporation->dry() && $name){
if($corporation->valid() && $name){
$this->has('structureCorporations', ['corporationId = :corporationId', ':corporationId' => $corporation->_id]);
$this->load(['name = :name AND systemId = :systemId AND active = :active',
':name' => $name,

View File

@@ -53,7 +53,7 @@ requirejs.config({
blueImpGallery: 'lib/blueimp-gallery', // v2.21.3 Image Gallery - https://github.com/blueimp/Gallery
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.4.2 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.5 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
bootstrapConfirmation: 'lib/bootstrap-confirmation.min', // v1.0.7 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
bootstrapToggle: 'lib/bootstrap-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
lazyload: 'lib/jquery.lazyload.min', // v1.9.7 LazyLoader images - https://appelsiini.net/projects/lazyload/
sortable: 'lib/sortable.min', // v1.6.0 Sortable - drag&drop reorder - https://github.com/rubaxa/Sortable

View File

@@ -1249,7 +1249,7 @@ define([
class: config.tableToolsClass
}));
let buttons = new $.fn.dataTable.Buttons( logDataTable, {
let buttons = new $.fn.dataTable.Buttons(logDataTable, {
buttons: [
{
className: 'btn btn-sm btn-default',

View File

@@ -24,9 +24,6 @@ define([
// headline toolbar
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
moduleHeadlineIconAddClass: 'pf-module-icon-button-add', // class for "add structure" icon
moduleHeadlineIconReaderClass: 'pf-module-icon-button-reader', // class for "dScan reader" icon
moduleHeadlineIconRefreshClass: 'pf-module-icon-button-refresh', // class for "refresh" icon
// system intel module
intelTableId: 'pf-intel-table-', // id prefix for all tables in module
@@ -49,7 +46,8 @@ define([
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
tableCellActionClass: 'pf-table-action-cell', // class for "action" cells
tableCellActionIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
tableCellServicesClass: 'pf-table-services-cell' // class for table station "services" cells
tableCellServicesClass: 'pf-table-services-cell', // class for table station "services" cells
tableCellPopoverClass: 'pf-table-popover-cell' // class for table cells with a "popover"
};
let maxDescriptionLength = 512;
@@ -71,6 +69,15 @@ define([
return '<i class="fas fa-fw fa-id-card ' + config.tableCellActionIconClass + '" title="open ingame" data-toggle="tooltip"></i>';
};
/**
* get a dataTableApi instance from global cache
* @param mapId
* @param systemId
* @param tableType
* @returns {*}
*/
let getDataTableInstance = (mapId, systemId, tableType) => Util.getDataTableInstance(config.intelTableId, mapId, systemId, tableType);
/**
* get dataTable id
* @param mapId
@@ -284,8 +291,9 @@ define([
* @param tableApi
* @param systemId
* @param structureData
* @param bulkData
*/
let showStructureDialog = (moduleElement, tableApi, systemId, structureData) => {
let showStructureDialog = (moduleElement, tableApi, systemId, structureData = null, bulkData = null) => {
let structureStatusData = Util.getObjVal(Init, 'structureStatus');
let statusData = Object.keys(structureStatusData).map((k) => {
@@ -322,6 +330,7 @@ define([
let data = {
id: config.structureDialogId,
structureData: structureData,
bulkData: bulkData,
structureStatus: statusData,
nameInputId: config.nameInputId,
statusSelectId: config.statusSelectId,
@@ -334,9 +343,13 @@ define([
requirejs(['text!templates/dialog/structure.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
let title = 'Structure';
if(bulkData){
title += ' <span class="txt-color txt-color-warning">&nbsp;(' + bulkData.length + ' rows)</span>&nbsp;';
}
let structureDialog = bootbox.dialog({
title: 'Structure',
title: title,
message: content,
show: false,
buttons: {
@@ -346,7 +359,9 @@ define([
},
autoFill: {
label: buttonLabelAutoFill,
className: 'btn-primary' + (disableButtonAutoFill ? ' pf-font-italic disabled' : ''),
className: 'btn-primary' +
(disableButtonAutoFill ? ' pf-font-italic disabled' : '') +
(bulkData ? ' hidden' : ''),
callback: function(){
let form = this.find('form');
form.find('#' + config.nameInputId).val(characterStructureName);
@@ -378,7 +393,20 @@ define([
moduleElement.showLoadingAnimation();
let method = formData.id ? 'PATCH' : 'PUT';
Util.request(method, 'structure', formData.id, formData,
let ids = formData.id;
let data = formData;
if(bulkData){
// bulk update multiple rows
method = 'POST';
ids = [];
data = bulkData.map(structureData => {
structureData.corporationId = formData.corporationId;
return structureData;
});
}
Util.request(method, 'structure', ids, data,
{
moduleElement: moduleElement,
tableApi: tableApi
@@ -573,22 +601,6 @@ define([
$('<h5>', {
class: config.moduleHandlerClass
}),
$('<h5>', {
class: 'pull-right'
}).append(
$('<i>', {
class: ['fas', 'fa-fw', 'fa-plus', config.moduleHeadlineIconClass, config.moduleHeadlineIconAddClass].join(' '),
title: 'add'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
$('<i>', {
class: ['fas', 'fa-fw', 'fa-paste', config.moduleHeadlineIconClass, config.moduleHeadlineIconReaderClass].join(' '),
title: 'D-Scan&nbsp;reader'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
$('<i>', {
class: ['fas', 'fa-fw', 'fa-sync', config.moduleHeadlineIconClass, config.moduleHeadlineIconRefreshClass].join(' '),
title: 'refresh&nbsp;all'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip')
),
$('<h5>', {
text: 'Structures'
})
@@ -608,6 +620,10 @@ define([
},
order: [[10, 'desc' ], [0, 'asc' ]],
rowId: rowData => getRowId('structures', rowData.id),
select: {
style: 'os',
selector: 'td:not(.' + config.tableCellActionClass + ')'
},
language: {
emptyTable: 'No structures recorded',
info: '_START_ to _END_ of _MAX_',
@@ -693,7 +709,7 @@ define([
targets: 6,
name: 'note',
title: 'note',
className: [config.tableCellEllipsisClass, 'all'].join(' '),
className: [config.tableCellEllipsisClass, 'all', Util.config.popoverTriggerClass, config.tableCellPopoverClass].join(' '),
data: 'description'
},{
targets: 7,
@@ -726,10 +742,19 @@ define([
$(cell).removeClass(config.tableCellActionClass + ' ' + config.moduleHeadlineIconClass);
}else{
$(cell).on('click', function(e){
// get current row data (important!)
// -> "rowData" param is not current state, values are "on createCell()" state
rowData = tableApi.row( $(cell).parents('tr')).data();
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData);
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();
}
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData, bulkData);
});
}
}
@@ -812,9 +837,9 @@ define([
}
};
$.extend(true, structureDataTableOptions, getDataTableDefaults());
let tableApiStructure = structureTable.DataTable(structureDataTableOptions);
let tableApiStructure = structureTable.DataTable($.extend(true, {}, getDataTableDefaults(), structureDataTableOptions));
// "Responsive" Datatables Plugin
new $.fn.dataTable.Responsive(tableApiStructure);
tableApiStructure.on('responsive-resize', function(e, tableApi, columns){
@@ -822,6 +847,107 @@ define([
tableApi.draw();
});
// "Select" Datatables Plugin
tableApiStructure.select();
// "Buttons" Datatables Plugin
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();
}
});
let buttons = new $.fn.dataTable.Buttons(tableApiStructure, {
dom: {
container: {
tag: 'h5',
className: 'pull-right'
},
button: {
tag: 'i',
className: ['fas', 'fa-fw', config.moduleHeadlineIconClass].join(' '),
},
buttonLiner: {
tag: null
}
},
name: 'tableTools',
buttons: [
{
name: 'selectToggle',
className: ['fa-check-double'].join(' '),
titleAttr: 'select&nbsp;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: 'add',
className: 'fa-plus',
titleAttr: 'add',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config){
showStructureDialog(moduleElement, tableApi, systemData.systemId);
}
},
{
name: 'dScan',
className: 'fa-paste',
titleAttr: 'D-Scan&nbsp;reader',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config ){
showDscanReaderDialog(moduleElement, tableApi, systemData);
}
},
{
name: 'refresh',
className: 'fa-sync',
titleAttr: 'refresh&nbsp;all',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config ){
moduleElement.showLoadingAnimation();
Util.request('GET', 'system', systemData.id, {mapId: mapId},
{
moduleElement: moduleElement,
tableApi: tableApi,
removeMissing: true
},
context => context.moduleElement.hideLoadingAnimation()
).then(payload => callbackUpdateTableRows(payload.context, Util.getObjVal(payload.data, 'structures')));
}
}
]
});
tableApiStructure.buttons().container().appendTo(moduleElement.find('.' + config.moduleHeadClass));
if(showStationTable){
// "Stations" table ---------------------------------------------------------------------------------------
@@ -1057,8 +1183,7 @@ define([
}
};
$.extend(true, stationDataTableOptions, getDataTableDefaults());
let tableApiStation = stationTable.DataTable(stationDataTableOptions);
let tableApiStation = stationTable.DataTable($.extend(true, {}, getDataTableDefaults(), stationDataTableOptions));
new $.fn.dataTable.Responsive(tableApiStation);
@@ -1221,30 +1346,6 @@ define([
let structureTableElement = moduleElement.find('.' + config.systemStructuresTableClass);
let tableApi = structureTableElement.DataTable();
// init structure dialog --------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconAddClass).on('click', function(e){
showStructureDialog(moduleElement, tableApi, systemData.systemId);
});
// init structure dialog --------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconReaderClass).on('click', function(e){
showDscanReaderDialog(moduleElement, tableApi, systemData);
});
// init refresh button ----------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconRefreshClass).on('click', function(e){
moduleElement.showLoadingAnimation();
Util.request('GET', 'system', systemData.id, {mapId: mapId},
{
moduleElement: moduleElement,
tableApi: tableApi,
removeMissing: true
},
context => context.moduleElement.hideLoadingAnimation()
).then(payload => callbackUpdateTableRows(payload.context, Util.getObjVal(payload.data, 'structures')));
});
// init listener for global "past" dScan into this page -------------------------------------------------------
moduleElement.on('pf:updateIntelModuleByClipboard', function(e, clipboard){
updateStructureTableByClipboard(systemData, clipboard, {
@@ -1252,6 +1353,38 @@ define([
tableApi: tableApi
});
});
// init popovers for some table cells -------------------------------------------------------------------------
moduleElement.hoverIntent({
over: function(e){
let tableApi = getDataTableInstance(mapId, systemData.id, 'structure');
// simple <table> for layout (CSS)
let cellData = tableApi.cell(this).data();
if(cellData && cellData.length){
let content = '<table><tr><td>' + cellData.replace(/\r?\n/g, '<br />') + '</td></tr></table>';
let options = {
placement: 'top',
html: true,
trigger: 'manual',
container: 'body',
title: '',
content: content,
delay: {
show: 0,
hide: 0
},
};
$(this).popover(options).popover('show');
}
},
out: function(e){
$(this).destroyPopover();
},
selector: '.' + config.tableCellPopoverClass
});
};
/**
@@ -1263,8 +1396,8 @@ define([
let stationTable = moduleElement.find('.' + config.systemStationsTableClass);
let tableApiStructure = structureTable.DataTable();
let tableApiStation = stationTable.DataTable();
tableApiStructure.destroy();
tableApiStation.destroy();
tableApiStructure.destroy(true);
tableApiStation.destroy(true);
};
return {

View File

@@ -1684,23 +1684,25 @@ define([
* @param maxCharLength
*/
let updateCounter = (field, charCounterElement, maxCharLength) => {
let value = field.val();
let inputLength = value.length;
if(field.length){
let value = field.val();
let inputLength = value.length;
// line breaks are 2 characters!
let newLines = value.match(/(\r\n|\n|\r)/g);
let addition = 0;
if(newLines != null){
addition = newLines.length;
}
inputLength += addition;
// line breaks are 2 characters!
let newLines = value.match(/(\r\n|\n|\r)/g);
let addition = 0;
if(newLines != null){
addition = newLines.length;
}
inputLength += addition;
charCounterElement.text(maxCharLength - inputLength);
charCounterElement.text(maxCharLength - inputLength);
if(maxCharLength <= inputLength){
charCounterElement.toggleClass('txt-color-red', true);
}else{
charCounterElement.toggleClass('txt-color-red', false);
if(maxCharLength <= inputLength){
charCounterElement.toggleClass('txt-color-red', true);
}else{
charCounterElement.toggleClass('txt-color-red', false);
}
}
};

View File

@@ -1,256 +0,0 @@
/*!
* Bootstrap Confirmation v1.0.7
* https://github.com/tavicu/bs-confirmation
*/
+function ($) {
'use strict';
//var for check event at body can have only one.
var event_body = false;
// CONFIRMATION PUBLIC CLASS DEFINITION
// ===============================
var Confirmation = function (element, options) {
var that = this;
this.init('confirmation', element, options);
if (options.selector) {
$(element).on('click.bs.confirmation', options.selector, function(e) {
e.preventDefault();
});
} else {
$(element).on('show.bs.confirmation', function(event) {
that.runCallback(that.options.onShow, event, that.$element);
that.$element.addClass('open');
if (that.options.singleton) {
$(that.options.all_selector).not(that.$element).each(function() {
if ($(this).hasClass('open')) {
$(this).confirmation('hide');
}
});
}
}).on('hide.bs.confirmation', function(event) {
that.runCallback(that.options.onHide, event, that.$element);
that.$element.removeClass('open');
}).on('shown.bs.confirmation', function(e) {
if (!that.isPopout() && !event_body) {
return;
}
event_body = $('body').on('click', function (e) {
if (that.$element.is(e.target)) return;
if (that.$element.has(e.target).length) return;
if ($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}).on('click.bs.confirmation', function(e) {
e.preventDefault();
});
}
}
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
Confirmation.VERSION = '1.0.7'
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element) {},
onHide : function(event, element) {},
onConfirm : function(event, element) {},
onCancel : function(event, element) {},
template : '<div class="popover"><div class="arrow"></div>'
+ '<h3 class="popover-title"></h3>'
+ '<div class="popover-content">'
+ ' <a data-apply="confirmation">Yes</a>'
+ ' <a data-dismiss="confirmation">No</a>'
+ '</div>'
+ '</div>'
});
// NOTE: CONFIRMATION EXTENDS popover.js
// ================================
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
Confirmation.prototype.constructor = Confirmation;
Confirmation.prototype.getDefaults = function () {
return Confirmation.DEFAULTS;
}
Confirmation.prototype.setContent = function () {
var that = this;
var $tip = this.tip();
var title = this.getTitle();
var $btnOk = $tip.find('[data-apply="confirmation"]');
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
var options = this.options
$btnOk.addClass(this.getBtnOkClass())
.html(this.getBtnOkLabel())
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
.attr('href', this.getHref())
.attr('target', this.getTarget())
.off('click').on('click', function(event) {
that.runCallback(that.options.onConfirm, event, that.$element);
// If the button is a submit one
if (that.$element.attr('type') == 'submit') {
var form = that.$element.closest('form');
var novalidate = form.attr('novalidate') !== undefined;
if (novalidate || form[0].checkValidity()) {
form.submit();
}
}
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('confirm.bs.confirmation'));
});
$btnCancel.addClass(this.getBtnCancelClass())
.html(this.getBtnCancelLabel())
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
.off('click').on('click', function(event) {
that.runCallback(that.options.onCancel, event, that.$element);
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('cancel.bs.confirmation'));
});
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
$tip.removeClass('fade top bottom left right in');
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
}
Confirmation.prototype.getBtnOkClass = function () {
return this.$element.data('btnOkClass') ||
(typeof this.options.btnOkClass == 'function' ? this.options.btnOkClass.call(this, this.$element) : this.options.btnOkClass);
}
Confirmation.prototype.getBtnOkLabel = function () {
return this.$element.data('btnOkLabel') ||
(typeof this.options.btnOkLabel == 'function' ? this.options.btnOkLabel.call(this, this.$element) : this.options.btnOkLabel);
}
Confirmation.prototype.getBtnOkIcon = function () {
return this.$element.data('btnOkIcon') ||
(typeof this.options.btnOkIcon == 'function' ? this.options.btnOkIcon.call(this, this.$element) : this.options.btnOkIcon);
}
Confirmation.prototype.getBtnCancelClass = function () {
return this.$element.data('btnCancelClass') ||
(typeof this.options.btnCancelClass == 'function' ? this.options.btnCancelClass.call(this, this.$element) : this.options.btnCancelClass);
}
Confirmation.prototype.getBtnCancelLabel = function () {
return this.$element.data('btnCancelLabel') ||
(typeof this.options.btnCancelLabel == 'function' ? this.options.btnCancelLabel.call(this, this.$element) : this.options.btnCancelLabel);
}
Confirmation.prototype.getBtnCancelIcon = function () {
return this.$element.data('btnCancelIcon') ||
(typeof this.options.btnCancelIcon == 'function' ? this.options.btnCancelIcon.call(this, this.$element) : this.options.btnCancelIcon);
}
Confirmation.prototype.getTitle = function () {
return this.$element.data('confirmation-title') ||
this.$element.data('title') ||
this.$element.attr('title') ||
(typeof this.options.title == 'function' ? this.options.title.call(this, this.$element) : this.options.title);
}
Confirmation.prototype.getHref = function () {
return this.$element.data('href') ||
this.$element.attr('href') ||
(typeof this.options.href == 'function' ? this.options.href.call(this, this.$element) : this.options.href);
}
Confirmation.prototype.getTarget = function () {
return this.$element.data('target') ||
this.$element.attr('target') ||
(typeof this.options.target == 'function' ? this.options.target.call(this, this.$element) : this.options.target);
}
Confirmation.prototype.isPopout = function () {
var popout = this.$element.data('popout') ||
(typeof this.options.popout == 'function' ? this.options.popout.call(this, this.$element) : this.options.popout);
if (popout == 'false') popout = false;
return popout
}
Confirmation.prototype.runCallback = function (callback, event, element) {
if (typeof callback == 'function') {
callback.call(this, event, element);
} else if (typeof callback == 'string') {
eval(callback);
}
}
// CONFIRMATION PLUGIN DEFINITION
// =========================
var old = $.fn.confirmation;
$.fn.confirmation = function (option) {
var that = this;
return this.each(function () {
var $this = $(this);
var data = $this.data('bs.confirmation');
var options = typeof option == 'object' && option;
options = options || {};
options.all_selector = that.selector;
if (!data && option == 'destroy') return;
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
if (typeof option == 'string') data[option]();
});
}
$.fn.confirmation.Constructor = Confirmation
// CONFIRMATION NO CONFLICT
// ===================
$.fn.confirmation.noConflict = function () {
$.fn.confirmation = old;
return this;
}
}(jQuery);

5
js/lib/bootstrap-confirmation.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -53,7 +53,7 @@ requirejs.config({
blueImpGallery: 'lib/blueimp-gallery', // v2.21.3 Image Gallery - https://github.com/blueimp/Gallery
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.4.2 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.5 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
bootstrapConfirmation: 'lib/bootstrap-confirmation.min', // v1.0.7 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
bootstrapToggle: 'lib/bootstrap-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
lazyload: 'lib/jquery.lazyload.min', // v1.9.7 LazyLoader images - https://appelsiini.net/projects/lazyload/
sortable: 'lib/sortable.min', // v1.6.0 Sortable - drag&drop reorder - https://github.com/rubaxa/Sortable

View File

@@ -362,7 +362,7 @@ define([
// mapWrapper should always exist
if(mapWrapper && mapWrapper.length) {
// check available maxHeight for offset based on current map height (resizable)
// check available maxHeight for "locale" table based on current map height (resizable)
let mapHeight = mapWrapper[0].offsetHeight;
let localOverlay = MapOverlayUtil.getMapOverlay(table, 'local');
let paginationElement = localOverlay.find('.dataTables_paginate');
@@ -415,8 +415,8 @@ define([
});
});
let localTable = table.DataTable( {
pageLength: 5, // hint: if pagination visible => we need space to show it
let localTable = table.DataTable({
pageLength: 5,
paging: true,
pagingType: 'simple',
lengthChange: false,

View File

@@ -1249,7 +1249,7 @@ define([
class: config.tableToolsClass
}));
let buttons = new $.fn.dataTable.Buttons( logDataTable, {
let buttons = new $.fn.dataTable.Buttons(logDataTable, {
buttons: [
{
className: 'btn btn-sm btn-default',

View File

@@ -24,9 +24,6 @@ define([
// headline toolbar
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
moduleHeadlineIconAddClass: 'pf-module-icon-button-add', // class for "add structure" icon
moduleHeadlineIconReaderClass: 'pf-module-icon-button-reader', // class for "dScan reader" icon
moduleHeadlineIconRefreshClass: 'pf-module-icon-button-refresh', // class for "refresh" icon
// system intel module
intelTableId: 'pf-intel-table-', // id prefix for all tables in module
@@ -49,7 +46,8 @@ define([
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
tableCellActionClass: 'pf-table-action-cell', // class for "action" cells
tableCellActionIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
tableCellServicesClass: 'pf-table-services-cell' // class for table station "services" cells
tableCellServicesClass: 'pf-table-services-cell', // class for table station "services" cells
tableCellPopoverClass: 'pf-table-popover-cell' // class for table cells with a "popover"
};
let maxDescriptionLength = 512;
@@ -71,6 +69,15 @@ define([
return '<i class="fas fa-fw fa-id-card ' + config.tableCellActionIconClass + '" title="open ingame" data-toggle="tooltip"></i>';
};
/**
* get a dataTableApi instance from global cache
* @param mapId
* @param systemId
* @param tableType
* @returns {*}
*/
let getDataTableInstance = (mapId, systemId, tableType) => Util.getDataTableInstance(config.intelTableId, mapId, systemId, tableType);
/**
* get dataTable id
* @param mapId
@@ -284,8 +291,9 @@ define([
* @param tableApi
* @param systemId
* @param structureData
* @param bulkData
*/
let showStructureDialog = (moduleElement, tableApi, systemId, structureData) => {
let showStructureDialog = (moduleElement, tableApi, systemId, structureData = null, bulkData = null) => {
let structureStatusData = Util.getObjVal(Init, 'structureStatus');
let statusData = Object.keys(structureStatusData).map((k) => {
@@ -322,6 +330,7 @@ define([
let data = {
id: config.structureDialogId,
structureData: structureData,
bulkData: bulkData,
structureStatus: statusData,
nameInputId: config.nameInputId,
statusSelectId: config.statusSelectId,
@@ -334,9 +343,13 @@ define([
requirejs(['text!templates/dialog/structure.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
let title = 'Structure';
if(bulkData){
title += ' <span class="txt-color txt-color-warning">&nbsp;(' + bulkData.length + ' rows)</span>&nbsp;';
}
let structureDialog = bootbox.dialog({
title: 'Structure',
title: title,
message: content,
show: false,
buttons: {
@@ -346,7 +359,9 @@ define([
},
autoFill: {
label: buttonLabelAutoFill,
className: 'btn-primary' + (disableButtonAutoFill ? ' pf-font-italic disabled' : ''),
className: 'btn-primary' +
(disableButtonAutoFill ? ' pf-font-italic disabled' : '') +
(bulkData ? ' hidden' : ''),
callback: function(){
let form = this.find('form');
form.find('#' + config.nameInputId).val(characterStructureName);
@@ -378,7 +393,20 @@ define([
moduleElement.showLoadingAnimation();
let method = formData.id ? 'PATCH' : 'PUT';
Util.request(method, 'structure', formData.id, formData,
let ids = formData.id;
let data = formData;
if(bulkData){
// bulk update multiple rows
method = 'POST';
ids = [];
data = bulkData.map(structureData => {
structureData.corporationId = formData.corporationId;
return structureData;
});
}
Util.request(method, 'structure', ids, data,
{
moduleElement: moduleElement,
tableApi: tableApi
@@ -573,22 +601,6 @@ define([
$('<h5>', {
class: config.moduleHandlerClass
}),
$('<h5>', {
class: 'pull-right'
}).append(
$('<i>', {
class: ['fas', 'fa-fw', 'fa-plus', config.moduleHeadlineIconClass, config.moduleHeadlineIconAddClass].join(' '),
title: 'add'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
$('<i>', {
class: ['fas', 'fa-fw', 'fa-paste', config.moduleHeadlineIconClass, config.moduleHeadlineIconReaderClass].join(' '),
title: 'D-Scan&nbsp;reader'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
$('<i>', {
class: ['fas', 'fa-fw', 'fa-sync', config.moduleHeadlineIconClass, config.moduleHeadlineIconRefreshClass].join(' '),
title: 'refresh&nbsp;all'
}).attr('data-html', 'true').attr('data-toggle', 'tooltip')
),
$('<h5>', {
text: 'Structures'
})
@@ -608,6 +620,10 @@ define([
},
order: [[10, 'desc' ], [0, 'asc' ]],
rowId: rowData => getRowId('structures', rowData.id),
select: {
style: 'os',
selector: 'td:not(.' + config.tableCellActionClass + ')'
},
language: {
emptyTable: 'No structures recorded',
info: '_START_ to _END_ of _MAX_',
@@ -693,7 +709,7 @@ define([
targets: 6,
name: 'note',
title: 'note',
className: [config.tableCellEllipsisClass, 'all'].join(' '),
className: [config.tableCellEllipsisClass, 'all', Util.config.popoverTriggerClass, config.tableCellPopoverClass].join(' '),
data: 'description'
},{
targets: 7,
@@ -726,10 +742,19 @@ define([
$(cell).removeClass(config.tableCellActionClass + ' ' + config.moduleHeadlineIconClass);
}else{
$(cell).on('click', function(e){
// get current row data (important!)
// -> "rowData" param is not current state, values are "on createCell()" state
rowData = tableApi.row( $(cell).parents('tr')).data();
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData);
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();
}
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData, bulkData);
});
}
}
@@ -812,9 +837,9 @@ define([
}
};
$.extend(true, structureDataTableOptions, getDataTableDefaults());
let tableApiStructure = structureTable.DataTable(structureDataTableOptions);
let tableApiStructure = structureTable.DataTable($.extend(true, {}, getDataTableDefaults(), structureDataTableOptions));
// "Responsive" Datatables Plugin
new $.fn.dataTable.Responsive(tableApiStructure);
tableApiStructure.on('responsive-resize', function(e, tableApi, columns){
@@ -822,6 +847,107 @@ define([
tableApi.draw();
});
// "Select" Datatables Plugin
tableApiStructure.select();
// "Buttons" Datatables Plugin
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();
}
});
let buttons = new $.fn.dataTable.Buttons(tableApiStructure, {
dom: {
container: {
tag: 'h5',
className: 'pull-right'
},
button: {
tag: 'i',
className: ['fas', 'fa-fw', config.moduleHeadlineIconClass].join(' '),
},
buttonLiner: {
tag: null
}
},
name: 'tableTools',
buttons: [
{
name: 'selectToggle',
className: ['fa-check-double'].join(' '),
titleAttr: 'select&nbsp;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: 'add',
className: 'fa-plus',
titleAttr: 'add',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config){
showStructureDialog(moduleElement, tableApi, systemData.systemId);
}
},
{
name: 'dScan',
className: 'fa-paste',
titleAttr: 'D-Scan&nbsp;reader',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config ){
showDscanReaderDialog(moduleElement, tableApi, systemData);
}
},
{
name: 'refresh',
className: 'fa-sync',
titleAttr: 'refresh&nbsp;all',
attr: {
'data-toggle': 'tooltip',
'data-html': true
},
action: function(e, tableApi, node, config ){
moduleElement.showLoadingAnimation();
Util.request('GET', 'system', systemData.id, {mapId: mapId},
{
moduleElement: moduleElement,
tableApi: tableApi,
removeMissing: true
},
context => context.moduleElement.hideLoadingAnimation()
).then(payload => callbackUpdateTableRows(payload.context, Util.getObjVal(payload.data, 'structures')));
}
}
]
});
tableApiStructure.buttons().container().appendTo(moduleElement.find('.' + config.moduleHeadClass));
if(showStationTable){
// "Stations" table ---------------------------------------------------------------------------------------
@@ -1057,8 +1183,7 @@ define([
}
};
$.extend(true, stationDataTableOptions, getDataTableDefaults());
let tableApiStation = stationTable.DataTable(stationDataTableOptions);
let tableApiStation = stationTable.DataTable($.extend(true, {}, getDataTableDefaults(), stationDataTableOptions));
new $.fn.dataTable.Responsive(tableApiStation);
@@ -1221,30 +1346,6 @@ define([
let structureTableElement = moduleElement.find('.' + config.systemStructuresTableClass);
let tableApi = structureTableElement.DataTable();
// init structure dialog --------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconAddClass).on('click', function(e){
showStructureDialog(moduleElement, tableApi, systemData.systemId);
});
// init structure dialog --------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconReaderClass).on('click', function(e){
showDscanReaderDialog(moduleElement, tableApi, systemData);
});
// init refresh button ----------------------------------------------------------------------------------------
moduleElement.find('.' + config.moduleHeadlineIconRefreshClass).on('click', function(e){
moduleElement.showLoadingAnimation();
Util.request('GET', 'system', systemData.id, {mapId: mapId},
{
moduleElement: moduleElement,
tableApi: tableApi,
removeMissing: true
},
context => context.moduleElement.hideLoadingAnimation()
).then(payload => callbackUpdateTableRows(payload.context, Util.getObjVal(payload.data, 'structures')));
});
// init listener for global "past" dScan into this page -------------------------------------------------------
moduleElement.on('pf:updateIntelModuleByClipboard', function(e, clipboard){
updateStructureTableByClipboard(systemData, clipboard, {
@@ -1252,6 +1353,38 @@ define([
tableApi: tableApi
});
});
// init popovers for some table cells -------------------------------------------------------------------------
moduleElement.hoverIntent({
over: function(e){
let tableApi = getDataTableInstance(mapId, systemData.id, 'structure');
// simple <table> for layout (CSS)
let cellData = tableApi.cell(this).data();
if(cellData && cellData.length){
let content = '<table><tr><td>' + cellData.replace(/\r?\n/g, '<br />') + '</td></tr></table>';
let options = {
placement: 'top',
html: true,
trigger: 'manual',
container: 'body',
title: '',
content: content,
delay: {
show: 0,
hide: 0
},
};
$(this).popover(options).popover('show');
}
},
out: function(e){
$(this).destroyPopover();
},
selector: '.' + config.tableCellPopoverClass
});
};
/**
@@ -1263,8 +1396,8 @@ define([
let stationTable = moduleElement.find('.' + config.systemStationsTableClass);
let tableApiStructure = structureTable.DataTable();
let tableApiStation = stationTable.DataTable();
tableApiStructure.destroy();
tableApiStation.destroy();
tableApiStructure.destroy(true);
tableApiStation.destroy(true);
};
return {

View File

@@ -1684,23 +1684,25 @@ define([
* @param maxCharLength
*/
let updateCounter = (field, charCounterElement, maxCharLength) => {
let value = field.val();
let inputLength = value.length;
if(field.length){
let value = field.val();
let inputLength = value.length;
// line breaks are 2 characters!
let newLines = value.match(/(\r\n|\n|\r)/g);
let addition = 0;
if(newLines != null){
addition = newLines.length;
}
inputLength += addition;
// line breaks are 2 characters!
let newLines = value.match(/(\r\n|\n|\r)/g);
let addition = 0;
if(newLines != null){
addition = newLines.length;
}
inputLength += addition;
charCounterElement.text(maxCharLength - inputLength);
charCounterElement.text(maxCharLength - inputLength);
if(maxCharLength <= inputLength){
charCounterElement.toggleClass('txt-color-red', true);
}else{
charCounterElement.toggleClass('txt-color-red', false);
if(maxCharLength <= inputLength){
charCounterElement.toggleClass('txt-color-red', true);
}else{
charCounterElement.toggleClass('txt-color-red', false);
}
}
};

View File

@@ -1,256 +0,0 @@
/*!
* Bootstrap Confirmation v1.0.7
* https://github.com/tavicu/bs-confirmation
*/
+function ($) {
'use strict';
//var for check event at body can have only one.
var event_body = false;
// CONFIRMATION PUBLIC CLASS DEFINITION
// ===============================
var Confirmation = function (element, options) {
var that = this;
this.init('confirmation', element, options);
if (options.selector) {
$(element).on('click.bs.confirmation', options.selector, function(e) {
e.preventDefault();
});
} else {
$(element).on('show.bs.confirmation', function(event) {
that.runCallback(that.options.onShow, event, that.$element);
that.$element.addClass('open');
if (that.options.singleton) {
$(that.options.all_selector).not(that.$element).each(function() {
if ($(this).hasClass('open')) {
$(this).confirmation('hide');
}
});
}
}).on('hide.bs.confirmation', function(event) {
that.runCallback(that.options.onHide, event, that.$element);
that.$element.removeClass('open');
}).on('shown.bs.confirmation', function(e) {
if (!that.isPopout() && !event_body) {
return;
}
event_body = $('body').on('click', function (e) {
if (that.$element.is(e.target)) return;
if (that.$element.has(e.target).length) return;
if ($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}).on('click.bs.confirmation', function(e) {
e.preventDefault();
});
}
}
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
Confirmation.VERSION = '1.0.7'
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element) {},
onHide : function(event, element) {},
onConfirm : function(event, element) {},
onCancel : function(event, element) {},
template : '<div class="popover"><div class="arrow"></div>'
+ '<h3 class="popover-title"></h3>'
+ '<div class="popover-content">'
+ ' <a data-apply="confirmation">Yes</a>'
+ ' <a data-dismiss="confirmation">No</a>'
+ '</div>'
+ '</div>'
});
// NOTE: CONFIRMATION EXTENDS popover.js
// ================================
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
Confirmation.prototype.constructor = Confirmation;
Confirmation.prototype.getDefaults = function () {
return Confirmation.DEFAULTS;
}
Confirmation.prototype.setContent = function () {
var that = this;
var $tip = this.tip();
var title = this.getTitle();
var $btnOk = $tip.find('[data-apply="confirmation"]');
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
var options = this.options
$btnOk.addClass(this.getBtnOkClass())
.html(this.getBtnOkLabel())
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
.attr('href', this.getHref())
.attr('target', this.getTarget())
.off('click').on('click', function(event) {
that.runCallback(that.options.onConfirm, event, that.$element);
// If the button is a submit one
if (that.$element.attr('type') == 'submit') {
var form = that.$element.closest('form');
var novalidate = form.attr('novalidate') !== undefined;
if (novalidate || form[0].checkValidity()) {
form.submit();
}
}
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('confirm.bs.confirmation'));
});
$btnCancel.addClass(this.getBtnCancelClass())
.html(this.getBtnCancelLabel())
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
.off('click').on('click', function(event) {
that.runCallback(that.options.onCancel, event, that.$element);
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('cancel.bs.confirmation'));
});
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
$tip.removeClass('fade top bottom left right in');
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
}
Confirmation.prototype.getBtnOkClass = function () {
return this.$element.data('btnOkClass') ||
(typeof this.options.btnOkClass == 'function' ? this.options.btnOkClass.call(this, this.$element) : this.options.btnOkClass);
}
Confirmation.prototype.getBtnOkLabel = function () {
return this.$element.data('btnOkLabel') ||
(typeof this.options.btnOkLabel == 'function' ? this.options.btnOkLabel.call(this, this.$element) : this.options.btnOkLabel);
}
Confirmation.prototype.getBtnOkIcon = function () {
return this.$element.data('btnOkIcon') ||
(typeof this.options.btnOkIcon == 'function' ? this.options.btnOkIcon.call(this, this.$element) : this.options.btnOkIcon);
}
Confirmation.prototype.getBtnCancelClass = function () {
return this.$element.data('btnCancelClass') ||
(typeof this.options.btnCancelClass == 'function' ? this.options.btnCancelClass.call(this, this.$element) : this.options.btnCancelClass);
}
Confirmation.prototype.getBtnCancelLabel = function () {
return this.$element.data('btnCancelLabel') ||
(typeof this.options.btnCancelLabel == 'function' ? this.options.btnCancelLabel.call(this, this.$element) : this.options.btnCancelLabel);
}
Confirmation.prototype.getBtnCancelIcon = function () {
return this.$element.data('btnCancelIcon') ||
(typeof this.options.btnCancelIcon == 'function' ? this.options.btnCancelIcon.call(this, this.$element) : this.options.btnCancelIcon);
}
Confirmation.prototype.getTitle = function () {
return this.$element.data('confirmation-title') ||
this.$element.data('title') ||
this.$element.attr('title') ||
(typeof this.options.title == 'function' ? this.options.title.call(this, this.$element) : this.options.title);
}
Confirmation.prototype.getHref = function () {
return this.$element.data('href') ||
this.$element.attr('href') ||
(typeof this.options.href == 'function' ? this.options.href.call(this, this.$element) : this.options.href);
}
Confirmation.prototype.getTarget = function () {
return this.$element.data('target') ||
this.$element.attr('target') ||
(typeof this.options.target == 'function' ? this.options.target.call(this, this.$element) : this.options.target);
}
Confirmation.prototype.isPopout = function () {
var popout = this.$element.data('popout') ||
(typeof this.options.popout == 'function' ? this.options.popout.call(this, this.$element) : this.options.popout);
if (popout == 'false') popout = false;
return popout
}
Confirmation.prototype.runCallback = function (callback, event, element) {
if (typeof callback == 'function') {
callback.call(this, event, element);
} else if (typeof callback == 'string') {
eval(callback);
}
}
// CONFIRMATION PLUGIN DEFINITION
// =========================
var old = $.fn.confirmation;
$.fn.confirmation = function (option) {
var that = this;
return this.each(function () {
var $this = $(this);
var data = $this.data('bs.confirmation');
var options = typeof option == 'object' && option;
options = options || {};
options.all_selector = that.selector;
if (!data && option == 'destroy') return;
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
if (typeof option == 'string') data[option]();
});
}
$.fn.confirmation.Constructor = Confirmation
// CONFIRMATION NO CONFLICT
// ===================
$.fn.confirmation.noConflict = function () {
$.fn.confirmation = old;
return this;
}
}(jQuery);

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
<div id="{{id}}">
<form role="form" class="form-horizontal">
{{^bulkData}}
<div class="row">
<div class="col-xs-6 ">
<div class="form-group">
@@ -24,8 +25,10 @@
</div>
</div>
</div>
{{/bulkData}}
<div class="row">
{{^bulkData}}
<div class="col-sm-6">
<div class="form-group">
<label class="col-sm-2 control-label" for="{{typeSelectId}}">Type</label>
@@ -38,6 +41,7 @@
</div>
</div>
</div>
{{/bulkData}}
<div class="col-sm-6">
<div class="form-group">
<label class="col-sm-2 control-label" for="{{corporationSelectId}}">Owner</label>
@@ -55,7 +59,7 @@
</div>
</div>
</div>
{{^bulkData}}
<div class="row">
<div class="col-xs-8 col-sm-12">
<div class="form-group">
@@ -70,6 +74,6 @@
</div>
</div>
{{/bulkData}}
</form>
</div>

View File

@@ -1058,7 +1058,7 @@ table{
// icons in headline
.pf-module-icon-button{
margin-left: 5px;
margin-left: 3px;
}
}
}