Merge pull request #700 from exodus4d/develop

v1.4.2
This commit is contained in:
Mark Friedrich
2018-10-08 20:09:06 +02:00
committed by GitHub
108 changed files with 2415 additions and 1043 deletions

View File

@@ -231,13 +231,6 @@ class Map extends Controller\AccessController {
}
}
// Add data that should not be cached =========================================================================
// program mode (e.g. "maintenance") --------------------------------------------------------------------------
$return->programMode = [
'maintenance' => Config::getPathfinderData('login.mode_maintenance')
];
// get SSO error messages that should be shown immediately ----------------------------------------------------
// -> e.g. errors while character switch from previous HTTP requests
if($f3->exists(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR, $message)){

View File

@@ -10,6 +10,7 @@ namespace Controller\Api;
use Controller;
use Model;
use Exception;
class System extends Controller\AccessController {
@@ -79,24 +80,34 @@ class System extends Controller\AccessController {
}
if( !is_null($systemModel) ){
// set/update system custom data
$systemModel->copyfrom($systemData, ['statusId', 'locked', 'rallyUpdated', 'position', 'description']);
try{
// set/update system custom data
$systemModel->copyfrom($systemData, ['statusId', 'locked', 'rallyUpdated', 'position', 'description']);
if($systemModel->save($activeCharacter)){
// get data from "fresh" model (e.g. some relational data has changed: "statusId")
/**
* @var $newSystemModel Model\SystemModel
*/
$newSystemModel = Model\BasicModel::getNew('SystemModel');
$newSystemModel->getById( $systemModel->_id, 0);
$newSystemModel->clearCacheData();
$return->systemData = $newSystemModel->getData();
if($systemModel->save($activeCharacter)){
// get data from "fresh" model (e.g. some relational data has changed: "statusId")
/**
* @var $newSystemModel Model\SystemModel
*/
$newSystemModel = Model\BasicModel::getNew('SystemModel');
$newSystemModel->getById( $systemModel->_id, 0);
$newSystemModel->clearCacheData();
$return->systemData = $newSystemModel->getData();
// broadcast map changes
$this->broadcastMapData($newSystemModel->mapId);
}else{
$return->error = $systemModel->getErrors();
// broadcast map changes
$this->broadcastMapData($newSystemModel->mapId);
}else{
$return->error = $systemModel->getErrors();
}
}catch(Exception\ValidationException $e){
$validationError = (object) [];
$validationError->type = 'error';
$validationError->field = $e->getField();
$validationError->message = $e->getMessage();
$return->error[] = $validationError;
}
}
}
@@ -273,13 +284,14 @@ class System extends Controller\AccessController {
$requestData = (array)$f3->get('POST');
$mapId = (int)$requestData['mapId'];
$systemId = (int)$requestData['systemId'];
$isCcpId = (bool)$requestData['isCcpId'];
$activeCharacter = $this->getCharacter();
$return = (object) [];
if(
!is_null($map = $activeCharacter->getMap($mapId)) &&
!is_null($system = $map->getSystemById($systemId))
!is_null($system = $isCcpId ? $map->getSystemByCCPId($systemId) : $map->getSystemById($systemId))
){
$return->system = $system->getData();
$return->system->signatures = $system->getSignaturesData();

View File

@@ -94,10 +94,11 @@ class SystemModel extends AbstractMapTrackingModel {
'activity-log' => true
],
'description' => [
'type' => Schema::DT_VARCHAR512,
'type' => Schema::DT_TEXT,
'nullable' => false,
'default' => '',
'activity-log' => true
'activity-log' => true,
'validate' => true
],
'posX' => [
'type' => Schema::DT_INT,
@@ -262,6 +263,21 @@ class SystemModel extends AbstractMapTrackingModel {
return $valid;
}
/**
* @param string $key
* @param string $val
* @return bool
* @throws \Exception\ValidationException
*/
protected function validate_description(string $key, string $val): bool {
$valid = true;
if(mb_strlen($val) > 9000){
$valid = false;
$this->throwValidationException($key);
}
return $valid;
}
/**
* setter for system alias
* @param string $alias

View File

@@ -3,7 +3,7 @@
[PATHFINDER]
NAME = Pathfinder
; installed version (used for CSS/JS cache busting)
VERSION = v1.4.1
VERSION = v1.4.2
; contact information [optional]
CONTACT = https://github.com/exodus4d
; public contact email [optional]

View File

@@ -23,6 +23,7 @@
"php-64bit": ">=7.0",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-ctype": "*",
"ext-zmq": ">=1.1.3",
"react/zmq": "0.3.*",

View File

@@ -23,6 +23,7 @@
"php-64bit": ">=7.0",
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-ctype": "*",
"ext-zmq": ">=1.1.3",
"react/zmq": "0.3.*",

View File

@@ -25,37 +25,40 @@ requirejs.config({
admin: './app/admin', // initial start "admin page" view
notification: './app/notification', // "notification" view
jquery: 'lib/jquery-3.3.1.min', // v3.3.1 jQuery
bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript
text: 'lib/requirejs/text', // v2.0.12 A RequireJS/AMD loader plugin for loading text resources.
mustache: 'lib/mustache.min', // v1.0.0 Javascript template engine - http://mustache.github.io
localForage: 'lib/localforage.min', // v1.4.2 localStorage library - https://mozilla.github.io/localForage
velocity: 'lib/velocity.min', // v1.5.1 animation engine - http://julian.com/research/velocity
velocityUI: 'lib/velocity.ui.min', // v5.2.0 plugin for velocity - http://julian.com/research/velocity/#uiPack
slidebars: 'lib/slidebars', // v0.10 Slidebars - side menu plugin http://plugins.adchsm.me/slidebars
jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com
farahey: 'lib/farahey-0.5', // v0.5 jsPlumb "magnetizing" extension - https://github.com/jsplumb/farahey
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel
xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing
morris: 'lib/morris.min', // v0.5.1 Morris.js - graphs and charts
raphael: 'lib/raphael-min', // v2.1.2 Raphaël - required for morris (dependency)
bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com
easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart
peityInlineChart: 'lib/jquery.peity.min', // v3.2.1 Inline Chart - http://benpickles.github.io/peity/
dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select
hoverIntent: 'lib/jquery.hoverIntent.min', // v1.9.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
fullScreen: 'lib/jquery.fullscreen.min', // v0.6.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
select2: 'lib/select2.min', // v4.0.3 Drop Down customization - https://select2.github.io
validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info
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
bootstrapToggle: 'lib/bootstrap-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
lazyload: 'lib/jquery.lazyload.min', // v1.9.5 LazyLoader images - http://www.appelsiini.net/projects/lazyload
sortable: 'lib/sortable.min', // v1.6.0 Sortable - drag&drop reorder - https://github.com/rubaxa/Sortable
jquery: 'lib/jquery-3.3.1.min', // v3.3.1 jQuery
bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript
text: 'lib/requirejs/text', // v2.0.12 A RequireJS/AMD loader plugin for loading text resources.
mustache: 'lib/mustache.min', // v1.0.0 Javascript template engine - http://mustache.github.io
localForage: 'lib/localforage.min', // v1.4.2 localStorage library - https://mozilla.github.io/localForage
velocity: 'lib/velocity.min', // v1.5.1 animation engine - http://julian.com/research/velocity
velocityUI: 'lib/velocity.ui.min', // v5.2.0 plugin for velocity - http://julian.com/research/velocity/#uiPack
slidebars: 'lib/slidebars', // v0.10 Slidebars - side menu plugin http://plugins.adchsm.me/slidebars
jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com
farahey: 'lib/farahey-0.5', // v0.5 jsPlumb "magnetizing" extension - https://github.com/jsplumb/farahey
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel
xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing
morris: 'lib/morris.min', // v0.5.1 Morris.js - graphs and charts
raphael: 'lib/raphael-min', // v2.1.2 Raphaël - required for morris (dependency)
bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com
easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart
peityInlineChart: 'lib/jquery.peity.min', // v3.2.1 Inline Chart - http://benpickles.github.io/peity/
dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select
hoverIntent: 'lib/jquery.hoverIntent.min', // v1.9.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
fullScreen: 'lib/jquery.fullscreen.min', // v0.6.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
select2: 'lib/select2.min', // v4.0.3 Drop Down customization - https://select2.github.io
validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info
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
bootstrapToggle: 'lib/bootstrap-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
lazyload: 'lib/jquery.lazyload.min', // v1.9.5 LazyLoader images - http://www.appelsiini.net/projects/lazyload
sortable: 'lib/sortable.min', // v1.6.0 Sortable - drag&drop reorder - https://github.com/rubaxa/Sortable
'summernote.loader': './app/summernote.loader', // v0.8.10 Summernote WYSIWYG editor -https://summernote.org
'summernote': 'lib/summernote/summernote.min',
// header animation
easePack: 'lib/EasePack.min',
@@ -135,44 +138,47 @@ requirejs.config({
}
},
pnotify: {
deps : ['jquery']
deps: ['jquery']
},
easyPieChart: {
deps : ['jquery']
deps: ['jquery']
},
peityInlineChart: {
deps : ['jquery']
deps: ['jquery']
},
dragToSelect: {
deps : ['jquery']
deps: ['jquery']
},
hoverIntent: {
deps : ['jquery']
deps: ['jquery']
},
fullScreen: {
deps : ['jquery']
deps: ['jquery']
},
select2: {
deps : ['jquery', 'mousewheel'],
deps: ['jquery', 'mousewheel'],
exports: 'Select2'
},
validator: {
deps : ['jquery', 'bootstrap']
deps: ['jquery', 'bootstrap']
},
lazylinepainter: {
deps : ['jquery', 'bootstrap']
deps: ['jquery', 'bootstrap']
},
blueImpGallery: {
deps : ['jquery']
deps: ['jquery']
},
bootstrapConfirmation: {
deps : ['bootstrap']
deps: ['bootstrap']
},
bootstrapToggle: {
deps : ['jquery']
deps: ['jquery']
},
lazyload: {
deps : ['jquery']
deps: ['jquery']
},
summernote: {
deps: ['jquery']
}
}
});

View File

@@ -275,7 +275,8 @@ define([
// exclude some HTML Tags from watcher
if(
e.target.tagName !== 'INPUT' &&
e.target.tagName !== 'TEXTAREA'
e.target.tagName !== 'TEXTAREA' &&
!e.target.classList.contains('note-editable') // Summerstyle editor
){
let key = e.key.toUpperCase();
map[key] = true;

View File

@@ -54,11 +54,6 @@ define([
connectionContextMenuId: 'pf-map-connection-contextmenu',
systemContextMenuId: 'pf-map-system-contextmenu',
// dialogs
systemDialogId: 'pf-system-dialog', // id for system dialog
systemDialogSelectClass: 'pf-system-dialog-select', // class for system select Element
systemDialogStatusSelectId: 'pf-system-dialog-status-select', // id for "status" select
// system security classes
systemSec: 'pf-system-sec'
};
@@ -1325,228 +1320,6 @@ define([
}
};
/**
* save a new system and add it to the map
* @param requestData
* @param context
*/
let saveSystem = (requestData, context) => {
$.ajax({
type: 'POST',
url: Init.path.saveSystem,
data: requestData,
dataType: 'json',
context: context
}).done(function(responseData){
let newSystemData = responseData.systemData;
if( !$.isEmptyObject(newSystemData) ){
Util.showNotify({title: 'New system', text: newSystemData.name, type: 'success'});
// draw new system to map
drawSystem(this.map, newSystemData, this.sourceSystem);
// re/arrange systems (prevent overlapping)
MagnetizerWrapper.setElements(this.map);
if(this.onSuccess){
this.onSuccess();
}
}
// show errors
if(
responseData.error &&
responseData.error.length > 0
){
for(let i = 0; i < responseData.error.length; i++){
let error = responseData.error[i];
Util.showNotify({title: error.field + ' error', text: 'System: ' + error.message, type: error.type});
}
}
}).fail(function(jqXHR, status, error){
let reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveSystem', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
}).always(function(){
if(this.onAlways){
this.onAlways(this);
}
});
};
/**
* open "new system" dialog and add the system to map
* optional the new system is connected to a "sourceSystem" (if available)
*
* @param map
* @param options
*/
let showNewSystemDialog = (map, options) => {
let mapContainer = $(map.getContainer());
// format system status for form select -----------------------------------------------------------------------
// "default" selection (id = 0) prevents status from being overwritten
// -> e.g. keep status information if system was just inactive (active = 0)
let statusData = [{id: 0, text: 'auto'}];
// get current map data ---------------------------------------------------------------------------------------
let mapData = mapContainer.getMapDataFromClient({forceData: true});
let mapSystems = mapData.data.systems;
let mapSystemCount = mapSystems.length;
let mapTypeName = mapContainer.data('typeName');
let maxAllowedSystems = Init.mapTypes[mapTypeName].defaultConfig.max_systems;
// show error if system max count reached ---------------------------------------------------------------------
if(mapSystemCount >= maxAllowedSystems){
Util.showNotify({title: 'Max system count exceeded', text: 'Limit of ' + maxAllowedSystems + ' systems reached', type: 'warning'});
return;
}
// disable systems that are already on it ---------------------------------------------------------------------
let mapSystemIds = [];
for(let i = 0; i < mapSystems.length; i++ ){
mapSystemIds.push( mapSystems[i].systemId );
}
// dialog data ------------------------------------------------------------------------------------------------
let data = {
id: config.systemDialogId,
select2Class: Util.config.select2Class,
selectClass: config.systemDialogSelectClass,
statusSelectId: config.systemDialogStatusSelectId,
statusData: statusData
};
// set current position as "default" system to add ------------------------------------------------------------
let currentCharacterLog = Util.getCurrentCharacterLog();
if(
currentCharacterLog !== false &&
mapSystemIds.indexOf( currentCharacterLog.system.id ) === -1
){
// current system is NOT already on this map
// set current position as "default" system to add
data.currentSystem = currentCharacterLog.system;
}
requirejs(['text!templates/dialog/system.html', 'mustache'], function(template, Mustache){
let content = Mustache.render(template, data);
let systemDialog = bootbox.dialog({
title: 'Add new system',
message: content,
show: false,
buttons: {
close: {
label: 'cancel',
className: 'btn-default'
},
success: {
label: '<i class="fas fa-fw fa-check"></i> save',
className: 'btn-success',
callback: function(e){
// get form Values
let form = $('#' + config.systemDialogId).find('form');
let systemDialogData = $(form).getFormValues();
// validate form
form.validator('validate');
// check whether the form is valid
let formValid = form.isValidForm();
if(formValid === false){
// don't close dialog
return false;
}
// calculate new system position ----------------------------------------------------------
let newPosition = {
x: 0,
y: 0
};
let sourceSystem = null;
// add new position
if(options.sourceSystem !== undefined){
sourceSystem = options.sourceSystem;
// get new position
newPosition = System.calculateNewSystemPosition(sourceSystem);
}else{
// check mouse cursor position (add system to map)
newPosition = {
x: options.position.x,
y: options.position.y
};
}
systemDialogData.position = newPosition;
// ----------------------------------------------------------------------------------------
let requestData = {
systemData: systemDialogData,
mapData: {
id: mapContainer.data('id')
}
};
this.find('.modal-content').showLoadingAnimation();
saveSystem(requestData, {
map: map,
sourceSystem: sourceSystem,
systemDialog: this,
onSuccess: () => {
bootbox.hideAll();
},
onAlways: (context) => {
context.systemDialog.find('.modal-content').hideLoadingAnimation();
}
});
return false;
}
}
}
});
systemDialog.on('show.bs.modal', function(e){
let modalContent = $('#' + config.systemDialogId);
// init "status" select2
for(let [statusName, data] of Object.entries(Init.systemStatus)){
statusData.push({id: data.id, text: data.label, class: data.class});
}
modalContent.find('#' + config.systemDialogStatusSelectId).initStatusSelect({
data: statusData,
iconClass: 'fa-tag'
});
});
systemDialog.on('shown.bs.modal', function(e){
let modalContent = $('#' + config.systemDialogId);
// init system select live search - some delay until modal transition has finished
let selectElement = modalContent.find('.' + config.systemDialogSelectClass);
selectElement.delay(240).initSystemSelect({
key: 'id',
disabledOptions: mapSystemIds
});
});
// show dialog
systemDialog.modal('show');
});
};
/**
* make a system name/alias editable by x-editable
* @param system
@@ -2057,7 +1830,7 @@ define([
switch(action){
case 'add_system':
// add a new system
showNewSystemDialog(map, {sourceSystem: currentSystem} );
System.showNewSystemDialog(map, {sourceSystem: currentSystem}, saveSystemCallback);
break;
case 'lock_system':
@@ -2166,6 +1939,20 @@ define([
Util.singleDoubleClick(system, single, double);
};
/**
* callback after system save
* @param map
* @param newSystemData
* @param sourceSystem
*/
let saveSystemCallback = (map, newSystemData, sourceSystem) => {
// draw new system to map
drawSystem(map, newSystemData, sourceSystem);
// re/arrange systems (prevent overlapping)
MagnetizerWrapper.setElements(map);
};
/**
* mark a dom element (map, system, connection) as changed
*/
@@ -2480,7 +2267,7 @@ define([
position.y = dimensions[0].top;
}
showNewSystemDialog(currentMap, {position: position});
System.showNewSystemDialog(currentMap, {position: position}, saveSystemCallback);
break;
case 'select_all':
currentMapElement.selectAllSystems();
@@ -3022,7 +2809,7 @@ define([
let interval = mapElement.getMapOverlayInterval();
if(
! interval ||
!interval ||
options.forceData === true
){
@@ -3280,7 +3067,7 @@ define([
return {
getMapInstance: getMapInstance,
loadMap: loadMap,
showNewSystemDialog: showNewSystemDialog
saveSystemCallback: saveSystemCallback
};
});

View File

@@ -5,7 +5,7 @@ define([
'jquery',
'app/init',
'app/util'
], function($, Init, Util){
], ($, Init, Util) => {
'use strict';
/**

View File

@@ -29,8 +29,21 @@ define([
systemTooltipInnerIdPrefix: 'pf-system-tooltip-inner-', // id prefix for system tooltip content
systemTooltipInnerClass: 'pf-system-tooltip-inner', // class for system tooltip content
dialogRallyId: 'pf-rally-dialog', // id for "Rally point" dialog
// dialogs
dialogSystemId: 'pf-system-dialog', // id for system dialog
dialogSystemSelectClass: 'pf-system-dialog-select', // class for system select element
dialogSystemStatusSelectId: 'pf-system-dialog-status-select', // id for "status" select
dialogSystemLockId: 'pf-system-dialog-lock', // id for "locked" checkbox
dialogSystemRallyId: 'pf-system-dialog-rally', // id for "rally" checkbox
dialogSystemSectionInfoId: 'pf-system-dialog-section-info', // id for "info" section element
dialogSystemSectionInfoStatusId: 'pf-system-dialog-section-info-status', // id for "status" message in "info" element
dialogSystemAliasId: 'pf-system-dialog-alias', // id for "alias" static element
dialogSystemDescriptionId: 'pf-system-dialog-description', // id for "description" static element
dialogSystemCreatedId: 'pf-system-dialog-created', // id for "created" static element
dialogSystemUpdatedId: 'pf-system-dialog-updated', // id for "updated" static element
dialogRallyId: 'pf-rally-dialog', // id for "Rally point" dialog
dialogRallyPokeDesktopId: 'pf-rally-dialog-poke-desktop', // id for "desktop" poke checkbox
dialogRallyPokeSlackId: 'pf-rally-dialog-poke-slack', // id for "Slack" poke checkbox
dialogRallyPokeDiscordId: 'pf-rally-dialog-poke-discord', // id for "Discord" poke checkbox
@@ -43,6 +56,316 @@ define([
'- DPS and Logistic ships needed'
};
/**
* save a new system and add it to the map
* @param requestData
* @param context
* @param callback
*/
let saveSystem = (requestData, context, callback) => {
$.ajax({
type: 'POST',
url: Init.path.saveSystem,
data: requestData,
dataType: 'json',
context: context
}).done(function(responseData){
let newSystemData = responseData.systemData;
if( !$.isEmptyObject(newSystemData) ){
Util.showNotify({title: 'New system', text: newSystemData.name, type: 'success'});
callback(newSystemData);
}
if(
responseData.error &&
responseData.error.length > 0
){
for(let i = 0; i < responseData.error.length; i++){
let error = responseData.error[i];
Util.showNotify({title: error.field + ' error', text: 'System: ' + error.message, type: error.type});
}
}
}).fail(function(jqXHR, status, error){
let reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveSystem', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
}).always(function(){
this.systemDialog.find('.modal-content').hideLoadingAnimation();
});
};
/**
* open "new system" dialog and add the system to map
* optional the new system is connected to a "sourceSystem" (if available)
* @param map
* @param options
* @param callback
*/
let showNewSystemDialog = (map, options, callback) => {
let mapContainer = $(map.getContainer());
let mapId = mapContainer.data('id');
/**
* update new system dialog with some "additional" data
* -> if system was mapped before
* @param dialogElement
* @param systemData
*/
let updateDialog = (dialogElement, systemData = null) => {
let labelEmpty = '<span class="editable-empty">empty</span>';
let labelUnknown = '<span class="editable-empty">unknown</span>';
let labelExist = '<span class="txt-color txt-color-success">loaded</span>';
let showInfoHeadline = 'fadeOut';
let showInfoSection = 'hide';
let info = labelEmpty;
let statusId = false; // -> no value change
let alias = labelEmpty;
let description = labelEmpty;
let createdTime = labelUnknown;
let updatedTime = labelUnknown;
if(systemData){
// system data found for selected system
showInfoHeadline = 'fadeIn';
showInfoSection = 'show';
info = labelExist;
statusId = parseInt(Util.getObjVal(systemData, 'status.id')) || statusId;
alias = systemData.alias.length ? Util.htmlEncode(systemData.alias) : alias;
description = systemData.description.length ? systemData.description : description;
let dateCreated = new Date(systemData.created.created * 1000);
let dateUpdated = new Date(systemData.updated.updated * 1000);
let dateCreatedUTC = Util.convertDateToUTC(dateCreated);
let dateUpdatedUTC = Util.convertDateToUTC(dateUpdated);
createdTime = Util.convertDateToString(dateCreatedUTC);
updatedTime = Util.convertDateToString(dateUpdatedUTC);
}else if(systemData === null){
// no system found for selected system
showInfoHeadline = 'fadeIn';
}
// update new system dialog with new default data
dialogElement.find('#' + config.dialogSystemSectionInfoStatusId).html(info);
if(statusId !== false){
dialogElement.find('#' + config.dialogSystemStatusSelectId).val(statusId).trigger('change');
}
dialogElement.find('#' + config.dialogSystemAliasId).html(alias);
dialogElement.find('#' + config.dialogSystemDescriptionId).html(description);
dialogElement.find('#' + config.dialogSystemCreatedId).html('<i class="fas fa-fw fa-plus"></i>&nbsp' + createdTime);
dialogElement.find('#' + config.dialogSystemUpdatedId).html('<i class="fas fa-fw fa-pen"></i>&nbsp' + updatedTime);
dialogElement.find('[data-target="#' + config.dialogSystemSectionInfoId + '"]').velocity('stop').velocity(showInfoHeadline, {duration: 120});
dialogElement.find('[data-type="spinner"]').removeClass('in');
dialogElement.find('#' + config.dialogSystemSectionInfoId).collapse(showInfoSection);
};
/**
* request system data from server for persistent data -> update dialog
* @param dialogElement
* @param mapId
* @param systemId
*/
let requestSystemData = (dialogElement, mapId, systemId) => {
// show loading animation
dialogElement.find('[data-type="spinner"]').addClass('in');
MapUtil.requestSystemData({
mapId: mapId,
systemId: systemId,
isCcpId: 1
}, {
dialogElement: dialogElement
}).then(payload => updateDialog(payload.context.dialogElement, payload.data))
.catch(payload => updateDialog(payload.context.dialogElement));
};
// format system status for form select -----------------------------------------------------------------------
// "default" selection (id = 0) prevents status from being overwritten
// -> e.g. keep status information if system was just inactive (active = 0)
let statusData = [{id: 0, text: 'auto'}];
// get current map data ---------------------------------------------------------------------------------------
let mapData = mapContainer.getMapDataFromClient({forceData: true});
let mapSystems = mapData.data.systems;
let mapSystemCount = mapSystems.length;
let mapTypeName = mapContainer.data('typeName');
let maxAllowedSystems = Init.mapTypes[mapTypeName].defaultConfig.max_systems;
// show error if system max count reached ---------------------------------------------------------------------
if(mapSystemCount >= maxAllowedSystems){
Util.showNotify({title: 'Max system count exceeded', text: 'Limit of ' + maxAllowedSystems + ' systems reached', type: 'warning'});
return;
}
// disable systems that are already on it ---------------------------------------------------------------------
let mapSystemIds = mapSystems.map(systemData => systemData.systemId);
// dialog data ------------------------------------------------------------------------------------------------
let data = {
id: config.dialogSystemId,
select2Class: Util.config.select2Class,
systemSelectClass: config.dialogSystemSelectClass,
statusSelectId: config.dialogSystemStatusSelectId,
lockId: config.dialogSystemLockId,
rallyId: config.dialogSystemRallyId,
sectionInfoId: config.dialogSystemSectionInfoId,
sectionInfoStatusId: config.dialogSystemSectionInfoStatusId,
aliasId: config.dialogSystemAliasId,
descriptionId: config.dialogSystemDescriptionId,
createdId: config.dialogSystemCreatedId,
updatedId: config.dialogSystemUpdatedId,
statusData: statusData
};
// set current position as "default" system to add ------------------------------------------------------------
let currentCharacterLog = Util.getCurrentCharacterLog();
if(
currentCharacterLog !== false &&
mapSystemIds.indexOf( currentCharacterLog.system.id ) === -1
){
// current system is NOT already on this map
// set current position as "default" system to add
data.currentSystem = currentCharacterLog.system;
}
requirejs(['text!templates/dialog/system.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
let systemDialog = bootbox.dialog({
title: 'Add new system',
message: content,
show: false,
buttons: {
close: {
label: 'cancel',
className: 'btn-default'
},
success: {
label: '<i class="fas fa-fw fa-check"></i> save',
className: 'btn-success',
callback: function(e){
// get form Values
let form = this.find('form');
let systemDialogData = $(form).getFormValues();
// validate form
form.validator('validate');
// check whether the form is valid
let formValid = form.isValidForm();
// don't close dialog on invalid data
if(formValid === false) return false;
// calculate new system position ----------------------------------------------------------
let newPosition = {
x: 0,
y: 0
};
// add new position
let sourceSystem = null;
if(options.sourceSystem !== undefined){
sourceSystem = options.sourceSystem;
// get new position
newPosition = calculateNewSystemPosition(sourceSystem);
}else{
// check mouse cursor position (add system to map)
newPosition = {
x: options.position.x,
y: options.position.y
};
}
systemDialogData.position = newPosition;
// ----------------------------------------------------------------------------------------
let requestData = {
systemData: systemDialogData,
mapData: {
id: mapId
}
};
this.find('.modal-content').showLoadingAnimation();
saveSystem(requestData, {
systemDialog: this
}, (newSystemData) => {
// success callback
callback(map, newSystemData, sourceSystem);
bootbox.hideAll();
});
return false;
}
}
}
});
systemDialog.on('show.bs.modal', function(e){
let dialogElement = $(this);
// init "status" select2 ------------------------------------------------------------------------------
for(let [statusName, data] of Object.entries(Init.systemStatus)){
statusData.push({id: data.id, text: data.label, class: data.class});
}
dialogElement.find('#' + config.dialogSystemStatusSelectId).initStatusSelect({
data: statusData,
iconClass: 'fa-tag'
});
// initial dialog update with persistent system data --------------------------------------------------
// -> only if system is preselected (e.g. current active system)
let systemId = parseInt(dialogElement.find('.' + config.dialogSystemSelectClass).val()) || 0;
if(systemId){
requestSystemData(dialogElement, mapId, systemId);
}
});
systemDialog.on('shown.bs.modal', function(e){
let dialogElement = $(this);
// no system selected
updateDialog(dialogElement, false);
dialogElement.initTooltips();
// init system select live search - some delay until modal transition has finished
let selectElement = dialogElement.find('.' + config.dialogSystemSelectClass);
selectElement.delay(240).initSystemSelect({
key: 'id',
disabledOptions: mapSystemIds,
onChange: systemId => {
// on system select -> update dialog with persistent system data
if(systemId){
requestSystemData(dialogElement, mapId, systemId);
}else{
// no system selected
updateDialog(dialogElement, false);
}
}
});
});
// show dialog
systemDialog.modal('show');
});
};
/**
* show "set rally point" dialog for system
* @param system
@@ -535,9 +858,9 @@ define([
};
return {
showNewSystemDialog: showNewSystemDialog,
deleteSystems: deleteSystems,
removeSystems: removeSystems,
calculateNewSystemPosition: calculateNewSystemPosition,
getHeadInfoElement: getHeadInfoElement
};
});

View File

@@ -1314,10 +1314,11 @@ define([
// dynamic require Map module -> otherwise there is a require(), loop
let Map = require('app/map/map');
let System = require('app/map/system');
let map = Map.getMapInstance( mapElement.data('id'));
mapWrapper.watchKey('mapSystemAdd', (mapWrapper) => {
Map.showNewSystemDialog(map, {position: {x: 0, y: 0}});
System.showNewSystemDialog(map, {position: {x: 0, y: 0}}, Map.saveSystemCallback);
},{focus: true});
mapWrapper.watchKey('mapSystemsSelect', (mapWrapper) => {
@@ -1617,6 +1618,10 @@ define([
let requestSystemData = (requestData, context) => {
let requestSystemDataExecutor = (resolve, reject) => {
let payload = {
action: 'systemData'
};
$.ajax({
url: Init.path.getSystemData,
type: 'POST',
@@ -1624,17 +1629,20 @@ define([
data: requestData,
context: context
}).done(function(data){
payload.context = this;
if(data.system){
resolve({
action: 'systemData',
context: this,
data: data.system
});
// system data found
payload.data = data.system;
resolve(payload);
}else{
console.warn('Missing systemData in response!', requestData);
// no system data returned/found
reject(payload);
}
}).fail(function(jqXHR, status, error){
console.warn('Fail request systemData!', requestData);
payload.context = this;
reject(payload);
});
};

View File

@@ -136,7 +136,6 @@ define([
Init.structureStatus = response.structureStatus;
Init.universeCategories = response.universeCategories;
Init.routeSearch = response.routeSearch;
Init.programMode = response.programMode;
resolve({
action: 'initData',

187
js/app/summernote.loader.js Normal file
View File

@@ -0,0 +1,187 @@
define([
'jquery',
'app/init',
'summernote'
], ($, Init) => {
'use strict';
// all Summernote stuff is available...
let initDefaultSummernoteConfig = () => {
// "length" hint plugin ---------------------------------------------------------------------------------------
$.extend($.summernote.plugins, {
/**
* @param {Object} context - context object has status of editor.
*/
lengthField: function (context){
let self = this;
let ui = $.summernote.ui;
// add counter
context.memo('button.lengthField', () => {
return $('<kbd>', {
class: ['text-right', 'txt-color'].join(' ')
});
});
/**
* update counter element with left chars
* @param contents
*/
let updateCounter = (contents) => {
let maxTextLength = context.options.maxTextLength;
let textLength = contents.length;
let counter = context.layoutInfo.toolbar.find('kbd');
let counterLeft = maxTextLength - textLength;
counter.text(counterLeft).data('charCount', counterLeft);
counter.toggleClass('txt-color-red', maxTextLength <= textLength);
// disable "save" button
let saveBtn = context.layoutInfo.toolbar.find('.btn-save');
saveBtn.prop('disabled', maxTextLength < textLength);
};
// events
this.events = {
'summernote.init': function (we, e) {
updateCounter(context.$note.summernote('code'));
},
'summernote.change': function(we, contents){
updateCounter(contents);
}
};
}
});
// "discard" button plugin ------------------------------------------------------------------------------------
$.extend($.summernote.plugins, {
/**
* @param {Object} context - context object has status of editor.
*/
discardBtn: function (context){
let self = this;
let ui = $.summernote.ui;
// add button
context.memo('button.discardBtn', () => {
let button = ui.button({
contents: '<i class="fas fa-fw fa-ban"/>',
container: 'body',
click: function(){
// show confirmation dialog
$(this).confirmation('show');
}
});
let $button = button.render();
// show "discard" changes confirmation
let confirmationSettings = {
container: 'body',
placement: 'top',
btnCancelClass: 'btn btn-sm btn-default',
btnCancelLabel: 'cancel',
title: 'discard changes',
btnOkClass: 'btn btn-sm btn-warning',
btnOkLabel: 'discard',
btnOkIcon: 'fas fa-fw fa-ban',
onConfirm: (e, target) => {
// discard all changes
context.$note.summernote('reset');
context.$note.summernote('destroy');
}
};
$button.confirmation(confirmationSettings);
return $button;
});
}
});
};
/**
* init new Summernote editor
* @param element
* @param options
*/
let initSummernote = (element, options) => {
let defaultOptions = {
dialogsInBody: true,
dialogsFade: true,
//textareaAutoSync: false,
//hintDirection: 'right',
//tooltip: 'right',
//container: 'body',
styleTags: ['p', 'h2', 'h3', 'blockquote'],
linkTargetBlank: true,
tableClassName: 'table table-condensed table-bordered',
insertTableMaxSize: {
col: 5,
row: 5
},
icons: {
//'align': 'note-icon-align',
'alignCenter': 'fas fa-align-center',
'alignJustify': 'fas fa-align-justify',
'alignLeft': 'fas fa-align-left',
'alignRight': 'fas fa-align-right',
//'rowBelow': 'note-icon-row-below',
//'colBefore': 'note-icon-col-before',
//'colAfter': 'note-icon-col-after',
//'rowAbove': 'note-icon-row-above',
//'rowRemove': 'note-icon-row-remove',
//'colRemove': 'note-icon-col-remove',
'indent': 'fas fa-indent',
'outdent': 'fas fa-outdent',
'arrowsAlt': 'fas fa-expand-arrows-alt',
'bold': 'fas fa-bold',
'caret': 'fas fa-caret-down',
'circle': 'fas fa-circle',
'close': 'fas fa-time',
'code': 'fas fa-code',
'eraser': 'fas fa-eraser',
'font': 'fas fa-font',
//'frame': 'note-icon-frame',
'italic': 'fas fa-italic',
'link': 'fas fa-link',
'unlink': 'fas fa-unlink',
'magic': 'fas fa-magic',
'menuCheck': 'fas fa-check',
'minus': 'fas fa-minus',
'orderedlist': 'fas fa-list-ol',
'pencil': 'fa-pen',
'picture': 'fas fa-image',
'question': 'fas fa-question',
'redo': 'fas fa-redo',
'square': 'fas fa-square',
'strikethrough': 'fas fa-strikethrough',
'subscript': 'fas fa-subscript',
'superscript': 'fas fa-superscript',
'table': 'fas fa-table',
'textHeight': 'fas fa-text-height',
'trash': 'fas fa-trash',
'underline': 'fas fa-underline',
'undo': 'fas fa-undo',
'unorderedlist': 'fas fa-list-ul',
'video': 'fab fa-youtube'
},
colors: [
['#5cb85c', '#e28a0d', '#d9534f', '#e06fdf', '#9fa8da', '#e2ce48', '#428bca']
],
colorsName: [
['Green', 'Orange', 'Red', 'Pink', 'Indigo', 'Yellow', 'Blue']
],
};
options = $.extend({}, defaultOptions, options);
element.summernote(options);
};
initDefaultSummernoteConfig();
return {
initSummernote: initSummernote
};
});

View File

@@ -1254,7 +1254,7 @@ define([
*/
$.fn.showMapInfoDialog = function(options){
let activeMap = Util.getMapModule().getActiveMap();
let mapData = activeMap.getMapDataFromClient({forceData: true});
let mapData = activeMap ? activeMap.getMapDataFromClient({forceData: true}) : false;
if(mapData !== false){
// "log" tab -> get "Origin", not all config options are set in mapData
@@ -1351,6 +1351,13 @@ define([
});
});
}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'}
);
}
};

View File

@@ -333,11 +333,14 @@ define([
dropdownParent: selectElement.parents('.modal-body'),
minimumInputLength: 3,
templateResult: formatResultData,
placeholder: 'System name',
placeholder: 'Name or ID',
allowClear: true,
maximumSelectionLength: options.maxSelectionLength
}).on('change', function(e){
// select changed
if(options.onChange){
options.onChange(parseInt($(this).val()) || 0);
}
}).on('select2:open', function(){
// clear selected system (e.g. default system)
// => improves usability (not necessary). There is a small "x" if field can be cleared manually

View File

@@ -30,6 +30,9 @@ define([
connectionInfoPanelClass: 'pf-connection-info-panel', // class for connection info panels
connectionInfoPanelId: 'pf-connection-info-panel-', // id prefix for connection info panels
dynamicAreaClass: 'pf-dynamic-area', // class for "dynamic" areas
controlAreaClass: 'pf-module-control-area', // class for "control" areas
// info table
moduleTableClass: 'pf-module-table', // class for module tables
connectionInfoTableLabelSourceClass: 'pf-connection-info-label-source', // class for source label
@@ -107,7 +110,7 @@ define([
*/
let getInfoPanelControl = (mapId) => {
let connectionElement = getConnectionElement(mapId, 0).append($('<div>', {
class: 'pf-dynamic-area',
class: [config.dynamicAreaClass, config.controlAreaClass].join(' '),
html: '<i class="fas fa-fw fa-plus"></i>&nbsp;add connection&nbsp;&nbsp;<kbd>ctrl</kbd>&nbsp;+&nbsp;<kbd>click</kbd>'
}));
@@ -125,7 +128,7 @@ define([
let scopeLabel = MapUtil.getScopeInfoForConnection(connectionData.scope, 'label');
let element = $('<div>', {
class: 'pf-dynamic-area'
class: [config.dynamicAreaClass, config.controlAreaClass].join(' ')
}).append(
$('<table>', {
class: ['table', 'table-condensed', 'pf-table-fixed', config.moduleTableClass].join(' ')

View File

@@ -6,9 +6,8 @@ define([
'jquery',
'app/init',
'app/util',
'app/render',
'app/map/util'
], ($, Init, Util, Render, MapUtil) => {
], ($, Init, Util, MapUtil) => {
'use strict';
let config = {
@@ -38,50 +37,55 @@ define([
systemInfoWormholeClass: 'pf-system-info-wormhole-', // class prefix for static wormhole element
// description field
descriptionArea: 'pf-system-info-description-area', // class for "description" area
descriptionAreaClass: 'pf-system-info-description-area', // class for "description" area
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
moduleElementToolbarClass: 'pf-table-tools', // class for "module toolbar" element
tableToolsActionClass: 'pf-table-tools-action', // class for "edit" action
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (xEditable)
descriptionTextareaCharCounter: 'pf-form-field-char-count', // class for "character counter" element for form field
// fonts
fontTriglivianClass: 'pf-triglivian' // class for "Triglivian" names (e.g. Abyssal systems)
fontTriglivianClass: 'pf-triglivian', // class for "Triglivian" names (e.g. Abyssal systems)
// Summernote
defaultBgColor: '#e2ce48'
};
// disable Module update temporary (in case e.g. textarea is currently active)
let disableModuleUpdate = false;
// animation speed values
let animationSpeedToolbarAction = 200;
// max character length for system description
let maxDescriptionLength = 512;
let maxDescriptionLength = 9000;
/**
* shows the tool action element by animation
* @param toolsActionElement
* save system (description)
* @param requestData
* @param context
* @param callback
*/
let showToolsActionElement = (toolsActionElement) => {
toolsActionElement.velocity('stop').velocity({
opacity: 1,
height: '100%'
},{
duration: animationSpeedToolbarAction,
display: 'block',
visibility: 'visible'
});
};
let saveSystem = (requestData, context, callback) => {
context.descriptionArea.showLoadingAnimation();
/**
* hides the tool action element by animation
* @param toolsActionElement
*/
let hideToolsActionElement = (toolsActionElement) => {
toolsActionElement.velocity('stop').velocity('reverse', {
display: 'none',
visibility: 'hidden'
$.ajax({
type: 'POST',
url: Init.path.saveSystem,
data: requestData,
dataType: 'json',
context: context
}).done(function(responseData){
let newSystemData = responseData.systemData;
if( !$.isEmptyObject(newSystemData) ){
callback(newSystemData);
}
if(
responseData.error &&
responseData.error.length > 0
){
for(let error of responseData.error){
Util.showNotify({title: error.field + ' error', text: 'System: ' + error.message, type: error.type});
}
}
}).fail(function(jqXHR, status, error){
let reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveSystem', text: reason, type: 'warning'});
}).always(function(){
this.descriptionArea.hideLoadingAnimation();
});
};
@@ -93,8 +97,24 @@ define([
*/
let updateModule = (moduleElement, systemData) => {
let systemId = moduleElement.data('id');
let updated = moduleElement.data('updated');
if(
systemId === systemData.id &&
updated !== systemData.updated.updated
){
let setUpdated = true;
// created/updated tooltip --------------------------------------------------------------------------------
let nameRowElement = moduleElement.find('.' + config.systemInfoNameClass);
let tooltipData = {
created: systemData.created,
updated: systemData.updated
};
nameRowElement.addCharacterInfoTooltip( tooltipData );
if(systemId === systemData.id){
// update system status -----------------------------------------------------------------------------------
let systemStatusLabelElement = moduleElement.find('.' + config.systemInfoStatusLabelClass);
let systemStatusId = parseInt( systemStatusLabelElement.attr( config.systemInfoStatusAttributeName ) );
@@ -112,45 +132,33 @@ define([
// update description textarea ----------------------------------------------------------------------------
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
let description = descriptionTextareaElement.editable('getValue', true);
if(descriptionTextareaElement.length){
let description = descriptionTextareaElement.html();
if(description !== systemData.description){
// description has changed
if(typeof descriptionTextareaElement.data().summernote === 'object'){
// "Summernote" editor is currently open
setUpdated = false;
}else{
// not open
let newDescription = systemData.description;
if( !Util.isValidHtml(newDescription) ){
// try to convert raw text into valid html
newDescription = newDescription.replace(/(\r\n|\n|\r)/g, '<br>');
newDescription = '<p>' + newDescription + '</p>';
}
if(
!disableModuleUpdate && // don´t update if field is active
description !== systemData.description
){
// description changed
let descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
// set new value
descriptionTextareaElement.editable('setValue', systemData.description);
let actionElement = descriptionButton.siblings('.' + config.tableToolsActionClass);
if(systemData.description.length === 0){
// show/activate description field
// show button if value is empty
descriptionButton.show();
hideToolsActionElement(actionElement);
}else{
// hide/disable description field
// hide tool button
descriptionButton.hide();
showToolsActionElement(actionElement);
descriptionTextareaElement.html(newDescription);
}
}
}
// created/updated tooltip --------------------------------------------------------------------------------
let nameRowElement = moduleElement.find('.' + config.systemInfoNameClass);
let tooltipData = {
created: systemData.created,
updated: systemData.updated
};
nameRowElement.addCharacterInfoTooltip( tooltipData );
if(setUpdated){
moduleElement.data('updated', systemData.updated.updated);
}
}
moduleElement.find('.' + config.descriptionArea).hideLoadingAnimation();
moduleElement.find('.' + config.descriptionAreaClass).hideLoadingAnimation();
};
/**
@@ -181,188 +189,7 @@ define([
let effectName = MapUtil.getEffectInfoForSystem(systemData.effect, 'name');
let effectClass = MapUtil.getEffectInfoForSystem(systemData.effect, 'class');
// systemInfo template config
let moduleConfig = {
name: 'modules/system_info',
position: moduleElement,
link: 'append',
functions: {
after: function(conf){
let tempModuleElement = conf.position;
// lock "description" field until first update
tempModuleElement.find('.' + config.descriptionArea).showLoadingAnimation();
// "add description" button
let descriptionButton = tempModuleElement.find('.' + config.addDescriptionButtonClass);
// description textarea element
let descriptionTextareaElement = tempModuleElement.find('.' + config.descriptionTextareaElementClass);
// init description textarea
descriptionTextareaElement.editable({
url: Init.path.saveSystem,
dataType: 'json',
pk: systemData.id,
type: 'textarea',
mode: 'inline',
emptytext: '',
onblur: 'cancel',
showbuttons: true,
value: '', // value is set by trigger function updateModule()
rows: 5,
name: 'description',
inputclass: config.descriptionTextareaElementClass,
tpl: '<textarea maxlength="' + maxDescriptionLength + '"></textarea>',
params: function(params){
params.mapData = {
id: mapId
};
params.systemData = {};
params.systemData.id = params.pk;
params.systemData[params.name] = params.value;
// clear unnecessary data
delete params.pk;
delete params.name;
delete params.value;
return params;
},
validate: function(value){
if(value.length > 0 && $.trim(value).length === 0){
return {newValue: ''};
}
},
success: function(response, newValue){
Util.showNotify({title: 'System updated', text: 'Name: ' + response.name, type: 'success'});
},
error: function(jqXHR, newValue){
let reason = '';
let status = '';
if(jqXHR.name){
// save error new sig (mass save)
reason = jqXHR.name;
status = 'Error';
}else{
reason = jqXHR.responseJSON.text;
status = jqXHR.status;
}
Util.showNotify({title: status + ': save system information', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
return reason;
}
});
// on xEditable open ------------------------------------------------------------------------------
descriptionTextareaElement.on('shown', function(e, editable){
let textarea = editable.input.$input;
// disable module update until description field is open
disableModuleUpdate = true;
// create character counter
let charCounter = $('<kbd>', {
class: [config.descriptionTextareaCharCounter, 'txt-color', 'text-right'].join(' ')
});
textarea.parent().next().append(charCounter);
// update character counter
Util.updateCounter(textarea, charCounter, maxDescriptionLength);
textarea.on('keyup', function(){
Util.updateCounter($(this), charCounter, maxDescriptionLength);
});
});
// on xEditable close -----------------------------------------------------------------------------
descriptionTextareaElement.on('hidden', function(e){
let value = $(this).editable('getValue', true);
if(value.length === 0){
// show button if value is empty
hideToolsActionElement(descriptionButton.siblings('.' + config.tableToolsActionClass));
descriptionButton.show();
}
// enable module update
disableModuleUpdate = false;
});
// enable xEditable field on Button click ---------------------------------------------------------
descriptionButton.on('click', function(e){
e.stopPropagation();
let descriptionButton = $(this);
// hide tool buttons
descriptionButton.hide();
// show field *before* showing the element
descriptionTextareaElement.editable('show');
showToolsActionElement(descriptionButton.siblings('.' + config.tableToolsActionClass));
});
// init tooltips ----------------------------------------------------------------------------------
let tooltipElements = tempModuleElement.find('[data-toggle="tooltip"]');
tooltipElements.tooltip({
container: 'body',
placement: 'top'
});
// init system effect popover ---------------------------------------------------------------------
tempModuleElement.find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
// init planets popover ---------------------------------------------------------------------------
tempModuleElement.find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
// init static wormhole information ---------------------------------------------------------------
for(let staticData of staticsData){
let staticRowElement = tempModuleElement.find('.' + config.systemInfoWormholeClass + staticData.name);
staticRowElement.addWormholeInfoTooltip(staticData);
}
// copy system deeplink URL -----------------------------------------------------------------------
tempModuleElement.find('.' + config.urlLinkClass).on('click', function(){
let mapUrl = $(this).attr('data-url');
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
// constellation popover --------------------------------------------------------------------------
tempModuleElement.find('a.popup-ajax').popover({
html: true,
trigger: 'hover',
placement: 'top',
delay: 200,
container: 'body',
content: function(){
return details_in_popup(this);
}
});
function details_in_popup(popoverElement){
popoverElement = $(popoverElement);
let popover = popoverElement.data('bs.popover');
$.ajax({
url: popoverElement.data('url'),
success: function(data){
let systemEffectTable = Util.getSystemsInfoTable( data.systemsData );
popover.options.content = systemEffectTable;
// reopen popover (new content size)
popover.show();
}
});
return 'Loading...';
}
}
}
};
let moduleData = {
let data = {
system: systemData,
static: staticsData,
moduleHeadlineIconClass: config.moduleHeadlineIconClass,
@@ -385,9 +212,8 @@ define([
trueSecClass: Util.getTrueSecClassForSystem( systemData.trueSec ),
effectName: effectName,
effectClass: effectClass,
moduleToolbarClass: config.moduleElementToolbarClass,
descriptionAreaClass: config.descriptionAreaClass,
descriptionButtonClass: config.addDescriptionButtonClass,
tableToolsActionClass: config.tableToolsActionClass,
descriptionTextareaClass: config.descriptionTextareaElementClass,
systemNameClass: () => {
return (val, render) => {
@@ -409,7 +235,189 @@ define([
systemUrlLinkClass: config.urlLinkClass
};
Render.showModule(moduleConfig, moduleData);
requirejs(['text!templates/modules/system_info.html', 'mustache', 'summernote.loader'], (template, Mustache, Summernote) => {
let content = Mustache.render(template, data);
moduleElement.append(content);
let descriptionArea = moduleElement.find('.' + config.descriptionAreaClass);
let descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
// lock "description" field until first update
descriptionArea.showLoadingAnimation();
// WYSIWYG init on button click ---------------------------------------------------------------------------
descriptionButton.on('click', function(e){
e.stopPropagation();
let descriptionButton = $(this);
// hide edit button
descriptionButton.hide();
// content has changed
let descriptionChanged = false;
Summernote.initSummernote(descriptionTextareaElement, {
height: 75, // set editor height
minHeight: 75, // set minimum height of editor
maxHeight: 500, // set maximum height of editor
focus: true,
placeholder: false,
maxTextLength: maxDescriptionLength,
disableDragAndDrop: true,
shortcuts: false,
toolbar: [
['style', ['style']],
['font', ['underline', 'strikethrough', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
['insert', ['link', 'hr']],
//['view', ['codeview', 'help']],
['misc', ['undo', 'redo']],
['lengthField'],
['customBtn', ['discardBtn', 'saveBtn']]
],
buttons: {
saveBtn: context => {
let ui = $.summernote.ui;
let button = ui.button({
contents: '<i class="fas fa-fw fa-check"/>',
container: 'body',
className: ['btn-success', 'btn-save'],
click: e => {
context.layoutInfo.editable.removeClass('has-error');
// save changes
if(descriptionChanged){
let validDescription = true;
let description = '';
if( context.$note.summernote('isEmpty') ){
// ... isEmpty -> clear empty default tags as well
context.$note.summernote('code', '');
}else{
description = context.$note.summernote('code');
if( !Util.isValidHtml(description) ){
// ... not valid HTML
validDescription = false;
context.layoutInfo.editable.addClass('has-error');
Util.showNotify({title: 'Validation failed', text: 'HTML not valid', type: 'error'});
}
}
if(validDescription){
// ... valid -> save()
saveSystem({
mapData: {
id: mapId
},
systemData: {
id: systemData.id,
description: description
}
}, {
descriptionArea: descriptionArea
}, (systemData) => {
// .. save callback
context.$note.summernote('destroy');
updateModule(moduleElement, systemData);
});
}
}else{
// ... no changes -> no save()
context.$note.summernote('destroy');
}
}
});
return button.render();
}
},
callbacks: {
onInit: function(context){
// make editable field a big larger
context.editable.css('height', '150px');
// set default background color
// -> could not figure out how to set by API as default color
context.toolbar.find('.note-current-color-button').attr('data-backcolor', config.defaultBgColor)
.find('.note-recent-color').css('background-color', config.defaultBgColor);
},
onChange: function(contents){
descriptionChanged = true;
},
onPaste: function (e) {
let bufferText = ((e.originalEvent || e).clipboardData || window.clipboardData).getData('Text');
e.preventDefault();
// Firefox fix
setTimeout(() => {
document.execCommand('insertText', false, bufferText);
}, 10);
},
onDestroy: function(context){
descriptionButton.show();
}
}
});
});
// init system effect popover -----------------------------------------------------------------------------
moduleElement.find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
// init planets popover -----------------------------------------------------------------------------------
moduleElement.find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
// init static wormhole information -----------------------------------------------------------------------
for(let staticData of staticsData){
let staticRowElement = moduleElement.find('.' + config.systemInfoWormholeClass + staticData.name);
staticRowElement.addWormholeInfoTooltip(staticData);
}
// copy system deeplink URL -------------------------------------------------------------------------------
moduleElement.find('.' + config.urlLinkClass).on('click', function(){
let mapUrl = $(this).attr('data-url');
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
// constellation popover ----------------------------------------------------------------------------------
moduleElement.find('a.popup-ajax').popover({
html: true,
trigger: 'hover',
placement: 'top',
delay: 200,
container: 'body',
content: function(){
return details_in_popup(this);
}
});
let details_in_popup = popoverElement => {
popoverElement = $(popoverElement);
let popover = popoverElement.data('bs.popover');
$.ajax({
url: popoverElement.data('url'),
success: function(data){
popover.options.content = Util.getSystemsInfoTable(data.systemsData);
// reopen popover (new content size)
popover.show();
}
});
return 'Loading...';
};
// init tooltips ------------------------------------------------------------------------------------------
let tooltipElements = moduleElement.find('[data-toggle="tooltip"]');
tooltipElements.tooltip({
container: 'body',
placement: 'top'
});
});
return moduleElement;
};
@@ -418,10 +426,8 @@ define([
* efore module destroy callback
* @param moduleElement
*/
let beforeDestroy = (moduleElement) => {
// remove xEditable description textarea
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
descriptionTextareaElement.editable('destroy');
let beforeDestroy = moduleElement => {
moduleElement.find('.' + config.descriptionTextareaElementClass).summernote('destroy');
moduleElement.destroyPopover(true);
};
@@ -433,6 +439,3 @@ define([
beforeDestroy: beforeDestroy
};
});

View File

@@ -22,7 +22,6 @@ define([
// system killboard module
moduleTypeClass: 'pf-system-killboard-module', // class for this module
systemKillboardGraphKillsClass: 'pf-system-killboard-graph-kills', // class for system kill graph
// system killboard list
systemKillboardListClass: 'pf-system-killboard-list', // class for a list with kill entries
@@ -30,12 +29,18 @@ define([
systemKillboardListImgShip: 'pf-system-killboard-img-ship', // class for all ship images
systemKillboardListImgChar: 'pf-system-killboard-img-char', // class for all character logos
systemKillboardListImgAlly: 'pf-system-killboard-img-ally', // class for all alliance logos
systemKillboardListImgCorp: 'pf-system-killboard-img-corp' // class for all corp logos
systemKillboardListImgCorp: 'pf-system-killboard-img-corp', // class for all corp logos
labelRecentKillsClass: 'pf-system-killboard-label-recent', // class for "recent kills" label
dynamicAreaClass: 'pf-dynamic-area', // class for "dynamic" areas
controlAreaClass: 'pf-module-control-area', // class for "control" areas
minCountKills: 5,
chunkCountKills: 5,
maxCountKills: 43
};
let cache = {
systemKillsGraphData: {} // data for system kills info graph
};
let cache = {};
/**
*
@@ -43,81 +48,143 @@ define([
* @param options
* @returns {jQuery}
*/
let getLabel = (text, options) => {
let label = $('<span>', {
class: ['label', options.type, options.align].join(' ')
}).text( text );
let getLabel = (text, options) => $('<span>', {
class: ['label', options.type, options.align, options.class].join(' ')
}).text(text);
/**
* get killmail data from ESI
* @param requestData
* @param context
* @param callback
*/
let loadKillmailData = (requestData, context, callback) => {
let cacheKey = 'killmail_' + requestData.killId;
if(cache[cacheKey]){
// ... already cached -> return from cache
callback(context, cache[cacheKey])
.then(payload => showKills(payload.data.killboardElement, payload.data.systemId, payload.data.chunkSize));
}else{
// ...not cached -> request data
let url = 'https://esi.evetech.net/latest/killmails/' + requestData.killId + '/' + requestData.hash + '/';
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
context: context
}).done(function(responseData){
cache[cacheKey] = responseData;
callback(this, responseData)
.then(payload => showKills(payload.data.killboardElement, payload.data.systemId, payload.data.chunkSize));
}).fail(function(jqXHR, status, error){
// request failed -> skip this and load next
showKills(this.killboardElement, this.systemId, this.chunkSize);
});
}
return label;
};
/**
* show killMails
* @param moduleElement
* @param killboardData
* load a chunk of killmails and render them
* @param killboardElement
* @param systemId
* @param chunkSize
*/
let showKillmails = (moduleElement, killboardData) => {
let showKills = (killboardElement, systemId, chunkSize) => {
if(chunkSize){
if(
killboardElement.children().length < config.maxCountKills &&
cache['zkb_' + systemId].length
){
// next killmail to load
let nextZkb = cache['zkb_' + systemId].shift();
// show number of killMails
let killMailCounterMax = 20;
let killMailCounter = 0;
// change order (show right to left)
killboardData.tableData.reverse();
let data = {
tableData: killboardData.tableData,
systemKillboardListClass: config.systemKillboardListClass,
systemKillboardListEntryClass: config.systemKillboardListEntryClass,
systemKillboardListImgShip: config.systemKillboardListImgShip,
systemKillboardListImgChar: config.systemKillboardListImgChar,
systemKillboardListImgAlly: config.systemKillboardListImgAlly,
systemKillboardListImgCorp: config.systemKillboardListImgCorp,
zKillboardUrl: 'https://zkillboard.com',
ccpImageServerUrl: Init.url.ccpImageServer,
dateFormat: () => {
return (val, render) => {
let killDate = Util.convertDateToUTC(new Date(render(val)));
return Util.convertDateToString(killDate);
};
},
iskFormat: () => {
return (val, render) => {
return Util.formatPrice(render(val));
};
},
checkRender : () => {
return (val, render) => {
if(killMailCounter < killMailCounterMax){
return render(val);
}
};
},
increaseCount : () => {
return (val, render) => {
killMailCounter++;
};
loadKillmailData({
killId: parseInt(nextZkb.killmail_id) || 0,
hash: nextZkb.zkb.hash
}, {
chunkSize: --chunkSize,
zkb: nextZkb.zkb,
systemId: systemId,
killboardElement: killboardElement
}, renderKillmail);
}else{
// no more kills available OR max kills reached
killboardElement.closest('.' + config.moduleTypeClass).find('.' + config.controlAreaClass).hide();
}
}
};
/**
* render a single killmail
* @param context
* @param killmailData
* @returns {Promise<any>}
*/
let renderKillmail = (context, killmailData) => {
let renderKillmailExecutor = (resolve, reject) => {
// calculate time diff in hours
let serverDate= Util.getServerTime();
let killDate = Util.convertDateToUTC(new Date(killmailData.killmail_time));
// get time diff
let timeDiffMin = Math.round((serverDate - killDate) / 1000 / 60);
let timeDiffHour = Math.floor(timeDiffMin / 60);
let data = {
zkb: context.zkb,
killmail: killmailData,
systemKillboardListEntryClass: config.systemKillboardListEntryClass,
systemKillboardListImgShip: config.systemKillboardListImgShip,
systemKillboardListImgChar: config.systemKillboardListImgChar,
systemKillboardListImgCorp: config.systemKillboardListImgCorp,
systemKillboardListImgAlly: config.systemKillboardListImgAlly,
zKillboardUrl: 'https://zkillboard.com',
ccpImageServerUrl: Init.url.ccpImageServer,
dateFormat: () => {
return (val, render) => {
let killDate = Util.convertDateToUTC(new Date(render(val)));
return Util.convertDateToString(killDate);
};
},
iskFormat: () => {
return (val, render) => {
return Util.formatPrice(render(val));
};
},
};
requirejs(['text!templates/modules/killmail.html', 'mustache'], (template, Mustache) => {
// show hint for recent kills -------------------------------------------------------------------------
if(timeDiffHour === 0){
context.killboardElement.siblings('.' + config.labelRecentKillsClass).css('display', 'block');
}
// render killmail entry ------------------------------------------------------------------------------
let content = Mustache.render(template, data);
context.killboardElement.append(content);
// animate kill li-element ----------------------------------------------------------------------------
context.killboardElement.children().last().velocity('transition.expandIn', {
complete: function(){
$(this).find('[title]').tooltip({
container: 'body'
});
}
});
resolve({
action: 'renderKillmail',
data: context
});
});
};
requirejs(['text!templates/modules/killboard.html', 'mustache'], function(template, Mustache){
let content = Mustache.render(template, data);
moduleElement.append(content);
// animate kill li-elements
$('.' + config.systemKillboardListEntryClass).velocity('transition.expandIn', {
stagger: 50,
complete: function(){
// init tooltips
moduleElement.find('[title]').tooltip({
container: 'body'
});
}
});
});
return new Promise(renderKillmailExecutor);
};
/**
@@ -127,214 +194,69 @@ define([
$.fn.updateSystemInfoGraphs = function(systemData){
let moduleElement = $(this);
let killboardGraphElement = $('<div>', {
class: config.systemKillboardGraphKillsClass
});
moduleElement.append(killboardGraphElement);
let showHours = 24;
let maxKillmailCount = 200; // limited by API
let labelOptions = {
align: 'center-block'
};
let label = '';
// private function draws a "system kills" graph
let drawGraph = function(data){
let tableData = data.tableData;
// get kills within the last 24h
let timeFrameInSeconds = 60 * 60 * 24;
// change order (show right to left)
tableData.reverse();
if(data.count === 0){
labelOptions.type = 'label-success';
label = getLabel('No kills found within the last 24h', labelOptions );
killboardGraphElement.append( label );
minifyKillboardGraphElement(killboardGraphElement);
return;
}
let labelYFormat = function(y){
return Math.round(y);
};
// draw chart
Morris.Bar({
element: killboardGraphElement,
resize: true,
redraw: true,
grid: true,
gridStrokeWidth: 0.3,
gridTextSize: 9,
gridTextColor: '#63676a',
gridTextFamily: 'Oxygen Bold',
hideHover: true,
data: tableData,
xkey: 'label',
ykeys: ['kills'],
labels: ['Kills'],
yLabelFormat: labelYFormat,
xLabelMargin: 10,
padding: 10,
parseTime: false,
barOpacity: 0.8,
barRadius: [2, 2, 0, 0],
barSizeRatio: 0.5,
barGap: 3,
barColors: function(row, series, type){
if(type === 'bar'){
// highlight last row -> recent kills found
if(this.xmax === row.x){
return '#c2760c';
}
}
return '#375959';
}
});
// show hint for recent kills
if(tableData[tableData.length - 1].kills > 0){
labelOptions.type = 'label-warning';
label = getLabel( tableData[tableData.length - 1].kills + ' kills within the last hour', labelOptions );
killboardGraphElement.prepend( label );
}
};
// get recent KB stats (last 24h))
let localDate = new Date();
// cache result for 5min
let cacheKey = systemData.systemId + '_' + localDate.getHours() + '_' + ( Math.ceil( localDate.getMinutes() / 5 ) * 5);
if(cache.systemKillsGraphData.hasOwnProperty(cacheKey) ){
// cached results
drawGraph( cache.systemKillsGraphData[cacheKey] );
// show killmail information
showKillmails(moduleElement, cache.systemKillsGraphData[cacheKey]);
}else{
// chart data
let chartData = [];
for(let i = 0; i < showHours; i++){
let tempData = {
label: i + 'h',
kills: 0
};
chartData.push(tempData);
}
// get kills within the last 24h
let timeFrameInSeconds = 60 * 60 * 24;
// get current server time
let serverDate= Util.getServerTime();
// if system is w-space system -> add link modifier
let wSpaceLinkModifier = '';
if(systemData.type.id === 1){
wSpaceLinkModifier = 'w-space/';
}
let url = Init.url.zKillboard + '/';
url += 'no-items/' + wSpaceLinkModifier + 'no-attackers/solarSystemID/' + systemData.systemId + '/pastSeconds/' + timeFrameInSeconds + '/';
killboardGraphElement.showLoadingAnimation();
$.ajax({
url: url,
type: 'GET',
dataType: 'json'
}).done(function(kbData){
// the API wont return more than 200KMs ! - remember last bar block with complete KM information
let lastCompleteDiffHourData = 0;
// loop kills and count kills by hour
for(let i = 0; i < kbData.length; i++){
let killmailData = kbData[i];
let killDate = Util.convertDateToUTC(new Date(killmailData.killmail_time));
// get time diff
let timeDiffMin = Math.round(( serverDate - killDate ) / 1000 / 60);
let timeDiffHour = Math.floor(timeDiffMin / 60);
// update chart data
if(chartData[timeDiffHour]){
chartData[timeDiffHour].kills++;
// add kill mail data
if(chartData[timeDiffHour].killmails === undefined){
chartData[timeDiffHour].killmails = [];
}
chartData[timeDiffHour].killmails.push(killmailData);
if(timeDiffHour > lastCompleteDiffHourData){
lastCompleteDiffHourData = timeDiffHour;
}
}
}
// remove empty chart Data
if(kbData.length >= maxKillmailCount){
chartData = chartData.splice(0, lastCompleteDiffHourData + 1);
}
// fill cache
cache.systemKillsGraphData[cacheKey] = {};
cache.systemKillsGraphData[cacheKey].tableData = chartData;
cache.systemKillsGraphData[cacheKey].count = kbData.length;
// draw table
drawGraph(cache.systemKillsGraphData[cacheKey]);
// show killmail information
showKillmails(moduleElement, cache.systemKillsGraphData[cacheKey]);
killboardGraphElement.hideLoadingAnimation();
}).fail(function(e){
labelOptions.type = 'label-danger';
label = getLabel( 'zKillboard is not responding', labelOptions );
killboardGraphElement.prepend( label );
killboardGraphElement.hideLoadingAnimation();
minifyKillboardGraphElement(killboardGraphElement);
Util.showNotify({title: e.status + ': Get system kills', text: 'Loading failed', type: 'error'});
});
// if system is w-space system -> add link modifier
let wSpaceLinkModifier = '';
if(systemData.type.id === 1){
wSpaceLinkModifier = 'w-space/';
}
let url = Init.url.zKillboard + '/';
url += 'no-items/' + wSpaceLinkModifier + 'no-attackers/npc/0/solarSystemID/' + systemData.systemId + '/pastSeconds/' + timeFrameInSeconds + '/';
moduleElement.showLoadingAnimation();
$.ajax({
url: url,
type: 'GET',
dataType: 'json'
}).done(function(result){
// zkb result needs to be cached and becomes reduced on "load more"
let cacheKey = 'zkb_' + systemData.systemId;
cache[cacheKey] = result;
if(result.length){
// kills found -> insert hidden warning for recent kills
labelOptions.type = 'label-warning';
labelOptions.class = config.labelRecentKillsClass;
let label = getLabel('recent kills within the last hour', labelOptions);
moduleElement.append(label);
let killboardElement = $('<ul>', {
class: config.systemKillboardListClass
});
moduleElement.append(killboardElement);
moduleElement.append(getControlElement());
showKills(killboardElement, systemData.systemId, config.chunkCountKills);
}else{
// no kills found
labelOptions.type = 'label-success';
label = getLabel('No kills found within the last 24h', labelOptions);
moduleElement.append(label);
}
}).fail(function(e){
labelOptions.type = 'label-danger';
label = getLabel('zKillboard is not responding', labelOptions);
moduleElement.find('.' + config.moduleHeadClass).after(label);
Util.showNotify({title: e.status + ': Get system kills', text: 'Loading failed', type: 'error'});
}).always(function(){
moduleElement.hideLoadingAnimation();
});
// init tooltips
let tooltipElements = moduleElement.find('[data-toggle="tooltip"]');
tooltipElements.tooltip({
container: 'body'
});
};
/**
* minify the killboard graph element e.g. if no kills where found, or on error
* @param killboardGraphElement
*/
let minifyKillboardGraphElement = (killboardGraphElement) => {
killboardGraphElement.velocity({
height: '20px',
marginBottom: '0px'
},{
duration: Init.animationSpeed.mapModule
});
};
/**
@@ -364,6 +286,29 @@ define([
return headlineToolbar;
};
/**
* get info control element
* @returns {void|jQuery|*}
*/
let getControlElement = () => {
let controlElement = $('<div>', {
class: [config.dynamicAreaClass, config.controlAreaClass, config.moduleHeadlineIconClass].join(' '),
html: '<i class="fas fa-sync"></i>&nbsp;&nbsp;load more'
});
return controlElement;
};
/**
* @param moduleElement
* @param systemData
*/
let setModuleObserver = (moduleElement, systemData) => {
moduleElement.on('click', '.' + config.controlAreaClass, function(){
let killboardElement = moduleElement.find('.' + config.systemKillboardListClass);
showKills(killboardElement, systemData.systemId, config.chunkCountKills);
});
};
/**
* before module "show" callback
* @param moduleElement
@@ -396,6 +341,8 @@ define([
)
);
setModuleObserver(moduleElement, systemData);
return moduleElement;
};

View File

@@ -606,7 +606,12 @@ define([
let signatureOptions = {
deleteOld: (formData.deleteOld) ? 1 : 0
};
updateSignatureTableByClipboard(moduleElement, systemData, formData.clipboard, signatureOptions);
let mapId = moduleElement.data('mapId');
let systemId = moduleElement.data('systemId');
let tableApi = getDataTableInstance(mapId, systemId, 'primary');
updateSignatureTableByClipboard(tableApi, systemData, formData.clipboard, signatureOptions);
}
}
}
@@ -975,7 +980,6 @@ define([
let activateNextCell = (tableApi, cell, columnSelectors) => {
let nextCell = searchNextCell(tableApi, cell, columnSelectors);
activateCell(nextCell);
let test;
};
/**
@@ -1149,6 +1153,22 @@ define([
// xEditable sets 'tabindex = -1'
};
/**
* en/disables xEditable element (select)
* -> disables if there are no source options found
* @param element
*/
let editableSelectCheck = element => {
if(element.data('editable')){
let options = element.data('editable').options.source();
if(options.length > 0){
editableEnable(element);
}else{
editableDisable(element);
}
}
};
/**
* get dataTables default options for signature tables
* @param mapId
@@ -1328,31 +1348,16 @@ define([
}
tableApi.draw();
// find related "type" select (same row) and change options
// find related "type" select (same row) and change options ---------------------------
let signatureTypeCell = getNeighboringCell(tableApi, cell, 'type:name');
let signatureTypeField = signatureTypeCell.nodes().to$();
editableSelectCheck(signatureTypeField);
let typeOptions = getAllSignatureNames(
systemData,
systemData.type.id,
Util.getAreaIdBySecurity(systemData.security),
newValue
);
signatureTypeField.editable('option', 'source', typeOptions);
if(
newValue > 0 &&
typeOptions.length > 0
){
editableEnable(signatureTypeField);
}else{
editableDisable(signatureTypeField);
}
signatureTypeCell.data(0);
signatureTypeField.editable('setValue', 0);
// find "connection" select (same row) and change "enabled" flag
// find "connection" select (same row) and change "enabled" flag ----------------------
let signatureConnectionCell = getNeighboringCell(tableApi, cell, 'connection:name');
let signatureConnectionField = signatureConnectionCell.nodes().to$();
@@ -2255,6 +2260,26 @@ define([
// xEditable is active -> should always be active!
// set new value even if no change -> e.g. render selected Ids as text labels
let oldValue = node.editable('getValue', true);
// ... some editable cells depend on each other (e.g. group->type, group->connection)
switch(node.data('editable').options.name){
case 'typeId':
// ... disable if no type options found
editableSelectCheck(node);
break;
case 'connectionId':
// disables if no wormhole group set
let groupId = cell.cell(rowIndex, 'group:name').data();
if(groupId === 5){
// wormhole
editableEnable(node);
}else{
editableDisable(node);
}
break;
}
// values should be set AFTER en/disabling of a field
node.editable('setValue', cell.data());
if(oldValue !== cell.data()){
@@ -2340,6 +2365,9 @@ define([
// table data changed -> draw() table changes
tableApi.draw();
// check for "leads to" conflicts -> important if there are just "update" (no add/delete) changes
checkConnectionConflicts();
if(!updateEmptyTable){
// no notifications if table was empty just progressbar notification is needed
// sum payloads by "action"

View File

@@ -25,6 +25,9 @@ define([
ajaxOverlayClass: 'pf-loading-overlay',
ajaxOverlayWrapperClass: 'pf-loading-overlay-wrapper',
// page
noScrollClass: 'no-scroll',
// form
formEditableFieldClass: 'pf-editable', // class for all xEditable fields
formErrorContainerClass: 'pf-dialog-error-container', // class for "error" containers in dialogs
@@ -497,6 +500,8 @@ define([
let data = {};
if(
tooltipData.created &&
tooltipData.updated &&
tooltipData.created.character &&
tooltipData.updated.character
){
@@ -522,39 +527,41 @@ define([
createdStatusClass: statusCreatedClass,
updatedStatusClass: statusUpdatedClass
};
}
let defaultOptions = {
placement: 'top',
html: true,
trigger: 'hover',
container: 'body',
title: 'Created / Updated',
delay: {
show: 150,
hide: 0
}
};
options = $.extend({}, defaultOptions, options);
return this.each(function(){
let element = $(this);
requirejs(['text!templates/tooltip/character_info.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
element.popover(options);
// set new popover content
let popover = element.data('bs.popover');
popover.options.content = content;
if(options.show){
element.popover('show');
let defaultOptions = {
placement: 'top',
html: true,
trigger: 'hover',
container: 'body',
title: 'Created / Updated',
delay: {
show: 150,
hide: 0
}
};
options = $.extend({}, defaultOptions, options);
return this.each(function(){
let element = $(this);
requirejs(['text!templates/tooltip/character_info.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
element.popover(options);
// set new popover content
let popover = element.data('bs.popover');
popover.options.content = content;
if(options.show){
element.popover('show');
}
});
});
});
}else{
return this;
}
};
/**
@@ -778,9 +785,7 @@ define([
default: console.error('insertElement: %s is not specified!', defaultOptions.insertElement);
}
//containerElement.children().first().velocity('stop').velocity('fadeIn');
$('#' + defaultOptions.messageId).velocity('stop').velocity('fadeIn');
});
};
@@ -1074,7 +1079,12 @@ define([
callbacks: {
alwaysTriggerOffsets: false, // only trigger callback.onTotalScroll() once
onTotalScrollOffset: 300, // trigger callback.onTotalScroll() 100px before end
onTotalScroll: function(a){
onInit: function(){
// disable page scroll -> otherwise page AND customScrollbars will scroll
// -> this is because the initPassiveEvents() delegates the mouseWheel events
togglePageScroll(false);
},
onTotalScroll: function(){
// we want to "trigger" Select2´s 'scroll' event
// in order to make its "infinite scrolling" function working
this.mcs.content.find(':first-child').trigger('scroll');
@@ -1117,6 +1127,10 @@ define([
// the only way to prevent this is to remove the element
// https://stackoverflow.com/questions/17995057/prevent-select2-from-autmatically-focussing-its-search-input-when-dropdown-is-op
$(this).parents('.editableform').find(this).next().find('.select2-selection').remove();
// re-enable page scroll -> might be disabled before by mCustomScrollbar onInit() event
// -> in case there is a custom <select> with scrollable options
togglePageScroll(true);
});
};
@@ -1138,6 +1152,14 @@ define([
'<div class="editableform-loading"><i class="fas fa-lg fa-sync fa-spin"></i></div>';
};
/**
* prevent page from scrolling
* @param enable
*/
let togglePageScroll = (enable = true) => {
$('html').toggleClass(config.noScrollClass, !enable);
};
/**
* request a captcha image
* @param reason
@@ -1759,7 +1781,7 @@ define([
/**
* get a HTML table with system effect information
* e.g. for popover
* @param data
* @param effects
* @returns {string}
*/
let getSystemEffectTable = effects => {
@@ -2785,6 +2807,31 @@ define([
return instance;
};
/**
* HTML encode string
* @param value
* @returns {jQuery}
*/
let htmlEncode = value => $('<div>').text(value).html();
/**
* HTML decode string
* @param value
* @returns {jQuery}
*/
let htmlDecode = value => $('<div>').html(value).text();
/**
* checks if html is valid
* -> see https://stackoverflow.com/a/15458968/4329969
* @param html
* @returns {boolean}
*/
let isValidHtml = html => {
let doc = new DOMParser().parseFromString(html, 'text/html');
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};
/**
* get deep json object value if exists
* -> e.g. key = 'first.last.third' string
@@ -2983,6 +3030,9 @@ define([
singleDoubleClick: singleDoubleClick,
getTableId: getTableId,
getDataTableInstance: getDataTableInstance,
htmlEncode: htmlEncode,
htmlDecode: htmlDecode,
isValidHtml: isValidHtml,
getObjVal: getObjVal,
redirect: redirect,
logout: logout,

3
js/lib/summernote/summernote.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
public/fonts/summernote.eot Normal file

Binary file not shown.

BIN
public/fonts/summernote.ttf Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +0,0 @@
"use strict";var mainScriptPath=document.body.getAttribute("data-script"),jsBaseUrl=document.body.getAttribute("data-js-path");requirejs.config({baseUrl:"js",paths:{layout:"layout",conf:"app/conf",dialog:"app/ui/dialog",templates:"../../templates",img:"../../img",login:"./app/login",mappage:"./app/mappage",setup:"./app/setup",admin:"./app/admin",notification:"./app/notification",jquery:"lib/jquery-3.3.1.min",bootstrap:"lib/bootstrap.min",text:"lib/requirejs/text",mustache:"lib/mustache.min",localForage:"lib/localforage.min",velocity:"lib/velocity.min",velocityUI:"lib/velocity.ui.min",slidebars:"lib/slidebars",jsPlumb:"lib/dom.jsPlumb-1.7.6",farahey:"lib/farahey-0.5",customScrollbar:"lib/jquery.mCustomScrollbar.min",mousewheel:"lib/jquery.mousewheel.min",xEditable:"lib/bootstrap-editable.min",morris:"lib/morris.min",raphael:"lib/raphael-min",bootbox:"lib/bootbox.min",easyPieChart:"lib/jquery.easypiechart.min",peityInlineChart:"lib/jquery.peity.min",dragToSelect:"lib/jquery.dragToSelect",hoverIntent:"lib/jquery.hoverIntent.min",fullScreen:"lib/jquery.fullscreen.min",select2:"lib/select2.min",validator:"lib/validator.min",lazylinepainter:"lib/jquery.lazylinepainter-1.5.1.min",blueImpGallery:"lib/blueimp-gallery",blueImpGalleryHelper:"lib/blueimp-helper",blueImpGalleryBootstrap:"lib/bootstrap-image-gallery",bootstrapConfirmation:"lib/bootstrap-confirmation",bootstrapToggle:"lib/bootstrap-toggle.min",lazyload:"lib/jquery.lazyload.min",sortable:"lib/sortable.min",easePack:"lib/EasePack.min",tweenLite:"lib/TweenLite.min","datatables.loader":"./app/datatables.loader","datatables.net":"lib/datatables/DataTables-1.10.12/js/jquery.dataTables.min","datatables.net-buttons":"lib/datatables/Buttons-1.2.1/js/dataTables.buttons.min","datatables.net-buttons-html":"lib/datatables/Buttons-1.2.1/js/buttons.html5.min","datatables.net-responsive":"lib/datatables/Responsive-2.1.0/js/dataTables.responsive.min","datatables.net-select":"lib/datatables/Select-1.2.0/js/dataTables.select.min","datatables.plugins.render.ellipsis":"lib/datatables/plugins/render/ellipsis",pnotify:"lib/pnotify/pnotify","pnotify.buttons":"lib/pnotify/pnotify.buttons","pnotify.confirm":"lib/pnotify/pnotify.confirm","pnotify.nonblock":"lib/pnotify/pnotify.nonblock","pnotify.desktop":"lib/pnotify/pnotify.desktop","pnotify.history":"lib/pnotify/pnotify.history","pnotify.callbacks":"lib/pnotify/pnotify.callbacks","pnotify.reference":"lib/pnotify/pnotify.reference"},shim:{bootstrap:{deps:["jquery"]},farahey:{deps:["jsPlumb"]},velocity:{deps:["jquery"]},velocityUI:{deps:["velocity"]},slidebars:{deps:["jquery"]},customScrollbar:{deps:["jquery","mousewheel"]},"datatables.loader":{deps:["jquery"]},"datatables.net":{deps:["jquery"]},"datatables.net-buttons":{deps:["datatables.net"]},"datatables.net-buttons-html":{deps:["datatables.net-buttons"]},"datatables.net-responsive":{deps:["datatables.net"]},"datatables.net-select":{deps:["datatables.net"]},"datatables.plugins.render.ellipsis":{deps:["datatables.net"]},xEditable:{deps:["bootstrap"]},bootbox:{deps:["jquery","bootstrap"],exports:"bootbox"},morris:{deps:["jquery","raphael"],exports:"Morris",init:function(e,t){window.Raphael=t}},pnotify:{deps:["jquery"]},easyPieChart:{deps:["jquery"]},peityInlineChart:{deps:["jquery"]},dragToSelect:{deps:["jquery"]},hoverIntent:{deps:["jquery"]},fullScreen:{deps:["jquery"]},select2:{deps:["jquery","mousewheel"],exports:"Select2"},validator:{deps:["jquery","bootstrap"]},lazylinepainter:{deps:["jquery","bootstrap"]},blueImpGallery:{deps:["jquery"]},bootstrapConfirmation:{deps:["bootstrap"]},bootstrapToggle:{deps:["jquery"]},lazyload:{deps:["jquery"]}}}),require.config({baseUrl:jsBaseUrl}),requirejs([mainScriptPath]);
//# sourceMappingURL=app.js.map

Binary file not shown.

View File

@@ -1 +0,0 @@
{"version":3,"sources":["app.js"],"names":["mainScriptPath","document","body","getAttribute","jsBaseUrl","requirejs","config","baseUrl","paths","layout","conf","dialog","templates","img","login","mappage","setup","admin","notification","jquery","bootstrap","text","mustache","localForage","velocity","velocityUI","slidebars","jsPlumb","farahey","customScrollbar","mousewheel","xEditable","morris","raphael","bootbox","easyPieChart","peityInlineChart","dragToSelect","hoverIntent","fullScreen","select2","validator","lazylinepainter","blueImpGallery","blueImpGalleryHelper","blueImpGalleryBootstrap","bootstrapConfirmation","bootstrapToggle","lazyload","sortable","easePack","tweenLite","datatables.loader","datatables.net","datatables.net-buttons","datatables.net-buttons-html","datatables.net-responsive","datatables.net-select","datatables.plugins.render.ellipsis","pnotify","pnotify.buttons","pnotify.confirm","pnotify.nonblock","pnotify.desktop","pnotify.history","pnotify.callbacks","pnotify.reference","shim","deps","exports","init","$","Raphael","window","require"],"mappings":"AAAA,aAGA,IAAIA,eAAiBC,SAASC,KAAKC,aAAa,eAI5CC,UAAYH,SAASC,KAAKC,aAAa,gBAG3CE,UAAUC,QACNC,QAAS,KAETC,OACIC,OAAQ,SACRC,KAAM,WACNC,OAAQ,gBACRC,UAAW,kBACXC,IAAK,YAGLC,MAAO,cACPC,QAAS,gBACTC,MAAO,cACPC,MAAO,cACPC,aAAc,qBAEdC,OAAQ,uBACRC,UAAW,oBACXC,KAAM,qBACNC,SAAU,mBACVC,YAAa,sBACbC,SAAU,mBACVC,WAAY,sBACZC,UAAW,gBACXC,QAAS,wBACTC,QAAS,kBACTC,gBAAiB,kCACjBC,WAAY,4BACZC,UAAW,6BACXC,OAAQ,iBACRC,QAAS,kBACTC,QAAS,kBACTC,aAAc,8BACdC,iBAAkB,uBAClBC,aAAc,0BACdC,YAAa,6BACbC,WAAY,4BACZC,QAAS,kBACTC,UAAW,oBACXC,gBAAiB,uCACjBC,eAAgB,sBAChBC,qBAAsB,qBACtBC,wBAAyB,8BACzBC,sBAAuB,6BACvBC,gBAAiB,2BACjBC,SAAU,0BACVC,SAAU,mBAGVC,SAAU,mBACVC,UAAW,oBAGXC,oBAAqB,0BACrBC,iBAAkB,6DAClBC,yBAA0B,yDAC1BC,8BAA+B,oDAC/BC,4BAA6B,+DAC7BC,wBAAyB,uDACzBC,qCAAsC,yCAGtCC,QAAS,sBACTC,kBAAmB,8BACnBC,kBAAmB,8BACnBC,mBAAoB,+BACpBC,kBAAmB,8BACnBC,kBAAmB,8BACnBC,oBAAqB,gCACrBC,oBAAqB,iCAEzBC,MACI/C,WACIgD,MAAO,WAEXxC,SACIwC,MAAO,YAEX5C,UACI4C,MAAO,WAEX3C,YACI2C,MAAO,aAEX1C,WACI0C,MAAO,WAEXvC,iBACIuC,MAAO,SAAU,eAErBhB,qBACIgB,MAAO,WAEXf,kBACIe,MAAO,WAEXd,0BACIc,MAAO,mBAEXb,+BACIa,MAAO,2BAEXZ,6BACIY,MAAO,mBAEXX,yBACIW,MAAO,mBAEXV,sCACIU,MAAO,mBAEXrC,WACIqC,MAAO,cAEXlC,SACIkC,MAAO,SAAU,aACjBC,QAAS,WAEbrC,QACIoC,MAAO,SAAU,WACjBC,QAAS,SACTC,KAAM,SAAUC,EAAGC,GACfC,OAAOD,QAAUA,IAGzBb,SACIS,MAAQ,WAEZjC,cACIiC,MAAQ,WAEZhC,kBACIgC,MAAQ,WAEZ/B,cACI+B,MAAQ,WAEZ9B,aACI8B,MAAQ,WAEZ7B,YACI6B,MAAQ,WAEZ5B,SACI4B,MAAQ,SAAU,cAClBC,QAAS,WAEb5B,WACI2B,MAAQ,SAAU,cAEtB1B,iBACI0B,MAAQ,SAAU,cAEtBzB,gBACIyB,MAAQ,WAEZtB,uBACIsB,MAAQ,cAEZrB,iBACIqB,MAAQ,WAEZpB,UACIoB,MAAQ,cAQpBM,QAAQpE,QACJC,QAASH,YAIbC,WAAYL","file":"app.js","sourceRoot":"/js"}

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

2
public/js/v1.4.2/app.js Normal file
View File

@@ -0,0 +1,2 @@
"use strict";var mainScriptPath=document.body.getAttribute("data-script"),jsBaseUrl=document.body.getAttribute("data-js-path");requirejs.config({baseUrl:"js",paths:{layout:"layout",conf:"app/conf",dialog:"app/ui/dialog",templates:"../../templates",img:"../../img",login:"./app/login",mappage:"./app/mappage",setup:"./app/setup",admin:"./app/admin",notification:"./app/notification",jquery:"lib/jquery-3.3.1.min",bootstrap:"lib/bootstrap.min",text:"lib/requirejs/text",mustache:"lib/mustache.min",localForage:"lib/localforage.min",velocity:"lib/velocity.min",velocityUI:"lib/velocity.ui.min",slidebars:"lib/slidebars",jsPlumb:"lib/dom.jsPlumb-1.7.6",farahey:"lib/farahey-0.5",customScrollbar:"lib/jquery.mCustomScrollbar.min",mousewheel:"lib/jquery.mousewheel.min",xEditable:"lib/bootstrap-editable.min",morris:"lib/morris.min",raphael:"lib/raphael-min",bootbox:"lib/bootbox.min",easyPieChart:"lib/jquery.easypiechart.min",peityInlineChart:"lib/jquery.peity.min",dragToSelect:"lib/jquery.dragToSelect",hoverIntent:"lib/jquery.hoverIntent.min",fullScreen:"lib/jquery.fullscreen.min",select2:"lib/select2.min",validator:"lib/validator.min",lazylinepainter:"lib/jquery.lazylinepainter-1.5.1.min",blueImpGallery:"lib/blueimp-gallery",blueImpGalleryHelper:"lib/blueimp-helper",blueImpGalleryBootstrap:"lib/bootstrap-image-gallery",bootstrapConfirmation:"lib/bootstrap-confirmation",bootstrapToggle:"lib/bootstrap-toggle.min",lazyload:"lib/jquery.lazyload.min",sortable:"lib/sortable.min","summernote.loader":"./app/summernote.loader",summernote:"lib/summernote/summernote.min",easePack:"lib/EasePack.min",tweenLite:"lib/TweenLite.min","datatables.loader":"./app/datatables.loader","datatables.net":"lib/datatables/DataTables-1.10.12/js/jquery.dataTables.min","datatables.net-buttons":"lib/datatables/Buttons-1.2.1/js/dataTables.buttons.min","datatables.net-buttons-html":"lib/datatables/Buttons-1.2.1/js/buttons.html5.min","datatables.net-responsive":"lib/datatables/Responsive-2.1.0/js/dataTables.responsive.min","datatables.net-select":"lib/datatables/Select-1.2.0/js/dataTables.select.min","datatables.plugins.render.ellipsis":"lib/datatables/plugins/render/ellipsis",pnotify:"lib/pnotify/pnotify","pnotify.buttons":"lib/pnotify/pnotify.buttons","pnotify.confirm":"lib/pnotify/pnotify.confirm","pnotify.nonblock":"lib/pnotify/pnotify.nonblock","pnotify.desktop":"lib/pnotify/pnotify.desktop","pnotify.history":"lib/pnotify/pnotify.history","pnotify.callbacks":"lib/pnotify/pnotify.callbacks","pnotify.reference":"lib/pnotify/pnotify.reference"},shim:{bootstrap:{deps:["jquery"]},farahey:{deps:["jsPlumb"]},velocity:{deps:["jquery"]},velocityUI:{deps:["velocity"]},slidebars:{deps:["jquery"]},customScrollbar:{deps:["jquery","mousewheel"]},"datatables.loader":{deps:["jquery"]},"datatables.net":{deps:["jquery"]},"datatables.net-buttons":{deps:["datatables.net"]},"datatables.net-buttons-html":{deps:["datatables.net-buttons"]},"datatables.net-responsive":{deps:["datatables.net"]},"datatables.net-select":{deps:["datatables.net"]},"datatables.plugins.render.ellipsis":{deps:["datatables.net"]},xEditable:{deps:["bootstrap"]},bootbox:{deps:["jquery","bootstrap"],exports:"bootbox"},morris:{deps:["jquery","raphael"],exports:"Morris",init:function(e,t){window.Raphael=t}},pnotify:{deps:["jquery"]},easyPieChart:{deps:["jquery"]},peityInlineChart:{deps:["jquery"]},dragToSelect:{deps:["jquery"]},hoverIntent:{deps:["jquery"]},fullScreen:{deps:["jquery"]},select2:{deps:["jquery","mousewheel"],exports:"Select2"},validator:{deps:["jquery","bootstrap"]},lazylinepainter:{deps:["jquery","bootstrap"]},blueImpGallery:{deps:["jquery"]},bootstrapConfirmation:{deps:["bootstrap"]},bootstrapToggle:{deps:["jquery"]},lazyload:{deps:["jquery"]},summernote:{deps:["jquery"]}}}),require.config({baseUrl:jsBaseUrl}),requirejs([mainScriptPath]);
//# sourceMappingURL=app.js.map

BIN
public/js/v1.4.2/app.js.br Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"version":3,"sources":["app.js"],"names":["mainScriptPath","document","body","getAttribute","jsBaseUrl","requirejs","config","baseUrl","paths","layout","conf","dialog","templates","img","login","mappage","setup","admin","notification","jquery","bootstrap","text","mustache","localForage","velocity","velocityUI","slidebars","jsPlumb","farahey","customScrollbar","mousewheel","xEditable","morris","raphael","bootbox","easyPieChart","peityInlineChart","dragToSelect","hoverIntent","fullScreen","select2","validator","lazylinepainter","blueImpGallery","blueImpGalleryHelper","blueImpGalleryBootstrap","bootstrapConfirmation","bootstrapToggle","lazyload","sortable","summernote.loader","summernote","easePack","tweenLite","datatables.loader","datatables.net","datatables.net-buttons","datatables.net-buttons-html","datatables.net-responsive","datatables.net-select","datatables.plugins.render.ellipsis","pnotify","pnotify.buttons","pnotify.confirm","pnotify.nonblock","pnotify.desktop","pnotify.history","pnotify.callbacks","pnotify.reference","shim","deps","exports","init","$","Raphael","window","require"],"mappings":"AAAA,aAGA,IAAIA,eAAiBC,SAASC,KAAKC,aAAa,eAI5CC,UAAYH,SAASC,KAAKC,aAAa,gBAG3CE,UAAUC,QACNC,QAAS,KAETC,OACIC,OAAQ,SACRC,KAAM,WACNC,OAAQ,gBACRC,UAAW,kBACXC,IAAK,YAGLC,MAAO,cACPC,QAAS,gBACTC,MAAO,cACPC,MAAO,cACPC,aAAc,qBAEdC,OAAQ,uBACRC,UAAW,oBACXC,KAAM,qBACNC,SAAU,mBACVC,YAAa,sBACbC,SAAU,mBACVC,WAAY,sBACZC,UAAW,gBACXC,QAAS,wBACTC,QAAS,kBACTC,gBAAiB,kCACjBC,WAAY,4BACZC,UAAW,6BACXC,OAAQ,iBACRC,QAAS,kBACTC,QAAS,kBACTC,aAAc,8BACdC,iBAAkB,uBAClBC,aAAc,0BACdC,YAAa,6BACbC,WAAY,4BACZC,QAAS,kBACTC,UAAW,oBACXC,gBAAiB,uCACjBC,eAAgB,sBAChBC,qBAAsB,qBACtBC,wBAAyB,8BACzBC,sBAAuB,6BACvBC,gBAAiB,2BACjBC,SAAU,0BACVC,SAAU,mBAEVC,oBAAqB,0BACrBC,WAAc,gCAGdC,SAAU,mBACVC,UAAW,oBAGXC,oBAAqB,0BACrBC,iBAAkB,6DAClBC,yBAA0B,yDAC1BC,8BAA+B,oDAC/BC,4BAA6B,+DAC7BC,wBAAyB,uDACzBC,qCAAsC,yCAGtCC,QAAS,sBACTC,kBAAmB,8BACnBC,kBAAmB,8BACnBC,mBAAoB,+BACpBC,kBAAmB,8BACnBC,kBAAmB,8BACnBC,oBAAqB,gCACrBC,oBAAqB,iCAEzBC,MACIjD,WACIkD,MAAO,WAEX1C,SACI0C,MAAO,YAEX9C,UACI8C,MAAO,WAEX7C,YACI6C,MAAO,aAEX5C,WACI4C,MAAO,WAEXzC,iBACIyC,MAAO,SAAU,eAErBhB,qBACIgB,MAAO,WAEXf,kBACIe,MAAO,WAEXd,0BACIc,MAAO,mBAEXb,+BACIa,MAAO,2BAEXZ,6BACIY,MAAO,mBAEXX,yBACIW,MAAO,mBAEXV,sCACIU,MAAO,mBAEXvC,WACIuC,MAAO,cAEXpC,SACIoC,MAAO,SAAU,aACjBC,QAAS,WAEbvC,QACIsC,MAAO,SAAU,WACjBC,QAAS,SACTC,KAAM,SAAUC,EAAGC,GACfC,OAAOD,QAAUA,IAGzBb,SACIS,MAAO,WAEXnC,cACImC,MAAO,WAEXlC,kBACIkC,MAAO,WAEXjC,cACIiC,MAAO,WAEXhC,aACIgC,MAAO,WAEX/B,YACI+B,MAAO,WAEX9B,SACI8B,MAAO,SAAU,cACjBC,QAAS,WAEb9B,WACI6B,MAAO,SAAU,cAErB5B,iBACI4B,MAAO,SAAU,cAErB3B,gBACI2B,MAAO,WAEXxB,uBACIwB,MAAO,cAEXvB,iBACIuB,MAAO,WAEXtB,UACIsB,MAAO,WAEXnB,YACImB,MAAO,cAQnBM,QAAQtE,QACJC,QAASH,YAIbC,WAAYL","file":"app.js","sourceRoot":"/js"}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
define(["jquery","app/init","summernote"],(e,a)=>{"use strict";return e.extend(e.summernote.plugins,{lengthField:function(a){e.summernote.ui,a.memo("button.lengthField",()=>e("<kbd>",{class:["text-right","txt-color"].join(" ")}));let t=e=>{let t=a.options.maxTextLength,n=e.length,s=a.layoutInfo.toolbar.find("kbd"),f=t-n;s.text(f).data("charCount",f),s.toggleClass("txt-color-red",t<=n),a.layoutInfo.toolbar.find(".btn-save").prop("disabled",t<n)};this.events={"summernote.init":function(e,n){t(a.$note.summernote("code"))},"summernote.change":function(e,a){t(a)}}}}),e.extend(e.summernote.plugins,{discardBtn:function(a){let t=e.summernote.ui;a.memo("button.discardBtn",()=>{let n=t.button({contents:'<i class="fas fa-fw fa-ban"/>',container:"body",click:function(){e(this).confirmation("show")}}).render(),s={container:"body",placement:"top",btnCancelClass:"btn btn-sm btn-default",btnCancelLabel:"cancel",title:"discard changes",btnOkClass:"btn btn-sm btn-warning",btnOkLabel:"discard",btnOkIcon:"fas fa-fw fa-ban",onConfirm:(e,t)=>{a.$note.summernote("reset"),a.$note.summernote("destroy")}};return n.confirmation(s),n})}}),{initSummernote:(a,t)=>{t=e.extend({},{dialogsInBody:!0,dialogsFade:!0,styleTags:["p","h2","h3","blockquote"],linkTargetBlank:!0,tableClassName:"table table-condensed table-bordered",insertTableMaxSize:{col:5,row:5},icons:{alignCenter:"fas fa-align-center",alignJustify:"fas fa-align-justify",alignLeft:"fas fa-align-left",alignRight:"fas fa-align-right",indent:"fas fa-indent",outdent:"fas fa-outdent",arrowsAlt:"fas fa-expand-arrows-alt",bold:"fas fa-bold",caret:"fas fa-caret-down",circle:"fas fa-circle",close:"fas fa-time",code:"fas fa-code",eraser:"fas fa-eraser",font:"fas fa-font",italic:"fas fa-italic",link:"fas fa-link",unlink:"fas fa-unlink",magic:"fas fa-magic",menuCheck:"fas fa-check",minus:"fas fa-minus",orderedlist:"fas fa-list-ol",pencil:"fa-pen",picture:"fas fa-image",question:"fas fa-question",redo:"fas fa-redo",square:"fas fa-square",strikethrough:"fas fa-strikethrough",subscript:"fas fa-subscript",superscript:"fas fa-superscript",table:"fas fa-table",textHeight:"fas fa-text-height",trash:"fas fa-trash",underline:"fas fa-underline",undo:"fas fa-undo",unorderedlist:"fas fa-list-ul",video:"fab fa-youtube"},colors:[["#5cb85c","#e28a0d","#d9534f","#e06fdf","#9fa8da","#e2ce48","#428bca"]],colorsName:[["Green","Orange","Red","Pink","Indigo","Yellow","Blue"]]},t),a.summernote(t)}}});
//# sourceMappingURL=summernote.loader.js.map

Binary file not shown.

View File

@@ -0,0 +1 @@
{"version":3,"sources":["app/summernote.loader.js"],"names":["define","$","Init","extend","summernote","plugins","lengthField","context","ui","memo","class","join","updateCounter","contents","maxTextLength","options","textLength","length","counter","layoutInfo","toolbar","find","counterLeft","text","data","toggleClass","prop","this","events","summernote.init","we","e","$note","summernote.change","discardBtn","$button","button","container","click","confirmation","render","confirmationSettings","placement","btnCancelClass","btnCancelLabel","title","btnOkClass","btnOkLabel","btnOkIcon","onConfirm","target","initSummernote","element","dialogsInBody","dialogsFade","styleTags","linkTargetBlank","tableClassName","insertTableMaxSize","col","row","icons","alignCenter","alignJustify","alignLeft","alignRight","indent","outdent","arrowsAlt","bold","caret","circle","close","code","eraser","font","italic","link","unlink","magic","menuCheck","minus","orderedlist","pencil","picture","question","redo","square","strikethrough","subscript","superscript","table","textHeight","trash","underline","undo","unorderedlist","video","colors","colorsName"],"mappings":"AAAAA,QACI,SACA,WACA,cACD,CAACC,EAAGC,KACH,aAkLA,OA7KID,EAAEE,OAAOF,EAAEG,WAAWC,SAIlBC,YAAa,SAAUC,GAEVN,EAAEG,WAAWI,GAGtBD,EAAQE,KAAK,qBAAsB,IACxBR,EAAE,SACLS,OAAQ,aAAc,aAAaC,KAAK,QAQhD,IAAIC,EAAiBC,IACjB,IAAIC,EAAgBP,EAAQQ,QAAQD,cAChCE,EAAaH,EAASI,OACtBC,EAAUX,EAAQY,WAAWC,QAAQC,KAAK,OAC1CC,EAAcR,EAAgBE,EAElCE,EAAQK,KAAKD,GAAaE,KAAK,YAAaF,GAC5CJ,EAAQO,YAAY,gBAAiBX,GAAiBE,GAGxCT,EAAQY,WAAWC,QAAQC,KAAK,aACtCK,KAAK,WAAYZ,EAAgBE,IAI7CW,KAAKC,QACDC,kBAAmB,SAAUC,EAAIC,GAC7BnB,EAAcL,EAAQyB,MAAM5B,WAAW,UAE3C6B,oBAAqB,SAASH,EAAIjB,GAC9BD,EAAcC,QAQ9BZ,EAAEE,OAAOF,EAAEG,WAAWC,SAIlB6B,WAAY,SAAU3B,GAClB,IACIC,EAAKP,EAAEG,WAAWI,GAGtBD,EAAQE,KAAK,oBAAqB,KAC9B,IAQI0B,EARS3B,EAAG4B,QACZvB,SAAU,gCACVwB,UAAW,OACXC,MAAO,WAEHrC,EAAE0B,MAAMY,aAAa,WAGRC,SAGjBC,GACAJ,UAAW,OACXK,UAAW,MACXC,eAAgB,yBAChBC,eAAgB,SAChBC,MAAO,kBACPC,WAAY,yBACZC,WAAY,UACZC,UAAW,mBACXC,UAAW,CAAClB,EAAGmB,KAEX3C,EAAQyB,MAAM5B,WAAW,SACzBG,EAAQyB,MAAM5B,WAAW,aAKjC,OAFA+B,EAAQI,aAAaE,GAEdN,QAyFnBgB,eA9EiB,CAACC,EAASrC,KAsE3BA,EAAUd,EAAEE,WAnERkD,eAAe,EACfC,aAAa,EAKbC,WAAY,IAAK,KAAM,KAAM,cAC7BC,iBAAiB,EACjBC,eAAgB,uCAChBC,oBACIC,IAAK,EACLC,IAAK,GAETC,OAEIC,YAAe,sBACfC,aAAgB,uBAChBC,UAAa,oBACbC,WAAc,qBAOdC,OAAU,gBACVC,QAAW,iBACXC,UAAa,2BACbC,KAAQ,cACRC,MAAS,oBACTC,OAAU,gBACVC,MAAS,cACTC,KAAQ,cACRC,OAAU,gBACVC,KAAQ,cAERC,OAAU,gBACVC,KAAQ,cACRC,OAAU,gBACVC,MAAS,eACTC,UAAa,eACbC,MAAS,eACTC,YAAe,iBACfC,OAAU,SACVC,QAAW,eACXC,SAAY,kBACZC,KAAQ,cACRC,OAAU,gBACVC,cAAiB,uBACjBC,UAAa,mBACbC,YAAe,qBACfC,MAAS,eACTC,WAAc,qBACdC,MAAS,eACTC,UAAa,mBACbC,KAAQ,cACRC,cAAiB,iBACjBC,MAAS,kBAEbC,SACK,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,YAEvEC,aACK,QAAS,SAAU,MAAO,OAAQ,SAAU,SAAU,UAIxBpF,GAEvCqC,EAAQhD,WAAWW","file":"summernote.loader.js","sourceRoot":"/js"}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -49,7 +49,7 @@
<div class="col-sm-12 col-md-6">
<div class="form-group">
<div class="col-sm-12 col-xs-6 checkbox">
<div class="col-xs-12 col-sm-12 col-xs-6 checkbox">
<input id="{{deleteExpiredConnectionsId}}" name="deleteExpiredConnections" value="1" type="checkbox" {{#deleteExpiredConnections}}checked{{/deleteExpiredConnections}}>
<label for="{{deleteExpiredConnectionsId}}">Auto delete outdated wormholes
<i class="fas fa-fw fa-question-circle pf-help-light" title="outdated WHs (~2 days)"></i>
@@ -60,7 +60,7 @@
<div class="col-sm-12 col-md-6">
<div class="form-group">
<div class="col-sm-12 col-xs-6 checkbox" >
<div class="col-xs-12 col-sm-12 col-xs-6 checkbox" >
<input id="{{deleteEolConnectionsId}}" name="deleteEolConnections" value="1" type="checkbox" {{#deleteEolConnections}}checked{{/deleteEolConnections}}>
<label for="{{deleteEolConnectionsId}}">Auto delete expired wormholes
<i class="fas fa-fw fa-question-circle pf-help-light" title="expired EOL WHs (~4h 15min)"></i>
@@ -69,7 +69,7 @@
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="col-xs-12 col-sm-12 col-md-6">
<div class="form-group">
<div class="col-sm-12 col-xs-6 checkbox">
<input id="{{persistentAliasesId}}" name="persistentAliases" value="1" type="checkbox" {{#persistentAliases}}checked{{/persistentAliases}}>
@@ -88,7 +88,7 @@
<div class="col-sm-12 col-md-6">
<div class="form-group">
<div class="col-sm-12 col-xs-6 checkbox">
<div class="col-xs-12 col-sm-12 col-xs-6 checkbox">
<input id="{{logHistoryId}}" name="logHistory" value="1" type="checkbox" {{#logHistory}}checked{{/logHistory}}>
<label for="{{logHistoryId}}">Save map changes to logfile
<i class="fas fa-fw fa-question-circle pf-help-light" title="Map changes will be stored in a log file"></i>
@@ -99,7 +99,7 @@
<div class="col-sm-12 col-md-6">
<div class="form-group">
<div class="col-sm-12 col-xs-6 checkbox">
<div class="col-xs-12 col-sm-12 col-xs-6 checkbox">
<input id="{{logActivityId}}" name="logActivity" value="1" type="checkbox" {{#logActivity}}checked{{/logActivity}}>
<label for="{{logActivityId}}">Store user statistics
<i class="fas fa-fw fa-question-circle pf-help-light" title="Map changes will be tracked in order to generate user statistics"></i>

View File

@@ -2,37 +2,40 @@
<form role="form" class="form-horizontal">
<div class="row">
<div class="col-xs-8">
<div class="col-xs-9">
<div class="form-group">
<label class="col-sm-2 control-label" for="form_system">System</label>
<div class="col-sm-10">
<div class="input-group">
<label for="form_system"></label>
<select id="form_system" name="systemId" class="pf-select2 {{selectClass}}" data-error="Choose a valid system" required>
<select id="form_system" name="systemId" class="pf-select2 {{systemSelectClass}}" data-error="Choose a valid system" required>
{{#currentSystem}}
<option value="{{id}}">{{name}}</option>
{{/currentSystem}}
</select>
<span class="form-control-static fade" data-type="spinner">&nbsp;&nbsp;
<i class="fas fa-fw fa-lg fa-spin fa-sync txt-color txt-color-grayLight"></i>
</span>
<span class="help-block with-errors">Search system name</span>
</div>
</div>
</div>
</div>
<div class="col-xs-4">
<div class="col-xs-3">
<div class="form-group" style="margin-bottom: 0;">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox checkbox-primary">
<input id="form_lock" name="locked" value="1" type="checkbox">
<label for="form_lock">
<input id="{{lockId}}" name="locked" value="1" type="checkbox">
<label for="{{lockId}}">
Lock system
</label>
<div class="help-block with-errors"></div>
</div>
<div class="checkbox checkbox-primary">
<input id="form_rally" name="rallyUpdated" value="1" type="checkbox">
<label for="form_rally">
<input id="{{rallyId}}" name="rallyUpdated" value="1" type="checkbox">
<label for="{{rallyId}}">
Rally point
</label>
<div class="help-block with-errors"></div>
@@ -42,13 +45,12 @@
</div>
</div>
<div class="row">
<div class="col-xs-8">
<div class="col-xs-9">
<div class="form-group">
<label class="col-sm-2 control-label" for="{{statusSelectId}}">Status</label>
<div class="col-sm-6">
<select name="statusId" id="{{statusSelectId}}" class="form-control {{select2Class}}">
<select id="{{statusSelectId}}" name="statusId" class="form-control {{select2Class}}">
{{#statusData}}
<option value="{{id}}">{{text}}</option>
{{/statusData}}
@@ -58,5 +60,49 @@
</div>
</div>
{{! system info -------------------------------------------------------- }}
<h4 class="pf-dynamic-area collapsed" data-toggle="collapse" data-target="#{{sectionInfoId}}" style="display: none;">
System intel : <span id="{{sectionInfoStatusId}}"></span>
<i class="fas fa-fw fa-question-circle pf-help-light" title="show persistent system data"></i>
</h4>
<div id="{{sectionInfoId}}" class="collapse">
<div class="row">
<div class="col-xs-12 col-sm-9">
<div class="form-group">
<label class="col-xs-4 col-sm-2 control-label">Alias</label>
<div class="col-xs-8 col-sm-10">
<div class="controls">
<div id="{{aliasId}}" class="form-control-static"></div>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-3">
<div id="{{createdId}}" class="well well-sm text-center" title="first create"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-9">
<div class="form-group">
<label class="col-xs-12 col-sm-2 control-label">Description</label>
<div class="col-xs-12 col-sm-10">
<div class="controls">
<div id="{{descriptionId}}" class="form-control-static"></div>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-3">
<div id="{{updatedId}}" class="well well-sm text-center" title="last update/delete"></div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,49 +0,0 @@
{{#tableData}}
{{#killmails.length}}
{{#checkRender}}
<h5>{{label}} ago</h5>
<ul class="media-list {{systemKillboardListClass}}">
{{#killmails}}
{{#checkRender}}
<li class="media {{systemKillboardListEntryClass}}">
<a href="{{{zKillboardUrl}}}/kill/{{killmail_id}}/" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Type/{{victim.ship_type_id}}_64.png" class="media-object pull-left {{systemKillboardListImgShip}}" title="killmail">
</a>
<a href="{{{zKillboardUrl}}}/character/{{victim.character_id}}/" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Character/{{victim.character_id}}_32.jpg" class="media-object pull-left {{systemKillboardListImgChar}}" title="pilot KB">
</a>
<div class="media-body pull-right text-right">
<h5 class="media-heading">
<small>{{#dateFormat}}{{killmail_time}}{{/dateFormat}}</small>
</h5>
<h3 class="media-heading">
<small class="txt-color txt-color-green">{{#iskFormat}}{{zkb.totalValue}}{{/iskFormat}}</small>
</h3>
</div>
<div class="media-body">
<h5 class="media-heading">
<a href="{{{zKillboardUrl}}}/corporation/{{victim.corporation_id}}/" title="corporation KB" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Corporation/{{victim.corporation_id}}_32.png" class="{{systemKillboardListImgCorp}}">
</a>
</h5>
{{#victim.alliance_id}}
<h5 class="media-heading">
<a href="{{{zKillboardUrl}}}/alliance/{{victim.alliance_id}}/" title="alliance KB" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Alliance/{{victim.alliance_id}}_32.png" class="{{systemKillboardListImgAlly}}">
</a>
</h5>
{{/victim.alliance_id}}
</div>
</li>
{{#increaseCount}}{{/increaseCount}}
{{/checkRender}}
{{/killmails}}
</ul>
{{/checkRender}}
{{/killmails.length}}
{{/tableData}}

View File

@@ -0,0 +1,40 @@
<li class="media {{systemKillboardListEntryClass}}">
<a href="{{{zKillboardUrl}}}/kill/{{killmail.killmail_id}}/" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Type/{{killmail.victim.ship_type_id}}_64.png" class="media-object pull-left {{systemKillboardListImgShip}}" title="killmail">
</a>
{{#killmail.victim.character_id}}
<a href="{{{zKillboardUrl}}}/character/{{killmail.victim.character_id}}/" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Character/{{killmail.victim.character_id}}_32.jpg" class="media-object pull-left {{systemKillboardListImgChar}}" title="pilot KB">
</a>
{{/killmail.victim.character_id}}
{{^killmail.victim.character_id}}
<a href="{{{zKillboardUrl}}}/corporation/{{killmail.victim.corporation_id}}/" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Corporation/{{killmail.victim.corporation_id}}_32.jpg" class="media-object pull-left {{systemKillboardListImgChar}}" title="corporation KB">
</a>
{{/killmail.victim.character_id}}
<div class="media-body pull-right text-right">
<h5 class="media-heading">
<small>{{#dateFormat}}{{killmail.killmail_time}}{{/dateFormat}}</small>
</h5>
<h3 class="media-heading">
<small class="txt-color txt-color-green">{{#iskFormat}}{{zkb.totalValue}}{{/iskFormat}}</small>
</h3>
</div>
<div class="media-body">
<h5 class="media-heading">
<a href="{{{zKillboardUrl}}}/corporation/{{killmail.victim.corporation_id}}/" title="corporation KB" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Corporation/{{killmail.victim.corporation_id}}_32.png" class="{{systemKillboardListImgCorp}}">
</a>
</h5>
{{#killmail.victim.alliance_id}}
<h5 class="media-heading">
<a href="{{{zKillboardUrl}}}/alliance/{{killmail.victim.alliance_id}}/" title="alliance KB" target="_blank" rel="noopener">
<img src="{{{ccpImageServerUrl}}}/Alliance/{{killmail.victim.alliance_id}}_32.png" class="{{systemKillboardListImgAlly}}">
</a>
</h5>
{{/killmail.victim.alliance_id}}
</div>
</li>

View File

@@ -36,18 +36,15 @@
<div class="row">
{{! info text ================================================================================================ }}
<div class="col-xs-12 col-sm-7">
<div class="pf-dynamic-area pf-system-info-description-area">
<div class="col-xs-12 col-sm-9">
<div class="pf-dynamic-area {{descriptionAreaClass}}">
<div class="{{descriptionTextareaClass}}"></div>
<i class="fas fa-fw fa-lg fa-pen pull-right {{moduleHeadlineIconClass}} {{descriptionButtonClass}}" data-toggle="tooltip" title="edit description"></i>
<div class="{{tableToolsActionClass}}">
<a href="#" class="{{descriptionTextareaClass}}"></a>
</div>
</div>
</div>
{{! info table ================================================================================================ }}
<div class="col-xs-12 col-sm-5">
<div class="col-xs-12 col-sm-3">
<span data-toggle="tooltip" title="status" data-status="{{systemStatusId}}" class="label center-block {{statusInfoClass}} {{systemStatusClass}}">
{{systemStatusLabel}}
@@ -59,7 +56,7 @@
<thead>
<tr>
<th>Name</th>
<th class="text-right">
<th class="text-right pf-system-info-name-cell">
{{#system.shattered}}
<i class="fas fa-fw fa-skull {{shatteredClass}}" data-toggle="tooltip" title="shattered"></i>&nbsp;
{{/system.shattered}}

View File

@@ -1,4 +1,4 @@
<div id="{{id}}" class="alert alert-warning">
<div class="ui-pnotify-icon"><span class="fas fa-exclamation fa-fw fa-lg"></span></div>
<h4 class="ui-pnotify-title">Scheduled maintenance: Update v1.4.0 <i class="fas fa-long-arrow-alt-right"></i> v1.4.1; Shutdown: ~15:30 (UTC). ETA ~15:45 (UTC)</h4>
<h4 class="ui-pnotify-title">Scheduled maintenance: Update v1.4.1 <i class="fas fa-long-arrow-alt-right"></i> v1.4.2; Shutdown: ~17:45 (UTC). ETA ~18:00 (UTC)</h4>
</div>

View File

@@ -7,21 +7,13 @@
<div class="panel-body no-padding text-align-center">
<div class="price-features" style="min-height: inherit;">
<ul class="list-unstyled text-left">
<li>
<i class="fas fa-fw fa-angle-right"></i>Signature module: New filter <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/376" rel="noopener">#376</a>,
keyboard navigation <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/266" rel="noopener">#266</a>,
UI changes <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/679" rel="noopener">#679</a>,
tooltips <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/390" rel="noopener">#390</a>,
layout <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/629" rel="noopener">#629</a>
<li><i class="fas fa-fw fa-angle-right"></i>New HTML editor for system description <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/698" rel="noopener">#698</a></li>
<li><i class="fas fa-fw fa-angle-right"></i>New preview data section added to "new system" dialog <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/662" rel="noopener">#662</a></li>
<li><i class="fas fa-fw fa-angle-right"></i>Fixed bugs with the signature table
<a target="_blank" href="//github.com/exodus4d/pathfinder/issues/690" rel="noopener">#690</a>,
<a target="_blank" href="//github.com/exodus4d/pathfinder/issues/691" rel="noopener">#691</a>
</li>
<li><i class="fas fa-fw fa-angle-right"></i>"Rally point and "route search" improvements <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/664" rel="noopener">#664</a></li>
<li><i class="fas fa-fw fa-angle-right"></i>Unique system URLs (e.g. in <em>Discord/Slack</em> messages) <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/682" rel="noopener">#682</a></li>
<li><i class="fas fa-fw fa-angle-right"></i>Improved "planet" information <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/684" rel="noopener">#684</a></li>
<li>
<i class="fas fa-fw fa-angle-right"></i>Performance improvements <a target="_blank" href="//github.com/exodus4d/pathfinder/issues/685" rel="noopener">#685</a>,
<a target="_blank" href="//github.com/exodus4d/pathfinder/issues/686" rel="noopener">#686</a>
</li>
<li><i class="fas fa-fw fa-angle-double-right"></i>Many more improvements/fixes and performance optimizations. Complete <a href="javascript:void(0)" class="pf-navbar-version-info">changelog</a></li>
<li><i class="fas fa-fw fa-angle-double-right"></i>Many more improvements/fixes. Complete <a href="javascript:void(0)" class="pf-navbar-version-info">changelog</a></li>
</ul>
</div>
</div>

View File

@@ -38,7 +38,7 @@ $red-darker: #a52521;
$red-darkest: #58100d;
// indigo
$indigo-light: #9fa8da;
$indigo-light: #9fa8da;
$indigo: #7986cb;
$indigo-dark: #5c6bc0;
$indigo-darkest: #313966;

View File

@@ -969,17 +969,17 @@ input[type="email"]{
.dropdown-submenu>a {
&:after{
display: block;
content: " ";
float: right;
display: block;
position: absolute;
right: 5px;
top: 7px;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: $gray-darker;
margin-top: 4px;
margin-right: 3px;
}
&:hover{

Some files were not shown because too many files have changed in this diff Show More