3540 lines
125 KiB
JavaScript
3540 lines
125 KiB
JavaScript
define([
|
|
'jquery',
|
|
'app/init',
|
|
'app/util',
|
|
'app/render',
|
|
'bootbox',
|
|
'app/ccp',
|
|
'jsPlumb',
|
|
'dragToSelect',
|
|
'select2',
|
|
'app/map/contextmenu',
|
|
'app/map/overlay'
|
|
], function($, Init, Util, Render, bootbox, CCP) {
|
|
|
|
'use strict';
|
|
|
|
var config = {
|
|
zIndexCounter: 110,
|
|
newSystemOffset: {
|
|
x: 130,
|
|
y: 0
|
|
},
|
|
|
|
mapSnapToGridDimension: 20, // px for grid snapping (grid YxY)
|
|
mapSnapToGrid: false, // Snap systems to grid while dragging
|
|
mapTabContentClass: 'pf-map-tab-content', // Tab-Content element (parent element)
|
|
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
|
headMapTrackingId: 'pf-head-map-tracking', // id for "map tracking" toggle (checkbox)
|
|
|
|
mapClass: 'pf-map', // class for all maps
|
|
mapGridClass: 'pf-grid-small', // class for map grid snapping
|
|
mapIdPrefix: 'pf-map-', // id prefix for all maps
|
|
systemIdPrefix: 'pf-system-', // id prefix for a system
|
|
systemClass: 'pf-system', // class for all systems
|
|
systemActiveClass: 'pf-system-active', // class for an active system in a map
|
|
systemSelectedClass: 'pf-system-selected', // class for selected systems in a map
|
|
systemLockedClass: 'pf-system-locked', // class for locked systems in a map
|
|
systemHeadClass: 'pf-system-head', // class for system head
|
|
systemHeadNameClass: 'pf-system-head-name', // class for system name
|
|
systemHeadExpandClass: 'pf-system-head-expand', // class for system head expand arrow
|
|
systemBodyClass: 'pf-system-body', // class for system body
|
|
systemBodyItemHeight: 16, // px of a system body entry
|
|
systemBodyItemClass: 'pf-system-body-item', // class for a system body entry
|
|
systemBodyItemStatusClass: 'pf-user-status', // class for player status in system body
|
|
systemBodyItemNameClass: 'pf-system-body-item-name', // class for player name in system body
|
|
systemBodyRightClass: 'pf-system-body-right', // class for player ship name in system body
|
|
systemTooltipInnerClass: 'pf-system-tooltip-inner', // class for system tooltip content
|
|
systemTooltipInnerIdPrefix: 'pf-system-tooltip-inner-', // id prefix for system tooltip content
|
|
dynamicElementWrapperId: 'pf-dialog-wrapper', // wrapper div for dynamic content (dialogs, context-menus,...)
|
|
|
|
// endpoint classes
|
|
endpointSourceClass: 'pf-map-endpoint-source',
|
|
endpointTargetClass: 'pf-map-endpoint-target',
|
|
|
|
// context menus
|
|
mapContextMenuId: 'pf-map-contextmenu',
|
|
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
|
|
|
|
// system security classes
|
|
systemSec: 'pf-system-sec',
|
|
systemSecHigh: 'pf-system-sec-highSec',
|
|
systemSecLow: 'pf-system-sec-lowSec',
|
|
systemSecNull: 'pf-system-sec-nullSec',
|
|
systemSecWHHeigh: 'pf-system-sec-high',
|
|
systemSecWHMid: 'pf-system-sec-mid',
|
|
systemSecWHLow: 'pf-system-sec-low'
|
|
};
|
|
|
|
// active jsPlumb instances currently running
|
|
var activeInstances = {};
|
|
|
|
// active connections per map (cache object)
|
|
var connectionCache = {};
|
|
|
|
// characterID => systemIds are cached temporary where the active user character is in
|
|
// if a character switches/add system, establish connection with "previous" system
|
|
var activeSystemCache = '';
|
|
|
|
// jsPlumb config
|
|
var globalMapConfig = {
|
|
source: {
|
|
filter: '.' + config.systemHeadNameClass,
|
|
//isSource:true,
|
|
isTarget:true, // add target Endpoint to each system (e.g. for drag&drop)
|
|
allowLoopback: false, // loopBack connections are not allowed
|
|
cssClass: config.endpointSourceClass,
|
|
uniqueEndpoint: false, // each connection has its own endpoint visible
|
|
dragOptions:{
|
|
},
|
|
connectionsDetachable: true, // dragOptions are set -> allow detaching them
|
|
maxConnections: 10 // due to isTarget is true, this is the max count of !out!-going connections
|
|
},
|
|
target: {
|
|
filter: '.' + config.systemHeadNameClass,
|
|
isSource:true,
|
|
//isTarget:true,
|
|
allowLoopback: false, // loopback connections are not allowed
|
|
cssClass: config.endpointTargetClass,
|
|
dropOptions: {
|
|
tolerance: 'touch',
|
|
hoverClass: config.systemActiveClass,
|
|
activeClass: 'dragActive',
|
|
}
|
|
},
|
|
connectionTypes: Init.connectionTypes
|
|
};
|
|
|
|
/**
|
|
* updates a system with current information
|
|
* @param map
|
|
* @param data
|
|
* @param currentUserIsHere boolean - if the current user is in this system
|
|
*/
|
|
$.fn.updateSystemUserData = function(map, data, currentUserIsHere){
|
|
|
|
var system = $(this);
|
|
var systemId = system.attr('id');
|
|
|
|
// find system body
|
|
var systemBody = $( system.find('.' + config.systemBodyClass) );
|
|
|
|
// find expand arrow
|
|
var systemHeadExpand = $( system.find('.' + config.systemHeadExpandClass) );
|
|
|
|
var oldCacheKey = system.data('userCache');
|
|
var oldUserCount = system.data('userCount');
|
|
oldUserCount = (oldUserCount !== undefined ? oldUserCount : 0);
|
|
var userCounter = 0;
|
|
|
|
system.data('currentUser', false);
|
|
|
|
// if current user is in THIS system trigger event
|
|
if(currentUserIsHere){
|
|
system.data('currentUser', true);
|
|
}
|
|
|
|
// add user information
|
|
if(
|
|
data &&
|
|
data.user
|
|
){
|
|
var cacheArray = [];
|
|
// loop all active pilots and build cache-key
|
|
for(var i = 0; i < data.user.length; i++){
|
|
userCounter++;
|
|
var tempUserData = data.user[i];
|
|
cacheArray.push(tempUserData.id + '_' + tempUserData.log.ship.id);
|
|
}
|
|
var cacheKey = cacheArray.join('_');
|
|
|
|
// check for if cacheKey has changed
|
|
if(cacheKey !== oldCacheKey){
|
|
// set new CacheKey
|
|
system.data('userCache', cacheKey);
|
|
system.data('userCount', userCounter);
|
|
|
|
// remove all content
|
|
systemBody.empty();
|
|
|
|
// loop "again" and build DOM object with user information
|
|
for(var j = 0; j < data.user.length; j++){
|
|
var userData = data.user[j];
|
|
|
|
var statusClass = Util.getStatusInfoForCharacter(userData, 'class');
|
|
var userName = userData.name;
|
|
|
|
var item = $('<div>', {
|
|
class: config.systemBodyItemClass
|
|
}).append(
|
|
$('<span>', {
|
|
text: userData.log.ship.typeName,
|
|
class: config.systemBodyRightClass
|
|
})
|
|
).append(
|
|
$('<i>', {
|
|
class: ['fa', 'fa-circle', config.systemBodyItemStatusClass, statusClass].join(' ')
|
|
})
|
|
).append(
|
|
$('<span>', {
|
|
class: config.systemBodyItemNameClass,
|
|
text: userName
|
|
})
|
|
);
|
|
|
|
systemBody.append(item);
|
|
}
|
|
|
|
|
|
// =================================================================
|
|
|
|
// user count changed -> change tooltip content
|
|
var tooltipOptions = {placement: 'top', trigger: 'manual'};
|
|
|
|
// set tooltip color
|
|
var highlight = false;
|
|
var tooltipIconClass = '';
|
|
if(userCounter > oldUserCount){
|
|
highlight = 'good';
|
|
tooltipIconClass = 'fa-caret-up';
|
|
}else if(userCounter < oldUserCount){
|
|
highlight = 'bad';
|
|
tooltipIconClass = 'fa-caret-down';
|
|
}
|
|
|
|
tooltipOptions.id = systemId;
|
|
tooltipOptions.highlight = highlight;
|
|
tooltipOptions.title = "<i class='fa " + tooltipIconClass + "'></i>";
|
|
tooltipOptions.title += ' ' + userCounter;
|
|
|
|
// show system head
|
|
systemHeadExpand.velocity('stop', true).velocity({
|
|
width: '10px'
|
|
},{
|
|
duration: 50,
|
|
display: 'inline-block',
|
|
progress: function(){
|
|
//revalidate element size and repaint
|
|
map.revalidate( systemId );
|
|
},
|
|
complete: function(){
|
|
// show system body
|
|
system.toggleBody(true, map, {complete: function(system){
|
|
// complete callback function
|
|
// show active user tooltip
|
|
system.toggleSystemTooltip('show', tooltipOptions);
|
|
}});
|
|
}
|
|
});
|
|
}
|
|
}else{
|
|
// no user data found for this system
|
|
system.data('userCache', false);
|
|
system.data('userCount', 0);
|
|
systemBody.empty();
|
|
|
|
if(
|
|
oldCacheKey &&
|
|
oldCacheKey.length > 0
|
|
){
|
|
// remove tooltip
|
|
system.toggleSystemTooltip('destroy', {});
|
|
|
|
// no user -> clear SystemBody
|
|
systemHeadExpand.velocity('stop').velocity('reverse',{
|
|
display: 'none',
|
|
complete: function(){
|
|
system.toggleBody(false, map, {});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* show/hide system body element
|
|
* @param type
|
|
* @param map
|
|
* @param callback
|
|
*/
|
|
$.fn.toggleBody = function(type, map, callback){
|
|
var system = $(this);
|
|
var systemBody = system.find('.' + config.systemBodyClass);
|
|
|
|
var systemDomId = system.attr('id');
|
|
|
|
if(type === true){
|
|
// show minimal body
|
|
systemBody.velocity({
|
|
height: config.systemBodyItemHeight + 'px'
|
|
},{
|
|
duration: 50,
|
|
display: 'auto',
|
|
progress: function(){
|
|
//revalidate element size and repaint
|
|
map.revalidate( systemDomId );
|
|
},
|
|
complete: function(){
|
|
map.revalidate( systemDomId );
|
|
|
|
if(callback.complete){
|
|
callback.complete(system);
|
|
}
|
|
}
|
|
});
|
|
}else if(type === false){
|
|
// hide body
|
|
// remove all inline styles -> possible relict from previous hover-extend
|
|
systemBody.velocity({
|
|
height: 0 + 'px',
|
|
width: '100%',
|
|
'min-width': 'none'
|
|
},{
|
|
duration: 50,
|
|
display: 'none',
|
|
begin: function(){
|
|
},
|
|
progress: function(){
|
|
// revalidate element size and repaint
|
|
map.revalidate( systemDomId );
|
|
},
|
|
complete: function(){
|
|
map.revalidate( systemDomId );
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* show/hide systems tooltip
|
|
* @param systems
|
|
* @param show
|
|
* @param options
|
|
*/
|
|
$.fn.toggleSystemTooltip = function(show, options){
|
|
|
|
// tooltip colors
|
|
var colorClasses = {
|
|
good: 'txt-color-green',
|
|
bad: 'txt-color-red'
|
|
};
|
|
|
|
return this.each(function(){
|
|
var system = $(this);
|
|
var tooltipId = 0;
|
|
var tooltipClassHighlight = false;
|
|
|
|
// do not update tooltips while a system is dragged
|
|
if(system.hasClass('jsPlumb_dragged')){
|
|
// skip system
|
|
return true;
|
|
}
|
|
|
|
if(show === 'destroy'){
|
|
system.tooltip( show );
|
|
system.removeAttr('data-original-title');
|
|
}else if(show === 'hide'){
|
|
system.tooltip( show );
|
|
} else if(show === 'toggle'){
|
|
system.tooltip( show );
|
|
}else if(show === 'show'){
|
|
|
|
// check if tooltip is currently visible
|
|
var tooltipActive = (system.attr('aria-describedby') !== undefined ? true : false);
|
|
|
|
if(options === undefined){
|
|
options = {};
|
|
}
|
|
|
|
// optional color highlight
|
|
if(colorClasses.hasOwnProperty( options.highlight )){
|
|
tooltipClassHighlight = colorClasses[ options.highlight ];
|
|
}
|
|
|
|
if(
|
|
tooltipActive === false &&
|
|
options.id
|
|
){
|
|
|
|
// init new tooltip
|
|
tooltipId = config.systemTooltipInnerIdPrefix + options.id;
|
|
|
|
var template = '<div class="tooltip" role="tooltip">' +
|
|
'<div class="tooltip-arrow"></div>' +
|
|
'<div id="' + tooltipId + '" class="tooltip-inner txt-color ' + config.systemTooltipInnerClass + '"></div>' +
|
|
'</div>';
|
|
|
|
options.html = true;
|
|
options.animation = true;
|
|
options.template = template;
|
|
options.viewport = system.parent('.' + config.mapClass);
|
|
|
|
system.attr('title', options.title);
|
|
|
|
system.tooltip(options);
|
|
|
|
system.tooltip(show);
|
|
|
|
if(tooltipClassHighlight !== false){
|
|
// set tooltip observer and set new class after open -> due to transition effect
|
|
|
|
system.on('shown.bs.tooltip', function() {
|
|
$('#' + tooltipId).addClass( tooltipClassHighlight );
|
|
// remove observer -> color should not be changed every time a tooltip toggles e.g. dragging system
|
|
$(this).off('shown.bs.tooltip');
|
|
});
|
|
}
|
|
}else{
|
|
// update/change/toggle tooltip text or color without tooltip reload
|
|
|
|
var tooltipInner = false;
|
|
if(
|
|
options.title ||
|
|
tooltipClassHighlight !== false
|
|
){
|
|
tooltipInner = system.tooltip('fixTitle')
|
|
.data('bs.tooltip')
|
|
.$tip.find('.tooltip-inner');
|
|
|
|
if(options.title){
|
|
tooltipInner.html( options.title );
|
|
}
|
|
|
|
if(tooltipClassHighlight !== false){
|
|
tooltipInner.removeClass( colorClasses.good + ' ' + colorClasses.bad).addClass(tooltipClassHighlight);
|
|
}
|
|
}
|
|
|
|
// show() can be forced
|
|
if(options.show === true){
|
|
system.tooltip('show');
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
});
|
|
};
|
|
|
|
/**
|
|
* set or change the status of a system
|
|
* @param status
|
|
*/
|
|
$.fn.setSystemStatus = function(status){
|
|
var system = $(this);
|
|
|
|
var statusId = Util.getStatusInfoForSystem(status, 'id');
|
|
var statusClass = Util.getStatusInfoForSystem(status, 'class');
|
|
|
|
for(var property in Init.systemStatus) {
|
|
if (Init.systemStatus.hasOwnProperty(property)) {
|
|
system.removeClass( Init.systemStatus[property].class );
|
|
}
|
|
}
|
|
|
|
// add new class
|
|
system.data('statusId', statusId);
|
|
system.addClass( statusClass );
|
|
};
|
|
|
|
/**
|
|
* returns a new system or updates an existing system
|
|
* @param map
|
|
* @param data
|
|
* @returns {HTMLElement}
|
|
*/
|
|
$.fn.getSystem = function(map, data){
|
|
|
|
// get map container for mapId information
|
|
var mapContainer = $(this);
|
|
|
|
var systemId = config.systemIdPrefix + mapContainer.data('id') + '-' + data.id;
|
|
|
|
// check if system already exists
|
|
var system = document.getElementById( systemId );
|
|
|
|
var newPosX = data.position.x + 'px';
|
|
var newPosY = data.position.y + 'px';
|
|
|
|
if(!system){
|
|
|
|
// set system name or alias
|
|
var systemName = data.name;
|
|
|
|
if(
|
|
data.alias &&
|
|
data.alias !== ''
|
|
){
|
|
systemName = data.alias;
|
|
}
|
|
|
|
// get system info classes
|
|
var effectBasicClass = Util.getEffectInfoForSystem('effect', 'class');
|
|
var effectName = Util.getEffectInfoForSystem(data.effect, 'name');
|
|
var effectClass = Util.getEffectInfoForSystem(data.effect, 'class');
|
|
var secClass = Util.getSecurityClassForSystem(data.security);
|
|
|
|
system = $('<div>', {
|
|
// system
|
|
id: systemId,
|
|
class: config.systemClass
|
|
}).append(
|
|
// system head
|
|
$('<div>', {
|
|
class: config.systemHeadClass
|
|
}).append(
|
|
// System name is editable
|
|
$('<a>', {
|
|
href: '#',
|
|
class: config.systemHeadNameClass
|
|
}).attr('data-value', systemName)
|
|
).append(
|
|
// System locked status
|
|
$('<i>', {
|
|
class: ['fa', 'fa-lock', 'fa-fw'].join(' ')
|
|
}).attr('title', 'locked')
|
|
).append(
|
|
// System effect color
|
|
$('<i>', {
|
|
class: ['fa', 'fa-square ', 'fa-fw', effectBasicClass, effectClass].join(' ')
|
|
}).attr('title', effectName)
|
|
).append(
|
|
// expand option
|
|
$('<i>', {
|
|
class: ['fa', 'fa-angle-down ', config.systemHeadExpandClass].join(' ')
|
|
})
|
|
).prepend(
|
|
$('<span>', {
|
|
class: [config.systemSec, secClass].join(' '),
|
|
text: data.security
|
|
})
|
|
)
|
|
).append(
|
|
// system body
|
|
$('<div>', {
|
|
class: config.systemBodyClass
|
|
})
|
|
);
|
|
|
|
// set initial system position
|
|
system.css({
|
|
'left': newPosX,
|
|
'top': newPosY
|
|
});
|
|
|
|
}else{
|
|
system = $(system);
|
|
|
|
// set system position
|
|
var currentPosX = system.css('left');
|
|
var currentPosY = system.css('top');
|
|
|
|
if(
|
|
newPosX !== currentPosX ||
|
|
newPosY !== currentPosY
|
|
){
|
|
// change position with animation
|
|
system.velocity(
|
|
{
|
|
left: newPosX,
|
|
top: newPosY
|
|
},{
|
|
easing: 'linear',
|
|
duration: Init.animationSpeed.mapMoveSystem,
|
|
begin: function(system){
|
|
// hide system tooltip
|
|
$(system).toggleSystemTooltip('hide', {});
|
|
|
|
// move them to the "top"
|
|
$(system).updateSystemZIndex();
|
|
},
|
|
progress: function(){
|
|
map.revalidate( systemId );
|
|
},
|
|
complete: function(system){
|
|
// show tooltip
|
|
$(system).toggleSystemTooltip('show', {show: true});
|
|
|
|
map.revalidate( systemId );
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
// set system alias
|
|
var alias = system.getSystemInfo(['alias']);
|
|
|
|
if(alias !== data.alias){
|
|
// alias changed
|
|
system.find('.' + config.systemHeadNameClass).editable('setValue', data.alias);
|
|
}
|
|
}
|
|
|
|
// set system status
|
|
system.setSystemStatus(data.status.name);
|
|
system.data('id', parseInt(data.id));
|
|
system.data('systemId', parseInt(data.systemId));
|
|
system.data('name', data.name);
|
|
system.data('typeId', parseInt(data.type.id));
|
|
system.data('effect', data.effect);
|
|
system.data('security', data.security);
|
|
system.data('trueSec', parseFloat(data.trueSec));
|
|
system.data('regionId', parseInt(data.region.id));
|
|
system.data('region', data.region.name);
|
|
system.data('constellationId', parseInt(data.constellation.id));
|
|
system.data('constellation', data.constellation.name);
|
|
system.data('statics', data.statics);
|
|
system.data('updated', parseInt(data.updated.updated));
|
|
system.attr('data-mapid', parseInt(mapContainer.data('id')));
|
|
|
|
// locked system
|
|
if( Boolean( system.data( 'locked') ) !== Boolean( parseInt( data.locked ) )){
|
|
system.toggleLockSystem(false, {hideNotification: true, hideCounter: true, map: map});
|
|
}
|
|
|
|
// rally system
|
|
if( Boolean( system.data( 'rally') ) !== Boolean( parseInt( data.rally ) )){
|
|
system.toggleRallyPoint(false, {hideNotification: true, hideCounter: true});
|
|
}
|
|
|
|
return system;
|
|
};
|
|
|
|
/**
|
|
* draw a new map or update an existing map with all its systems and connections
|
|
* @param parentElement
|
|
* @param mapConfig
|
|
* @returns {*}
|
|
*/
|
|
var updateMap = function(parentElement, mapConfig){
|
|
|
|
var mapContainer = mapConfig.map.getContainer();
|
|
|
|
if(mapContainer === undefined){
|
|
// add new map
|
|
|
|
// create map wrapper
|
|
var mapWrapper = $('<div>', {
|
|
class: config.mapWrapperClass
|
|
});
|
|
|
|
// create new map container
|
|
mapContainer = $('<div>', {
|
|
id: config.mapIdPrefix + mapConfig.config.id,
|
|
class: [config.mapClass].join(' ')
|
|
});
|
|
|
|
// add additional information
|
|
mapContainer.data('id', mapConfig.config.id);
|
|
|
|
mapWrapper.append(mapContainer);
|
|
|
|
// append mapWrapper to parent element (at the top)
|
|
$(parentElement).prepend(mapWrapper);
|
|
|
|
// set main Container for current map -> the container exists now in DOM !! very important
|
|
mapConfig.map.setContainer( config.mapIdPrefix + mapConfig.config.id );
|
|
|
|
// set map observer
|
|
setMapObserver(mapConfig.map);
|
|
}
|
|
|
|
mapContainer = $(mapContainer);
|
|
|
|
// add additional information for this map
|
|
if(mapContainer.data('updated') !== mapConfig.config.updated){
|
|
mapContainer.data('name', mapConfig.config.name);
|
|
mapContainer.data('scopeId', mapConfig.config.scope.id);
|
|
mapContainer.data('typeId', mapConfig.config.type.id);
|
|
mapContainer.data('icon', mapConfig.config.icon);
|
|
mapContainer.data('created', mapConfig.config.created);
|
|
mapContainer.data('updated', mapConfig.config.updated);
|
|
}
|
|
|
|
|
|
// get map data
|
|
var mapData = mapContainer.getMapDataFromClient({forceData: false});
|
|
|
|
if(mapData !== false){
|
|
// map data available -> map not locked by update counter :)
|
|
|
|
var currentSystemData = mapData.data.systems;
|
|
var currentConnectionData = mapData.data.connections;
|
|
|
|
// update systems ===========================================================
|
|
for(var i = 0; i < mapConfig.data.systems.length; i++){
|
|
var systemData = mapConfig.data.systems[i];
|
|
|
|
// add system
|
|
var addNewSystem = true;
|
|
|
|
for(var k = 0; k < currentSystemData.length; k++){
|
|
if(currentSystemData[k].id === systemData.id){
|
|
if( currentSystemData[k].updated.updated < systemData.updated.updated ){
|
|
// system changed -> update
|
|
mapContainer.getSystem(mapConfig.map, systemData);
|
|
}
|
|
|
|
addNewSystem = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( addNewSystem === true){
|
|
drawSystem(mapConfig.map, systemData);
|
|
}
|
|
}
|
|
|
|
// check for systems that are gone -> delete system
|
|
for(var a = 0; a < currentSystemData.length; a++){
|
|
|
|
var deleteThisSystem = true;
|
|
|
|
for(var b = 0; b < mapConfig.data.systems.length; b++){
|
|
var deleteSystemData = mapConfig.data.systems[b];
|
|
|
|
if(deleteSystemData.id === currentSystemData[a].id){
|
|
deleteThisSystem = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(deleteThisSystem === true){
|
|
var deleteSystem = $('#' + config.systemIdPrefix + mapContainer.data('id') + '-' + currentSystemData[a].id);
|
|
|
|
// system not found -> delete system
|
|
removeSystem(mapConfig.map, deleteSystem);
|
|
}
|
|
}
|
|
|
|
// update connections =========================================================
|
|
|
|
// jsPlumb batch() is used, otherwise there are some "strange" visual bugs
|
|
// when switching maps (Endpoints are not displayed correctly)
|
|
mapConfig.map.batch(function() {
|
|
|
|
for(var j = 0; j < mapConfig.data.connections.length; j++){
|
|
var connectionData = mapConfig.data.connections[j];
|
|
|
|
// add connection
|
|
var addNewConnection= true;
|
|
|
|
for(var c = 0; c < currentConnectionData.length; c++){
|
|
if(
|
|
currentConnectionData[c].id === connectionData.id
|
|
){
|
|
// connection already exists -> check for updates
|
|
if(
|
|
currentConnectionData[c].updated < connectionData.updated
|
|
){
|
|
// connection changed -> update
|
|
var tempConnection = $().getConnectionById(mapData.config.id, connectionData.id);
|
|
updateConnection(tempConnection, currentConnectionData[c], connectionData);
|
|
}
|
|
|
|
addNewConnection = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(addNewConnection === true){
|
|
drawConnection(mapConfig.map, connectionData);
|
|
}
|
|
}
|
|
|
|
// check for connections that are gone -> delete connection
|
|
for(var d = 0; d < currentConnectionData.length; d++){
|
|
|
|
var deleteThisConnection = true;
|
|
|
|
for(var e = 0; e < mapConfig.data.connections.length;e++){
|
|
var deleteConnectionData = mapConfig.data.connections[e];
|
|
|
|
if(deleteConnectionData.id === currentConnectionData[d].id){
|
|
deleteThisConnection = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(deleteThisConnection === true){
|
|
// get connection from cache -> delete connection
|
|
var deleteConnection = $().getConnectionById(mapData.config.id, currentConnectionData[d].id);
|
|
|
|
if(deleteConnection){
|
|
// check if "source" and "target" still exist before remove
|
|
// this is NOT the case if the system was removed previous
|
|
if(
|
|
deleteConnection.source &&
|
|
deleteConnection.target
|
|
){
|
|
mapConfig.map.detach(deleteConnection, {fireEvent: false});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
return mapContainer;
|
|
};
|
|
|
|
/**
|
|
* update local connection cache
|
|
* @param mapId
|
|
* @param connection
|
|
*/
|
|
var updateConnectionCache = function(mapId, connection){
|
|
|
|
if(
|
|
mapId > 0 &&
|
|
connection
|
|
){
|
|
var connectionId = parseInt( connection.getParameter('connectionId') );
|
|
|
|
if(connectionId > 0){
|
|
connectionCache[mapId][connectionId] = connection;
|
|
}else{
|
|
console.error('updateConnectionCache', 'connectionId missing');
|
|
}
|
|
}else{
|
|
console.error('updateConnectionCache', 'missing data');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* get a connection object from "cache" (this requires the "connectionCache" cache to be actual!
|
|
* @param mapId
|
|
* @param connectionId
|
|
* @returns {*}
|
|
*/
|
|
$.fn.getConnectionById = function(mapId, connectionId){
|
|
|
|
var connection = null;
|
|
|
|
if(
|
|
connectionCache[mapId] &&
|
|
connectionCache[mapId][connectionId]
|
|
){
|
|
connection = connectionCache[mapId][connectionId];
|
|
}
|
|
|
|
return connection;
|
|
};
|
|
|
|
/**
|
|
* make all systems appear visual on the map with its connections
|
|
* @param show
|
|
* @param callback
|
|
*/
|
|
$.fn.visualizeMap = function(show, callback){
|
|
var mapElement = $(this);
|
|
|
|
// start map update counter -> prevent map updates during animations
|
|
mapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
var systemElements = mapElement.find('.' + config.systemClass);
|
|
var endpointElements = mapElement.find('._jsPlumb_endpoint');
|
|
var connectorElements = mapElement.find('._jsPlumb_connector');
|
|
var overlayElements = mapElement.find('._jsPlumb_overlay, .tooltip');
|
|
|
|
// if map empty (no systems), execute callback and return
|
|
// no visual effects in IGB (glitches)
|
|
if(
|
|
systemElements.length === 0 ||
|
|
endpointElements.length === 0 ||
|
|
CCP.isInGameBrowser() === true
|
|
){
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
// show nice animation
|
|
if(show === 'show'){
|
|
// hide elements
|
|
systemElements.css('opacity', 0);
|
|
endpointElements.css('opacity', 0);
|
|
connectorElements.css('opacity', 0);
|
|
overlayElements.css('opacity', 0);
|
|
|
|
systemElements.velocity('transition.whirlIn', {
|
|
stagger: 30,
|
|
drag: true,
|
|
duration: 100,
|
|
//display: 'auto',
|
|
complete: function(){
|
|
// show connections
|
|
endpointElements.velocity('transition.fadeIn', {
|
|
duration: 0
|
|
});
|
|
|
|
connectorElements.velocity('transition.fadeIn', {
|
|
stagger: 30,
|
|
duration: 120
|
|
});
|
|
|
|
// show overlay elements (if some exist)
|
|
if(overlayElements.length > 0){
|
|
overlayElements.delay(500).velocity('transition.fadeIn', {
|
|
stagger: 50,
|
|
duration: 180,
|
|
display: 'auto',
|
|
complete: function(){
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}else if(show === 'hide'){
|
|
|
|
$('.mCSB_container').velocity('callout.shake', {
|
|
stagger: 0,
|
|
drag: false,
|
|
duration: 180,
|
|
display: 'auto'
|
|
});
|
|
|
|
overlayElements.velocity('transition.fadeOut', {
|
|
stagger: 50,
|
|
drag: true,
|
|
duration: 180,
|
|
display: 'auto'
|
|
});
|
|
|
|
endpointElements.velocity('transition.fadeOut', {
|
|
duration: 0,
|
|
display: 'block',
|
|
complete: function(){
|
|
// show connections
|
|
connectorElements.velocity('transition.fadeOut', {
|
|
stagger: 0,
|
|
drag: true,
|
|
duration: 20,
|
|
display: 'block'
|
|
});
|
|
|
|
systemElements.delay(100).velocity('transition.slideUpOut', {
|
|
stagger: 30,
|
|
drag: true,
|
|
duration: 180,
|
|
display: 'block',
|
|
complete: function(){
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* mark a system as source
|
|
* @param map
|
|
* @param system
|
|
*/
|
|
var makeSource = function(map, system){
|
|
|
|
// get scope from map defaults
|
|
var sourceConfig = globalMapConfig.source;
|
|
sourceConfig.scope = map.Defaults.Scope; // set all allowed connections for this scopes
|
|
|
|
// default connector for initial dragging a new connection
|
|
sourceConfig.connector = Util.getScopeInfoForConnection('wh', 'connectorDefinition');
|
|
|
|
map.makeSource(system, sourceConfig);
|
|
};
|
|
|
|
/**
|
|
* mark a system as target
|
|
* @param map
|
|
* @param system
|
|
*/
|
|
var makeTarget = function(map, system){
|
|
|
|
// get scope from map defaults
|
|
var targetConfig = globalMapConfig.target;
|
|
targetConfig.scope = map.Defaults.Scope; // set all allowed connections for this scopes
|
|
|
|
map.makeTarget(system, targetConfig);
|
|
};
|
|
|
|
/**
|
|
* checks if json system data is valid
|
|
* @param systemData
|
|
* @returns {boolean}
|
|
*/
|
|
var isValidSystem = function(systemData){
|
|
|
|
var isValid = true;
|
|
|
|
if(
|
|
! systemData.hasOwnProperty('name') ||
|
|
systemData.name.length === 0
|
|
){
|
|
return false;
|
|
}
|
|
|
|
return isValid;
|
|
};
|
|
|
|
/**
|
|
* draw a system with its data to a map
|
|
* @param map object
|
|
* @param systemData
|
|
* @param {String[]} optional Systems for connection
|
|
*/
|
|
var drawSystem = function(map, systemData, connectedSystem){
|
|
|
|
// check if systemData is valid
|
|
if(isValidSystem(systemData)){
|
|
var mapContainer = $(map.getContainer());
|
|
|
|
// get System Element by data
|
|
var newSystem = mapContainer.getSystem(map, systemData);
|
|
|
|
// add new system to map
|
|
mapContainer.append(newSystem);
|
|
|
|
// make new system editable
|
|
makeEditable(newSystem);
|
|
|
|
// make target
|
|
makeTarget(map, newSystem);
|
|
|
|
// make source
|
|
makeSource(map, newSystem);
|
|
|
|
// set system observer
|
|
setSystemObserver(map, newSystem);
|
|
|
|
// connect new system (if connection data is given)
|
|
if(connectedSystem){
|
|
|
|
// hint: "type" will be auto detected by jump distance
|
|
var connectionData = {
|
|
source: $(connectedSystem).data('id'),
|
|
target: newSystem.data('id'),
|
|
type: ['wh_fresh'] // default type.
|
|
};
|
|
var connection = drawConnection(map, connectionData);
|
|
|
|
// store connection
|
|
saveConnection(connection);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* delete a system with all its connections
|
|
* (ajax call) remove system from DB
|
|
* @param map
|
|
* @param systems
|
|
* @param callback function
|
|
*/
|
|
var deleteSystems = function(map, systems, callback){
|
|
|
|
var mapContainer = $( map.getContainer() );
|
|
|
|
mapContainer.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
var systemIds = [];
|
|
// systemIds for delete request
|
|
for(var i = 0; i < systems.length; i++){
|
|
systemIds.push( $(systems[i]).data('id') );
|
|
}
|
|
|
|
var requestData = {
|
|
systemIds: systemIds
|
|
};
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: Init.path.deleteSystem,
|
|
data: requestData,
|
|
dataType: 'json',
|
|
context: {
|
|
map: map,
|
|
systems: systems
|
|
}
|
|
}).done(function(){
|
|
// deleted SystemIds
|
|
var triggerData = {
|
|
systemIds: []
|
|
};
|
|
|
|
// remove systems from map
|
|
for(var i = 0; i < this.systems.length; i++){
|
|
var system = $(this.systems[i]);
|
|
triggerData.systemIds.push( system.data('id') );
|
|
removeSystem(this.map, system );
|
|
}
|
|
|
|
callback();
|
|
}).fail(function( jqXHR, status, error) {
|
|
var reason = status + ' ' + error;
|
|
Util.showNotify({title: jqXHR.status + ': deleteSystem', text: reason, type: 'warning'});
|
|
$(document).setProgramStatus('problem');
|
|
});
|
|
};
|
|
|
|
/**
|
|
* remove a system from map (no backend requests)
|
|
* @param map
|
|
* @param system
|
|
*/
|
|
var removeSystem = function(map, system){
|
|
system = $(system);
|
|
|
|
// check if system is "active"
|
|
if( system.hasClass(config.systemActiveClass) ){
|
|
// get parent Tab Content and fire clear modules event
|
|
var tabContentElement = getTabContentElementByMapElement( system );
|
|
|
|
$(tabContentElement).trigger('pf:removeSystemModules');
|
|
}
|
|
|
|
// remove endpoints and their connections
|
|
// do not fire a "connectionDetached" event
|
|
map.detachAllConnections(system, {fireEvent: false});
|
|
|
|
// hide tooltip
|
|
system.toggleSystemTooltip('destroy', {});
|
|
|
|
// remove system
|
|
system.velocity('transition.whirlOut', {
|
|
duration: Init.animationSpeed.mapDeleteSystem,
|
|
complete: function(){
|
|
map.remove(this);
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* make a system name/alias editable by x-editable
|
|
* @param system
|
|
*/
|
|
var makeEditable = function(system){
|
|
system = $(system);
|
|
var headElement = $(system).find('.' + config.systemHeadNameClass);
|
|
|
|
headElement.editable({
|
|
mode: 'popup',
|
|
type: 'text',
|
|
name: 'alias',
|
|
emptytext: system.data('name'),
|
|
title: 'System alias',
|
|
placement: 'top',
|
|
onblur: 'submit',
|
|
container: 'body',
|
|
toggle: 'manual', // is triggered manually on dblclick
|
|
showbuttons: false
|
|
});
|
|
|
|
headElement.on('save', function(e, params) {
|
|
// system alias changed -> mark system as updated
|
|
system.markAsChanged();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* update z-index for a system (dragged systems should be always on top)
|
|
* @param system
|
|
*/
|
|
$.fn.updateSystemZIndex = function(){
|
|
return this.each(function(){
|
|
// increase global counter
|
|
var newZIndexSystem = config.zIndexCounter++;
|
|
$(this).css('z-index', newZIndexSystem);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* get all connections of multiple systems
|
|
* @param map
|
|
* @param systems
|
|
* @returns {Array}
|
|
*/
|
|
var getConnections = function(map, systems){
|
|
|
|
var connections = [];
|
|
|
|
var withBackConnection = false;
|
|
|
|
$.each(systems, function(i, system){
|
|
// get connections where system is source
|
|
connections = connections.concat( map.getConnections({source: system}) );
|
|
|
|
if(withBackConnection === true){
|
|
// get connections where system is target
|
|
connections = connections.concat( map.getConnections({target: system}) );
|
|
}
|
|
|
|
});
|
|
|
|
return connections;
|
|
};
|
|
|
|
/**
|
|
* get all direct connections between two given systems
|
|
* @param map
|
|
* @param systemA
|
|
* @param systemB
|
|
* @returns {Array}
|
|
*/
|
|
var checkForConnection = function(map, systemA, systemB){
|
|
|
|
var connections = [];
|
|
|
|
connections = connections.concat( map.getConnections({scope: '*', source: systemA, target: systemB}) );
|
|
// get connections where system is target
|
|
connections = connections.concat( map.getConnections({scope: '*', source: systemB, target: systemA}) );
|
|
|
|
return connections;
|
|
};
|
|
|
|
/**
|
|
* connect two systems
|
|
* @param mapConfig
|
|
* @param connectionData
|
|
* @returns new connection
|
|
*/
|
|
var drawConnection = function(map, connectionData){
|
|
|
|
var mapContainer = $( map.getContainer() );
|
|
var mapId = mapContainer.data('id');
|
|
|
|
// connection id
|
|
var connectionId = 0;
|
|
if(connectionData.id){
|
|
connectionId = connectionData.id;
|
|
}
|
|
|
|
var connection = map.connect({
|
|
source: config.systemIdPrefix + mapId + '-' + connectionData.source,
|
|
target: config.systemIdPrefix + mapId + '-' + connectionData.target,
|
|
parameters: {
|
|
connectionId: connectionId,
|
|
updated: connectionData.updated
|
|
},
|
|
type: null
|
|
/* experimental (straight connections)
|
|
anchors: [
|
|
[ "Perimeter", { shape: 'Rectangle' }],
|
|
[ "Perimeter", { shape: 'Rectangle' }]
|
|
]
|
|
*/
|
|
});
|
|
|
|
// add connection types -----------------------------------------------------
|
|
if(connectionData.type){
|
|
for(var i = 0; i < connectionData.type.length; i++){
|
|
connection.addType(connectionData.type[i]);
|
|
}
|
|
}
|
|
|
|
// add connection scope -----------------------------------------------------
|
|
// connection have the default map Scope scope
|
|
var scope = map.Defaults.Scope;
|
|
if(connectionData.scope){
|
|
scope = connectionData.scope;
|
|
}
|
|
setConnectionScope(connection, scope);
|
|
|
|
// set Observer for new Connection -> is automatically set
|
|
|
|
return connection;
|
|
};
|
|
|
|
/**
|
|
* stores a connection in database
|
|
* @param connection
|
|
*/
|
|
var saveConnection = function(connection){
|
|
|
|
var map = connection._jsPlumb.instance;
|
|
var mapContainer = $( map.getContainer() );
|
|
mapContainer.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
var mapId = mapContainer.data('id');
|
|
var connectionData = getDataByConnection(connection);
|
|
|
|
var requestData = {
|
|
mapData: {
|
|
id: mapId
|
|
},
|
|
connectionData: connectionData
|
|
};
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: Init.path.saveConnection,
|
|
data: requestData,
|
|
dataType: 'json',
|
|
//context: connection
|
|
context: {
|
|
connection: connection,
|
|
mapId: mapId
|
|
}
|
|
}).done(function(newConnectionData){
|
|
|
|
// update connection data e.g. "scope" has auto detected
|
|
connection = updateConnection(this.connection, connectionData, newConnectionData);
|
|
|
|
// new connection should be cached immediately!
|
|
updateConnectionCache(this.mapId, connection);
|
|
|
|
// connection scope
|
|
var scope = Util.getScopeInfoForConnection(newConnectionData.scope, 'label');
|
|
|
|
var title = 'New connection established';
|
|
if(connectionData.id > 0){
|
|
title = 'Connection switched';
|
|
}
|
|
|
|
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
|
|
}).fail(function( jqXHR, status, error) {
|
|
|
|
// remove this connection from map
|
|
this._jsPlumb.instance.detach(this);
|
|
|
|
var reason = status + ' ' + error;
|
|
Util.showNotify({title: jqXHR.status + ': saveConnection', text: reason, type: 'warning'});
|
|
$(document).setProgramStatus('problem');
|
|
});
|
|
};
|
|
|
|
/**
|
|
* delete a connection and all related data
|
|
* @param connections
|
|
*/
|
|
$.fn.deleteConnections = function(connections, callback){
|
|
if(connections.length > 0){
|
|
|
|
// remove connections from map
|
|
var removeConnections = function(tempConnections){
|
|
for(var i = 0; i < tempConnections.length; i++){
|
|
// if a connection is manually (drag&drop) detached, the jsPlumb instance does not exist any more
|
|
// connection is already deleted!
|
|
if(tempConnections[i]._jsPlumb){
|
|
tempConnections[i]._jsPlumb.instance.detach(tempConnections[i], {fireEvent: false});
|
|
}
|
|
}
|
|
};
|
|
|
|
// prepare delete request
|
|
var map = connections[0]._jsPlumb.instance;
|
|
var mapContainer = $( map.getContainer() );
|
|
mapContainer.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
var connectionIds = [];
|
|
// connectionIds for delete request
|
|
for(var i = 0; i < connections.length; i++){
|
|
var connectionId = connections[i].getParameter('connectionId');
|
|
// drag&drop a new connection does not have an id yet, if connection is not established correct
|
|
if(connectionId !== undefined){
|
|
connectionIds[i] = connections[i].getParameter('connectionId');
|
|
}
|
|
}
|
|
|
|
if(connectionIds.length > 0){
|
|
var requestData = {
|
|
connectionIds: connectionIds
|
|
};
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: Init.path.deleteConnection,
|
|
data: requestData,
|
|
dataType: 'json',
|
|
context: connections
|
|
}).done(function(data){
|
|
|
|
// remove connections from map
|
|
removeConnections(this);
|
|
|
|
// optional callback
|
|
if(callback){
|
|
callback();
|
|
}
|
|
|
|
}).fail(function( jqXHR, status, error) {
|
|
var reason = status + ' ' + error;
|
|
Util.showNotify({title: jqXHR.status + ': deleteSystem', text: reason, type: 'warning'});
|
|
$(document).setProgramStatus('problem');
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* compares the current data and new data of a connection and updates status
|
|
* @param connection
|
|
* @param connectionData
|
|
* @param newConnectionData
|
|
* @returns {*}
|
|
*/
|
|
var updateConnection = function(connection, connectionData, newConnectionData){
|
|
|
|
var map = connection._jsPlumb.instance;
|
|
var mapContainer = $( map.getContainer() );
|
|
var mapId = mapContainer.data('id');
|
|
|
|
// check id, IDs should never change but must be set after initial save
|
|
if(connection.getParameter('connectionId') !== newConnectionData.id){
|
|
connection.setParameter('connectionId', newConnectionData.id);
|
|
}
|
|
|
|
// check scope
|
|
if(connectionData.scope !== newConnectionData.scope){
|
|
setConnectionScope(connection, newConnectionData.scope);
|
|
// for some reason the observers are gone after scope change...
|
|
setConnectionObserver(map, connection);
|
|
}
|
|
|
|
var addType = $(newConnectionData.type).not(connectionData.type).get();
|
|
var removeType = $(connectionData.type).not(newConnectionData.type).get();
|
|
|
|
// check if source or target has changed
|
|
if(connectionData.source !== newConnectionData.source ){
|
|
map.setSource(connection, config.systemIdPrefix + mapId + '-' + newConnectionData.source);
|
|
}
|
|
if(connectionData.target !== newConnectionData.target ){
|
|
map.setTarget(connection, config.systemIdPrefix + mapId + '-' + newConnectionData.target);
|
|
}
|
|
|
|
// connection.targetId
|
|
// add types
|
|
for(var i = 0; i < addType.length; i++){
|
|
if(
|
|
addType[i].indexOf('fresh') !== -1 ||
|
|
addType[i].indexOf('reduced') !== -1 ||
|
|
addType[i].indexOf('critical') !== -1
|
|
){
|
|
setConnectionWHStatus(connection, addType[i]);
|
|
}else if( connection.hasType(addType[i]) !== true ){
|
|
// additional types e.g. eol, frig, preserve mass
|
|
connection.addType(addType[i]);
|
|
setConnectionObserver(map, connection);
|
|
}
|
|
}
|
|
|
|
// remove types
|
|
for(var j = 0; j < removeType.length; j++){
|
|
if(
|
|
removeType[j] === 'wh_eol' ||
|
|
removeType[j] === 'frigate' ||
|
|
removeType[j] === 'preserve_mass'
|
|
){
|
|
connection.removeType(removeType[j]);
|
|
setConnectionObserver(map, connection);
|
|
}
|
|
}
|
|
|
|
// set update date
|
|
connection.setParameter('updated', newConnectionData.updated);
|
|
|
|
return connection;
|
|
};
|
|
|
|
/**
|
|
* set/change connection scope
|
|
* @param connection
|
|
* @param scope
|
|
*/
|
|
var setConnectionScope = function(connection, scope){
|
|
var map = connection._jsPlumb.instance;
|
|
var currentConnector = connection.getConnector();
|
|
var newConnector = Util.getScopeInfoForConnection(scope, 'connectorDefinition');
|
|
|
|
if(currentConnector.type !== newConnector[0]){
|
|
// connector has changed
|
|
|
|
connection.setConnector( newConnector );
|
|
|
|
// remove all connection types
|
|
connection.clearTypes();
|
|
|
|
// set new new connection type
|
|
// if scope changed -> connection type == scope
|
|
connection.setType( getDefaultConnectionTypeByScope(scope) );
|
|
|
|
// change scope
|
|
connection.scope = scope;
|
|
|
|
// new observer is required after scope change
|
|
setConnectionObserver(map, connection);
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* get the default connection type for a scope
|
|
* e.g. for new type after scope change
|
|
* @param scope
|
|
* @returns {string}
|
|
*/
|
|
var getDefaultConnectionTypeByScope = function(scope){
|
|
|
|
var type = '';
|
|
switch(scope){
|
|
case 'wh':
|
|
type = 'wh_fresh';
|
|
break;
|
|
case 'jumpbridge':
|
|
type = 'jumpbridge';
|
|
break;
|
|
case'stargate':
|
|
type = 'stargate';
|
|
break;
|
|
}
|
|
|
|
return type;
|
|
};
|
|
|
|
/**
|
|
* set/change connection status of a wormhole
|
|
* @param connection
|
|
* @param status
|
|
*/
|
|
var setConnectionWHStatus = function(connection, status){
|
|
|
|
if(
|
|
status === 'wh_fresh' &&
|
|
connection.hasType('wh_fresh') !== true
|
|
){
|
|
connection.removeType('wh_reduced');
|
|
connection.removeType('wh_critical');
|
|
connection.addType('wh_fresh');
|
|
}else if(
|
|
status === 'wh_reduced' &&
|
|
connection.hasType('wh_reduced') !== true
|
|
){
|
|
connection.removeType('wh_fresh');
|
|
connection.removeType('wh_critical');
|
|
connection.addType('wh_reduced');
|
|
}else if(
|
|
status === 'wh_critical' &&
|
|
connection.hasType('wh_critical') !== true
|
|
){
|
|
connection.removeType('wh_fresh');
|
|
connection.removeType('wh_reduced');
|
|
connection.addType('wh_critical');
|
|
}else if(
|
|
status === 'wh_eol' &&
|
|
connection.hasType('wh_eol') !== true
|
|
){
|
|
connection.addType('wh_eol');
|
|
}else if(
|
|
status === 'wh_eol' &&
|
|
connection.hasType('wh_eol') !== true
|
|
){
|
|
connection.addType('wh_eol');
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* load context menu template for map
|
|
*/
|
|
var initMapContextMenu = function(){
|
|
|
|
var moduleConfig = {
|
|
name: 'modules/contextmenu',
|
|
position: $('#' + config.dynamicElementWrapperId)
|
|
};
|
|
|
|
var moduleData = {
|
|
id: config.mapContextMenuId,
|
|
items: [
|
|
{icon: 'fa-info', action: 'info', text: 'info'},
|
|
{icon: 'fa-plus', action: 'add_system', text: 'add system'},
|
|
{icon: 'fa-object-ungroup', action: 'select_all', text: 'select all'},
|
|
{icon: 'fa-filter', action: 'filter_scope', text: 'filter scope', subitems: [
|
|
{subIcon: '', subAction: 'filter_wh', subText: 'wormhole'},
|
|
{subIcon: '', subAction: 'filter_stargate', subText: 'stargate'},
|
|
{subIcon: '', subAction: 'filter_jumpbridge', subText: 'jumpbridge'}
|
|
]},
|
|
{divider: true, action: 'delete_systems'},
|
|
{icon: 'fa-eraser', action: 'delete_systems', text: 'delete systems'}
|
|
]
|
|
};
|
|
|
|
Render.showModule(moduleConfig, moduleData);
|
|
};
|
|
|
|
/**
|
|
* load contextmenu template for connections
|
|
*/
|
|
var initConnectionContextMenu = function(){
|
|
|
|
var moduleConfig = {
|
|
name: 'modules/contextmenu',
|
|
position: $('#' + config.dynamicElementWrapperId)
|
|
};
|
|
|
|
var moduleData = {
|
|
id: config.connectionContextMenuId,
|
|
items: [
|
|
{icon: 'fa-plane', action: 'frigate', text: 'frigate hole'},
|
|
{icon: 'fa-warning', action: 'preserve_mass', text: 'preserve mass'},
|
|
{icon: 'fa-crosshairs', action: 'change_scope', text: 'change scope', subitems: [
|
|
{subIcon: 'fa-minus-circle', subIconClass: '', subAction: 'scope_wh', subText: 'wormhole'},
|
|
{subIcon: 'fa-minus-circle', subIconClass: 'txt-color txt-color-indigoDarkest', subAction: 'scope_stargate', subText: 'stargate'},
|
|
{subIcon: 'fa-minus-circle', subIconClass: 'txt-color txt-color-tealLighter', subAction: 'scope_jumpbridge', subText: 'jumpbridge'}
|
|
|
|
]},
|
|
{icon: 'fa-reply fa-rotate-180', action: 'change_status', text: 'change status', subitems: [
|
|
{subIcon: 'fa-clock-o', subAction: 'wh_eol', subText: 'toggle EOL'},
|
|
{subDivider: true},
|
|
{subIcon: 'fa-circle', subAction: 'status_fresh', subText: 'stage 0 (fresh)'},
|
|
{subIcon: 'fa-adjust', subAction: 'status_reduced', subText: 'stage 1 (reduced)'},
|
|
{subIcon: 'fa-circle-o', subAction: 'status_critical', subText: 'stage 2 (critical)'}
|
|
|
|
]},
|
|
{divider: true, action: 'delete_connection'},
|
|
{icon: 'fa-eraser', action: 'delete_connection', text: 'delete'}
|
|
]
|
|
};
|
|
|
|
Render.showModule(moduleConfig, moduleData);
|
|
|
|
};
|
|
|
|
/**
|
|
* load contextmenu template for systems
|
|
*/
|
|
var initSystemContextMenu = function(){
|
|
|
|
var systemStatus = [];
|
|
$.each(Init.systemStatus, function(status, statusData){
|
|
var tempStatus = {
|
|
subIcon: 'fa-tag',
|
|
subIconClass: statusData.class,
|
|
subAction: 'change_status_' + status,
|
|
subText: statusData.label
|
|
};
|
|
systemStatus.push(tempStatus);
|
|
});
|
|
|
|
var moduleConfig = {
|
|
name: 'modules/contextmenu',
|
|
position: $('#' + config.dynamicElementWrapperId)
|
|
};
|
|
|
|
var moduleData = {
|
|
id: config.systemContextMenuId,
|
|
items: [
|
|
{icon: 'fa-plus', action: 'add_system', text: 'add system'},
|
|
{icon: 'fa-lock', action: 'lock_system', text: 'lock system'},
|
|
{icon: 'fa-users', action: 'set_rally', text: 'set rally point'},
|
|
{icon: 'fa-tags', text: 'set status', subitems: systemStatus},
|
|
{divider: true, action: 'ingame'},
|
|
{icon: 'fa-reply fa-rotate-180', action: 'ingame', text: 'ingame actions', subitems: [
|
|
{subIcon: 'fa-info', subAction: 'ingame_show_info', subText: 'show info'},
|
|
{subDivider: true, action: 'ingame'},
|
|
{subIcon: 'fa-flag', subAction: 'ingame_add_waypoint', subText: 'add waypoint'},
|
|
{subIcon: 'fa-flag-checkered', subAction: 'ingame_set_destination', subText: 'set destination'},
|
|
]},
|
|
{divider: true, action: 'delete_system'},
|
|
{icon: 'fa-eraser', action: 'delete_system', text: 'delete system'}
|
|
]
|
|
};
|
|
|
|
Render.showModule(moduleConfig, moduleData);
|
|
|
|
};
|
|
|
|
/**
|
|
* set up all actions that can be preformed on a system
|
|
* @param map
|
|
* @param system
|
|
*/
|
|
var setSystemObserver = function(map, system){
|
|
|
|
system = $(system);
|
|
|
|
|
|
// get map container
|
|
var mapContainer = $( map.getContainer() );
|
|
var systemHeadExpand = $( system.find('.' + config.systemHeadExpandClass) );
|
|
var systemBody = $( system.find('.' + config.systemBodyClass) );
|
|
|
|
// map overlay will be set on "drag" start
|
|
var mapOverlayTimer = null;
|
|
|
|
// make system draggable
|
|
map.draggable(system, {
|
|
containment: 'parent',
|
|
constrain: true,
|
|
//scroll: true, // not working because of customized scrollbar
|
|
filter: '.' + config.systemHeadNameClass, // disable drag on "system name"
|
|
snapThreshold: config.mapSnapToGridDimension, // distance for grid snapping "magnet" effect
|
|
start: function(params, a, b){
|
|
var dragSystem = $(params.el);
|
|
|
|
mapOverlayTimer = dragSystem.getMapOverlay('timer');
|
|
|
|
// start map update timer
|
|
mapOverlayTimer.startMapUpdateCounter();
|
|
|
|
// check if grid-snap is enable
|
|
if(config.mapSnapToGrid){
|
|
params.drag.params.grid = [config.mapSnapToGridDimension, config.mapSnapToGridDimension];
|
|
}else{
|
|
delete( params.drag.params.grid );
|
|
}
|
|
|
|
// stop "system click event" right after drop event is finished
|
|
dragSystem.addClass('no-click');
|
|
|
|
// drag system is not always selected
|
|
var selectedSystems = mapContainer.getSelectedSystems().get();
|
|
selectedSystems = selectedSystems.concat( dragSystem.get() );
|
|
selectedSystems = $.unique( selectedSystems );
|
|
|
|
// hide tooltip
|
|
$(selectedSystems).toggleSystemTooltip('hide', {});
|
|
|
|
// move them to the "top"
|
|
$(selectedSystems).updateSystemZIndex();
|
|
},
|
|
drag: function(){
|
|
// start map update timer
|
|
mapOverlayTimer.startMapUpdateCounter();
|
|
},
|
|
stop: function(params){
|
|
var dragSystem = $(params.el);
|
|
|
|
// start map update timer
|
|
mapOverlayTimer.startMapUpdateCounter();
|
|
|
|
setTimeout(function(){
|
|
dragSystem.removeClass('no-click');
|
|
}, Init.timer.DBL_CLICK + 50);
|
|
|
|
// show tooltip
|
|
dragSystem.toggleSystemTooltip('show', {show: true});
|
|
|
|
// drag system is not always selected
|
|
var selectedSystems = mapContainer.getSelectedSystems().get();
|
|
selectedSystems = selectedSystems.concat( dragSystem.get() );
|
|
selectedSystems = $.unique( selectedSystems );
|
|
|
|
|
|
for(var i = 0; i < selectedSystems.length; i++){
|
|
var tempSystem = $(selectedSystems[i]);
|
|
|
|
// set all selected systems as "changes" for update
|
|
tempSystem.markAsChanged();
|
|
|
|
|
|
// set new position for popover edit field (system name)
|
|
var tempPosition = tempSystem.position();
|
|
|
|
var placement = 'top';
|
|
if(tempPosition.top < 100){
|
|
placement = 'bottom';
|
|
}
|
|
if(tempPosition.left < 100){
|
|
placement = 'right';
|
|
}
|
|
|
|
tempSystem.find('.' + config.systemHeadNameClass).editable('option', 'placement', placement);
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
if(system.data('locked') === true){
|
|
map.setDraggable(system, false);
|
|
}
|
|
|
|
// init system tooltips =============================================================================
|
|
var systemTooltipOptions = {
|
|
toggle: 'tooltip',
|
|
placement: 'right',
|
|
container: 'body',
|
|
viewport: system.id
|
|
};
|
|
|
|
system.find('.fa').tooltip(systemTooltipOptions);
|
|
|
|
// init system body expand ==========================================================================
|
|
systemHeadExpand.hoverIntent(function(e){
|
|
// hover in
|
|
var hoverSystem = $(this).parents('.' + config.systemClass);
|
|
var hoverSystemId = hoverSystem.attr('id');
|
|
|
|
// get ship counter and calculate expand height
|
|
var userCount = parseInt( hoverSystem.data('userCount') );
|
|
|
|
var expandHeight = userCount * config.systemBodyItemHeight;
|
|
|
|
systemBody.velocity('stop').velocity(
|
|
{
|
|
height: expandHeight + 'px',
|
|
width: 150,
|
|
'min-width': '150px'
|
|
},{
|
|
easing: 'easeInOutQuart',
|
|
duration: 150,
|
|
progress: function(){
|
|
// repaint connections of current system
|
|
map.revalidate( hoverSystemId );
|
|
},
|
|
complete: function(){
|
|
map.revalidate( hoverSystemId );
|
|
|
|
// extend player name element
|
|
$(this).find('.' + config.systemBodyItemNameClass).css({width: '80px'});
|
|
|
|
$(this).find('.' + config.systemBodyRightClass).velocity('stop').velocity({
|
|
opacity: 1
|
|
},{
|
|
duration: 150,
|
|
display: 'auto'
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
}, function(e){
|
|
// hover out
|
|
var hoverSystem = $(this).parents('.' + config.systemClass);
|
|
var hoverSystemId = hoverSystem.attr('id');
|
|
|
|
// stop animation (prevent visual bug if user spams hover-icon [in - out])
|
|
systemBody.velocity('stop');
|
|
|
|
// reduce player name element back to "normal" size (css class width is used)
|
|
systemBody.find('.' + config.systemBodyItemNameClass).css({width: ''});
|
|
|
|
systemBody.find('.' + config.systemBodyRightClass).velocity('stop').velocity( {
|
|
opacity: 0,
|
|
'min-width': '0px'
|
|
},{
|
|
easing: 'easeInOutQuart',
|
|
duration: 150,
|
|
display: 'none',
|
|
complete: function(){
|
|
systemBody.velocity('stop').velocity('reverse', {
|
|
complete: function(){
|
|
// overwrite "complete" function from first "hover"-open
|
|
map.revalidate( hoverSystemId );
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
// context menu =====================================================================================
|
|
|
|
// trigger context menu
|
|
system.off('contextmenu').on('contextmenu', function(e){
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
var systemElement = $(this);
|
|
|
|
// hide all map contextmenu options
|
|
var hideOptions = getHiddenContextMenuOptions(systemElement);
|
|
|
|
var activeOptions = getActiveContextMenuOptions(systemElement);
|
|
|
|
$(e.target).trigger('pf:openContextMenu', [e, this, hideOptions, activeOptions]);
|
|
return false;
|
|
});
|
|
|
|
// init context menu
|
|
system.contextMenu({
|
|
menuSelector: "#" + config.systemContextMenuId,
|
|
menuSelected: function (params) {
|
|
|
|
// click action
|
|
var action = params.selectedMenu.attr('data-action');
|
|
|
|
// current system
|
|
var currentSystem = $(params.component);
|
|
|
|
// system name
|
|
var currentSystemName = currentSystem.getSystemInfo( ['alias'] );
|
|
|
|
var systemData = {};
|
|
|
|
switch(action){
|
|
case 'add_system':
|
|
// add a new system
|
|
showNewSystemDialog(map, {sourceSystem: currentSystem} );
|
|
|
|
break;
|
|
case 'lock_system':
|
|
// lock system
|
|
currentSystem.toggleLockSystem(true, {map: map});
|
|
|
|
// repaint connections, -> system changed its size!
|
|
map.repaint( currentSystem );
|
|
|
|
currentSystem.markAsChanged();
|
|
break;
|
|
case 'set_rally':
|
|
// set rally point
|
|
if( ! currentSystem.data( 'rally' ) ){
|
|
|
|
// show confirm dialog
|
|
var rallyDialog = bootbox.dialog({
|
|
message: 'Do you want to poke active pilots?',
|
|
title: 'Set rally point for system "' + currentSystemName + '"',
|
|
buttons: {
|
|
close: {
|
|
label: 'cancel',
|
|
className: 'btn-default',
|
|
callback: function(){
|
|
$(rallyDialog).modal('hide');
|
|
}
|
|
},
|
|
setRallyPoke: {
|
|
label: '<i class="fa fa-fw fa-bullhorn"></i> Set rally and poke',
|
|
className: 'btn-primary',
|
|
callback: function() {
|
|
currentSystem.toggleRallyPoint(true, {});
|
|
currentSystem.markAsChanged();
|
|
}
|
|
},
|
|
success: {
|
|
label: '<i class="fa fa-fw fa-check"></i> save',
|
|
className: 'btn-success',
|
|
callback: function() {
|
|
currentSystem.toggleRallyPoint(false, {});
|
|
currentSystem.markAsChanged();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}else{
|
|
// remove rally point
|
|
currentSystem.toggleRallyPoint(false, {});
|
|
currentSystem.markAsChanged();
|
|
}
|
|
break;
|
|
case 'change_status_unknown':
|
|
case 'change_status_friendly':
|
|
case 'change_status_occupied':
|
|
case 'change_status_hostile':
|
|
case 'change_status_empty':
|
|
case 'change_status_unscanned':
|
|
// change system status
|
|
currentSystem.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
var statusString = action.split('_');
|
|
|
|
currentSystem.setSystemStatus(statusString[2]);
|
|
|
|
currentSystem.markAsChanged();
|
|
break;
|
|
case 'delete_system':
|
|
// confirm dialog
|
|
var systemDeleteDialog = bootbox.confirm('Delete system and all its connections?', function(result) {
|
|
if(result){
|
|
var systemName = currentSystem.getSystemInfo(['alias']);
|
|
deleteSystems(map, [currentSystem], function(){
|
|
// callback function after delete -> close dialog
|
|
bootbox.hideAll();
|
|
Util.showNotify({title: 'System deleted', text: systemName, type: 'success'});
|
|
});
|
|
|
|
return false;
|
|
}
|
|
});
|
|
break;
|
|
case 'ingame_show_info':
|
|
systemData = system.getSystemData();
|
|
|
|
CCPEVE.showInfo(5, systemData.systemId );
|
|
break;
|
|
case 'ingame_set_destination':
|
|
systemData = system.getSystemData();
|
|
|
|
CCPEVE.setDestination( systemData.systemId );
|
|
break;
|
|
case 'ingame_add_waypoint':
|
|
systemData = system.getSystemData();
|
|
|
|
CCPEVE.addWaypoint( systemData.systemId );
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
// system click events ==============================================================================
|
|
var double = function(e){
|
|
var system = $(this);
|
|
var headElement = $(system).find('.' + config.systemHeadNameClass);
|
|
|
|
// update z-index for system, editable field should be on top
|
|
// move them to the "top"
|
|
$(system).updateSystemZIndex();
|
|
|
|
// show "set alias" input (x-editable)
|
|
headElement.editable('show');
|
|
};
|
|
|
|
var single = function(e){
|
|
|
|
// check if click was performed on "popover" (x-editable)
|
|
var popoverClick = false;
|
|
if( $(e.target).parents('.popover').length ){
|
|
popoverClick = true;
|
|
}
|
|
|
|
// continue if click was *not* on a popover dialog of a system
|
|
if( !popoverClick ){
|
|
var system = $(this);
|
|
|
|
// check if system is locked for "click" events
|
|
if( !system.hasClass('no-click') ){
|
|
// left mouse button
|
|
if(e.which === 1){
|
|
if(! system.hasClass('no-click')){
|
|
if(e.ctrlKey === true){
|
|
// select system
|
|
system.toggleSelectSystem(map);
|
|
}else{
|
|
system.showSystemInfo(map);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
system.singleDoubleClick(single, double);
|
|
|
|
};
|
|
|
|
/**
|
|
* mark a dom element (map, system, connection) as changed
|
|
*/
|
|
$.fn.markAsChanged = function(){
|
|
return this.each(function(){
|
|
var element = $(this);
|
|
|
|
if( element.hasClass(config.systemClass) ){
|
|
// system element
|
|
element.data('updated', 0);
|
|
}else{
|
|
// connection element
|
|
this.setParameter('updated', 0);
|
|
}
|
|
|
|
});
|
|
};
|
|
|
|
/**
|
|
* check if an dom element (system, connection) has changed
|
|
* @returns {boolean}
|
|
*/
|
|
$.fn.hasChanged = function(){
|
|
var element = $(this);
|
|
var changed = false;
|
|
|
|
if( element.hasClass(config.systemClass) ){
|
|
// system element
|
|
changed = (element.data('updated') === 0);
|
|
}else{
|
|
// connection element
|
|
changed = (this[0].getParameter('updated') === 0);
|
|
}
|
|
|
|
return changed;
|
|
};
|
|
|
|
/**
|
|
* triggers the "showSystemInfo" event, that is responsible for initializing the "map info" panel
|
|
* @param map
|
|
*/
|
|
$.fn.showSystemInfo = function(map){
|
|
var system = $(this);
|
|
|
|
// activate system
|
|
markSystemActive(map, system);
|
|
|
|
// get parent Tab Content and fire update event
|
|
var tabContentElement = getTabContentElementByMapElement( system );
|
|
|
|
// collect all required data from map module to update the info element
|
|
// store them global and assessable for each module
|
|
var currentSystemData = {
|
|
systemData: system.getSystemData(),
|
|
mapId: parseInt( system.attr('data-mapid') )
|
|
};
|
|
|
|
Util.setCurrentSystemData(currentSystemData);
|
|
|
|
$(tabContentElement).trigger('pf:drawSystemModules');
|
|
};
|
|
|
|
/**
|
|
* toggle selectable status of a system
|
|
*/
|
|
$.fn.toggleSelectSystem = function(map){
|
|
|
|
return this.each(function(){
|
|
var system = $(this);
|
|
|
|
if( system.data('locked') !== true ){
|
|
|
|
if( system.hasClass( config.systemSelectedClass ) ){
|
|
system.removeClass( config.systemSelectedClass );
|
|
|
|
map.removeFromDragSelection(system);
|
|
}else{
|
|
system.addClass( config.systemSelectedClass );
|
|
map.addToDragSelection(system);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* get all selected (NOT active) systems in a map
|
|
* @returns {*}
|
|
*/
|
|
$.fn.getSelectedSystems = function(){
|
|
|
|
var mapElement = $(this);
|
|
|
|
var systems = mapElement.find('.' + config.systemSelectedClass);
|
|
|
|
return systems;
|
|
};
|
|
|
|
/**
|
|
* toggle log status of a system
|
|
* @param poke
|
|
* @param options
|
|
*/
|
|
$.fn.toggleLockSystem = function(poke, options){
|
|
|
|
var system = $(this);
|
|
|
|
var map = options.map;
|
|
|
|
var hideNotification = false;
|
|
if(options.hideNotification === true){
|
|
hideNotification = true;
|
|
}
|
|
|
|
var hideCounter = false;
|
|
if(options.hideCounter === true){
|
|
hideCounter = true;
|
|
}
|
|
|
|
var systemName = system.getSystemInfo( ['alias'] );
|
|
|
|
if( system.data( 'locked' ) === true ){
|
|
system.data('locked', false);
|
|
system.removeClass( config.systemLockedClass );
|
|
|
|
// enable draggable
|
|
map.setDraggable(system, true);
|
|
|
|
if(! hideNotification){
|
|
Util.showNotify({title: 'System unlocked', text: systemName, type: 'unlock'});
|
|
}
|
|
}else{
|
|
system.data('locked', true);
|
|
system.addClass( config.systemLockedClass );
|
|
|
|
// enable draggable
|
|
map.setDraggable(system, false);
|
|
|
|
if(! hideNotification){
|
|
Util.showNotify({title: 'System locked', text: systemName, type: 'lock'});
|
|
}
|
|
}
|
|
|
|
// repaint connections
|
|
map.revalidate( system.attr('id') );
|
|
|
|
|
|
if(! hideCounter){
|
|
$(system).getMapOverlay('timer').startMapUpdateCounter();
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* toggle a system as rally point and display notifications
|
|
* @param poke
|
|
* @param options
|
|
*/
|
|
$.fn.toggleRallyPoint = function(poke, options){
|
|
|
|
var system = $(this);
|
|
|
|
var rallyClass = Util.getInfoForSystem('rally', 'class');
|
|
|
|
var hideNotification = false;
|
|
if(options.hideNotification === true){
|
|
hideNotification = true;
|
|
}
|
|
|
|
var hideCounter = false;
|
|
if(options.hideCounter === true){
|
|
hideCounter = true;
|
|
}
|
|
|
|
// check of system is already marked as rally
|
|
if( system.data( 'rally' ) === true ){
|
|
system.removeClass( rallyClass );
|
|
system.data( 'rally', false );
|
|
|
|
if(! hideNotification){
|
|
Util.showNotify({title: 'Rally point removed', type: 'success'});
|
|
}
|
|
}else{
|
|
system.addClass( rallyClass );
|
|
system.data( 'rally', true );
|
|
|
|
if(! hideNotification){
|
|
var systemName = system.getSystemInfo( ['alias'] );
|
|
|
|
var notificationOptions = {
|
|
title: 'Rally Point',
|
|
text: 'System: ' + systemName,
|
|
type: 'success'
|
|
};
|
|
|
|
if(poke === true){
|
|
// desktop poke
|
|
Util.showNotify(notificationOptions, {desktop: true, stack: 'barBottom'});
|
|
}else{
|
|
Util.showNotify(notificationOptions, {stack: 'barBottom'});
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(! hideCounter){
|
|
$(system).getMapOverlay('timer').startMapUpdateCounter();
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* get TabContentElement by any element on a map e.g. system
|
|
* @param element
|
|
* @returns {*}
|
|
*/
|
|
var getTabContentElementByMapElement = function(element){
|
|
var tabContentElement = $(element).parents('.' + config.mapTabContentClass);
|
|
return tabContentElement;
|
|
};
|
|
|
|
/**
|
|
* set observer for a map container
|
|
* @param map
|
|
*/
|
|
var setMapObserver = function(map){
|
|
|
|
// get map container
|
|
var mapContainer = map.getContainer();
|
|
|
|
$(mapContainer).bind('contextmenu', function(e){
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
// make sure map is clicked and NOT a connection
|
|
if($(e.target).hasClass( config.mapClass )){
|
|
var mapElement = $(this);
|
|
|
|
var hideOptions = getHiddenContextMenuOptions(mapElement);
|
|
|
|
var activeOptions = getActiveContextMenuOptions(mapElement);
|
|
|
|
$(e.target).trigger('pf:openContextMenu', [e, mapElement, hideOptions, activeOptions]);
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
$(mapContainer).contextMenu({
|
|
menuSelector: "#" + config.mapContextMenuId,
|
|
menuSelected: function (params) {
|
|
|
|
// click action
|
|
var action = params.selectedMenu.attr('data-action');
|
|
|
|
// current map
|
|
var currentMapElement = $(params.component);
|
|
|
|
var currentMapId = parseInt( currentMapElement.data('id') );
|
|
|
|
// get map instance
|
|
var currentMap = getMapInstance(currentMapId);
|
|
|
|
// click position
|
|
var position = params.position;
|
|
|
|
switch(action){
|
|
case 'add_system':
|
|
// add new system dialog
|
|
showNewSystemDialog(currentMap, {position: position});
|
|
break;
|
|
case 'select_all':
|
|
|
|
var allSystems = currentMapElement.find('.' + config.systemClass + ':not(.' + config.systemSelectedClass + ')');
|
|
|
|
// filter non-locked systems
|
|
allSystems = allSystems.filter(function(i, el){
|
|
return ( $(el).data('locked') !== true );
|
|
});
|
|
|
|
allSystems.toggleSelectSystem(currentMap);
|
|
|
|
Util.showNotify({title: allSystems.length + ' systems selected', type: 'success'});
|
|
break;
|
|
case 'filter_wh':
|
|
case 'filter_stargate':
|
|
case 'filter_jumpbridge':
|
|
// filter (show/hide)
|
|
var filterScope = action.split('_')[1];
|
|
|
|
// scope label
|
|
var filterScopeLabel = Util.getScopeInfoForMap(filterScope, 'label');
|
|
|
|
var showScope = true;
|
|
if(
|
|
currentMapElement.data('filter_scope') &&
|
|
currentMapElement.data('filter_scope') === filterScope
|
|
){
|
|
// remove scope filter
|
|
currentMapElement.data('filter_scope', false);
|
|
showScope = false;
|
|
|
|
// hide map overlay filter info
|
|
currentMapElement.getMapOverlay('info').updateOverlayIcon('filter', 'hide');
|
|
}else{
|
|
// set scope filter
|
|
currentMapElement.data('filter_scope', filterScope);
|
|
|
|
// show map overlay filter info
|
|
currentMapElement.getMapOverlay('info').updateOverlayIcon('filter', 'show');
|
|
}
|
|
|
|
var filteredConnections = currentMap.getAllConnections(filterScope);
|
|
|
|
for(var i = 0; i < filteredConnections.length; i++){
|
|
var tempConnection = filteredConnections[i];
|
|
|
|
var tempEndpoints = tempConnection.endpoints;
|
|
var setVisible = true;
|
|
|
|
if(
|
|
showScope &&
|
|
tempConnection.scope !== filterScope
|
|
){
|
|
setVisible = false;
|
|
}
|
|
|
|
|
|
for(var j = 0; j < tempEndpoints.length; j++){
|
|
tempEndpoints[j].setVisible( setVisible );
|
|
}
|
|
}
|
|
|
|
Util.showNotify({title: 'Scope filter changed', text: filterScopeLabel, type: 'success'});
|
|
|
|
break;
|
|
case 'delete_systems':
|
|
// delete all selected systems with its connections
|
|
var selectedSystems = $(currentMapElement).getSelectedSystems();
|
|
|
|
if(selectedSystems.length > 0){
|
|
var systemDeleteDialog = bootbox.confirm('Delete ' + selectedSystems.length + ' selected systems and its connections?', function(result) {
|
|
if(result){
|
|
currentMapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
deleteSystems(currentMap, selectedSystems, function(){
|
|
// callback function after delete -> close dialog
|
|
|
|
$(systemDeleteDialog).modal('hide');
|
|
Util.showNotify({title: selectedSystems.length + ' systems deleted', type: 'success'});
|
|
});
|
|
}
|
|
});
|
|
}else{
|
|
Util.showNotify({title: 'No systems selected', type: 'error'});
|
|
}
|
|
|
|
break;
|
|
case 'info':
|
|
// open map info dialog
|
|
$(document).triggerMenuEvent('ShowMapInfo');
|
|
break;
|
|
|
|
}
|
|
}
|
|
});
|
|
|
|
// init drag-frame selection
|
|
$(mapContainer).dragToSelect({
|
|
selectables: '.' + config.systemClass,
|
|
onHide: function (selectBox, deselectedSystems) {
|
|
var selectedSystems = $(mapContainer).getSelectedSystems();
|
|
|
|
if(selectedSystems.length > 0){
|
|
// make all selected systems draggable
|
|
Util.showNotify({title: selectedSystems.length + ' systems selected', type: 'success'});
|
|
|
|
// convert former group draggable systems so single draggable
|
|
for(var i = 0; i < selectedSystems.length; i++){
|
|
map.addToDragSelection( selectedSystems[i] );
|
|
}
|
|
}
|
|
|
|
// convert former group draggable systems so single draggable
|
|
for(var j = 0; j < deselectedSystems.length; j++){
|
|
map.removeFromDragSelection( deselectedSystems[j] );
|
|
}
|
|
|
|
},
|
|
onShow: function(){
|
|
$(document).trigger('pf:closeMenu', [{}]);
|
|
},
|
|
onRefresh: function(){
|
|
}
|
|
});
|
|
|
|
|
|
// catch events =========================================================
|
|
|
|
// toggle "snap to grid" option
|
|
$(mapContainer).on('pf:menuGrid', function(e, data){
|
|
|
|
var currentMapElement = $(this);
|
|
|
|
config.mapSnapToGrid = !config.mapSnapToGrid;
|
|
|
|
// toggle grid class
|
|
currentMapElement.toggleClass(config.mapGridClass);
|
|
|
|
// toggle button class
|
|
$(data.button).toggleClass('active');
|
|
|
|
var notificationText = 'disabled';
|
|
if(config.mapSnapToGrid){
|
|
notificationText = 'enabled';
|
|
|
|
// show map overlay grid info
|
|
currentMapElement.getMapOverlay('info').updateOverlayIcon('grid', 'show');
|
|
}else{
|
|
|
|
// hide map overlay grid info
|
|
currentMapElement.getMapOverlay('info').updateOverlayIcon('grid', 'hide');
|
|
}
|
|
|
|
Util.showNotify({title: 'Grid snapping', text: notificationText, type: 'info'});
|
|
});
|
|
|
|
// delete system event
|
|
// triggered from "map info" dialog scope
|
|
$(mapContainer).on('pf:deleteSystems', function(e, data){
|
|
deleteSystems(map, data.systems, data.callback);
|
|
});
|
|
|
|
$(mapContainer).on('pf:menuSelectSystem', function(e, data){
|
|
var tempMapContainer = $(this);
|
|
var systemId = config.systemIdPrefix + tempMapContainer.data('id') + '-' + data.systemId;
|
|
var system = $(this).find('#' + systemId);
|
|
|
|
if(system.length === 1){
|
|
// scroll to system
|
|
var tempMapWrapper = tempMapContainer.parents('.' + config.mapWrapperClass);
|
|
tempMapWrapper.scrollTo(system);
|
|
|
|
// select system
|
|
system.showSystemInfo(map);
|
|
}
|
|
});
|
|
|
|
|
|
};
|
|
|
|
/**
|
|
* get hidden menu entry options for a context menu
|
|
* @param component
|
|
* @returns {Array}
|
|
*/
|
|
var getHiddenContextMenuOptions = function(component){
|
|
|
|
var hiddenOptions = [];
|
|
|
|
if(component instanceof jsPlumb.Connection){
|
|
// disable connection menu entries
|
|
|
|
var scope = component.scope;
|
|
|
|
if(scope === 'stargate'){
|
|
hiddenOptions.push('frigate');
|
|
hiddenOptions.push('preserve_mass');
|
|
hiddenOptions.push('change_status');
|
|
|
|
hiddenOptions.push('scope_stargate');
|
|
}else if(scope === 'jumpbridge'){
|
|
hiddenOptions.push('frigate');
|
|
hiddenOptions.push('preserve_mass');
|
|
hiddenOptions.push('change_status');
|
|
hiddenOptions.push('scope_jumpbridge');
|
|
}else if(scope === 'wh'){
|
|
hiddenOptions.push('scope_wh');
|
|
}
|
|
|
|
}else if( component.hasClass(config.systemClass) ){
|
|
// disable system menu entries
|
|
if(component.data('locked') === true){
|
|
hiddenOptions.push('delete_system');
|
|
}
|
|
|
|
// disable ingame options if not IGB browser
|
|
if(! CCP.isInGameBrowser() ){
|
|
hiddenOptions.push('ingame');
|
|
}
|
|
}
|
|
|
|
return hiddenOptions;
|
|
};
|
|
|
|
/**
|
|
* get active menu entry options for a context menu
|
|
* @param component
|
|
* @returns {Array}
|
|
*/
|
|
var getActiveContextMenuOptions = function(component){
|
|
|
|
var activeOptions = [];
|
|
|
|
if(component instanceof jsPlumb.Connection){
|
|
var scope = component.scope;
|
|
|
|
if(component.hasType('wh_eol') === true){
|
|
activeOptions.push('wh_eol');
|
|
}
|
|
|
|
if(component.hasType('frigate') === true){
|
|
activeOptions.push('frigate');
|
|
}
|
|
if(component.hasType('preserve_mass') === true){
|
|
activeOptions.push('preserve_mass');
|
|
}
|
|
if(component.hasType('wh_reduced') === true){
|
|
activeOptions.push('status_reduced');
|
|
}else if(component.hasType('wh_critical') === true){
|
|
activeOptions.push('status_critical');
|
|
}else{
|
|
// not reduced is default
|
|
activeOptions.push('status_fresh');
|
|
}
|
|
|
|
}else if( component.hasClass(config.mapClass) ){
|
|
|
|
// active map menu entries
|
|
if(component.data('filter_scope') === 'wh'){
|
|
activeOptions.push('filter_wh');
|
|
}
|
|
if(component.data('filter_scope') === 'stargate'){
|
|
activeOptions.push('filter_stargate');
|
|
}
|
|
if(component.data('filter_scope') === 'jumpbridge'){
|
|
activeOptions.push('filter_jumpbridge');
|
|
}
|
|
}else if( component.hasClass(config.systemClass) ){
|
|
// active system menu entries
|
|
if(component.data('locked') === true){
|
|
activeOptions.push('lock_system');
|
|
}
|
|
if(component.data('rally') === true){
|
|
activeOptions.push('set_rally');
|
|
}
|
|
}
|
|
|
|
return activeOptions;
|
|
};
|
|
|
|
/**
|
|
* set observer for a given connection
|
|
* @param map
|
|
* @param connection
|
|
*/
|
|
var setConnectionObserver = function(map, connection){
|
|
|
|
// get map container
|
|
var mapElement = $( map.getContainer() );
|
|
|
|
// if the connection already exists -> do not set it twice
|
|
connection.unbind('contextmenu').bind('contextmenu', function(component, e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
// trigger menu "open
|
|
|
|
// get invisible menu entries
|
|
var hideOptions = getHiddenContextMenuOptions(component);
|
|
var activeOptions = getActiveContextMenuOptions(component);
|
|
$(e.target).trigger('pf:openContextMenu', [e, component, hideOptions, activeOptions]);
|
|
|
|
return false;
|
|
});
|
|
|
|
/**
|
|
* init context menu for all connections
|
|
* must be triggered manually on demand
|
|
*/
|
|
$(connection.canvas).contextMenu({
|
|
menuSelector: "#" + config.connectionContextMenuId,
|
|
menuSelected: function (params){
|
|
|
|
var action = params.selectedMenu.attr('data-action');
|
|
var activeConnection = params.component;
|
|
var activeScope = activeConnection.scope;
|
|
var activeScopeName = Util.getScopeInfoForConnection( activeScope, 'label');
|
|
|
|
switch(action){
|
|
case 'delete_connection':
|
|
// delete a single connection
|
|
|
|
// confirm dialog
|
|
bootbox.confirm('Is this connection really gone?', function(result) {
|
|
if(result){
|
|
$().deleteConnections([activeConnection]);
|
|
}
|
|
});
|
|
break;
|
|
case 'frigate': // set as frigate hole
|
|
case 'preserve_mass': // set "preserve mass
|
|
case 'wh_eol': // set "end of life"
|
|
mapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
activeConnection.toggleType( action );
|
|
|
|
$(activeConnection).markAsChanged();
|
|
break;
|
|
case 'status_fresh':
|
|
case 'status_reduced':
|
|
case 'status_critical':
|
|
var newStatus = action.split('_')[1];
|
|
mapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
setConnectionWHStatus(activeConnection, 'wh_' + newStatus);
|
|
$(activeConnection).markAsChanged();
|
|
break;
|
|
case 'scope_wh':
|
|
case 'scope_stargate':
|
|
case 'scope_jumpbridge':
|
|
var newScope = action.split('_')[1];
|
|
var newScopeName = Util.getScopeInfoForConnection( newScope, 'label');
|
|
|
|
bootbox.confirm('Change scope from ' + activeScopeName + ' to ' + newScopeName + '?', function(result) {
|
|
if(result){
|
|
|
|
mapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
setConnectionScope(activeConnection, newScope);
|
|
|
|
Util.showNotify({title: 'Connection scope changed', text: 'New scope: ' + newScopeName, type: 'success'});
|
|
|
|
$(activeConnection).markAsChanged();
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
};
|
|
|
|
/**
|
|
* mark a system as active
|
|
* @param map
|
|
* @param system
|
|
*/
|
|
var markSystemActive = function(map, system){
|
|
|
|
// deactivate all systems in map
|
|
var mapContainer = $( map.getContainer() );
|
|
|
|
mapContainer.find('.' + config.systemClass).removeClass(config.systemActiveClass);
|
|
|
|
// set current system active
|
|
system.addClass(config.systemActiveClass);
|
|
};
|
|
|
|
/**
|
|
* get system data out of its object
|
|
* @param info
|
|
* @returns {*}
|
|
*/
|
|
$.fn.getSystemInfo = function(info){
|
|
|
|
var systemInfo = [];
|
|
|
|
for(var i = 0; i < info.length; i++){
|
|
switch(info[i]){
|
|
case 'alias':
|
|
// get current system alias
|
|
var systemHeadNameElement = $(this).find('.' + config.systemHeadNameClass);
|
|
var alias = '';
|
|
if( systemHeadNameElement.hasClass('editable') ){
|
|
// xEditable is initiated
|
|
alias = systemHeadNameElement.editable('getValue', true);
|
|
}
|
|
|
|
systemInfo.push(alias );
|
|
break;
|
|
default:
|
|
systemInfo.push('bad system query');
|
|
}
|
|
|
|
}
|
|
|
|
if(systemInfo.length === 1){
|
|
return systemInfo[0];
|
|
}else{
|
|
return systemInfo;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
var showNewSystemDialog = function(map, options){
|
|
|
|
var mapContainer = $(map.getContainer());
|
|
|
|
// format system status for form select ------------------------------------------------------------------------
|
|
var systemStatus = {};
|
|
$.each(Init.systemStatus, function(status, statusData){
|
|
systemStatus[statusData.id] = statusData.label;
|
|
});
|
|
|
|
// default system status -> first status entry
|
|
var tempKeys = [];
|
|
for(var k in Init.systemStatus){
|
|
if (Init.systemStatus.hasOwnProperty(k)){
|
|
tempKeys.push(k);
|
|
}
|
|
}
|
|
var defaultSystemStatus = Init.systemStatus[ tempKeys[0] ].id;
|
|
|
|
// dialog data -------------------------------------------------------------------------------------------------
|
|
var data = {
|
|
id: config.systemDialogId,
|
|
selectClass: config.systemDialogSelectClass
|
|
};
|
|
|
|
// current character log data ----------------------------------------------------------------------------------
|
|
var currentCharacterLog = Util.getCurrentCharacterLog();
|
|
|
|
if(currentCharacterLog !== false){
|
|
// set current position as "default" system to add
|
|
data.currentSystem = currentCharacterLog.system;
|
|
}
|
|
|
|
// get current map data -> disable systems that are already on it ----------------------------------------------
|
|
var mapData = mapContainer.getMapDataFromClient({forceData: true});
|
|
var mapSystems = mapData.data.systems;
|
|
var mapSystemIds = [];
|
|
for(var i = 0; i < mapSystems.length; i++ ){
|
|
mapSystemIds.push( mapSystems[i].systemId );
|
|
}
|
|
|
|
requirejs(['text!templates/dialog/system.html', 'mustache'], function(template, Mustache) {
|
|
|
|
var content = Mustache.render(template, data);
|
|
|
|
// disable modal focus event -> otherwise select2 is not working! -> quick fix
|
|
$.fn.modal.Constructor.prototype.enforceFocus = function() {};
|
|
|
|
var systemDialog = bootbox.dialog({
|
|
title: 'Add new system',
|
|
message: content,
|
|
buttons: {
|
|
close: {
|
|
label: 'cancel',
|
|
className: 'btn-default'
|
|
},
|
|
success: {
|
|
label: '<i class="fa fa-fw fa-check"></i> save',
|
|
className: 'btn-success',
|
|
callback: function (e) {
|
|
// get form Values
|
|
var form = $('#' + config.systemDialogId).find('form');
|
|
|
|
var systemDialogData = $(form).getFormValues();
|
|
|
|
// validate form
|
|
form.validator('validate');
|
|
|
|
// check weather the form is valid
|
|
var formValid = form.isValidForm();
|
|
|
|
if(formValid === false){
|
|
// don't close dialog
|
|
return false;
|
|
}
|
|
|
|
mapContainer.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
// calculate new system position -----------------------------------------------
|
|
var newPosition = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
|
|
var sourceSystem = null;
|
|
|
|
// add new position
|
|
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;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
var requestData = {
|
|
systemData: systemDialogData,
|
|
mapData: {
|
|
id: mapContainer.data('id')
|
|
}
|
|
};
|
|
|
|
saveSystem(map, requestData, sourceSystem, function(){
|
|
bootbox.hideAll();
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// init dialog
|
|
systemDialog.on('shown.bs.modal', function(e) {
|
|
|
|
var modalContent = $('#' + config.systemDialogId);
|
|
|
|
// init system select live search - some delay until modal transition has finished
|
|
var selectElement = modalContent.find('.' + config.systemDialogSelectClass);
|
|
selectElement.delay(240).initSystemSelect({
|
|
key: 'systemId',
|
|
disabledOptions: mapSystemIds
|
|
});
|
|
});
|
|
|
|
// init system status select
|
|
var modalFields = $('.bootbox .modal-dialog').find('.pf-editable-system-status');
|
|
|
|
modalFields.editable({
|
|
mode: 'inline',
|
|
emptytext: 'unknown',
|
|
onblur: 'submit',
|
|
showbuttons: false,
|
|
source: systemStatus,
|
|
value: defaultSystemStatus,
|
|
inputclass: config.systemDialogSelectClass
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* save a new system and add it to the map
|
|
* @param map
|
|
* @param requestData
|
|
* @param sourceSystem
|
|
* @param callback
|
|
*/
|
|
var saveSystem = function(map, requestData, sourceSystem, callback){
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: Init.path.saveSystem,
|
|
data: requestData,
|
|
dataType: 'json',
|
|
context: {
|
|
map: map,
|
|
sourceSystem: sourceSystem
|
|
}
|
|
}).done(function(newSystemData){
|
|
|
|
// draw new system to map
|
|
drawSystem(this.map, newSystemData, this.sourceSystem);
|
|
|
|
Util.showNotify({title: 'New system', text: newSystemData.name, type: 'success'});
|
|
|
|
if(callback){
|
|
callback();
|
|
}
|
|
}).fail(function( jqXHR, status, error) {
|
|
var reason = status + ' ' + error;
|
|
Util.showNotify({title: jqXHR.status + ': saveSystem', text: reason, type: 'warning'});
|
|
$(document).setProgramStatus('problem');
|
|
});
|
|
|
|
};
|
|
|
|
/**
|
|
* calculate the x/y coordinates for a new system - relativ to a source system
|
|
* @param sourceSystem
|
|
* @returns {{x: *, y: *}}
|
|
*/
|
|
var calculateNewSystemPosition = function(sourceSystem){
|
|
|
|
// related system is available
|
|
var currentX = sourceSystem.css('left');
|
|
var currentY = sourceSystem.css('top');
|
|
|
|
// remove "px"
|
|
currentX = parseInt( currentX.substring(0, currentX.length - 2) );
|
|
currentY = parseInt( currentY.substring(0, currentY.length - 2) );
|
|
|
|
var newPosition = {
|
|
x: currentX + config.newSystemOffset.x,
|
|
y: currentY + config.newSystemOffset.y
|
|
};
|
|
|
|
return newPosition;
|
|
};
|
|
|
|
/**
|
|
* updates all systems on map with current user Data (all users on this map)
|
|
* update the Data of the user that is currently viewing the map (if available)
|
|
* @param userData
|
|
* @returns {boolean}
|
|
*/
|
|
$.fn.updateUserData = function(userData){
|
|
|
|
var returnStatus = true;
|
|
|
|
// get new map instance or load existing
|
|
var map = getMapInstance(userData.config.id);
|
|
|
|
var mapElement = map.getContainer();
|
|
|
|
// get map tracking toggle value
|
|
// if "false" -> new systems/connections will not automatically added
|
|
var mapTracking = $('#' + config.headMapTrackingId).is(':checked');
|
|
|
|
|
|
// container must exist! otherwise systems can not be updated
|
|
if(mapElement !== undefined){
|
|
|
|
mapElement = $(mapElement);
|
|
|
|
// get current character log data
|
|
var currentCharacterLog = Util.getCurrentCharacterLog();
|
|
|
|
// check if map is frozen
|
|
if(mapElement.data('frozen') === true){
|
|
return returnStatus;
|
|
}
|
|
|
|
// data for header update
|
|
var headerUpdateData = {
|
|
mapId: userData.config.id,
|
|
userCount: 0 // active user in a map
|
|
};
|
|
|
|
// check if current user was found on the map
|
|
var currentUserOnMap = false;
|
|
|
|
// get all systems
|
|
var systems = mapElement.find('.' + config.systemClass);
|
|
|
|
for(var i = 0; i < systems.length; i++){
|
|
// get user Data for System
|
|
|
|
var system = $( systems[i] );
|
|
|
|
var systemId = $(system).data('systemId');
|
|
|
|
var tempUserData = null;
|
|
|
|
// check if user is currently in "this" system
|
|
var currentUserIsHere = false;
|
|
|
|
var j = userData.data.systems.length;
|
|
|
|
// search backwards to avoid decrement the counter after splice()
|
|
while (j--) {
|
|
var systemData = userData.data.systems[j];
|
|
|
|
// check if any user is in this system
|
|
if (systemId === systemData.id) {
|
|
tempUserData = systemData;
|
|
|
|
// add "user count" to "total map user count"
|
|
headerUpdateData.userCount += tempUserData.user.length;
|
|
|
|
// remove system from "search" array -> speed up loop
|
|
userData.data.systems.splice(j, 1);
|
|
}
|
|
}
|
|
|
|
// the current user can only be in a single system -------------------------------------------------------
|
|
if( !currentUserOnMap){
|
|
|
|
if(
|
|
currentCharacterLog &&
|
|
currentCharacterLog.system &&
|
|
currentCharacterLog.system.id === systemId
|
|
){
|
|
currentUserIsHere = true;
|
|
currentUserOnMap = true;
|
|
|
|
// set current location data for header update
|
|
headerUpdateData.currentSystemId = $(system).data('id');
|
|
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
|
|
|
|
// check connection exists between new and previous systems --------o------------------------------
|
|
// e.g. a loop
|
|
if(
|
|
activeSystemCache &&
|
|
mapTracking &&
|
|
activeSystemCache.data('systemId') !== currentCharacterLog.system.id
|
|
){
|
|
// maybe a loop detected (both systems already on map -> connection missing
|
|
var connections = checkForConnection(map, activeSystemCache, system );
|
|
|
|
if(connections.length === 0){
|
|
var connectionData = {
|
|
source: activeSystemCache.data('id') ,
|
|
target: system.data('id'),
|
|
type: ['wh_fresh'] // default type.
|
|
};
|
|
|
|
var connection = drawConnection(map, connectionData);
|
|
saveConnection(connection);
|
|
}
|
|
|
|
}
|
|
|
|
// cache current location
|
|
activeSystemCache = system;
|
|
}
|
|
}
|
|
|
|
system.updateSystemUserData(map, tempUserData, currentUserIsHere);
|
|
}
|
|
|
|
// current user was not found on any map system -> add new system to map where the user is in ----------------
|
|
// this is restricted to IGB-usage! CharacterLog data is always set through the IGB
|
|
// ->this prevent adding the same system multiple times, if a user is online with IGB AND OOG
|
|
if(
|
|
CCP.isInGameBrowser() === true &&
|
|
currentUserOnMap === false &&
|
|
currentCharacterLog &&
|
|
mapTracking
|
|
){
|
|
|
|
// add new system to the map
|
|
var requestData = {
|
|
systemData: {
|
|
systemId: currentCharacterLog.system.id
|
|
},
|
|
mapData: {
|
|
id: userData.config.id
|
|
}
|
|
};
|
|
|
|
// check if a system jump is detected previous system !== current system
|
|
// and add a connection to the previous system as well
|
|
// hint: if a user just logged on -> there is no active system cached
|
|
var sourceSystem = false;
|
|
if(
|
|
activeSystemCache &&
|
|
activeSystemCache.data('systemId') !== currentCharacterLog.system.id
|
|
){
|
|
|
|
// draw new connection
|
|
sourceSystem = activeSystemCache;
|
|
// calculate new system coordinates
|
|
requestData.systemData.position = calculateNewSystemPosition(sourceSystem);
|
|
}
|
|
|
|
mapElement.getMapOverlay('timer').startMapUpdateCounter();
|
|
|
|
saveSystem(map, requestData, sourceSystem, false);
|
|
}
|
|
|
|
// trigger document event -> update header
|
|
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
|
|
}
|
|
|
|
return returnStatus;
|
|
};
|
|
|
|
/**
|
|
* collect all map data for export/save for a map
|
|
* this function returns the "client" data NOT the "server" data for a map
|
|
* @param options
|
|
* @returns {*}
|
|
*/
|
|
$.fn.getMapDataFromClient = function(options){
|
|
|
|
var mapElement = $(this);
|
|
|
|
var map = getMapInstance( mapElement.data('id') );
|
|
|
|
var mapData = {};
|
|
|
|
// check if there is an active map counter that prevents collecting map data
|
|
var overlay = mapElement.getMapOverlay('timer');
|
|
var counterChart = overlay.getMapCounter();
|
|
|
|
var interval = counterChart.data('interval');
|
|
|
|
if(
|
|
! interval ||
|
|
options.forceData === true
|
|
){
|
|
|
|
// map config -----------------------------------------------------------
|
|
var mapConfig = {};
|
|
mapConfig.id = parseInt( mapElement.data('id') );
|
|
mapConfig.name = mapElement.data('name');
|
|
mapConfig.scope = {
|
|
id: parseInt( mapElement.data('scopeId') )
|
|
};
|
|
mapConfig.icon = mapElement.data('icon');
|
|
mapConfig.type = {
|
|
id: parseInt( mapElement.data('typeId') )
|
|
};
|
|
mapConfig.created = parseInt( mapElement.data('created') );
|
|
mapConfig.updated = parseInt( mapElement.data('updated') );
|
|
mapData.config = mapConfig;
|
|
|
|
// map data -------------------------------------------------------------
|
|
var data = {};
|
|
|
|
// systems data ---------------------------------------------------------
|
|
var systemsData = [];
|
|
var systems = mapElement.find('.' + config.systemClass);
|
|
|
|
for(var i = 0; i < systems.length; i++){
|
|
var tempSystem = $(systems[i]);
|
|
|
|
// check if system data should be added
|
|
var addSystemData = true;
|
|
if(
|
|
options.checkForChange === true &&
|
|
!tempSystem.hasChanged()
|
|
){
|
|
addSystemData = false;
|
|
}
|
|
|
|
if(addSystemData){
|
|
systemsData.push( tempSystem.getSystemData() );
|
|
}
|
|
}
|
|
|
|
data.systems = systemsData;
|
|
|
|
// connections ----------------------------------------------------------
|
|
var connections = map.getAllConnections();
|
|
var connectionsFormatted = [];
|
|
|
|
// new connections cache
|
|
var updatedConnectionCache = {};
|
|
|
|
// format connections
|
|
for(var j = 0; j < connections.length; j++){
|
|
var tempConnection = connections[j];
|
|
|
|
// check if connection data should be added
|
|
var addConnectionData = true;
|
|
if(
|
|
options.checkForChange === true &&
|
|
!$(tempConnection).hasChanged()
|
|
){
|
|
addConnectionData = false;
|
|
}
|
|
|
|
var connectionData = getDataByConnection(tempConnection);
|
|
|
|
if(addConnectionData){
|
|
connectionsFormatted.push( connectionData );
|
|
}
|
|
|
|
// add to cache
|
|
updatedConnectionCache[connectionData.id] = tempConnection;
|
|
}
|
|
|
|
// overwrite connection cache
|
|
connectionCache[mapConfig.id] = updatedConnectionCache;
|
|
|
|
data.connections = connectionsFormatted;
|
|
|
|
mapData.data = data;
|
|
}else{
|
|
return false;
|
|
}
|
|
|
|
return mapData;
|
|
};
|
|
|
|
/**
|
|
* get all relevant data for a system object
|
|
* @returns {{}}
|
|
*/
|
|
$.fn.getSystemData = function(){
|
|
var system = $(this);
|
|
|
|
var systemData = {};
|
|
systemData.id = parseInt( system.data('id') );
|
|
systemData.systemId = parseInt( system.data('systemId') );
|
|
systemData.name = system.data('name');
|
|
systemData.alias = system.getSystemInfo(['alias']);
|
|
systemData.effect = system.data('effect');
|
|
systemData.type = {
|
|
id: system.data('typeId')
|
|
};
|
|
systemData.security = system.data('security');
|
|
systemData.trueSec = system.data('trueSec');
|
|
systemData.region = {
|
|
id: system.data('regionId'),
|
|
name: system.data('region')
|
|
};
|
|
systemData.constellation = {
|
|
id: system.data('constellationId'),
|
|
name: system.data('constellation')
|
|
};
|
|
systemData.status = {
|
|
id: system.data('statusId')
|
|
};
|
|
systemData.locked = system.data('locked') ? 1 : 0;
|
|
systemData.rally = system.data('rally') ? 1 : 0;
|
|
systemData.currentUser = system.data('currentUser'); // if user is currently in this system
|
|
systemData.statics = system.data('statics');
|
|
systemData.updated = {
|
|
updated: parseInt( system.data('updated') )
|
|
};
|
|
systemData.userCount = (system.data('userCount') ? parseInt( system.data('userCount') ) : 0);
|
|
|
|
// position -----------------------------------------------------------------
|
|
var positionData = {};
|
|
var currentX = system.css('left');
|
|
var currentY = system.css('top');
|
|
|
|
// remove 'px'
|
|
positionData.x = parseInt( currentX.substring(0, currentX.length - 2) );
|
|
positionData.y = parseInt( currentY.substring(0, currentY.length - 2) );
|
|
|
|
systemData.position = positionData;
|
|
|
|
return systemData;
|
|
};
|
|
|
|
/**
|
|
* get all relevant data for a connection object
|
|
* @param connection
|
|
* @returns {{id: Number, source: Number, sourceName: (*|T|JQuery|{}), target: Number, targetName: (*|T|JQuery), scope: *, type: *, updated: Number}}
|
|
*/
|
|
var getDataByConnection = function(connection){
|
|
|
|
var source = $(connection.source);
|
|
var target = $(connection.target);
|
|
|
|
var id = connection.getParameter('connectionId');
|
|
var updated = connection.getParameter('updated');
|
|
|
|
var connectionTypes = connection.getType();
|
|
|
|
// normalize connection array
|
|
connectionTypes = $.grep(connectionTypes, function(n){
|
|
if(
|
|
n.length > 0 &&
|
|
n !== 'default' // this is added by jsplumb by default -_-
|
|
){
|
|
return true;
|
|
}else{
|
|
return false;
|
|
}
|
|
});
|
|
|
|
var data = {
|
|
id: id ? id : 0,
|
|
source: parseInt( source.data('id') ),
|
|
sourceName: source.data('name'),
|
|
target: parseInt( target.data('id') ),
|
|
targetName: target.data('name'),
|
|
scope: connection.scope,
|
|
type: connectionTypes,
|
|
updated: updated ? updated : 0
|
|
};
|
|
|
|
return data;
|
|
};
|
|
|
|
|
|
/**
|
|
* get a new jsPlumb map instance or or get a cached one for update
|
|
* @param mapId
|
|
* @returns {*}
|
|
*/
|
|
var getMapInstance = function(mapId){
|
|
|
|
if(typeof activeInstances[mapId] !== 'object'){
|
|
// create new instance
|
|
jsPlumb.Defaults.LogEnabled = true;
|
|
|
|
var newJsPlumbInstance = jsPlumb.getInstance({
|
|
Anchor: 'Continuous', // anchors on each site
|
|
Container: null, // will be set as soon as container is connected to DOM
|
|
PaintStyle:{
|
|
lineWidth: 4, // width of a Connector's line. An integer.
|
|
strokeStyle: 'red', // color for a Connector
|
|
outlineColor: 'red', // color of the outline for an Endpoint or Connector. see fillStyle examples.
|
|
outlineWidth: 2 // width of the outline for an Endpoint or Connector. An integer.
|
|
},
|
|
Connector:[ 'Bezier', { curviness: 40 } ], // default connector style (this is not used!) all connections have their own style (by scope)
|
|
Endpoints: [ [ 'Dot', { radius: 5 } ], [ 'Dot', { radius: 5 } ] ],
|
|
// Endpoint: 'Blank', // does not work... :(
|
|
ReattachConnections: false, // re-attach connection if dragged with mouse to "nowhere"
|
|
Scope: Init.defaultMapScope, // default map scope for connections
|
|
LogEnabled: true
|
|
});
|
|
|
|
// register all available connection types ------------------------------
|
|
newJsPlumbInstance.registerConnectionTypes(globalMapConfig.connectionTypes);
|
|
|
|
// event after a new connection is established --------------------------
|
|
newJsPlumbInstance.bind('connection', function(info, e) {
|
|
// set connection observer
|
|
setConnectionObserver(newJsPlumbInstance, info.connection);
|
|
});
|
|
|
|
// event after connection moved -----------------------------------------
|
|
newJsPlumbInstance.bind('connectionMoved', function(info, e) {
|
|
|
|
});
|
|
|
|
// event after DragStop a connection or new connection ------------------
|
|
newJsPlumbInstance.bind('beforeDrop', function(info) {
|
|
var connection = info.connection;
|
|
|
|
// lock the target system for "click" events
|
|
// to prevent loading system information
|
|
var sourceSystem = $('#' + info.sourceId);
|
|
var targetSystem = $('#' + info.targetId);
|
|
sourceSystem.addClass('no-click');
|
|
targetSystem.addClass('no-click');
|
|
setTimeout(function(){
|
|
sourceSystem.removeClass('no-click');
|
|
targetSystem.removeClass('no-click');
|
|
}, Init.timer.DBL_CLICK + 50);
|
|
|
|
// set "default" connection status only for NEW connections
|
|
if(!connection.suspendedElement){
|
|
setConnectionWHStatus(connection, getDefaultConnectionTypeByScope(connection.scope) );
|
|
}
|
|
|
|
// prevent multiple connections between same systems
|
|
var connections = checkForConnection(newJsPlumbInstance, info.sourceId, info.targetId );
|
|
|
|
if(connections.length > 1){
|
|
bootbox.confirm('Connection already exists. Do you really want to add an additional one?', function(result) {
|
|
if(!result){
|
|
connection._jsPlumb.instance.detach(connection);
|
|
}
|
|
});
|
|
}
|
|
|
|
// always save the new connection
|
|
saveConnection(connection);
|
|
|
|
return true;
|
|
});
|
|
|
|
// event before Detach connection ---------------------------------------
|
|
newJsPlumbInstance.bind('beforeDetach', function(info) {
|
|
return true;
|
|
});
|
|
|
|
newJsPlumbInstance.bind('connectionDetached', function(info, e){
|
|
// a connection is manually (drag&drop) detached! otherwise this event should not be send!
|
|
var connection = info.connection;
|
|
$().deleteConnections([connection]);
|
|
});
|
|
|
|
newJsPlumbInstance.bind('checkDropAllowed', function(params){
|
|
// connections can not be attached to foreign endpoints
|
|
// the only endpoint available is endpoint from where the connection was dragged away (re-attach)
|
|
|
|
return true;
|
|
});
|
|
|
|
activeInstances[mapId] = newJsPlumbInstance;
|
|
}
|
|
|
|
return activeInstances[mapId];
|
|
};
|
|
|
|
/**
|
|
* load OR updates system map
|
|
* @param mapConfig
|
|
*/
|
|
$.fn.loadMap = function(mapConfig, options){
|
|
|
|
// parent element where the map will be loaded
|
|
var parentElement = $(this);
|
|
|
|
// add context menus to dom (if not already
|
|
initMapContextMenu();
|
|
initConnectionContextMenu();
|
|
initSystemContextMenu();
|
|
|
|
// new map init
|
|
var newMap = false;
|
|
|
|
// init jsPlumb
|
|
jsPlumb.ready(function() {
|
|
// get new map instance or load existing
|
|
mapConfig.map = getMapInstance(mapConfig.config.id);
|
|
|
|
// check for map Container -> first time initialization
|
|
if(mapConfig.map.getContainer() === undefined){
|
|
// new map instance
|
|
newMap = true;
|
|
}
|
|
|
|
// draw/update map initial map and set container
|
|
var mapContainer = updateMap(parentElement, mapConfig);
|
|
|
|
if(newMap){
|
|
// init custom scrollbars and add overlay
|
|
parentElement.initMapScrollbar();
|
|
}
|
|
|
|
// callback function after tab switch
|
|
function switchTabCallback( mapName ){
|
|
Util.showNotify({title: 'Map initialized', text: mapName + ' - loaded', type: 'success'});
|
|
|
|
return false;
|
|
}
|
|
|
|
if(options.showAnimation){
|
|
// show nice visualization effect
|
|
mapContainer.visualizeMap('show', function(){
|
|
switchTabCallback( mapConfig.config.name );
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* init scrollbar for Map element
|
|
*/
|
|
$.fn.initMapScrollbar = function(){
|
|
// get Map Scrollbar
|
|
var scrollableElement = $(this).find('.' + config.mapWrapperClass);
|
|
initCustomScrollbar( scrollableElement );
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// add map overlays after scrollbar is initialized
|
|
// because of its absolute position
|
|
scrollableElement.initMapOverlays();
|
|
};
|
|
|
|
/**
|
|
* init a custom scrollbar
|
|
* @param scrollableElement
|
|
*/
|
|
var initCustomScrollbar = function( scrollableElement ){
|
|
|
|
// prevent multiple initialization
|
|
$(scrollableElement).mCustomScrollbar('destroy');
|
|
|
|
// init custom scrollbars
|
|
$(scrollableElement).mCustomScrollbar({
|
|
axis: 'x',
|
|
theme: 'light-thick',
|
|
scrollInertia: 300,
|
|
autoExpandScrollbar: false,
|
|
scrollButtons:{
|
|
scrollAmount: 30,
|
|
enable: true
|
|
},
|
|
callbacks:{
|
|
onTotalScrollOffset: 0,
|
|
onTotalScrollBackOffset: 0,
|
|
alwaysTriggerOffsets:true,
|
|
onScrollStart: function(){
|
|
// hide all open xEditable fields
|
|
$(this).find('.editable').editable('hide');
|
|
|
|
// hide all system head tooltips
|
|
$(this).find('.' + config.systemHeadClass + ' .fa').tooltip('hide');
|
|
},
|
|
whileScrolling:function(){
|
|
// update scroll position for drag-frame-selection
|
|
var mapElement = $(scrollableElement).find('.' + config.mapClass);
|
|
$(mapElement).data('scrollLeft', this.mcs.left);
|
|
$(mapElement).data('scrollTop', this.mcs.top);
|
|
}
|
|
},
|
|
|
|
advanced: {
|
|
updateOnBrowserResize: true,
|
|
updateOnContentResize: true,
|
|
autoExpandHorizontalScroll: true,
|
|
autoScrollOnFocus: "div"
|
|
},
|
|
mouseWheel:{
|
|
enable: false, // scroll weel currently disabled
|
|
scrollAmount: 'auto',
|
|
axis: 'x',
|
|
preventDefault: true
|
|
},
|
|
scrollbarPosition: 'inside',
|
|
autoDraggerLength: true
|
|
//autoHideScrollbar: false
|
|
});
|
|
};
|
|
|
|
/**
|
|
* scroll to a specific position in the map
|
|
* @returns {*} // string or id
|
|
*/
|
|
$.fn.scrollTo = function(position){
|
|
return this.each(function(){
|
|
$(this).mCustomScrollbar('scrollTo', position);
|
|
});
|
|
};
|
|
|
|
}); |